# ftp.pl, by Roger Espel Llima # # this is an ftp client integrated into sirc. once loaded, it provides # the following commands: # # /ftp open ftp.site ftp.site can be a hostname or a full ftp URL # in the form # ftp://user:password@hostname:port/path/to/file # or just user@hostname. if no user is specified, # sirc attempts an anonymous login. if the file # is not specified, it acts like an interactive # ftp client # # /ftp list lists all currently open ftp connections. the # "list" can be omitted # # /ftp quit quits an established ftp session. can be shortened # /ftp close to /ftp q. # # /ftp cwd does a cwd (change working directory). can be # shortened to "cd" # # /ftp mkdir changes the current directory. "md" also works. # # /ftp rmdir erases a directory. "rd" also works. # # /ftp delete deletes a file. "rm", "del" and "dele" also work. # # /ftp break interrupts a running transfer. "abor" also works # # /ftp rename renames a file. "ren" and "mv" also work. # # /ftp dir lists files. "ls" also works. # # /ftp binary sets binary mode. "bin" also works. # # /ftp ascii sets ASCII mode. # # /ftp get file [name] gets a file; if a name is specified, it is used # as the local name to save the file as. # # most of these commands have shortcut aliases: # /fopen, /fdir, /fls, /fcd, /fget, /fmkdir, /fmd, /frmdir, /frd # /fquit, /fq # global variables: # # $ftpopen : have a control connection # $ftpactive : have a data connection # $ftpfopen : have a file open # $ftpwait : waiting for a data connection # $ftpuser : username # $ftppass : password # $ftpport : ftp port # $ftpfile : filename to download # $ftpxfermsg : what we're currently xferring # $ftpxferbytes : bytes so far # $ftpfh : control connection fh # $ftpdfh : data connection fh # $ftpffh : file fh # $ftpstart : time of the connection # $ftprename : new name in a rename operation # $ftpquit : quit after one get $add_ons.="+ftp.pl" if $add_ons !~ /ftp/; sub ftpcleanup { &remsel($ftpfh); close $ftpfh; if ($ftpwait || $ftpactive) { &remsel($ftpdfh); close $ftpdfh; } close $ftpffh if $ftpfopen; $ftpopen = $ftpactive = $ftpwait = $ftpfopen = $ftpquit = 0; $ftpfile = ""; } $ftpopen = $ftpactive = $ftpwait = $ftpfopen = 0; sub ftpmakeport { local($c1, $c2, $c3, $c4)=unpack("C4", $bindaddr); return "$c1,$c2,$c3,$c4," . int($ftpport/256) . "," . ($ftpport%256); } sub cmd_ftp { &getarg; $ftpquit = 0 unless $newarg =~ /^zoinx$/i; if ($newarg =~ /^o(pen)?$/i) { &tell("*\cbE\cb* You already have an open ftp session, use /ftp close"). return if $ftpopen; &getarg; $newarg =~ s/^ftp\:\/\///; if ($newarg =~ /^([^\@]+\@)?([^\:\/]+)(:\d+)?(\/.*)?$/) { ($ftpuser, $ftphost, $ftpport, $ftpfile, $ftppass)=($1, $2, $3, $4, ''); $ftpuser =~ s/\@$//; $ftppass = $1 if $ftpuser =~ s/:(.*)$//; $ftpport =~ s/^://; $ftpport = 21 unless $ftpport; $ftpuser = "anonymous" if $ftpuser eq ''; $ftppass = "$username\@" if $ftppass eq '' && ($ftpuser eq 'anonymous' || $ftpuser eq 'ftp'); &connect($ftpfh, $ftphost, $ftpport) || return; $ftpopen = 1; &addsel($ftpfh, "ftp", 1); } else { &tell("*\cbE\cb* Use: /ftp open [user[:passwd]\@]ftp.host[:port]"); } } elsif (!$ftpopen) { &tell("*\cbE\cb* No open ftp session"); } elsif ($newarg =~ /^(list)?$/i) { if ($ftpuser =~ /^(anonymous|ftp)$/i) { &tell("*\cbF\cb* anonymous FTP connection established with $ftphost"); } else { &tell("*\cbF\cb* FTP connection established with $ftphost, userid $ftpuser"); } if ($ftpactive) { &tell("*\cbF\cb* Currently $ftpxfermsg, $ftpxferbytes bytes so far"); } elsif ($ftpwait) { &tell("*\cbF\cb* Waiting for data connection..."); } } elsif ($newarg =~ /^(q|quit|close)$/i) { &ftpcleanup; &tell("*\cbF\cb* FTP session closed"); } elsif ($newarg =~ /^(cd|cwd)$/i) { &getarg; &tell("*\cbE\cb* I need a directory name"), return if $newarg eq ''; print $ftpfh "CWD $newarg\n"; } elsif ($newarg =~ /^(md|mkdir)$/i) { &getarg; &tell("*\cbE\cb* I need a directory name"), return if $newarg eq ''; print $ftpfh "MKD $newarg\n"; } elsif ($newarg =~ /^(rd|rmdir)$/i) { &getarg; &tell("*\cbE\cb* I need a directory name"), return if $newarg eq ''; print $ftpfh "RMD $newarg\n"; } elsif ($newarg =~ /^(del|dele|delete|rm)$/i) { &getarg; &tell("*\cbE\cb* I need a file name"), return if $newarg eq ''; print $ftpfh "DELE $newarg\n"; } elsif ($newarg =~ /^(break|abor|abort)$/i) { &tell("*\cbE\cb* No established connection"), return unless $ftpwait || $ftpactive; &tell("*\cbF\cb* Aborting connection"); print $ftpfh "ABOR\n"; if ($ftpwait || $ftpactive) { &remsel($ftpdfh); close $ftpdfh; $ftpwait = $ftpactive = 0; } if ($ftpfopen) { close $ftpffh; $ftpfopen = 0; } } elsif ($newarg =~ /^(ren|rename|mv)$/i) { &getarg; &tell("*\cbE\cb* I need two file names"), return if $newarg eq '' || $args eq ''; print $ftpfh "RNFR $newarg\n"; &getarg; $ftprename=$newarg; } elsif ($newarg =~ /^(ls|dir)$/i) { &tell("*\cbE\cb* There is an active transfer, break it with /ftp break"), return if $ftpactive || $ftpwait; $ftpport = &listen($ftpdfh) || return; print $ftpfh "PORT ".&ftpmakeport()."\n"; if ($args eq '') { print $ftpfh "LIST\n"; } else { print $ftpfh "LIST $args\n"; } $ftpwait = 1; &addsel($ftpdfh, "ftplist1", 0); } elsif ($newarg =~ /^bin(ary)?/i) { print $ftpfh "TYPE I\n"; } elsif ($newarg =~ /^ascii/i) { print $ftpfh "TYPE A\n"; } elsif ($newarg =~ /^(get|zoinx)$/i) { &getarg; &tell("*\cbE\cb* I need a filename"), return if $newarg eq ''; &tell("*\cbE\cb* There is an active transfer, break it with /ftp break"), return if $ftpactive || $ftpwait; local($rf, $lf)=($newarg); &getarg; $ftpxfermsg = "getting $rf"; $lf = ($newarg ne '' ? $newarg : $rf); $lf =~ s/^.*\///; $ftpffh=&newfh; &tell("*\cbE\cb* Can't write to ${lf}!"), return unless open($ftpffh, "> $lf"); select($ftpffh); $|=1; select(STDOUT); $ftpfopen=1; $ftpport = &listen($ftpdfh); if ($ftpport == 0) { close $ftpffh; $ftpfopen = 0; return; } print $ftpfh "PORT ".&ftpmakeport()."\n"; print $ftpfh "RETR $rf\n"; $ftpwait = 1; &addsel($ftpdfh, "ftpget1", 0); $ftpstart = time; } elsif ($newarg =~ /^(put|send)$/i) { &tell("*\cbE\cb* FTP PUT is not implemented"); } else { &tell("*\cbE\cb* FTP command not understood"); } } &addcmd("ftp"); sub sel_ftplist1 { local($nfh); &remsel($ftpdfh); if (&accept($nfh, $ftpdfh)) { $ftpdfh = $nfh; &addsel($ftpdfh, "ftplist2", 1); $ftpwait = 0; $ftpactive = 1; $ftpxfermsg = "getting a file list"; $ftpxferbytes = 0; } else { &tell("*\cbE\cb* FTP protocol error"); $ftpwait = $ftpactive = 0; } } sub sel_ftpget1 { local($nfh); &remsel($ftpdfh); if (&accept($nfh, $ftpdfh)) { $ftpdfh = $nfh; &addsel($ftpdfh, "ftpget2", 0); $ftpwait = 0; $ftpactive = 1; $ftpxferbytes = 0; } else { &tell("*\cbE\cb* FTP protocol error"); $ftpwait = $ftpactive = $ftpfopen = 0; close $ftpffh; } } sub sel_ftplist2 { local($l)=@_; if ($l eq '') { $ftpwait = $ftpactive = 0; &tell("*\cbF\cb* End of list"); } else { $ftpxferbytes += length($l); chop($l); &tell("*\cbF\cb* $l"); } } sub sel_ftpget2 { local($a, $buf)=(0, ''); $a = sysread($ftpdfh, $buf, 4096); if ($a) { $ftpxferbytes += $a; print $ftpffh $buf; } else { close $ftpdfh; close $ftpffh; &remsel($ftpdfh); $ftpwait = $ftpactive = $ftpfopen = 0; if ($ftpquit) { &tell("*\cbF\cb* FTP session terminated; $ftpxferbytes transferred in " . (time - $ftpstart) . " seconds"); &ftpcleanup; } else { &tell("*\cbF\cb* FTP transfer terminated; $ftpxferbytes transferred in " . (time - $ftpstart) . " seconds"); } } } sub sel_ftp { local($l)=@_; if ($l eq '') { &ftpcleanup; &tell("*\cbE\cb* FTP connection lost"); return; } chop($l); &tell("*\cbF\cb* $l") unless $l =~ /^331 / || ($ftpfile ne '' && ($l =~ /^\d\d\d-/ || $l =~ /^200/)); if ($ftphookcwd) { return if $l =~ /^200/ || $l =~ /^250-/; $ftphookcwd = 0; if ($l =~ /^250/) { &docommand("ftp zoinx $ftpfile"); $ftpfile = ""; $ftpquit = 1; return; } } if ($l =~ /^\d\d\d-/ || $l =~ /^226/) { # nothing } elsif ($l =~ /^(220|530)/) { print $ftpfh "USER $ftpuser\n"; } elsif ($l =~ /^230/) { print $ftpfh "TYPE I\n"; if ($ftpfile) { local($path); $path=$1 if $ftpfile =~ s/^(.*)\///; if ($ftpfile ne '') { print $ftpfh "CWD $path\n"; $ftphookcwd = 1; } } } elsif ($l =~ /^331/) { if ($ftppass ne '') { print $ftpfh "PASS $ftppass\n"; } else { &getuserpass("*\cbF\cb* Password for $ftpuser? ", "Passwd: "); print $ftpfh "PASS $_\n"; } } elsif ($l =~ /^350/) { print $ftpfh "RNTO $ftprename\n"; } elsif ($l =~ /^550/) { if ($ftpwait) { $ftpwait = 0; &remsel($ftpdfh); close $ftpdfh; } if ($ftpfopen) { $ftpfopen = 0; close $ftpffh; } $ftpfile = $ftphookcwd = 0; } } &docommand("^alias fopen ftp open"); &docommand("^alias fdir ftp dir"); &docommand("^alias fls ftp dir"); &docommand("^alias fcd ftp cd"); &docommand("^alias fget ftp get"); &docommand("^alias fmkdir ftp mkdir"); &docommand("^alias fmd ftp mkdir"); &docommand("^alias frmdir ftp rmdir"); &docommand("^alias frd ftp rmdir"); &docommand("^alias fquit ftp quit"); &docommand("^alias fq ftp quit");