(*@\\\*)
(*@/// procedure t_http.DoBasicAuthorization(const username,password:string); *)
procedure t_http.DoBasicAuthorization(const username,password:string);
var
h: TMemoryStream;
encoded: TStringlist;
begin
f_author:=username+':'+password;
h:=NIL;
encoded:=NIL;
try
h:=TMemoryStream.Create;
stream_write_s(h,f_author);
encoded:=encode_base64(h);
if encoded.count>0 then
f_author:='Basic '+encoded.strings[0];
finally
h.free;
encoded.free;
end;
end;
(*@\\\0000000C1D*)
(*@\\\0000000501*)
(*@/// class t_ftp(t_tcpip) *)
(*@/// constructor t_ftp.Create(Aowner:TComponent); *)
constructor t_ftp.Create(Aowner:TComponent);
begin
inherited create(AOwner);
f_port:=21;
f_user:='ftp';
f_password:='nobody@nowhere'; (* only to make it running without setting user/password *)
f_passive:=true;
f_mode:=tftp_download;
f_cur_dir:=TStringlist.Create;
f_comm_socket:=INVALID_SOCKET;
f_busy:=false;
f_dir_stream:=TMemorystream.Create;
end;
(*@\\\*)
(*@/// destructor t_ftp.Destroy; *)
destructor t_ftp.Destroy;
begin
f_cur_dir.free;
f_dir_stream.free;
inherited destroy;
end;
(*@\\\0000000301*)
(*@/// procedure t_ftp.action; *)
procedure t_ftp.action;
begin
login;
TMemorystream(f_stream).clear;
case f_mode of
tftp_download: download;
tftp_upload: upload;
tftp_getdir: getdir('.');
end;
logout;
end;
(*@\\\0000000303*)
(*@/// procedure t_ftp.response; *)
procedure t_ftp.response;
var
s: string;
begin
s:=self.read_line_comm;
if assigned(f_tracer) then
f_tracer(s,tt_proto_get);
try
f_status_nr:=strtoint(copy(s,1,3));
except
f_status_nr:=999;
end;
f_status_txt:=copy(s,5,length(s));
if f_status_nr>=400 then
raise EProtocolError.Create('FTP',f_status_txt,f_status_nr);
(* if the answer consists of several lines read and discard all the following *)
while (pos('-',s)=4) or (pos(' ',s)=1) do begin
s:=self.read_line_comm;
if assigned(f_tracer) then
f_tracer(s,tt_proto_get);
end;
end;
(*@\\\0000000701*)
(*@/// procedure t_ftp.login; // USER and PASS commands *)
procedure t_ftp.login;
begin
f_socket_number:=f_port;
inherited login;
f_comm_socket:=f_socket;
self.response; (* Read the welcome message *)
self.SendCommand('USER '+f_user);
self.response;
{ self.SendCommand('PASS '+f_password); }
write_s(f_comm_socket,'PASS '+f_password+#13#10);
if assigned(f_tracer) then
f_tracer('PASS ******',tt_proto_sent);
self.response;
self.SendCommand('TYPE I'); (* always use binary *)
self.response;
end;
(*@\\\0000000301*)
(*@/// procedure t_ftp.logout; // QUIT command *)
procedure t_ftp.logout;
begin
if f_busy then self.abort;
if f_logged_in then begin
if f_comm_socket<>INVALID_SOCKET then begin
self.SendCommand('QUIT');
self.response;
end;
if f_socket<>invalid_socket then
closesocket(f_socket);
f_socket:=f_comm_socket;
f_comm_socket:=INVALID_SOCKET;
end;
inherited logout;
end;
(*@\\\0000000406*)
(*@/// procedure t_ftp.getdir(const dirname:string); // LIST command *)
procedure t_ftp.getdir(const dirname:string);
begin
if f_busy then raise(EProtocolBusy.create);
if not f_logged_in then login;
if (dirname='') then EXIT;
get_datasocket;
self.SendCommand('TYPE A');
self.response;
self.SendCommand('LIST '+dirname);
self.response;
f_mode_intern:=tftp_getdir;
f_busy:=true;
TMemorystream(f_dir_stream).clear;
if not f_async_data then begin
while do_read do ;
f_eof:=false;
self.response;
finish_getdir;
end
else begin
winsock.WSAAsyncSelect(f_comm_socket,f_handle,uwm_socketevent,fd_read);
f_eof:=false;
f_async:=true;
self.response;
f_async:=false;
winsock.WSAAsyncSelect(f_comm_socket,f_handle,uwm_socketevent,0);
finish_getdir;
end;
end;
(*@\\\0000000501*)
(*@/// procedure t_ftp.download; // RETR command *)
procedure t_ftp.download;
begin
if f_busy then raise(EProtocolBusy.create);
if not f_logged_in then login;
if f_url<>'' then begin
self.SendCommand('SIZE '+f_url); (* can I use the path here? *)
try
self.response;
f_size:=strtoint(f_status_txt);
except
f_size:=0;
end;
get_datasocket;
self.SendCommand('RETR '+f_url); (* can I use the path here? *)
self.response;
f_mode_intern:=tftp_download;
f_busy:=true;
TMemorystream(f_stream).clear;
if not f_async_data then begin
while do_read do ;
f_eof:=false;
self.response;
finish_download;
end
else begin
winsock.WSAAsyncSelect(f_comm_socket,f_handle,uwm_socketevent,fd_read);
f_eof:=false;
f_async:=true;
self.response;
f_async:=false;
winsock.WSAAsyncSelect(f_comm_socket,f_handle,uwm_socketevent,0);
finish_download;
end;
end;
end;
(*@\\\0000000907*)
(*@/// procedure t_ftp.upload; // STOR command *)
procedure t_ftp.upload;
begin
if f_busy then raise(EProtocolBusy.create);
if not f_logged_in then login;
if f_url<>'' then begin
get_datasocket;
self.SendCommand('STOR '+f_url); (* can I use the path here? *)
self.response;
f_mode_intern:=tftp_upload;
f_busy:=true;
f_size:=TMemorystream(f_stream).size;
TMemorystream(f_stream).seek(0,0);
if not f_async_data then begin
while do_write do;
finish_upload;
end
else begin
winsock.WSAAsyncSelect(f_comm_socket,f_handle,uwm_socketevent,fd_read);
finish_upload;
winsock.WSAAsyncSelect(f_comm_socket,f_handle,uwm_socketevent,0);
end;
end;
end;
(*@\\\0000000B0B*)
(*@/// procedure t_ftp.abort; // ABOR command *)
procedure t_ftp.abort;
begin
if f_busy then begin
self.SendCommand('ABOR');
try
self.response;
except
on EProtocolError do begin
if f_status_nr<>426 then
raise EProtocolError.Create('FTP',f_status_txt,f_status_nr)
else begin
self.response;
f_busy:=false;
end;
end;
end;
end;
end;
(*@\\\0000000301*)
(*@/// procedure t_ftp.noop; // NOOP command *)
procedure t_ftp.noop;
begin
if f_busy then raise(EProtocolBusy.create);
if not f_logged_in then login;
self.SendCommand('NOOP');
self.response;
end;
(*@\\\0000000501*)
(*@/// procedure t_ftp.changedir(const f_dir:string); // CWD command *)
procedure t_ftp.changedir(const f_dir:string);
begin
if f_busy then raise(EProtocolBusy.create);
if not f_logged_in then login;
self.SendCommand('CWD '+f_dir);
self.response;
end;
(*@\\\*)
(*@/// procedure t_ftp.removefile(const filename:string); // DELE command *)
procedure t_ftp.removefile(const filename:string);
begin
if f_busy then raise(EProtocolBusy.create);
if not f_logged_in then login;
self.SendCommand('DELE '+filename);
self.response;
end;
(*@\\\*)
(*@/// procedure t_ftp.removedir(const dirname:string); // RMD command *)
procedure t_ftp.removedir(const dirname:string);
begin
if f_busy then raise(EProtocolBusy.create);
if not f_logged_in then login;
self.SendCommand('RMD '+dirname);
self.response;
end;
(*@\\\*)
(*@/// procedure t_ftp.makedir(const dirname:string); // MKD command *)
procedure t_ftp.makedir(const dirname:string);
begin
if f_busy then raise(EProtocolBusy.create);
if not f_logged_in then login;
self.SendCommand('MKD '+dirname);
self.response;
end;
(*@\\\*)
(*@/// procedure t_ftp.renamefile(const prior,after:string); // RNFR and RNTO commands *)
procedure t_ftp.renamefile(const prior,after:string);
begin
if f_busy then raise(EProtocolBusy.create);
if not f_logged_in then login;
self.SendCommand('RNFR '+prior);
self.response;
self.SendCommand('RNTO '+after);
self.response;
end;
(*@\\\*)
(*@/// function t_ftp.do_write:boolean; *)
function t_ftp.do_write:boolean;
var
ok:integer;
begin
result:=false;
if f_socket=invalid_socket then EXIT;
ok:=f_stream.read(f_buffer^,buf_size);
if ok>0 then
write_buf(f_socket,f_buffer^,ok);
result:=ok>0;
end;
(*@\\\0000000501*)
(*@/// function t_ftp.do_read:boolean; *)
function t_ftp.do_read:boolean;
var
ok,ok2:integer;
h:integer;
p: pointer;
begin
result:=false;
if f_socket=invalid_socket then EXIT;
read_var(f_socket,f_buffer^,buf_size,ok);
p:=f_buffer;
h:=ok;
while ok>0 do begin (* just to be sure everything goes into the stream *)
ok2:=0; (* Delphi 2 shut up! *)
case f_mode_intern of
tftp_download: ok2:=f_stream.write(p^,ok);
tftp_getdir: ok2:=f_dir_stream.write(p^,ok);
end;
dec(ok,ok2);
p:=pointer(longint(p)+ok2);
end;
result:=h>0;
if assigned(f_ondata_got) then
f_ondata_got(self,f_mode_intern,h);
end;
(*@\\\0000000901*)
(*@/// procedure t_ftp.finish_upload; *)
procedure t_ftp.finish_upload;
begin
while do_write do ;
f_eof:=false;
shutdown(f_socket,1);
closesocket(f_socket);
f_async:=true;
self.response;
f_async:=false;
if assigned(f_onaction) then
f_onaction(self,f_mode_intern);
f_busy:=false;
end;
(*@\\\0000000901*)
(*@/// procedure t_ftp.finish_download; *)
procedure t_ftp.finish_download;
begin
while do_read do ;
f_eof:=false;
shutdown(f_socket,1);
closesocket(f_socket);
f_stream.seek(0,0); (* set the stream back to start *)
if assigned(f_onaction) then
f_onaction(self,f_mode_intern);
f_busy:=false;
end;
(*@\\\0000000701*)
(*@/// procedure t_ftp.finish_getdir; *)
procedure t_ftp.finish_getdir;
begin
f_eof:=false;
while do_read do ;
f_eof:=false;
shutdown(f_socket,1);
closesocket(f_socket);
self.SendCommand('TYPE I'); (* always use binary *)
self.response;
f_dir_stream.seek(0,0); (* set the stream back to start *)
f_cur_dir.clear;
f_cur_dir.LoadFromStream(f_dir_stream);
f_dir_stream.clear;
f_cur_dir_index:=0;
if assigned(f_onaction) then
f_onaction(self,f_mode_intern);
f_busy:=false;
end;
(*@\\\0000000901*)
(*@/// procedure t_ftp.get_datasocket; *)
procedure t_ftp.get_datasocket;
var
po: integer;
ip: longint;
s,t: string;
temp_socket: TSocket;
SockInfo:TSockAddr;
f_data_socket_number: smallint;
begin
f_socket:=INVALID_SOCKET;
(*@/// if self.passive then ask for the port and open the socket active *)
if self.passive then begin
self.SendCommand('PASV');
self.response;
if f_status_nr<>227 then
raise EProtocolError.Create('FTP',f_status_txt,f_status_nr)
else begin
s:=copy(f_status_txt,pos('(',f_status_txt)+1,length(f_status_txt));
s:=copy(s,1,pos(')',s)-1);
po:=posn(',',s,4);
t:=copy(s,1,po-1);
while pos(',',t)<>0 do
t[pos(',',t)]:='.';
(*@/// ip_address:=Winsock.Inet_Addr(PChar(t)); { try a xxx.xxx.xxx.xx } *)
(*$ifdef ver80 *)
t:=t+#0;
ip_address:=Winsock.Inet_Addr(PChar(@t[1])); (* try a xxx.xxx.xxx.xx first *)
(*$else *)
(*$ifopt h- *)
t:=t+#0;
ip_address:=Winsock.Inet_Addr(PChar(@t[1])); (* try a xxx.xxx.xxx.xx first *)
(*$else *)
ip_address:=Winsock.Inet_Addr(PChar(t)); (* try a xxx.xxx.xxx.xx first *)
(*$endif *)
(*$endif *)
(*@\\\0000000801*)
s:=copy(s,po+1,length(s));
try
f_data_socket_number:=strtoint(copy(s,1,pos(',',s)-1))*256
+strtoint(copy(s,pos(',',s)+1,length(s)));
f_socket:=self.create_socket;
if f_async_data then
winsock.WSAAsyncSelect(f_socket,f_handle,uwm_socketevent+1,
fd_connect or fd_read or fd_write or fd_accept);
self.connect_socket(f_socket, f_data_socket_number, ip_address);
except
f_socket:=INVALID_SOCKET;
end;
end;
end
(*@\\\0000000F01*)
(*@/// else send the port and open the socket passive *)
else begin
ip:=my_ip_address;
self.SendCommand('PORT '+inttostr(ip and $000000ff )+','+
inttostr(ip and $0000ff00 shr 8)+','+
inttostr(ip and $00ff0000 shr 16)+','+
inttostr(ip and $ff000000 shr 24)+','+
inttostr(f_port and $ff00 shr 8 )+','+
inttostr(f_port and $00ff ));
self.response;
open_socket_in(f_socket,f_port,ip);
(* take the first out of the queue and close the listening socket *)
if not f_async_data then begin
temp_socket:=accept_socket_in(f_socket,SockInfo);
if temp_socket=INVALID_SOCKET then
{do nothing}
else begin
close_socket(f_socket); (* no more listening necessary *)
f_socket:=temp_socket;
end;
end;
end;
(*@\\\0000000B01*)
if f_async_data and (f_socket<>INVALID_SOCKET) then
winsock.WSAAsyncSelect(f_socket,f_handle,uwm_socketevent+1,
fd_connect or fd_read or fd_write or fd_accept);
end;