#pragma ident "@(#)ftp.c 1.9 94/08/25"
/*
* Copyright (c) 1985, 1989 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char sccsid[] = "@(#)ftp.c 5.38 (Berkeley) 4/22/91";
#endif /* not lint */
#include "ftptool.h"
#include "ftp_var.h"
#ifdef USE_PROTOTYPES
int ftp_hookup(char *host, short port)
#else
int ftp_hookup(host, port)
char *host;
short port;
#endif
{
register struct hostent *hp = 0;
int s, len;
static char hostnamebuf[MAXHOSTNAMELEN + 1];
char *ftperr;
code = 0;
bzero((char *)&hisctladdr, sizeof (hisctladdr));
hisctladdr.sin_addr.s_addr = inet_addr(host);
if (hisctladdr.sin_addr.s_addr != -1) {
hisctladdr.sin_family = AF_INET;
(void) strncpy(hostnamebuf, host, sizeof (hostnamebuf));
} else {
hp = gethostbyname(host);
if (hp == NULL) {
if (try_proxy)
footer_message("%s unknown. Trying proxy.",
host);
else
footer_message("%s: unknown host", host);
code = -1;
return (1);
}
hisctladdr.sin_family = hp->h_addrtype;
bcopy(hp->h_addr_list[0],
(caddr_t)&hisctladdr.sin_addr, hp->h_length);
(void) strncpy(hostnamebuf, hp->h_name, sizeof (hostnamebuf));
}
s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
if (s < 0) {
perror("ftptool: socket");
code = -1;
return (0);
}
hisctladdr.sin_port = port;
while (connect(s, (struct sockaddr *)&hisctladdr,
sizeof (hisctladdr)) < 0) {
if (hp && hp->h_addr_list[1]) {
extern char *inet_ntoa();
sprintf(scratch, "connect to address %s: %s",
inet_ntoa(hisctladdr.sin_addr), strerror(errno));
log_message(scratch);
hp->h_addr_list++;
bcopy(hp->h_addr_list[0],
(caddr_t)&hisctladdr.sin_addr, hp->h_length);
sprintf(scratch, "Trying %s...",
inet_ntoa(hisctladdr.sin_addr));
log_message(scratch);
footer_message(scratch);
(void) close(s);
s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
if (s < 0) {
perror("ftptool: socket");
code = -1;
return (0);
}
continue;
}
code = -1;
if ((errno == ENETUNREACH) || (errno == EHOSTUNREACH) ||
(errno == ETIMEDOUT)) {
if (try_proxy)
footer_message("%s unreachable. Trying proxy.",
host);
(void) close(s);
return (1);
}
sprintf(scratch, "connect: %s: %s", host, strerror(errno));
footer_message(scratch);
goto bad;
}
len = sizeof (myctladdr);
if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
perror("ftptool: getsockname");
code = -1;
goto bad;
}
#ifdef SYSV386
hp = gethostbyname(myhostname);
myctladdr.sin_family = hp->h_addrtype;
bcopy(hp->h_addr_list[0], (caddr_t)&myctladdr.sin_addr, hp->h_length);
#endif
responsefp = fdopen(s, "r");
commandfp = fdopen(s, "w");
if (responsefp == NULL || commandfp == NULL) {
fprintf(stderr, "ftptool: fdopen failed.\n");
close_files();
code = -1;
goto bad;
}
if (verbose) {
sprintf(scratch, "Connected to %s.\n", hostnamebuf);
log_message(scratch);
}
if (getreply(0) > 2) { /* read startup message from server */
close_files();
code = -1;
ftperr = ftp_error(' ', "Service not available.");
footer_message(ftperr);
goto bad;
}
/*
* Could get:
* Connected to sun-barr.ebay.sun.com.
* The Internet FTP relay is down for system maintenance.
* Please try again later this weekend.
* Sorry for any inconvenience.
* Network Operations
* 421 Service not available, remote server has closed connection
*/
if (!strncmp(response_line, "The Internet", 12)) {
footer_message("The proxy FTP relay is down. Try again later.");
close_files();
code = -1;
goto bad;
}
#ifdef SO_OOBINLINE
{
int on = 1;
if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on,
sizeof (on)) < 0 && debug) {
perror("ftptool: setsockopt");
}
}
#endif /* SO_OOBINLINE */
return (2);
bad:
(void) close(s);
return (0);
}
#ifdef USE_PROTOTYPES
int ftp_login(char *user, char *pass, char *acct)
#else
int ftp_login(user, pass, acct)
char *user;
char *pass;
char *acct;
#endif
{
int n;
char *ftperr;
int aflag;
n = command("USER %s", user);
/*
* We may have just consumed some startup messages from a
* server that spews them at connection, but we only grabbed
* the sun-barr one.
*/
if (code == 220) {
cpend = 1;
n = getreply(0);
} else if (code == 0) {
/* for nic.ddn.mil */
while (code == 0 || code == 220) {
cpend = 1;
n = getreply(0);
}
}
if (code == 500) {
/* sun-barr.ebay doesn't recognize host */
/* 500 yavin: unknown host */
/* 500 connect: connection timed out */
ftperr = ftp_error(' ', "Connect failed.");
footer_message(ftperr);
quit_ftp();
} else if (code == 530) {
/* XXX login unknown */
/* login failed */
ftperr = ftp_error(' ', "Connect failed. Login unknown.");
footer_message(ftperr);
quit_ftp();
} else if (code == 421) {
footer_message("Service not available.");
quit_ftp();
}
/* Contact line is in the Sorry line */
/* 421 Service not available (for Iftp ) */
if (!strncmp(response_line, "Sorry", 5)) {
ftperr = "Connect failed. This host is directly reachable.";
footer_message(ftperr);
quit_ftp();
return (0);
}
if (n == CONTINUE) {
code = 0;
n = command("PASS %s", pass);
if (n == ERROR || code == 421) {
if (code == 421)
ftperr = &response_line[4];
else
ftperr = ftp_error(' ', "Connect failed.");
footer_message(ftperr);
quit_ftp();
return (0);
}
}
aflag = 0;
if (n == CONTINUE) {
/* Account needed */
aflag++;
if (acct != NULL)
n = command("ACCT %s", acct);
else
n = command("ACCT %s", "anonymous");
}
if (n != COMPLETE) {
return (0);
}
if (!aflag && acct != NULL && *acct != '\0')
(void) command("ACCT %s", acct);
return (1);
}
#ifdef USE_PROTOTYPES
int command(char *fmt, ...)
#else
/*VARARGS*/
int command(va_alist)
va_dcl
#endif
{
#ifndef USE_PROTOTYPES
char *fmt;
#endif
va_list ap;
int r;
notify_do_dispatch();
abrtflag = 0;
if (commandfp == NULL) {
/*
perror ("No control connection for command");
*/
code = 421;
return (0);
}
#ifdef USE_PROTOTYPES
va_start(ap, fmt);
#else
va_start(ap);
fmt = (char *)va_arg(ap, char *);
#endif
vfprintf(commandfp, fmt, ap);
va_end(ap);
fprintf(commandfp, "\r\n");
(void) fflush(commandfp);
cpend = 1;
r = getreply(!strcmp(fmt, "QUIT"));
return (r);
}
#ifdef USE_PROTOTYPES
int command_dataconn(FILE **a_file, char *lmode, char *fmt, ...)
#else
/*VARARGS2*/
int command_dataconn(a_file, lmode, va_alist)
FILE **a_file;
char *lmode;
va_dcl
#endif
{
#ifndef USE_PROTOTYPES
char *fmt;
#endif
va_list ap;
int r;
notify_do_dispatch();
abrtflag = 0;
if (commandfp == NULL) {
/*
perror ("No control connection for command");
*/
code = 421;
return (0);
}
#ifdef USE_PROTOTYPES
va_start(ap, fmt);
#else
va_start(ap);
fmt = (char *)va_arg(ap, char *);
#endif
vfprintf(commandfp, fmt, ap);
va_end(ap);
fprintf(commandfp, "\r\n");
(void) fflush(commandfp);
#ifdef SYSV386
*a_file = dataconn(lmode);
#endif
cpend = 1;
r = getreply(!strcmp(fmt, "QUIT"));
#ifndef SYSV386
if (r == PRELIM)
*a_file = dataconn(lmode);
#endif
return (r);
}
#include <ctype.h>
#ifdef USE_PROTOTYPES
int getreply(int expecteof)
#else
int getreply(expecteof)
int expecteof;
#endif
{
register int c, n;
register int dig;
register char *cp;
int originalcode = 0, continuation = 0;
int pflag = 0;
for (;;) {
dig = n = code = 0;
cp = response_line;
notify_do_dispatch();
while ((c = getc(responsefp)) != '\n') {
if (c == IAC) { /* handle telnet commands */
switch (c = getc(responsefp)) {
case WILL:
case WONT:
c = getc(responsefp);
fprintf(commandfp,
"%c%c%c", IAC, DONT, c);
(void) fflush(commandfp);
break;
case DO:
case DONT:
c = getc(responsefp);
fprintf(commandfp,
"%c%c%c", IAC, WONT, c);
(void) fflush(commandfp);
break;
default:
break;
}
continue;
}
dig++;
if (c == EOF) {
if (expecteof) {
code = 221;
notify_no_dispatch();
return (0);
}
lostpeer();
if (verbose) {
log_message("421 Service not available, remote server has closed connection\n");
}
code = 421;
notify_no_dispatch();
return (4);
}
if (c != '\r' && (verbose > 0 ||
(verbose > -1 && n == '5' && dig > 4))) {
/*
(void) putchar(c);
*/
log_char(c);
}
if (dig < 4 && isdigit(c))
code = code * 10 + (c - '0');
if (!pflag && code == 227)
pflag = 1;
if (dig > 4 && pflag == 1 && isdigit(c))
pflag = 2;
/*
if (pflag == 2) {
if (c != '\r' && c != ')')
*pt++ = c;
else {
*pt = '\0';
pflag = 3;
}
}
*/
if (dig == 4 && c == '-') {
if (continuation)
code = 0;
continuation++;
}
if (n == 0)
n = c;
if (cp < &response_line[sizeof (response_line) - 1])
*cp++ = c;
}
if (verbose > 0 || (verbose > -1 && n == '5')) {
/*
(void) putchar(c);
*/
log_char(c);
(void) fflush (stdout);
}
if (continuation && code != originalcode) {
if (originalcode == 0)
originalcode = code;
continue;
}
*cp = '\0';
if (n != '1')
cpend = 0;
if (code == 421 || originalcode == 421)
lostpeer();
notify_no_dispatch();
return (n - '0');
}
}
#ifdef USE_PROTOTYPES
int empty(fd_set *mask, int sec)
#else
int empty(mask, sec)
fd_set *mask;
int sec;
#endif
{
struct timeval t;
t.tv_sec = (long) sec;
t.tv_usec = 0;
return (select(32, mask, (fd_set *)NULL, (fd_set *)NULL, &t));
}
#define HASHBYTES 1024
#ifdef USE_PROTOTYPES
int sendrequest(char *cmd, char *local, char *remote, int size)
#else
int sendrequest(cmd, local, remote, size)
char *cmd, *local, *remote;
int size;
#endif
{
struct stat st;
struct timeval start, stop;
register int c, bytes;
long d;
FILE *fin = NULL, *dout = 0, *popen();
int (*closefunc)(), pclose(), fclose();
char *lmode, buf[BUFSIZ], *bufp;
char *ftperr;
int errormsg = 0;
int gettimeofday();
closefunc = NULL;
lmode = "w";
update_status_label("Sending", remote, size);
fin = fopen(local, "r");
if (fin == NULL) {
local_footer_message("Open: %s: %s.", local, strerror(errno));
code = -1;
return (0);
}
closefunc = fclose;
if (fstat(fileno(fin), &st) < 0 ||
(st.st_mode&S_IFMT) != S_IFREG) {
local_footer_message("%s: not a plain file.", local);
fclose(fin);
fin = NULL;
code = -1;
return (1);
}
if (initconn()) {
code = -1;
if (closefunc != NULL)
(*closefunc)(fin);
return (0);
}
if (remote) {
#ifdef SYSV386
if (command_dataconn(&dout, lmode, "%s %s", cmd, remote)
!= PRELIM) {
#else
if (command("%s %s", cmd, remote) != PRELIM) {
#endif
if (closefunc != NULL)
(*closefunc)(fin);
/* Permission denied */
sprintf(scratch, "Put %s failed.", remote);
ftperr = ftp_error(' ', scratch);
local_footer_message(ftperr);
return (1);
}
} else
#ifdef SYSV386
if (command_dataconn(&dout, lmode, "%s", cmd) != PRELIM) {
#else
if (command("%s", cmd) != PRELIM) {
#endif
if (closefunc != NULL)
(*closefunc)(fin);
fprintf(stderr, "command != PRELIM\n");
return (1);
}
#ifndef SYSV386
dout = dataconn(lmode);
#endif
if (dout == NULL)
goto abort;
(void) gettimeofday(&start, (struct timezone *)0);
switch (curtype) {
case TYPE_I:
case TYPE_L:
errno = d = 0;
notify_do_dispatch();
while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) {
if (abort_transfer) {
notify_no_dispatch();
goto abort;
}
for (bufp = buf; c > 0; c -= d, bufp += d)
if ((d = write(fileno(dout), bufp, c)) <= 0) {
break;
} else {
/* change image */
update_status_gauge(d);
}
if (abort_transfer) {
notify_no_dispatch();
goto abort;
}
}
notify_no_dispatch();
if (c < 0) {
footer_message("Read %s: %s.", local, strerror(errno));
errormsg = 1;
}
if (d < 0) {
local_footer_message(
"Write failed (remote file system full?).");
errormsg = 1;
goto abort;
}
break;
case TYPE_A:
notify_do_dispatch();
bytes = 0;
while ((c = getc(fin)) != EOF) {
if (abort_transfer) {
notify_no_dispatch();
goto abort;
}
if (c == '\n') {
if (ferror(dout))
break;
(void) putc('\r', dout);
bytes++;
}
(void) putc(c, dout);
bytes++;
if (bytes >= 1024) {
/* change image */
update_status_gauge(bytes);
bytes = 0;
}
if (abort_transfer) {
notify_no_dispatch();
goto abort;
}
}
notify_no_dispatch();
if (ferror(fin)) {
errormsg = 1;
local_footer_message("%s: %s.", local, strerror(errno));
}
if (ferror(dout)) {
if (errno != EPIPE)
perror("netout");
}
break;
}
(void) gettimeofday(&stop, (struct timezone *)0);
if (closefunc != NULL)
(*closefunc)(fin);
(void) fclose(dout);
dout = NULL;
(void) getreply(0);
if (!errormsg)
local_footer_message("Send of %s complete.", remote);
return (0);
abort:
(void) gettimeofday(&stop, (struct timezone *)0);
if (!cpend) {
code = -1;
return (0);
}
if (data >= 0) {
(void) close(data);
data = -1;
}
if (dout) {
(void) fclose(dout);
dout = NULL;
}
(void) getreply(0);
code = -1;
if (closefunc != NULL && fin != NULL)
(*closefunc)(fin);
if (!errormsg)
local_footer_message("Send of %s aborted.", remote);
return (2);
}
#ifdef USE_PROTOTYPES
int recvrequest(char *cmd, char *local, char *remote,
char *lmode, int size)
#else
int recvrequest(cmd, local, remote, lmode, size)
char *cmd, *local, *remote, *lmode;
int size;
#endif
{
FILE *fout = NULL, *din = 0, *popen();
int (*closefunc)(), pclose(), fclose();
int is_retr, tcrflag, bare_lfs = 0;
register int bytes;
char *gunique();
static int bufsize;
static char *buf;
register int c;
long d;
struct timeval start, stop;
struct stat st;
off_t lseek();
char *ftperr;
int errormsg = 0;
int gettimeofday();
update_status_label("Receiving", remote, size);
is_retr = strcmp(cmd, "RETR") == 0;
closefunc = NULL;
tcrflag = !crflag && is_retr;
if (strcmp(local, "-") && *local != '|') {
if (access(local, 2) < 0) {
char *dir = rindex(local, '/');
if (errno != ENOENT && errno != EACCES) {
footer_message("Access: %s: %s.", local,
strerror(errno));
code = -1;
return (0);
}
if (dir != NULL)
*dir = 0;
d = access(dir ? local : ".", 2);
if (dir != NULL)
*dir = '/';
if (d < 0) {
footer_message("Access: %s: %s.", local,
strerror(errno));
code = -1;
return (0);
}
if (!unique_local_names && errno == EACCES &&
chmod(local, 0600) < 0) {
footer_message("Chmod: %s: %s.", local,
strerror(errno));
code = -1;
return (1);
}
if (unique_local_names && errno == EACCES &&
(local = gunique(local)) == NULL) {
code = -1;
return (1);
}
} else if (unique_local_names &&
(local = gunique(local)) == NULL) {
code = -1;
return (1);
}
}
if (initconn()) {
code = -1;
return (0);
}
if (remote) {
#ifdef SYSV386
if (command_dataconn(&din, "r", "%s %s", cmd, remote)
!= PRELIM){
#else
if (command("%s %s", cmd, remote) != PRELIM) {
#endif
/* Not a plain file */
/* Permission denied */
/* No such file or directory */
sprintf(scratch, "Get %s failed.", remote);
ftperr = ftp_error(' ', scratch);
footer_message(ftperr);
return (1);
}
} else {
#ifdef SYSV386
if (command_dataconn(&din, "r", "%s", cmd) != PRELIM) {
#else
if (command("%s", cmd) != PRELIM) {
#endif
footer_message("command != PRELIM");
/*
fprintf(stderr, "command != PRELIM\n");
*/
return (1);
}
}
#ifndef SYSV386
din = dataconn("r");
#endif
if (din == NULL)
goto abort;
if (strcmp(local, "-") == 0)
fout = stdout;
else if (*local == '|') {
fout = popen(local + 1, "w");
if (fout == NULL) {
perror(local+1);
goto abort;
}
closefunc = pclose;
} else {
fout = fopen(local, lmode);
if (fout == NULL) {
footer_message("Open: %s: %s.", local, strerror(errno));
errormsg = 1;
goto abort;
}
closefunc = fclose;
}
if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
st.st_blksize = BUFSIZ;
if (st.st_blksize > bufsize) {
if (buf)
(void) free(buf);
buf = malloc((unsigned)st.st_blksize);
if (buf == NULL) {
perror("malloc");
bufsize = 0;
goto abort;
}
bufsize = st.st_blksize;
}
(void) gettimeofday(&start, (struct timezone *)0);
switch (curtype) {
case TYPE_I:
case TYPE_L:
errno = d = 0;
notify_do_dispatch();
while ((c = read(fileno(din), buf, bufsize)) > 0) {
if (abort_transfer) {
notify_no_dispatch();
goto abort;
}
if ((d = write(fileno(fout), buf, c)) <= 0)
break;
/* change image */
update_status_gauge(d);
if (d != c)
break;
if (abort_transfer) {
notify_no_dispatch();
goto abort;
}
}
notify_no_dispatch();
if (c < 0) {
if (errno != EPIPE)
perror("netin");
}
if (d < c) {
errormsg = 1;
if (d < 0) {
footer_message("Write failed: %s",
strerror(errno));
goto abort;
} else {
footer_message("Short write: %s",
strerror(errno));
}
}
break;
case TYPE_A:
notify_do_dispatch();
bytes = 0;
while ((c = getc(din)) != EOF) {
if (abort_transfer) {
notify_no_dispatch();
goto abort;
}
if (c == '\n')
bare_lfs++;
while (c == '\r') {
bytes++;
if ((c = getc(din)) != '\n' || tcrflag) {
if (ferror(fout))
goto break2;
(void) putc('\r', fout);
}
}
(void) putc(c, fout);
bytes++;
if (bytes >= 1024) {
/* change image */
update_status_gauge(bytes);
bytes = 0;
}
if (abort_transfer) {
notify_no_dispatch();
goto abort;
}
}
break2:
notify_no_dispatch();
if (bare_lfs) {
fprintf(stderr,
"WARNING! %d bare linefeeds received in ASCII mode\n",
bare_lfs);
fprintf(stderr,
"File may not have transferred correctly.\n");
}
if (ferror(din)) {
if (errno != EPIPE)
perror("netin");
}
if (ferror(fout)) {
errormsg = 1;
footer_message("%s: %s.", local, strerror(errno));
}
break;
}
if (closefunc != NULL)
(*closefunc)(fout);
(void) gettimeofday(&stop, (struct timezone *)0);
(void) fclose(din);
din = NULL;
(void) getreply(0);
if (!errormsg)
footer_message("Receive of %s complete.", remote);
return (0);
abort:
/* abort using RFC959 recommended IP,SYNC sequence */
(void) gettimeofday(&stop, (struct timezone *)0);
if (!cpend) {
code = -1;
return (0);
}
abort_remote(din);
code = -1;
if (data >= 0) {
(void) close(data);
data = -1;
}
if (closefunc != NULL && fout != NULL)
(*closefunc)(fout);
if (din) {
(void) fclose(din);
din = NULL;
}
if (!errormsg)
footer_message("Receive of %s aborted.", remote);
return (2);
}
/*
* Need to start a listen on the data channel before we send the command,
* otherwise the server's connect may fail.
*/
#ifdef USE_PROTOTYPES
int initconn(void)
#else
int initconn()
#endif
{
register char *p, *a;
int result, len, tmpno = 0;
int on = 1;
#ifdef SYSV386
ushort data_port;
#endif
noport:
data_addr = myctladdr;
if (sendport)
data_addr.sin_port = 0; /* let system pick one */
if (data != -1) {
(void) close(data);
data = -1;
}
data = socket(AF_INET, SOCK_STREAM, 0);
if (data < 0) {
perror("ftptool: socket");
if (tmpno)
sendport = 1;
return (1);
}
if (!sendport)
if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
sizeof (on)) < 0) {
perror("ftptool: setsockopt (reuse address)");
goto bad;
}
if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
perror("ftptool: bind");
goto bad;
}
len = sizeof (data_addr);
if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
perror("ftptool: getsockname");
goto bad;
}
if (listen(data, 1) < 0)
perror("ftptool: listen");
if (sendport) {
a = (char *)&data_addr.sin_addr;
#ifdef SYSV386
data_port = htons(data_addr.sin_port);
p = (char *)&data_port;
p[0] += p[1]; /* Switches variables, without a temp var */
p[1] = p[0] - p[1];
p[0] -= p[1];
#else
p = (char *)&data_addr.sin_port;
#endif
#define UC(b) (((int)b)&0xff)
result = command("PORT %d,%d,%d,%d,%d,%d",
UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
UC(p[0]), UC(p[1]));
if (result == ERROR && sendport == -1) {
sendport = 0;
tmpno = 1;
goto noport;
}
return (result != COMPLETE);
}
if (tmpno)
sendport = 1;
return (0);
bad:
(void) close(data), data = -1;
if (tmpno)
sendport = 1;
return (1);
}
#ifdef USE_PROTOTYPES
FILE *dataconn(char *lmode)
#else
FILE *dataconn(lmode)
char *lmode;
#endif
{
struct sockaddr_in from;
int s, fromlen = sizeof (from);
restart:
s = accept(data, (struct sockaddr *) &from, &fromlen);
if (s < 0) {
if (errno == EINTR)
goto restart;
perror("ftptool: accept");
(void) close(data);
data = -1;
return (NULL);
}
(void) close(data);
data = s;
return (fdopen(data, lmode));
}
#ifdef USE_PROTOTYPES
char *gunique(char *local)
#else
char *gunique(local)
char *local;
#endif
{
static char new[MAXPATHLEN + 1];
static char first[MAXPATHLEN + 1], last[MAXNAMLEN + 1];
char *slash;
int d, count = 0;
extern char *newname; /* from view_remote_file */
if ((strlen(local) + 3) > (size_t)MAXPATHLEN) {
sprintf(scratch, "Unique name for %s too long.", local);
footer_message(scratch);
log_message(scratch);
log_char('\n');
return (NULL);
}
slash = rindex(local, '/');
if (slash) {
*slash = '\0';
strcpy(first, local);
strcpy(last, slash + 1);
*slash = '/';
} else {
*first = '\0';
strcpy(last, local);
}
d = 0;
while (!d) {
if (++count == 100) {
sprintf(scratch,
"Cannot find unique name for %s.", local);
footer_message(scratch);
log_message(scratch);
log_char('\n');
return (NULL);
}
if (slash)
sprintf(new, "%s/%02d.%s", first, count, last);
else
sprintf(new, "%02d.%s", count, last);
if ((d = access(new, 0)) < 0)
break;
}
newname = new;
footer_message("Unique name %s generated.", new);
return (new);
}
#ifdef USE_PROTOTYPES
void abort_remote(FILE *din)
#else
void abort_remote(din)
FILE *din;
#endif
{
char buf[BUFSIZ];
int nfnd;
fd_set mask;
int rval;
/*
* send IAC in urgent mode instead of DM because 4.3BSD places oob mark
* after urgent byte rather than before as is protocol now
*/
sprintf(buf, "%c%c%c", IAC, IP, IAC);
restart:
rval = send(fileno(commandfp), buf, 3, MSG_OOB);
if (rval == -1 && errno == EINTR)
goto restart;
if (rval != 3)
perror("abort_remote1");
fprintf(commandfp, "%cABOR\r\n", DM);
(void) fflush(commandfp);
FD_ZERO(&mask);
FD_SET(fileno(responsefp), &mask);
if (din) {
FD_SET(fileno(din), &mask);
}
if ((nfnd = empty(&mask, 10)) <= 0) {
if (nfnd < 0) {
perror("abort_remote2");
}
/*
if (ptabflg)
code = -1;
*/
lostpeer();
}
if (din && FD_ISSET(fileno(din), &mask)) {
while (read(fileno(din), buf, BUFSIZ) > 0)
/* LOOP */;
}
if (getreply(0) == ERROR && code == 552) {
/* 552 needed for nic style abort */
(void) getreply(0);
}
(void) getreply(0);
}
#ifdef USE_PROTOTYPES
void lostpeer(void)
#else
void lostpeer()
#endif
{
if (connected) {
if (commandfp != NULL) {
(void) shutdown(fileno(commandfp), 1+1);
(void) fclose(commandfp);
commandfp = NULL;
}
if (data >= 0) {
(void) shutdown(data, 1+1);
(void) close(data);
data = -1;
}
connected = 0;
}
}
#ifdef USE_PROTOTYPES
FILE *open_remote_ls(int nlst)
#else
FILE *open_remote_ls(nlst)
int nlst;
#endif
{
char *ftperr;
char *cmd;
FILE *din = 0;
char *gunique();
off_t lseek();
if (nlst)
cmd = "NLST"; /* dir */
else
cmd = "LIST"; /* ls */
settype(ASCII);
if (initconn()) {
code = -1;
return (NULL);
}
#ifdef SYSV386
if (command_dataconn(&din, "r", "%s", cmd) != PRELIM) {
#else
if (command("%s", cmd) != PRELIM) {
#endif
if (code == 530) {
/* 530 You must define working directory with CWD */
ftperr = ftp_error(' ',
"cd somewhere first or invalid directory");
footer_message(ftperr);
} else if (code == 550) {
/* 550 No files found. */
ftperr = ftp_error(' ', "No files found.");
footer_message(ftperr);
} else {
footer_message("Unknown error %d.", code);
}
return (NULL);
}
#ifndef SYSV386
din = dataconn("r");
#endif
if (din == NULL)
return (NULL);
return (din);
}
#ifdef USE_PROTOTYPES
char *next_remote_line(FILE *din)
#else
char *next_remote_line(din)
FILE *din;
#endif
{
char *str = response_line;
char *cptr = str;
int c;
notify_do_dispatch();
while ((c = getc(din)) != '\n' && c != EOF && c != '\0') {
if (c == '\r')
continue;
*cptr++ = (char)c;
}
*cptr = '\0';
notify_no_dispatch();
if (c == EOF)
return (NULL);
return (str);
}
#ifdef USE_PROTOTYPES
void close_remote_ls(FILE *din)
#else
void close_remote_ls(din)
FILE *din;
#endif
{
if (ferror(din))
perror("netin");
(void) fclose(din);
(void) getreply(0);
return;
}
struct types {
char *t_name;
char *t_mode;
int t_type;
char *t_arg;
} types[] = {
{ "binary", "I", TYPE_I, 0 },
{ "ascii", "A", TYPE_A, 0 },
{ "tenex", "L", TYPE_L, "8" },
/*
{ "image", "I", TYPE_I, 0 },
{ "ebcdic", "E", TYPE_E, 0 },
*/
};
/*
* Set transfer type.
*/
#ifdef USE_PROTOTYPES
void settype(int type)
#else
void settype(type)
int type;
#endif
{
register struct types *p;
int comret;
if (type > (sizeof (types)/sizeof (types[0]))) {
fprintf(stderr, "%d: unknown mode\n", type);
code = -1;
return;
}
/* make sure values in window match table! */
p = &types[type];
if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
else
comret = command("TYPE %s", p->t_mode);
if (comret == COMPLETE) {
curtype = p->t_type;
}
}
#ifdef USE_PROTOTYPES
char *parse_hostname(const char *host, int *port)
#else
char *parse_hostname(host, port)
char *host;
int *port;
#endif
{
static char ftphost[MAXHOSTNAMELEN + 1];
char *tmp;
struct servent *servent;
/* strip leading whitespace */
while (*host != '\0' && isspace(*host))
host++;
if (*host == '\0')
return (NULL);
(void) strcpy(ftphost, host);
tmp = strtok(ftphost, " \t");
/* now ftphost is terminated. */
tmp = strtok(NULL, " \t");
if (tmp == NULL) /* no port */
return (ftphost);
if (isdigit(*tmp)) {
*port = htons(atoi(tmp));
} else {
servent = getservbyname(tmp, "tcp");
if (servent == NULL) {
sprintf(scratch, "%s service unknown. Using %d.",
tmp, *port);
footer_message(scratch);
log_message(scratch);
} else {
*port = servent->s_port;
}
}
return (ftphost);
}
syntax highlighted by Code2HTML, v. 0.9.1