(*@/// Parse a FTP directory line into a filedata record (UNIX and DOS style only) *)
const month_string: array[0..11] of string =
('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
(*@/// function getmonth(const s:string):integer; Month -> Integer *)
function getmonth(const s:string):integer;
var
i: integer;
begin
result:=0;
for i:=0 to 11 do
if s=month_string[i] then begin
result:=i+1;
EXIT;
end;
end;
(*@\\\0000000301*)
const
empty_filedata:t_filedata=
(filetype:ft_none; size:0; name:''; datetime:0);
(*@/// function parse_line_unix(const s: string):t_filedata; *)
function parse_line_unix(const v: string):t_filedata;
(* known problems: filename with spaces (most unix's don't allow the anyway) *)
(* links aren't parsed at all *)
var
t,date: string;
y,m,d,h,n,s: word;
begin
try
case v[1] of
'd': result.filetype:=ft_dir;
'-': result.filetype:=ft_file;
'l': result.filetype:=ft_link;
end;
result.name:=copy(v,posn(' ',v,-1)+1,length(v));
t:=copy(v,12,length(v)-length(result.name)-12);
date:=copy(t,length(t)-11,12);
decodedate(now,y,m,d);
h:=0; n:=0; s:=0;
if pos(':',date)>0 then begin
h:=strtoint(copy(date,8,2));
n:=strtoint(copy(date,11,2));
end
else
y:=strtoint(copy(date,9,4));
d:=strtoint(trim(copy(date,5,2)));
m:=getmonth(copy(date,1,3));
t:=copy(t,1,length(t)-13);
result.size:=strtoint(copy(t,posn(' ',t,-1)+1,length(t)));
result.datetime:=encodedate(y,m,d)+encodetime(h,n,s,0);
except
result:=empty_filedata;
end;
end;
(*@\\\0000000201*)
(*@/// function parse_line_dos(const s: string):t_filedata; *)
function parse_line_dos(const v: string):t_filedata;
(* known problems: filename with spaces (why do something like that?) *)
var
t: string;
sd,st: string;
ds: char;
begin
ds:=DateSeparator;
sd:=ShortdateFormat;
st:=Shorttimeformat;
try
if pos('<DIR>',v)=0 then
result.filetype:=ft_file
else
result.filetype:=ft_dir;
result.name:=copy(v,posn(' ',v,-1)+1,length(v));
t:=copy(v,1,length(v)-length(result.name)-1);
result.size:=strtoint('0'+copy(t,posn(' ',t,-1)+1,length(t)));
DateSeparator:='-';
ShortDateFormat:='mm/dd/yy';
Shorttimeformat:='hh:nnAM/PM';
result.datetime:=strtodatetime(copy(t,1,17));
except
result:=empty_filedata;
end;
DateSeparator:=ds;
ShortdateFormat:=sd;
Shorttimeformat:=st;
end;
(*@\\\0000000201*)
(*@/// function parse_ftp_line(const s:string):t_filedata; *)
function parse_ftp_line(const s:string):t_filedata;
begin
if copy(s,1,5)='total' then (* first line for some UNIX ftp server *)
result:=empty_filedata
else if s[1] in ['d','l','-','s'] then
result:=parse_line_unix(s)
else if s[1] in ['0'..'9'] then
result:=parse_line_dos(s);
end;
(*@\\\0000000301*)
(*@\\\0000000401*)
(*@/// procedure stream_write_s(h:TMemoryStream; const s:string); // string -> stream *)
procedure stream_write_s(h:TMemoryStream; const s:string);
var
buf: pointer;
begin
buf:=@s[1];
h.write(buf^,length(s));
end;
(*@\\\0000000301*)
const
back_log=2; (* possible values 1..5 *)
fingerd_timeout=5;
buf_size=$7f00; (* size of the internal standard buffer *)
(*@/// class EProtocolError(ETcpIpError) *)
constructor EProtocolError.Create(const proto,Msg:String; number:word);
begin
Inherited Create(Msg);
protocoll:=proto;
errornumber:=number;
end;
(*@\\\0000000301*)
(*@/// class ESocketError(ETcpIpError) *)
constructor ESocketError.Create(number:word);
begin
inherited create('Error creating socket');
errornumber:=number;
end;
(*@\\\*)
(*@/// class EProtocolBusy(ETcpIpError) *)
constructor EProtocolBusy.Create;
begin
inherited create('Protocol busy');
end;
(*@\\\0000000301*)
(*@/// procedure parse_url(const url:string; var proto,user,pass,host,port,path:string); *)
procedure parse_url(const url:string; var proto,user,pass,host,port,path:string);
(* standard syntax of an URL:
protocol://[user[:password]@]server[:port]/path *)
var
p,q: integer;
s: string;
begin
proto:='';
user:='';
pass:='';
host:='';
port:='';
path:='';
p:=pos('://',url);
if p=0 then begin
if lowercase(copy(url,1,7))='mailto:' then begin (* mailto:// not common *)
proto:='mailto';
p:=pos(':',url);
end;
end
else begin
proto:=copy(url,1,p-1);
inc(p,2);
end;
s:=copy(url,p+1,length(url));
p:=pos('/',s);
if p=0 then p:=length(s)+1;
path:=copy(s,p,length(s));
s:=copy(s,1,p-1);
p:=posn(':',s,-1);
if p>length(s) then p:=0;
q:=posn('@',s,-1);
if q>length(s) then q:=0;
if (p=0) and (q=0) then begin (* no user, password or port *)
host:=s;
EXIT;
end
else if q<p then begin (* a port given *)
port:=copy(s,p+1,length(s));
host:=copy(s,q+1,p-q-1);
if q=0 then EXIT; (* no user, password *)
s:=copy(s,1,q-1);
end
else begin
host:=copy(s,q+1,length(s));
s:=copy(s,1,q-1);
end;
p:=pos(':',s);
if p=0 then
user:=s
else begin
user:=copy(s,1,p-1);
pass:=copy(s,p+1,length(s));
end;
end;
(*@\\\0000003C07*)
{ The base component }
(*@/// class t_tcpip(TComponent) *)
(*@/// constructor t_tcpip.Create(Aowner:TComponent); *)
constructor t_tcpip.Create(Aowner:TComponent);
begin
inherited create(AOwner);
{ f_buffer:=NIL; }
getmem(f_buffer,buf_size);
f_stream:=TMemorystream.Create;
f_Socket:=INVALID_SOCKET;
ip_address:=INVALID_IP_ADDRESS;
(* A windows dummy handle to get messages *)
f_handle:=AllocateHwnd(self.WndProc);
f_async:=false;
f_logged_in:=false;
end;
(*@\\\0000000C03*)
(*@/// destructor t_tcpip.Destroy; *)
destructor t_tcpip.Destroy;
begin
f_tracer:=NIL;
if f_buffer<>NIL then
freemem(f_buffer,buf_size);
f_stream.free;
if f_socket<>invalid_socket then
logout;
DeallocateHwnd(f_Handle);
inherited destroy;
end;
(*@\\\0000000301*)
(*@/// procedure t_tcpip.WndProc(var Msg : TMessage); *)
procedure t_tcpip.WndProc(var Msg : TMessage);
begin
if msg.msg=uwm_socketevent then begin
if msg.lparamhi=socket_error then
else begin
case msg.lparamlo of
(*@/// fd_read: *)
fd_read: begin
f_newdata:=true;
end;
(*@\\\0000000213*)
end;
end;
end
else
dispatch(msg);
end;
(*@\\\0000000701*)
(*@/// function t_tcpip.Create_Socket:TSocket; *)
function t_tcpip.Create_Socket:TSocket;
begin
result:=Winsock.Socket(PF_INET,SOCK_STREAM,IPPROTO_IP);
end;
(*@\\\*)
(*@/// procedure t_tcpip.bind_socket(var socket:TSocket; out_port_min,out_port_max: word); *)
procedure t_tcpip.bind_socket(var socket:TSocket; out_port_min,out_port_max: word);
var
LocalAddress : TSockAddr;
i: word;
begin
with LocalAddress do begin
Sin_Family:=PF_INET;
Sin_addr.S_addr:=INADDR_ANY;
end;
i:=out_port_min;
while i<=out_port_max do begin
LocalAddress.Sin_Port:=Winsock.htons(i);
if Winsock.bind(socket,LocalAddress,
SizeOf(LocalAddress))<>SOCKET_ERROR then BREAK;
inc(i);
end;
end;
(*@\\\0000000401*)
(*@/// procedure t_tcpip.connect_socket(var socket:TSocket; Socket_number:smallint;ip_address:longint); *)
procedure t_tcpip.connect_socket(var socket:TSocket; Socket_number:smallint;ip_address:longint);
var
RemoteAddress : TSockAddr;
begin
with RemoteAddress do begin
Sin_Family:=PF_INET;
Sin_Port:=Winsock.htons(Socket_number);
Sin_addr:=TInAddr(ip_address);
end;
if Winsock.Connect(Socket,RemoteAddress,
SizeOf(RemoteAddress))=SOCKET_ERROR then begin
if winsock.WSAGetLastError<>wsaewouldblock then begin
Close_Socket(socket);
if assigned(f_tracer) then
f_tracer('Failed to open output socket '+inttostr(Socket_number)+' to host '+
ip2string(ip_address),tt_socket);
end
end
else
if assigned(f_tracer) then
f_tracer('Opened output socket '+inttostr(Socket_number)+' to host '+
ip2string(ip_address)+' successfully; ID '+inttostr(socket),
tt_socket);
end;
(*@\\\000E00101C00101C00101C00101C*)
(*@/// procedure t_tcpip.open_socket_out(var socket:TSocket; Socket_number:smallint;ip_address:longint); *)
procedure t_tcpip.open_socket_out(var socket:TSocket; Socket_number:smallint;ip_address:longint);
begin
close_socket(socket);
socket:=Create_Socket;
connect_socket(socket,Socket_number,ip_address);
end;
(*@\\\0000000501*)
(*@/// procedure t_tcpip.open_socket_in(var socket:TSocket; Socket_number:smallint;ip_address:longint); *)
procedure t_tcpip.open_socket_in(var socket:TSocket; Socket_number:smallint;ip_address:longint);
var
LocalAddress : TSockAddr;
begin
close_socket(socket);
f_Socket:=Create_Socket;
(*@/// open the socket and let it listen *)
with LocalAddress do begin
Sin_Family:=PF_INET;
Sin_Port:=Winsock.htons(Socket_number);
Sin_addr:=TInAddr(ip_address);
end;
if Winsock.bind(socket,LocalAddress,
SizeOf(LocalAddress))=SOCKET_ERROR then begin
if assigned(f_tracer) then
f_tracer('Failed to bind socket '+inttostr(Socket_number)+' for local ip '+
ip2string(ip_address),tt_socket);
Close_Socket(socket);
EXIT;
end
else
if assigned(f_tracer) then
f_tracer('Bound to socket '+inttostr(Socket_number)+' for local ip '+
ip2string(ip_address),tt_socket);
if Winsock.Listen(Socket,back_log)=SOCKET_ERROR then begin
Close_Socket(socket);
if assigned(f_tracer) then
f_tracer('Failed to set input socket '+inttostr(Socket_number)+
' to listening mode',tt_socket);
end
else
if assigned(f_tracer) then
f_tracer('Set input socket '+inttostr(Socket_number)+
' to listening mode sucessfully; ID '+inttostr(socket),tt_socket);
(*@\\\0030000A18000A18001123*)
end;
(*@\\\0000000701*)
(*@/// function t_tcpip.accept_socket_in(socket:TSocket; var SockInfo:TSockAddr):TSocket; *)
function t_tcpip.accept_socket_in(socket:TSocket; var SockInfo:TSockAddr):TSocket;
var
x: u_int;
LocalAddress : TSockAddr;
temp_socket: TSocket;
begin
x:=SizeOf(LocalAddress);
(*$ifndef ver100 *)
temp_socket:=Winsock.Accept(Socket,LocalAddress,x);
(*$else *) { Delphi 3 ARGH! }
temp_socket:=Winsock.Accept(Socket,@LocalAddress,@x);
(*$endif *)
if temp_socket=SOCKET_ERROR then begin
(* no incoming call available *)
temp_socket:=INVALID_SOCKET;
if assigned(f_tracer) then
f_tracer('No incoming connection found on socket ID '+inttostr(Socket),
tt_socket);
end
else
if assigned(f_tracer) then
f_tracer('Incoming connection found on socket ID '+inttostr(Socket)+
'; generated socket ID '+inttostr(temp_socket),tt_socket);
accept_socket_in:=temp_socket;
sockinfo:=LocalAddress;
end;
(*@\\\0000001748*)
(*@/// function t_tcpip.socket_state(socket:TSocket):T_Socket_State; *)
function t_tcpip.socket_state(socket:TSocket):T_Socket_State;
var
peer_adr: TSockAddr;
x: u_int;
begin
if socket=INVALID_SOCKET then
socket_state:=invalid
else begin
x:=sizeof(TSockAddr);
if winsock.getpeername(socket,peer_adr,x)=0 then
socket_state:=connected
else begin
if winsock.WSAGetLastError<>WSAENOTCONN then
socket_state:=state_unknown
else
socket_state:=valid
end;
end;
end;