sdlwebftp.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. unit sdlwebftp;
  2. {******************************************************************************}
  3. {
  4. $Id: sdlwebftp.pas,v 1.2 2005/01/02 19:03:15 savage Exp $
  5. }
  6. { }
  7. { Borland Delphi SDL_Net - A x-platform network library for use with SDL.}
  8. { Conversion of the Simple DirectMedia Layer Network Headers }
  9. { }
  10. { Portions created by Sam Lantinga <[email protected]> are }
  11. { Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga }
  12. { 5635-34 Springhouse Dr. }
  13. { Pleasanton, CA 94588 (USA) }
  14. { }
  15. { All Rights Reserved. }
  16. { }
  17. { The original files are : SDL_net.h }
  18. { }
  19. { The initial developer of this Pascal code was : }
  20. { Dean Ellis <[email protected]> }
  21. { }
  22. { Portions created by Dean Ellis are }
  23. { Copyright (C) 2000 - 2001 Dean Ellis. }
  24. { }
  25. { }
  26. { Contributor(s) }
  27. { -------------- }
  28. { }
  29. { }
  30. { Obtained through: }
  31. { Joint Endeavour of Delphi Innovators ( Project JEDI ) }
  32. { }
  33. { You may retrieve the latest version of this file at the Project }
  34. { JEDI home page, located at http://delphi-jedi.org }
  35. { }
  36. { The contents of this file are used with permission, subject to }
  37. { the Mozilla Public License Version 1.1 (the "License"); you may }
  38. { not use this file except in compliance with the License. You may }
  39. { obtain a copy of the License at }
  40. { http://www.mozilla.org/MPL/MPL-1.1.html }
  41. { }
  42. { Software distributed under the License is distributed on an }
  43. { "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or }
  44. { implied. See the License for the specific language governing }
  45. { rights and limitations under the License. }
  46. { }
  47. { Description }
  48. { ----------- }
  49. { }
  50. { }
  51. { }
  52. { }
  53. { }
  54. { }
  55. { }
  56. { Requires }
  57. { -------- }
  58. { sdlweb.pas somehere in your search path }
  59. { }
  60. { Programming Notes }
  61. { ----------------- }
  62. { }
  63. { }
  64. { }
  65. { }
  66. { Revision History }
  67. { ---------------- }
  68. {
  69. $Log: sdlwebftp.pas,v $
  70. Revision 1.2 2005/01/02 19:03:15 savage
  71. Slight Bug fix due to stray closed comment ( Thanks Michalis Kamburelis )
  72. Revision 1.1 2004/12/31 00:30:14 savage
  73. Initial release of Dean's excellent SDL Web classes. Demo coming soon.
  74. }
  75. {******************************************************************************}
  76. interface
  77. uses
  78. Classes,
  79. sdlweb;
  80. type
  81. TFTPFiletype = ( ftNone, ftDir, ftFile, ftLink );
  82. TFTPRemoteFile = record
  83. Type_ : TFTPFiletype;
  84. Size : integer;
  85. Name : string;
  86. Datetime : TDateTime;
  87. end;
  88. TFTPRemoteDirectory = TStringList;
  89. // TFTPRemoteDirectory = record
  90. // Files:array of TFTPRemoteFile;
  91. // DirectoryName: string;
  92. // end;
  93. TFTPDownloadProgress = procedure( Position, Max : Integer );
  94. function SDLWeb_FTP_Login( var Connection : TSDLWebConnection;
  95. Username, Password : string; DirectoryInfo : TFTPRemoteDirectory ) : Boolean;
  96. function SDLWeb_FTP_Logout( var Connection : TSDLWebConnection ) : Boolean;
  97. function SDLWeb_FTP_GetDirectory( var Connection : TSDLWebConnection;
  98. ADirectory : string; DirectoryInfo : TFTPRemoteDirectory ) : Boolean;
  99. function SDLWeb_FTP_ChangeDirectory( var Connection : TSDLWebConnection;
  100. ADirectory : string ) : Boolean;
  101. function SDLWeb_FTP_DownloadToStream( var Connection : TSDLWebConnection;
  102. AFilename : string; var Download : TStream; Progress : TFTPDownloadProgress = nil ) : Boolean;
  103. implementation
  104. uses
  105. SysUtils,
  106. sdl_net;
  107. function ReadFTPStatus( var Connection : TSDLWebConnection; var Status : Integer; var Data : string ) : Boolean;
  108. var
  109. S : string;
  110. begin
  111. SDLWeb_ReadResponse( Connection, S );
  112. Status := StrToInt( Copy( S, 1, 3 ) );
  113. Data := Copy( S, 5, Length( S ) );
  114. Result := Status <= 400;
  115. end;
  116. {------------------------------------------------------------------------------}
  117. {Extracts Port and IP data from the string provided usially in
  118. <text> (128,0,0,0,7,534) }
  119. {------------------------------------------------------------------------------}
  120. procedure ExtractIPAndPort( Data : string; var IP : string; var Port : integer );
  121. var
  122. s : string;
  123. po : integer;
  124. begin
  125. s := copy( Data, pos( '(', Data ) + 1, length( Data ) );
  126. s := copy( s, 1, pos( ')', s ) - 1 );
  127. // get the 4th , this is the end of the IP address
  128. po := SDLWeb_Pos( ',', s, 4 );
  129. IP := copy( s, 1, po - 1 );
  130. IP := StringReplace( IP, ',', '.', [ rfReplaceAll ] );
  131. s := copy( s, po + 1, length( s ) );
  132. Port := strtoint( copy( s, 1, pos( ',', s ) - 1 ) ) * 256
  133. + strtoint( copy( s, pos( ',', s ) + 1, length( s ) ) );
  134. end;
  135. function GetFTPDataSocket( var Connection : TSDLWebConnection ) : PTCPSocket;
  136. var
  137. Status, Port : Integer;
  138. Data, IP : string;
  139. DataIP : TIPAddress;
  140. begin
  141. Result := nil;
  142. SDLWeb_SendRequest( Connection, 'PASV' );
  143. if ReadFTPStatus( Connection, Status, Data ) then
  144. begin
  145. ExtractIPAndPort( Data, IP, Port );
  146. if SDLNet_ResolveHost( DataIP, PChar( IP ), Port ) = 0 then
  147. Result := SDLNet_TCP_Open( DataIP );
  148. end;
  149. end;
  150. function SDLWeb_FTP_Login( var Connection : TSDLWebConnection;
  151. Username, Password : string; DirectoryInfo : TFTPRemoteDirectory ) : Boolean;
  152. var
  153. Status : Integer;
  154. Data : string;
  155. begin
  156. Result := False;
  157. if Connection.Type_ <> wcFTP then
  158. Exit;
  159. if not ReadFTPStatus( Connection, Status, Data ) then
  160. Exit;
  161. SDLWeb_SendRequest( Connection, 'USER ftp' );
  162. if not ReadFTPStatus( Connection, Status, Data ) then
  163. Exit;
  164. SDLWeb_SendRequest( Connection, 'PASS ' );
  165. if ReadFTPStatus( Connection, Status, Data ) then
  166. begin
  167. SDLWeb_SendRequest( Connection, 'TYPE I' );
  168. if not ReadFTPStatus( Connection, Status, Data ) then
  169. Exit;
  170. if DirectoryInfo <> nil then
  171. Result := SDLWeb_FTP_GetDirectory( Connection, '.', DirectoryInfo )
  172. else
  173. Result := True;
  174. end;
  175. end;
  176. function SDLWeb_FTP_Logout( var Connection : TSDLWebConnection ) : Boolean;
  177. var
  178. Status : Integer;
  179. Data : string;
  180. begin
  181. SDLWeb_SendRequest( Connection, 'QUIT' );
  182. Result := ReadFTPStatus( Connection, Status, Data );
  183. end;
  184. function ReadFTPData( var Socket : PTCPSocket; var Dest : TStream; var Buffer : Pointer ) : Boolean;
  185. var
  186. i, l : integer;
  187. lp : Pointer;
  188. begin
  189. l := SDLNet_TCP_Recv( Socket, Buffer, 1024 );
  190. Result := l > 0;
  191. lp := Buffer;
  192. if Result then
  193. begin
  194. while l > 0 do
  195. begin
  196. //i := 0;
  197. i := Dest.Write( lp^, l );
  198. dec( l, i );
  199. lp := pointer( longint( lp ) + i );
  200. end;
  201. end;
  202. end;
  203. function SDLWeb_FTP_GetDirectory( var Connection : TSDLWebConnection;
  204. ADirectory : string; DirectoryInfo : TFTPRemoteDirectory ) : Boolean;
  205. var
  206. Status : Integer;
  207. Data : string;
  208. Buffer : Pointer;
  209. DirectoryStream : TStream;
  210. DataSocket : PTCPSocket;
  211. begin
  212. Result := False;
  213. if ADirectory = EmptyStr then
  214. Exit;
  215. DataSocket := GetFTPDataSocket( Connection );
  216. if DataSocket = nil then
  217. Exit;
  218. try
  219. SDLWeb_SendRequest( Connection, 'TYPE A' );
  220. if ReadFTPStatus( Connection, Status, Data ) then
  221. begin
  222. SDLWeb_SendRequest( Connection, 'LIST ' + ADirectory );
  223. if ReadFTPStatus( Connection, Status, Data ) then
  224. begin
  225. GetMem( Buffer, 1024 );
  226. DirectoryStream := TMemoryStream.Create;
  227. try
  228. while ReadFTPData( DataSocket, DirectoryStream, Buffer ) do
  229. ;
  230. if ReadFTPStatus( Connection, Status, Data ) then
  231. begin
  232. SDLWeb_SendRequest( Connection, 'TYPE I' );
  233. Result := ReadFTPStatus( Connection, Status, Data );
  234. DirectoryStream.Position := 0;
  235. DirectoryInfo.Clear;
  236. DirectoryInfo.LoadFromStream( DirectoryStream );
  237. end;
  238. finally
  239. DirectoryStream.Free;
  240. FreeMem( Buffer );
  241. end;
  242. end;
  243. end;
  244. finally
  245. SDLNet_TCP_Close( DataSocket );
  246. end;
  247. end;
  248. function SDLWeb_FTP_ChangeDirectory( var Connection : TSDLWebConnection;
  249. ADirectory : string ) : Boolean;
  250. var
  251. Status : Integer;
  252. Data : string;
  253. begin
  254. SDLWeb_SendRequest( Connection, 'CWD ' + ADirectory );
  255. Result := ReadFTPStatus( Connection, Status, Data );
  256. end;
  257. function SDLWeb_FTP_DownloadToStream( var Connection : TSDLWebConnection;
  258. AFilename : string; var Download : TStream; Progress : TFTPDownloadProgress = nil ) : Boolean;
  259. var
  260. Status, FileSize : Integer;
  261. Data : string;
  262. DataSocket : PTCPSocket;
  263. Buffer : Pointer;
  264. procedure DoProgress;
  265. begin
  266. if Assigned( Progress ) then
  267. Progress( Download.Position, FileSize );
  268. end;
  269. begin
  270. // Download a file to a stream
  271. Result := False;
  272. SDLWeb_SendRequest( Connection, 'SIZE ' + AFilename );
  273. if ReadFTPStatus( Connection, Status, Data ) then
  274. begin
  275. FileSize := StrToInt( Data );
  276. DataSocket := GetFTPDataSocket( Connection );
  277. if DataSocket = nil then
  278. Exit;
  279. try
  280. SDLWeb_SendRequest( Connection, 'RETR ' + AFilename );
  281. if ReadFTPStatus( Connection, Status, Data ) then
  282. begin
  283. GetMem( Buffer, 1024 );
  284. if Download = nil then
  285. Download := TMemoryStream.Create;
  286. try
  287. DoProgress;
  288. while ReadFTPData( DataSocket, Download, Buffer ) do
  289. DoProgress;
  290. if ReadFTPStatus( Connection, Status, Data ) then
  291. begin
  292. SDLWeb_SendRequest( Connection, 'TYPE I' );
  293. Result := ReadFTPStatus( Connection, Status, Data );
  294. DoProgress;
  295. Download.Position := 0;
  296. end;
  297. finally
  298. FreeMem( Buffer );
  299. end;
  300. end;
  301. finally
  302. SDLNet_TCP_Close( DataSocket );
  303. end;
  304. end;
  305. end;
  306. end.