home *** CD-ROM | disk | FTP | other *** search
- /* ftp.c */
-
- /* $RCSfile: ftp.c,v $
- * $Revision: 14020.12 $
- * $Date: 93/07/09 11:30:28 $
- */
-
- #include "sys.h"
- #include <sys/types.h>
- #include <sys/param.h>
- #include <setjmp.h>
- #include <sys/stat.h>
- #include <sys/socket.h>
- #include <sys/time.h>
- #include <sys/file.h>
- #include <string.h>
- #include <time.h>
-
- #ifdef NO_UTIMEH
- struct utimbuf {time_t actime; time_t modtime;};
- #else
- # include <utime.h>
- #endif
-
- #ifdef SYSLOG
- # include <syslog.h>
- #endif
-
- /* You may need this for declarations of fd_set, etc. */
- #ifdef SYSSELECTH
- # include <sys/select.h>
- #else
- #ifdef STRICT_PROTOS
- extern int select (int, void *, void *, void *, struct timeval *);
- #endif
- #endif
-
- #ifndef NO_UNISTDH /* for prototypes only. */
- # include <unistd.h>
- #endif
-
- #include <netinet/in.h>
- #include <arpa/ftp.h>
- #include <arpa/inet.h>
- #include <arpa/telnet.h>
- #include <string.h>
- #include <signal.h>
- #include <errno.h>
- #include <netdb.h>
- #include <fcntl.h>
- #include <pwd.h>
- #include <ctype.h>
- #include "util.h"
- #include "ftp.h"
- #include "cmds.h"
- #include "main.h"
- #include "ftprc.h"
- #include "getpass.h"
- #include "defaults.h"
- #include "copyright.h"
-
- /* ftp.c globals */
- struct sockaddr_in hisctladdr;
- struct sockaddr_in data_addr;
- int data = -1;
- int abrtflag = 0;
- struct sockaddr_in myctladdr;
- FILE *cin = NULL, *cout = NULL;
- char *reply_string = NULL;
- jmp_buf sendabort, recvabort;
- int progress_meter = dPROGRESS;
- int cur_progress_meter;
- int sendport = -1; /* use PORT cmd for each data connection */
- int code; /* return/reply code for ftp command */
- string indataline;
- int cpend; /* flag: if != 0, then pending server reply */
- char *xferbuf; /* buffer for local and remote I/O */
- size_t xferbufsize; /* size in bytes, of the transfer buffer. */
- long next_report;
- long bytes;
- long now_sec;
- long file_size;
- struct timeval start, stop;
- int buffer_only = 0; /* True if reading into redir line
- * buffer only (not echoing to
- * stdout).
- */
-
- /* ftp.c externs */
- extern FILE *logf;
- extern string cwd, anon_password;
- extern Hostname hostname;
- extern int verbose, debug, macnum, margc;
- extern int curtype, creating;
- extern int options, activemcmd, paging;
- extern int ansi_escapes, logged_in, macnum;
- extern char *line, *margv[];
- extern char *tcap_normal, *tcap_boldface;
- extern char *tcap_underline, *tcap_reverse;
- extern struct userinfo uinfo;
- extern struct macel macros[];
- extern struct lslist *lshead, *lstail;
- extern int is_ls;
-
- #ifdef GATEWAY
- extern string gateway;
- extern string gate_login;
- #endif
-
-
- int hookup(char *host, unsigned int port)
- {
- register struct hostent *hp = 0;
- int s, len, hErr = -1;
- string errstr;
-
- bzero((char *)&hisctladdr, sizeof (hisctladdr));
- #ifdef BAD_INETADDR
- hisctladdr.sin_addr = inet_addr(host);
- #else
- hisctladdr.sin_addr.s_addr = inet_addr(host);
- #endif
- if (hisctladdr.sin_addr.s_addr != -1) {
- hisctladdr.sin_family = AF_INET;
- (void) Strncpy(hostname, host);
- } else {
- hp = gethostbyname(host);
- if (hp == NULL) {
- #ifdef HERROR
- extern int h_errno;
- if (h_errno == HOST_NOT_FOUND)
- (void) printf("%s: unknown host\n", host);
- else (void) fprintf(stderr, "%s: gethostbyname herror (%d): ",
- host, h_errno);
- herror(NULL);
- #else
- (void) printf("%s: unknown host\n", host);
- #endif
- goto done;
- }
- hisctladdr.sin_family = hp->h_addrtype;
- bcopy(hp->h_addr_list[0],
- (caddr_t)&hisctladdr.sin_addr, hp->h_length);
- (void) Strncpy(hostname, hp->h_name);
- }
- s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
- if (s < 0) {
- PERROR("hookup", "socket");
- goto done;
- }
- hisctladdr.sin_port = port;
- #ifdef SOCKS
- while (Rconnect(s, (struct sockaddr *) &hisctladdr, (int) sizeof (hisctladdr)) < 0) {
- #else
- while (connect(s, (struct sockaddr *) &hisctladdr, (int) sizeof (hisctladdr)) < 0) {
- #endif
- if (hp && hp->h_addr_list[1]) {
- (void) sprintf(errstr, "connect error to address %s",
- inet_ntoa(hisctladdr.sin_addr));
- PERROR("hookup", errstr);
- hp->h_addr_list++;
- bcopy(hp->h_addr_list[0],
- (caddr_t)&hisctladdr.sin_addr, hp->h_length);
- (void) fprintf(stdout, "Trying %s...\n",
- inet_ntoa(hisctladdr.sin_addr));
- (void) close(s);
- s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
- if (s < 0) {
- PERROR("hookup", "socket");
- goto done;
- }
- continue;
- }
- PERROR("hookup", "connect");
- switch (errno) {
- case ENETDOWN:
- case ENETUNREACH:
- case ECONNABORTED:
- case ETIMEDOUT:
- case ECONNREFUSED:
- case EHOSTDOWN:
- hErr = -2; /* we can re-try later. */
- }
- goto bad;
- }
- len = sizeof (myctladdr);
- if (Getsockname(s, (char *)&myctladdr, &len) < 0) {
- PERROR("hookup", "getsockname");
- goto bad;
- }
- cin = fdopen(s, "r");
- cout = fdopen(s, "w");
- if (cin == NULL || cout == NULL) {
- (void) fprintf(stderr, "ftp: fdopen failed.\n");
- close_streams(0);
- goto bad;
- }
- if (IS_VVERBOSE)
- (void) printf("Connected to %s.\n", hostname);
- if (getreply(0) > 2) { /* read startup message from server */
- close_streams(0);
- if (code == 421)
- hErr = -2; /* We can try again later. */
- goto bad;
- }
- #ifdef SO_OOBINLINE
- {
- int on = 1;
-
- if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *) &on, sizeof(on))
- < 0 && debug) {
- PERROR("hookup", "setsockopt");
- }
- }
- #endif /* SO_OOBINLINE */
-
- hErr = 0;
- goto done;
-
- bad:
- (void) close(s);
- done:
- return (hErr);
- } /* hookup */
-
-
-
- /* This registers the user's username, password, and account with the remote
- * host which validates it. If we get on, we also do some other things, like
- * enter a log entry and execute the startup macro.
- */
- int Login(char *userNamePtr, char *passWordPtr, char *accountPtr, int doInit)
- {
- string userName;
- string str;
- int n;
- int sentAcct = 0;
- int userWasPrompted = 0;
- int result = CMDERR;
- time_t now;
-
- if (userNamePtr == NULL) {
- /* Prompt for a username. */
- (void) sprintf(str, "Login Name (%s): ", uinfo.username);
- ++userWasPrompted;
- if (Gets(str, userName, sizeof(userName)) == NULL)
- goto done;
- else if (userName[0]) {
- /* User didn't just hit return. */
- userNamePtr = userName;
- } else {
- /*
- * User can hit return if he wants to enter his username
- * automatically.
- */
- if (*uinfo.username != '\0')
- userNamePtr = uinfo.username;
- else
- goto done;
- }
- }
-
- if (passWordPtr == NULL) {
- if ((strcmp("anonymous", userName) == 0) && (*anon_password))
- passWordPtr = anon_password;
- else {
- /* Prompt for a password. */
- ++userWasPrompted;
- passWordPtr = Getpass("Password:");
- }
- }
-
- #ifdef GATEWAY
- if (*gateway)
- (void) sprintf(str, "USER %s@%s",
- (*gate_login ? gate_login : dGATEWAY_LOGIN),
- hostname);
- else
- #endif
- (void) sprintf(str, "USER %s", userNamePtr);
-
- /* Send the user name. */
- n = command(str);
- if (n == CONTINUE) {
- /* The remote site is requesting us to send the password now. */
- (void) sprintf(str, "PASS %s", passWordPtr);
- n = command(str);
- if (n == CONTINUE) {
- /* The remote site is requesting us to send the account now. */
- (void) sprintf(str, "ACCT %s", Getpass("Account:"));
- ++sentAcct; /* Keep track that we've sent the account already. */
- ++userWasPrompted;
- n = command(str);
- }
- }
-
- if (n != COMPLETE) {
- (void) printf("Login failed.\n");
- goto done;
- }
-
- /* If you specified an account, and the remote-host didn't request it
- * (maybe it's optional), we will send the account information.
- */
- if (!sentAcct && accountPtr != NULL) {
- (void) sprintf(str, "ACCT %s", accountPtr);
- (void) command(str);
- }
-
- /* See if remote host dropped connection. Some sites will let you log
- * in anonymously, only to tell you that they already have too many
- * anon users, then drop you. We do a no-op here to see if they've
- * ditched us.
- */
- n = quiet_command("NOOP");
- if (n == 4)
- goto done;
-
- #ifdef SYSLOG
- syslog(LOG_INFO, "%s connected to %s as %s.",
- uinfo.username, hostname, userNamePtr);
- #endif
-
- /* Save which sites we opened to the user's logfile. */
- if (logf != NULL) {
- (void) time(&now);
- (void) fprintf(logf, "%s opened at %s",
- hostname,
- ctime(&now));
- }
-
- /* Let the user know we are logged in, unless he was prompted for some
- * information already.
- */
- if (!userWasPrompted)
- if (NOT_VQUIET)
- (void) printf("Logged into %s.\n", hostname);
-
- if ((doInit) && (macnum > 0)) {
- /* Run the startup macro, if any. */
- /* If macnum is non-zero, the init macro was defined from
- * ruserpass. It would be the only macro defined at this
- * point.
- */
- (void) strcpy(line, "$init");
- makeargv();
- (void) domacro(margc, margv);
- }
-
- _cd(NULL); /* Init cwd variable. */
-
- result = NOERR;
- logged_in = 1;
-
- done:
- return (result);
- } /* Login */
-
-
-
- /*ARGSUSED*/
- void cmdabort SIG_PARAMS
- {
- (void) printf("\n");
- (void) fflush(stdout);
- abrtflag++;
- } /* cmdabort */
-
-
-
-
- int command(char *cmd)
- {
- int r;
- sig_t oldintr;
- string str;
-
- abrtflag = 0;
- dbprintf("cmd: \"%s\" (length %d)\n", cmd, (int) strlen(cmd));
- if (cout == NULL) {
- (void) sprintf(str, "%s: No control connection for command", cmd);
- PERROR("command", str);
- return (0);
- }
- oldintr = Signal(SIGINT, /* cmdabort */ SIG_IGN);
- #ifndef BROKEN_MEMCPY
- if (cout != NULL)
- (void) fprintf(cout, "%s\r\n", cmd);
- #else
- {
- /*
- * The fprintf() above gives me a core-dump in memcpy()...
- * This does the trick though...
- */
-
- char *p = cmd;
- while (*p)
- fputc(*p++, cout);
- fputc('\r', cout);
- fputc('\n', cout);
- }
- #endif /* !SCO324 */
- (void) fflush(cout);
- cpend = 1;
- r = getreply(strcmp(cmd, "QUIT") == 0);
- if (abrtflag && oldintr != SIG_IGN && oldintr != NULL)
- (*oldintr)(0);
- (void) Signal(SIGINT, oldintr);
- return(r);
- } /* command */
-
-
-
-
- int quiet_command(char *cmd)
- {
- register int oldverbose, result;
-
- oldverbose = verbose;
- verbose = V_QUIET;
- result = command(cmd);
- verbose = oldverbose;
- return (result);
- } /* quiet_command */
-
-
-
-
- int verbose_command(char *cmd)
- {
- register int oldverbose, result;
-
- oldverbose = verbose;
- verbose = V_VERBOSE;
- result = command(cmd);
- verbose = oldverbose;
- return (result);
- } /* quiet_command */
-
-
-
-
- int getreply(int expecteof)
- {
- register int c, n;
- int dig;
- char *cp, *end, *dp;
- int thiscode, originalcode = 0, continuation = 0;
- sig_t oldintr;
-
- if (cin == NULL)
- return (-1);
- /* oldintr = Signal(SIGINT, SIG_IGN); */
- oldintr = Signal(SIGINT, cmdabort);
- end = reply_string + RECEIVEDLINELEN - 2;
- for (;abrtflag==0;) {
- dig = n = thiscode = code = 0;
- cp = reply_string;
- for (;abrtflag==0;) {
- c = fgetc(cin);
- if (c == IAC) { /* handle telnet commands */
- switch (c = fgetc(cin)) {
- case WILL:
- case WONT:
- c = fgetc(cin);
- (void) fprintf(cout, "%c%c%c",IAC,DONT,c);
- (void) fflush(cout);
- break;
- case DO:
- case DONT:
- c = fgetc(cin);
- (void) fprintf(cout, "%c%c%c",IAC,WONT,c);
- (void) fflush(cout);
- break;
- default:
- break;
- }
- continue;
- }
- dig++;
- if (c == EOF) {
- if (expecteof) {
- (void) Signal(SIGINT, oldintr);
- code = 221;
- return (0);
- }
- lostpeer(0);
- if (NOT_VQUIET) {
- (void) printf("421 Service not available, remote server has closed connection\n");
- (void) fflush(stdout);
- }
- code = 421;
- return(4);
- }
- if (cp < end && c != '\r')
- *cp++ = c;
-
- if (c == '\n')
- break;
- if (dig < 4 && isdigit(c))
- code = thiscode = code * 10 + (c - '0');
- else if (dig == 4 && c == '-') {
- if (continuation)
- code = 0;
- continuation++;
- }
- if (n == 0)
- n = c;
- } /* end for(;;) #2 */
-
- *cp = '\0';
- switch (verbose) {
- case V_QUIET:
- /* Don't print anything. */
- break;
- case V_ERRS:
- if (n == '5') {
- dp = reply_string;
- goto stripCode;
- }
- break;
- case V_IMPLICITCD:
- case V_TERSE:
- dp = NULL;
- if (n == '5' && verbose == V_TERSE)
- dp = reply_string;
- else {
- switch (thiscode) {
- case 230:
- case 214:
- case 332:
- case 421: /* For ftp.apple.com, etc. */
- dp = reply_string;
- break;
- case 220:
- /*
- * Skip the foo FTP server ready line.
- */
- if (strstr(reply_string, "ready.") == NULL)
- dp = reply_string;
- break;
- case 250:
- /*
- * Print 250 lines if they aren't
- * "250 CWD command successful."
- */
- if (strncmp(reply_string + 4, "CWD ", (size_t) 4))
- dp = reply_string;
- }
- }
- if (dp == NULL) break;
- stripCode:
- /* Try to strip out the code numbers, etc. */
- if (isdigit(*dp++) && isdigit(*dp++) && isdigit(*dp++)) {
- if (*dp == ' ' || *dp == '-') {
- dp++;
- if (*dp == ' ') dp++;
- } else dp = reply_string;
- } else {
- int spaces;
- dp = reply_string;
- for (spaces = 0; spaces < 4; ++spaces)
- if (dp[spaces] != ' ')
- break;
- if (spaces == 4)
- dp += spaces;
- }
- goto printLine;
- case V_VERBOSE:
- dp = reply_string;
- printLine: (void) fputs(dp, stdout);
- } /* end switch */
-
- if (continuation && code != originalcode) {
- if (originalcode == 0)
- originalcode = code;
- continue;
- }
- if (n != '1')
- cpend = 0;
- (void) Signal(SIGINT,oldintr);
- if (code == 421 || originalcode == 421)
- lostpeer(0);
- if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN && oldintr)
- (*oldintr)(0);
- return (n - '0');
- } /* end for(;;) #1 */
- } /* getreply */
-
-
-
-
- static int empty(struct fd_set *mask, int sec)
- {
- struct timeval t;
-
- t.tv_sec = (long) sec;
- t.tv_usec = 0;
-
- return(Select(32, mask, NULL, NULL, &t));
- } /* empty */
-
-
-
-
- static void tvsub(struct timeval *tdiff, struct timeval *t1, struct timeval *t0)
- {
- tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
- tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
- if (tdiff->tv_usec < 0)
- tdiff->tv_sec--, tdiff->tv_usec += 1000000;
- } /* tvsub */
-
-
- /* Variables private to progress_report code. */
- static int barlen;
- static long last_dot;
- static int dots;
-
- int start_progress(int sending, char *local)
- {
- long s;
- str32 spec;
-
- cur_progress_meter = progress_meter;
- if ((cur_progress_meter > pr_last) || (cur_progress_meter < 0))
- cur_progress_meter = dPROGRESS;
- if ((file_size <= 0) && ((cur_progress_meter == pr_percent) || (cur_progress_meter == pr_philbar) || (cur_progress_meter == pr_last)))
- cur_progress_meter = pr_kbytes;
- if (!ansi_escapes && (cur_progress_meter == pr_philbar))
- cur_progress_meter = pr_dots;
-
- (void) gettimeofday(&start, (struct timezone *)0);
- now_sec = start.tv_sec;
-
- switch (cur_progress_meter) {
- case pr_none:
- break;
- case pr_percent:
- (void) printf("%s: ", local);
- goto zz;
- case pr_kbytes:
- (void) printf("%s: ", local);
- goto zz;
- case pr_philbar:
- (void) printf("%s%s file: %s %s\n",
- tcap_boldface,
- sending ? "Sending" : "Receiving",
- local,
- tcap_normal
- );
- barlen = 64;
- for (s = file_size; s > 0; s /= 10L) barlen--;
- (void) sprintf(spec, " 0 %%%ds %%ld bytes.\r", barlen);
- (void) printf(spec, " ", file_size);
- goto zz;
- case pr_dots:
- last_dot = (file_size / 10) + 1;
- dots = 0;
- (void) printf("%s: ", local);
- zz:
- (void) fflush(stdout);
- echo(stdin, 0);
- } /* end switch */
- return (cur_progress_meter);
- } /* start_progress */
-
-
-
-
- int progress_report(int finish_up)
- {
- int size;
- long perc;
- str32 spec;
-
- next_report += xferbufsize;
- (void) gettimeofday(&stop, (struct timezone *)0);
- if ((stop.tv_sec > now_sec) || finish_up && file_size) {
- switch (cur_progress_meter) {
- case pr_none:
- break;
- case pr_percent:
- perc = 100L * bytes / file_size;
- if (perc > 100L) perc = 100L;
- (void) printf("\b\b\b\b%3ld%%", perc);
- (void) fflush(stdout);
- break;
- case pr_philbar:
- size = (int) ((float)barlen * ((float) (bytes > file_size ?
- file_size : bytes)/file_size));
- (void) sprintf(spec, "%%3ld%%%% 0 %%s%%%ds%%s\r", size);
- (void) printf(
- spec,
- 100L * (bytes > file_size ? file_size : bytes) / file_size,
- tcap_reverse,
- " ",
- tcap_normal
- );
- (void) fflush(stdout);
- break;
- case pr_kbytes:
- if ((bytes / 1024) > 0) {
- (void) printf("\b\b\b\b\b\b%5ldK", bytes / 1024);
- (void) fflush(stdout);
- }
- break;
- case pr_dots:
- if (bytes > last_dot) {
- (void) fputc('.', stdout);
- (void) fflush(stdout);
- last_dot += (file_size / 10) + 1;
- dots++;
- }
- } /* end switch */
- now_sec = stop.tv_sec;
- } /* end if we updated */
- return (UserLoggedIn());
- } /* progress_report */
-
-
-
-
- void end_progress(char *direction, char *local, char *remote)
- {
- struct timeval td;
- float s, bs = 0.0;
- char *cp, *bsstr;
- string str;
-
- if (bytes <= 0)
- return;
- (void) progress_report(1); /* tell progress proc to cleanup. */
-
- tvsub(&td, &stop, &start);
- s = td.tv_sec + (td.tv_usec / 1000000.0);
- if (s != 0.0)
- bs = bytes / s;
- if (bs > 1024.0) {
- bs /= 1024.0;
- bsstr = "K/s.\n";
- } else
- bsstr = "Bytes/s.\n";
-
- if (NOT_VQUIET) switch(cur_progress_meter) {
- case pr_none:
- zz:
- (void) printf("%s: %ld bytes %s in %.2f seconds, %.2f %s", local, bytes, direction, s, bs, bsstr);
- break;
- case pr_kbytes:
- case pr_percent:
- (void) printf("%s%ld bytes %s in %.2f seconds, %.2f %s",
- cur_progress_meter == pr_kbytes ? "\b\b\b\b\b\b" : "\b\b\b\b",
- bytes, direction, s, bs, bsstr);
- echo(stdin, 1);
- break;
- case pr_philbar:
- (void) printf("\n");
- echo(stdin, 1);
- break;
- case pr_dots:
- for (; dots < 10; dots++)
- (void) fputc('.', stdout);
- (void) fputc('\n', stdout);
- echo(stdin, 1);
- goto zz;
- }
-
- /* Save transfers to the logfile. */
- if (logf != NULL) {
- /* if a simple path is given, try to log the full path */
- if (rindex(remote, '/') == NULL && cwd != NULL) {
- (void) sprintf(str, "%s/%s", cwd, remote);
- cp = str;
- } else
- cp = remote;
- (void) fprintf(logf, "\t-> \"%s\" %s, %.2f %s", cp, direction, bs, bsstr);
- }
- #ifdef SYSLOG
- if (direction[0] == 'r')
- syslog (LOG_INFO, "%s %s %s as %s from %s (%ld bytes).",
- uinfo.username, direction, remote, local, hostname, bytes);
- else
- syslog (LOG_INFO, "%s %s %s as %s to %s (%ld bytes).",
- uinfo.username, direction, local, remote, hostname, bytes);
- #endif
- } /* end_progress */
-
-
-
- void close_file(FILE **fin, int filetype)
- {
- if (*fin != NULL) {
- if (filetype == IS_FILE) {
- (void) fclose(*fin);
- *fin = NULL;
- } else if (filetype == IS_PIPE) {
- (void) pclose(*fin);
- *fin = NULL;
- }
- }
- } /* close_file */
-
-
-
-
- /*ARGSUSED*/
- void abortsend SIG_PARAMS
- {
- activemcmd = 0;
- abrtflag = 0;
- (void) fprintf(stderr, "\nSend aborted.\n");
- echo(stdin, 1);
- longjmp(sendabort, 1);
- } /* abortsend */
-
-
-
- int sendrequest(char *cmd, char *local, char *remote)
- {
- FILE *fin, *dout = NULL;
- sig_t oldintr, oldintp;
- string str;
- register int c, d;
- struct stat st;
- int filetype, result = NOERR;
- int do_reports = 0;
- char *mode;
- register char *bufp;
-
- dbprintf("cmd: %s; rmt: %s; loc: %s.\n", cmd, remote, local);
- oldintr = NULL;
- oldintp = NULL;
- mode = "w";
- bytes = file_size = 0L;
- if (setjmp(sendabort)) {
- while (cpend) {
- (void) getreply(0);
- }
- if (data >= 0) {
- (void) close(data);
- data = -1;
- }
- if (oldintr)
- (void) Signal(SIGINT, oldintr);
- if (oldintp)
- (void) Signal(SIGPIPE, oldintp);
- result = -1;
- goto xx;
- }
- oldintr = Signal(SIGINT, abortsend);
- file_size = -1;
- if (strcmp(local, "-") == 0) {
- fin = stdin;
- filetype = IS_STREAM;
- } else if (*local == '|') {
- filetype = IS_PIPE;
- oldintp = Signal(SIGPIPE,SIG_IGN);
- fin = popen(local + 1, "r");
- if (fin == NULL) {
- PERROR("sendrequest", local + 1);
- (void) Signal(SIGINT, oldintr);
- (void) Signal(SIGPIPE, oldintp);
- result = -1;
- goto xx;
- }
- } else {
- filetype = IS_FILE;
- fin = fopen(local, "r");
- if (fin == NULL) {
- PERROR("sendrequest", local);
- (void) Signal(SIGINT, oldintr);
- result = -1;
- goto xx;
- }
- if (fstat(fileno(fin), &st) < 0 ||
- (st.st_mode&S_IFMT) != S_IFREG) {
- (void) fprintf(stdout, "%s: not a plain file.\n", local);
- (void) Signal(SIGINT, oldintr);
- (void) fclose(fin);
- result = -1;
- goto xx;
- }
- file_size = st.st_size;
- }
- if (initconn()) {
- (void) Signal(SIGINT, oldintr);
- if (oldintp)
- (void) Signal(SIGPIPE, oldintp);
- result = -1;
- close_file(&fin, filetype);
- goto xx;
- }
- if (setjmp(sendabort))
- goto Abort;
-
- if (remote) {
- (void) sprintf(str, "%s %s", cmd, remote);
- if (command(str) != PRELIM) {
- (void) Signal(SIGINT, oldintr);
- if (oldintp)
- (void) Signal(SIGPIPE, oldintp);
- close_file(&fin, filetype);
- goto xx;
- }
- } else
- if (command(cmd) != PRELIM) {
- (void) Signal(SIGINT, oldintr);
- if (oldintp)
- (void) Signal(SIGPIPE, oldintp);
- close_file(&fin, filetype);
- goto xx;
- }
- dout = dataconn(mode);
- if (dout == NULL)
- goto Abort;
- (void) gettimeofday(&start, (struct timezone *)0);
- oldintp = Signal(SIGPIPE, SIG_IGN);
- if (do_reports = (filetype == IS_FILE && NOT_VQUIET))
- do_reports = start_progress(1, local);
-
- switch (curtype) {
-
- case TYPE_I:
- case TYPE_L:
- errno = d = 0;
- while ((c = read(fileno(fin), xferbuf, (int)xferbufsize)) > 0) {
- bytes += c;
- for (bufp = xferbuf; c > 0; c -= d, bufp += d)
- if ((d = write(fileno(dout), bufp, c)) <= 0)
- break;
- /* Print progress indicator. */
- if (do_reports)
- do_reports = progress_report(0);
- }
- if (c < 0)
- PERROR("sendrequest", local);
- if (d <= 0) {
- if (d == 0 && !creating)
- (void) fprintf(stderr, "netout: write returned 0?\n");
- else if (errno != EPIPE)
- PERROR("sendrequest", "netout");
- bytes = -1;
- }
- break;
-
- case TYPE_A:
- next_report = xferbufsize;
- while ((c = getc(fin)) != EOF) {
- if (c == '\n') {
- if (ferror(dout))
- break;
- (void) putc('\r', dout);
- bytes++;
- }
- (void) putc(c, dout);
- bytes++;
-
- /* Print progress indicator. */
- if (do_reports && bytes > next_report)
- do_reports = progress_report(0);
- }
- if (ferror(fin))
- PERROR("sendrequest", local);
- if (ferror(dout)) {
- if (errno != EPIPE)
- PERROR("sendrequest", "netout");
- bytes = -1;
- }
- break;
- }
- Done:
- close_file(&fin, filetype);
- if (dout)
- (void) fclose(dout);
- (void) getreply(0);
- (void) Signal(SIGINT, oldintr);
- if (oldintp)
- (void) Signal(SIGPIPE, oldintp);
- if (do_reports)
- end_progress("sent", local, remote);
- xx:
- return (result);
- Abort:
- result = -1;
- if (!cpend)
- goto xx;
- if (data >= 0) {
- (void) close(data);
- data = -1;
- }
- goto Done;
- } /* sendrequest */
-
-
-
-
- /*ARGSUSED*/
- void abortrecv SIG_PARAMS
- {
- activemcmd = 0;
- abrtflag = 0;
- (void) fprintf(stderr,
- #ifdef TryAbort
- "(abort)\n");
- #else
- "\nAborting, please wait...");
- #endif
- (void) fflush(stderr);
- echo(stdin, 1);
- longjmp(recvabort, 1);
- } /* abortrecv */
-
-
-
-
- void GetLSRemoteDir(char *remote, char *remote_dir)
- {
- char *cp;
-
- /*
- * The ls() function can specify a directory to list along with ls flags,
- * if it sends the flags first followed by the directory name.
- *
- * So far, we don't care about the remote directory being listed. I put
- * it now so I won't forget in case I need to do something with it later.
- */
- remote_dir[0] = 0;
- if (remote != NULL) {
- cp = index(remote, LS_FLAGS_AND_FILE);
- if (cp == NULL)
- (void) Strncpy(remote_dir, remote);
- else {
- *cp++ = ' ';
- (void) Strncpy(remote_dir, cp);
- }
- }
- } /* GetLSRemoteDir */
-
-
-
-
- int AdjustLocalFileName(char *local)
- {
- char *dir;
-
- /*
- * Make sure we are writing to a valid local path.
- * First check the local directory, and see if we can write to it.
- */
- if (access(local, 2) < 0) {
- dir = rindex(local, '/');
-
- if (errno != ENOENT && errno != EACCES) {
- /* Report an error if it's one we can't handle. */
- PERROR("AdjustLocalFileName", local);
- return -1;
- }
- /* See if we have write permission on this directory. */
- if (dir != NULL) {
- /* Special case: /filename. */
- if (dir != local)
- *dir = 0;
- if (access(dir == local ? "/" : local, 2) < 0) {
- /*
- * We have a big long pathname, like /a/b/c/d,
- * but see if we can write into the current
- * directory and call the file ./d.
- */
- if (access(".", 2) < 0) {
- (void) strcpy(local, " and .");
- goto noaccess;
- }
- (void) strcpy(local, dir + 1); /* use simple filename. */
- } else
- *dir = '/';
- } else {
- /* We have a simple path name (file name only). */
- if (access(".", 2) < 0) {
- noaccess: PERROR("AdjustLocalFileName", local);
- return -1;
- }
- }
- }
- return (NOERR);
- } /* AdjustLocalFileName */
-
-
-
- int SetToAsciiForLS(int is_retr, int currenttype)
- {
- int oldt = 0, oldv;
-
- if (!is_retr) {
- if (currenttype != TYPE_A) {
- oldt = currenttype;
- oldv = verbose;
- if (!debug)
- verbose = V_QUIET;
- (void) setascii(0, NULL);
- verbose = oldv;
- }
- }
- return oldt;
- } /* SetToAsciiForLS */
-
-
-
- int IssueCommand(char *ftpcmd, char *remote)
- {
- string str;
- int result = NOERR;
-
- if (remote)
- (void) sprintf(str, "%s %s", ftpcmd, remote);
- else
- (void) Strncpy(str, ftpcmd);
-
- if (command(str) != PRELIM)
- result = -1;
- return (result);
- } /* IssueCommand */
-
-
-
- FILE *OpenOutputFile(int filetype, char *local, char *mode, sig_t *oldintp)
- {
- FILE *fout;
-
- if (filetype == IS_STREAM) {
- fout = stdout;
- } else if (filetype == IS_PIPE) {
- /* If it is a pipe, the pipecmd will have a | as the first char. */
- ++local;
- fout = popen(local, "w");
- *oldintp = Signal(SIGPIPE, abortrecv);
- } else {
- fout = fopen(local, mode);
- }
- if (fout == NULL)
- PERROR("OpenOutputFile", local);
- return (fout);
- } /* OpenOutputFile */
-
-
-
- void ReceiveBinary(FILE *din, FILE *fout, int *do_reports, char *localfn)
- {
- int c, d, do2;
-
- errno = 0; /* Clear any old error left around. */
- do2 = *do_reports; /* A slight optimization :-) */
- bytes = 0; /* Init the byte-transfer counter. */
-
- for (;;) {
- /* Read a block from the input stream. */
- c = read(fileno(din), xferbuf, (int)xferbufsize);
-
- /* If c is zero, then we've read the whole file. */
- if (c == 0)
- break;
-
- /* Check for errors that may have occurred while reading. */
- if (c < 0) {
- /* Error occurred while reading. */
- if (errno != EPIPE)
- PERROR("ReceiveBinary", "netin");
- bytes = -1;
- break;
- }
-
- /* Write out the same block we just read in. */
- d = write(fileno(fout), xferbuf, c);
-
- /* Check for write errors. */
- if ((d < 0) || (ferror(fout))) {
- /* Error occurred while writing. */
- PERROR("ReceiveBinary", "outfile");
- break;
- }
- if (d < c) {
- (void) fprintf(stderr, "%s: short write\n", localfn);
- break;
- }
-
- /* Update the byte counter. */
- bytes += (long) c;
-
- /* Print progress indicator. */
- if (do2 != 0)
- do2 = progress_report(0);
- }
-
- *do_reports = do2; /* Update the real do_reports variable. */
- } /* ReceiveBinary */
-
-
-
- void AddRedirLine(char *str2)
- {
- register struct lslist *new;
-
- (void) Strncpy(indataline, str2);
- new = (struct lslist *) malloc((size_t) sizeof(struct lslist));
- if (new != NULL) {
- if ((new->string = NewString(str2)) != NULL) {
- new->next = NULL;
- if (lshead == NULL)
- lshead = lstail = new;
- else {
- lstail->next = new;
- lstail = new;
- }
- }
- }
- } /* AddRedirLine */
-
-
-
- void ReceiveAscii(FILE *din, FILE *fout, int *do_reports, char *localfn, int
- lineMode)
- {
- string str2;
- int nchars = 0, c;
- char *linePtr;
- int do2 = *do_reports, stripped;
-
- next_report = xferbufsize;
- bytes = errno = 0;
- if (lineMode) {
- while ((linePtr = FGets(str2, din)) != NULL) {
- bytes += (long) RemoveTrailingNewline(linePtr, &stripped);
- if (is_ls || debug > 0)
- AddRedirLine(linePtr);
-
- /* Shutup while getting remote size and mod time. */
- if (!buffer_only) {
- c = fputs(linePtr, fout);
-
- if (c != EOF) {
- if (stripped > 0)
- c = fputc('\n', fout);
- }
- if ((c == EOF) || (ferror(fout))) {
- PERROR("ReceiveAscii", "outfile");
- break;
- }
- }
-
- /* Print progress indicator. */
- if (do2 && bytes > next_report)
- do2 = progress_report(0);
- }
- } else while ((c = getc(din)) != EOF) {
- linePtr = str2;
- while (c == '\r') {
- bytes++;
- if ((c = getc(din)) != '\n') {
- if (ferror(fout))
- goto break2;
- /* Shutup while getting remote size and mod time. */
- if (!buffer_only)
- (void) putc('\r', fout);
- if (c == '\0') {
- bytes++;
- goto contin2;
- }
- if (c == EOF)
- goto contin2;
- }
- }
- /* Shutup while getting remote size and mod time. */
- if (!buffer_only)
- (void) putc(c, fout);
- bytes++;
-
- /* Print progress indicator. */
- if (do2 && bytes > next_report)
- do2 = progress_report(0);
-
- /* No seg violations, please */
- if (nchars < sizeof(str2) - 1) {
- *linePtr++ = c; /* build redir string */
- nchars++;
- }
-
- contin2:
- /* Save the input line in the buffer for recall later. */
- if (c == '\n' && is_ls) {
- *--linePtr = 0;
- AddRedirLine(str2);
- nchars = 0;
- }
-
- } /* while ((c = getc(din)) != EOF) */
- break2:
- if (ferror(din)) {
- if (errno != EPIPE)
- PERROR("ReceiveAscii", "netin");
- bytes = -1;
- }
- if (ferror(fout)) {
- if (errno != EPIPE)
- PERROR("ReceiveAscii", localfn);
- }
- *do_reports = do2;
- } /* ReceiveAscii */
-
-
-
- void CloseOutputFile(FILE *f, int filetype, char *name, time_t mt)
- {
- struct utimbuf ut;
-
- if (f != NULL) {
- (void) fflush(f);
- if (filetype == IS_FILE) {
- (void) fclose(f);
- if (mt != (time_t)0) {
- ut.actime = ut.modtime = mt;
- (void) utime(name, &ut);
- }
- } else if (filetype == IS_PIPE) {
- (void)pclose(f);
- }
- }
- } /* close_file */
-
-
-
- void ResetOldType(int oldtype)
- {
- int oldv;
-
- if (oldtype) {
- oldv = verbose;
- if (!debug)
- verbose = V_QUIET;
- if (oldtype == TYPE_I)
- (void) setbinary(0, NULL);
- verbose = oldv;
- }
- } /* ResetOldType */
-
-
-
- int FileType(char *fname)
- {
- int ft = IS_FILE;
-
- if (strcmp(fname, "-") == 0)
- ft = IS_STREAM;
- else if (*fname == '|')
- ft = IS_PIPE;
- return (ft);
- } /* FileType */
-
-
-
-
- void CloseData(void) {
- if (data >= 0) {
- (void) close(data);
- data = -1;
- }
- } /* CloseData */
-
-
-
-
- int recvrequest(char *cmd, char *local, char *remote, char *mode)
- {
- FILE *fout = NULL, *din = NULL;
- sig_t oldintr = NULL, oldintp = NULL;
- int oldtype = 0, is_retr;
- int nfnd;
- char msg;
- struct fd_set mask;
- int filetype, do_reports = 0;
- string remote_dir;
- time_t remfTime = 0;
- int result = -1;
-
- dbprintf("---> cmd: %s; rmt: %s; loc: %s; mode: %s.\n",
- cmd, remote, local, mode);
- is_retr = strcmp(cmd, "RETR") == 0;
-
- GetLSRemoteDir(remote, remote_dir);
- if ((filetype = FileType(local)) == IS_FILE) {
- if (AdjustLocalFileName(local))
- goto xx;
- }
-
- file_size = -1;
- if (filetype == IS_FILE)
- file_size = GetDateAndSize(remote, (unsigned long *) &remfTime);
-
- if (initconn())
- goto xx;
-
- oldtype = SetToAsciiForLS(is_retr, curtype);
-
- if (IssueCommand(cmd, remote))
- goto xx;
-
- if ((fout = OpenOutputFile(filetype, local, mode, &oldintp)) == NULL)
- goto xx;
-
- if ((din = dataconn("r")) == NULL)
- goto Abort;
-
- do_reports = NOT_VQUIET && is_retr && filetype == IS_FILE;
- if (do_reports)
- do_reports = start_progress(0, local);
-
- if (setjmp(recvabort)) {
- #ifdef TryAbort
- goto Abort;
- #else
- /* Just read the rest of the stream without doing anything with
- * the results.
- */
- (void) Signal(SIGINT, SIG_IGN);
- (void) Signal(SIGPIPE, SIG_IGN); /* Don't bug us while aborting. */
- while (read(fileno(din), xferbuf, (int)xferbufsize) > 0)
- ;
- (void) fprintf(stderr, "\rAborted. \n");
- #endif
- } else {
- oldintr = Signal(SIGINT, abortrecv);
-
- if (curtype == TYPE_A)
- ReceiveAscii(din, fout, &do_reports, local, 1);
- else
- ReceiveBinary(din, fout, &do_reports, local);
- result = NOERR;
- /* Don't interrupt us now, since we finished successfully. */
- (void) Signal(SIGPIPE, SIG_IGN);
- (void) Signal(SIGINT, SIG_IGN);
- }
- (void) getreply(0);
- ResetOldType(oldtype);
-
- goto xx;
-
- Abort:
-
- /* Abort using RFC959 recommended IP,SYNC sequence */
-
- (void) Signal(SIGPIPE, SIG_IGN); /* Don't bug us while aborting. */
- (void) Signal(SIGINT, SIG_IGN);
- ResetOldType(oldtype);
- if (!cpend || !cout) goto xx;
- (void) fprintf(cout,"%c%c",IAC,IP);
- (void) fflush(cout);
- msg = IAC;
- /* send IAC in urgent mode instead of DM because UNIX places oob mark */
- /* after urgent byte rather than before as now is protocol */
- if (send(fileno(cout),&msg,1,MSG_OOB) != 1)
- PERROR("recvrequest", "abort");
- (void) fprintf(cout,"%cABOR\r\n",DM);
- (void) fflush(cout);
- FD_ZERO(&mask);
- FD_SET(fileno(cin), &mask);
- if (din)
- FD_SET(fileno(din), &mask);
- if ((nfnd = empty(&mask,10)) <= 0) {
- if (nfnd < 0)
- PERROR("recvrequest", "abort");
- lostpeer(0);
- }
- if (din && FD_ISSET(fileno(din), &mask)) {
- while ((read(fileno(din), xferbuf, xferbufsize)) > 0)
- ;
- }
- if ((getreply(0)) == ERROR && code == 552) { /* needed for nic style abort */
- CloseData();
- (void) getreply(0);
- }
- (void) getreply(0);
- result = -1;
- CloseData();
-
- xx:
- CloseOutputFile(fout, filetype, local, remfTime);
- dbprintf("outfile closed.\n");
- if (din)
- (void) fclose(din);
- if (do_reports)
- end_progress("received", local, remote);
- if (oldintr)
- (void) Signal(SIGINT, oldintr);
- if (oldintp)
- (void) Signal(SIGPIPE, oldintp);
- dbprintf("recvrequest result = %d.\n", result);
- return (result);
- } /* recvrequest */
-
-
-
-
- /*
- * Need to start a listen on the data channel
- * before we send the command, otherwise the
- * server's connect may fail.
- */
-
- int initconn(void)
- {
- register char *p, *a;
- int result, len, tmpno = 0;
- int on = 1, rval;
- string str;
- sig_t oldintr;
-
- oldintr = Signal(SIGINT, SIG_IGN);
- noport:
- data_addr = myctladdr;
- if (sendport)
- data_addr.sin_port = 0; /* let system pick one */
- if (data != -1)
- (void) close (data);
- data = socket(AF_INET, SOCK_STREAM, 0);
- if (data < 0) {
- PERROR("initconn", "socket");
- if (tmpno)
- sendport = 1;
- rval = 1; goto Return;
- }
- if (!sendport)
- if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
- PERROR("initconn", "setsockopt (reuse address)");
- goto bad;
- }
- #ifdef SOCKS
- if (Rbind(data, (struct sockaddr *)&data_addr, sizeof (data_addr), hisctladdr.sin_addr.s_addr) < 0) {
- #else
- if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
- #endif
- PERROR("initconn", "bind");
- goto bad;
- }
- if (options & SO_DEBUG &&
- setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
- PERROR("initconn", "setsockopt (ignored)");
- len = sizeof (data_addr);
- if (Getsockname(data, (char *)&data_addr, &len) < 0) {
- PERROR("initconn", "getsockname");
- goto bad;
- }
- #ifdef SOCKS
- if (Rlisten(data, 1) < 0)
- #else
- if (listen(data, 1) < 0)
- #endif
- PERROR("initconn", "listen");
- if (sendport) {
- a = (char *)&data_addr.sin_addr;
- p = (char *)&data_addr.sin_port;
- #define UC(x) (int) (((int) x) & 0xff)
- (void) sprintf(str, "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]));
- result = command(str);
- if (result == ERROR && sendport == -1) {
- sendport = 0;
- tmpno = 1;
- goto noport;
- }
- rval = (result != COMPLETE); goto Return;
- }
- if (tmpno)
- sendport = 1;
- rval = 0; goto Return;
- bad:
- (void) close(data), data = -1;
- if (tmpno)
- sendport = 1;
- rval = 1;
- Return:
- (void) Signal(SIGINT, oldintr);
- return (rval);
- } /* initconn */
-
-
-
-
- FILE *
- dataconn(char *mode)
- {
- struct sockaddr_in from;
- FILE *fp;
- int s, fromlen = sizeof (from);
-
- #ifdef SOCKS
- s = Raccept(data, (struct sockaddr *) &from, &fromlen);
- #else
- s = accept(data, (struct sockaddr *) &from, &fromlen);
- #endif
- if (s < 0) {
- PERROR("dataconn", "accept");
- (void) close(data), data = -1;
- fp = NULL;
- } else {
- (void) close(data);
- data = s;
- fp = fdopen(data, mode);
- }
- return (fp);
- } /* dataconn */
-
- /* eof ftp.c */
-