home *** CD-ROM | disk | FTP | other *** search
- /* ftp.c */
-
- #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>
-
- #ifdef SYSLOG
- # include <syslog.h>
- #endif
-
- /* You may need this for declarations of fd_set, etc. */
- #ifdef SYSSELECTH
- # include <sys/select.h>
- #else
- extern int select (int, void *, void *, void *, struct timeval *);
- #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 "ftpdefs.h"
- #include "defaults.h"
- #include "ftp.h"
- #include "cmds.h"
- #include "main.h"
- #include "ftprc.h"
- #include "getpass.h"
- #include "copyright.h"
-
- /* ftp.c globals */
- struct sockaddr_in hisctladdr;
- struct sockaddr_in data_addr;
- int data = -1;
- int abrtflag = 0;
- int connected; /* connected to server */
- struct sockaddr_in myctladdr;
- FILE *cin = NULL, *cout = NULL;
- char *reply_string = NULL;
- jmp_buf sendabort, recvabort;
- int progress_meter = 1;
- int cur_progress_meter;
- int sendport = -1; /* use PORT cmd for each data connection */
- int code; /* return/reply code for ftp command */
- string hostname; /* name of host connected to */
- 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;
-
- /* ftp.c externs */
- extern FILE *logf;
- extern string hostname, cwd, anon_password;
- extern int verbose, debug, macnum, margc;
- extern int curtype, creating;
- extern int options, activemcmd, paging;
- extern int ansi_escapes;
- extern char *line, *margv[];
- extern char *tcap_normal, *tcap_boldface;
- extern char *tcap_underline, *tcap_reverse;
- extern struct userinfo uinfo;
- extern struct macel macros[];
-
- #ifdef REDIR
- extern struct lslist *lshead, *lstail;
- extern int is_ls;
- #endif
-
- #define UPDATE_100 2
-
-
- int hookup(char *host, int port)
- {
- register struct hostent *hp = 0;
- int s, len, hErr = -1;
-
- 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("socket");
- goto done;
- }
- hisctladdr.sin_port = port;
- while (connect(s, (struct sockaddr *) &hisctladdr, (int) sizeof (hisctladdr)) < 0) {
- if (hp && hp->h_addr_list[1]) {
- int oerrno = errno;
-
- (void) fprintf(stderr, "NcFTP: connect error (%d) to address %s: ",
- errno, inet_ntoa(hisctladdr.sin_addr));
- errno = oerrno;
- Perror((char *) 0);
- 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("socket");
- goto done;
- }
- continue;
- }
- Perror("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("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);
- goto bad;
- }
- #ifdef SO_OOBINLINE
- {
- int on = 1;
-
- if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *) &on, sizeof(on))
- < 0 && debug) {
- Perror("setsockopt");
- }
- }
- #endif /* SO_OOBINLINE */
-
- hErr = 0;
- goto done;
-
- bad:
- (void) close(s);
- done:
- code = hErr;
- return (hErr);
- } /* hookup */
-
-
-
-
- int login(char *host, int openmode, int ignore_rc)
- {
- string tmp, str;
- char *username, *pass, *acct;
- int n, aflag = 0, prompted_login;
- int user_in_rc, tmpverbose;
-
- username = pass = acct = NULL;
- if (!ignore_rc) {
- if ((ruserpass2(host, &username, &pass, &acct)) < 0) {
- /*NOTREACHED */
- code = -1;
- return(0);
- }
- }
-
- user_in_rc = 1;
- prompted_login = 0;
- if (username == NULL) {
- user_in_rc = 0;
- prompted_login = 1;
- }
-
- if (!user_in_rc) {
- /* There was no username in the rc. */
- if (openmode == OPEN_A) {
- username = "anonymous";
- prompted_login = 0;
- } else { /* openmode == OPEN_U */
- /* Prompt for a username. */
- (void) printf("Name (%s:%s): ", host, uinfo.username);
- (void) FGets(tmp, stdin);
- tmp[strlen(tmp) - 1] = '\0';
- /*
- * User can hit return if he wants to enter his username
- * automatically.
- */
- if (*tmp == '\0')
- username = uinfo.username;
- else
- username = tmp;
- }
- }
- (void) sprintf(str, "USER %s", username);
- n = command(str);
- if (n == CONTINUE) {
- if (pass == NULL) {
- if (strcmp("anonymous", username) == 0)
- pass = anon_password;
- else
- pass = Getpass("Password:");
- }
- (void) sprintf(str, "PASS %s", pass);
- n = command(str);
- }
- if (n == CONTINUE) {
- aflag++;
- acct = Getpass("Account:");
- (void) sprintf(str, "ACCT %s", acct);
- n = command(str);
- }
- if (n != COMPLETE) {
- noLogin:
- (void) fprintf(stderr, "Login failed.\n");
- return (0);
- }
- #ifdef SYSLOG
- syslog (LOG_INFO, "%s connected to %s as %s.",
- uinfo.username, host, username);
- #endif
-
- if (!aflag && acct != NULL) {
- (void) sprintf(str, "ACCT %s", acct);
- (void) command(str);
- }
-
- /* See if remote host dropped connection. */
- tmpverbose = verbose;
- verbose = V_QUIET;
- n = command("NOOP");
- verbose = tmpverbose;
- if (n == 4)
- goto noLogin;
-
- if (NOT_VQUIET && !prompted_login)
- (void) printf("Logged into %s.\n", host);
- if (!ignore_rc)
- for (n = 0; n < macnum; ++n) {
- if (!strcmp("init", macros[n].mac_name)) {
- (void) strcpy(line, "$init");
- makeargv();
- domacro(margc, margv);
- break;
- }
- }
- return (1);
- } /* login */
-
-
-
- /*ARGSUSED*/
- void cmdabort(int unused)
- {
- (void) printf("\n");
- (void) fflush(stdout);
- abrtflag++;
- } /* cmdabort */
-
-
-
-
- command(char *cmd)
- {
- int r;
- void (*oldintr)(int);
- string str;
-
- abrtflag = 0;
- if (debug) {
- (void) printf("---> \"%s\" (length %lu)\n", cmd, strlen(cmd));
- }
- if (cout == NULL) {
- (void) sprintf(str, "%s: No control connection for command", cmd);
- Perror(str);
- code = -1;
- return (0);
- }
- oldintr = signal(SIGINT, /* cmdabort */ SIG_IGN);
- #ifndef SCO324
- 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 */
-
-
-
-
- getreply(int expecteof)
- {
- register int c, n;
- int dig;
- char *cp, *end, *dp;
- int thiscode, originalcode = 0, continuation = 0;
- void (*oldintr)(int);
-
- if (cin == NULL)
- return (-1);
- oldintr = signal(SIGINT, /* cmdabort */ SIG_IGN);
- end = reply_string + RECEIVEDLINELEN - 2;
- for (;;) {
- dig = n = code = 0;
- cp = reply_string;
- for (;;) {
- c = getc(cin);
- if (c == IAC) { /* handle telnet commands */
- switch (c = getc(cin)) {
- case WILL:
- case WONT:
- c = getc(cin);
- (void) fprintf(cout, "%c%c%c",IAC,DONT,c);
- (void) fflush(cout);
- break;
- case DO:
- case DONT:
- c = getc(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:
- 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 */
-
-
-
- static int barlen;
-
- int start_progress(int sending, char *local)
- {
- long s;
- str32 spec;
-
- cur_progress_meter = progress_meter;
- if ((cur_progress_meter > pr_kbytes) || (cur_progress_meter < 0))
- cur_progress_meter = pr_percent;
- if ((file_size <= 0) && ((cur_progress_meter == pr_percent) || (cur_progress_meter == pr_philbar)))
- cur_progress_meter = pr_kbytes;
- if (!ansi_escapes && (cur_progress_meter == pr_philbar))
- cur_progress_meter = pr_none;
-
- (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:
- 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);
- printf(spec, " ", file_size);
- zz:
- (void) fflush(stdout);
- echo(stdin, 0);
- } /* end switch */
- return (cur_progress_meter);
- } /* start_progress */
-
-
-
-
- void progress_report(int finish_up)
- {
- int i;
- int size;
- str32 spec;
-
- next_report += xferbufsize;
- (void) gettimeofday(&stop, (struct timezone *)0);
- if ((stop.tv_sec > now_sec) || finish_up) {
- switch (cur_progress_meter) {
- case pr_none:
- break;
- case pr_percent:
- (void) printf("\b\b\b\b%3ld%%", 100L * bytes / file_size);
- (void) fflush(stdout);
- break;
- case pr_philbar:
- size = (int) ((float)barlen * ((float) bytes/file_size));
- (void) sprintf(spec, "%%3ld%%%% 0 %%s%%%ds%%s\r", size);
- (void) printf(
- spec,
- 100L * 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);
- }
- } /* end switch */
- now_sec = stop.tv_sec;
- } /* end if we updated */
- } /* progress_report */
-
-
-
-
- void end_progress(char *direction, char *local, char *remote)
- {
- struct timeval td;
- float s, bs;
- char *cp, *bsstr;
- string str;
-
- if (bytes <= 0)
- return;
- 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:
- (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:
- printf("\n");
- echo(stdin, 1);
- break;
- }
-
- /* 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(int unused)
- {
- activemcmd = 0;
- abrtflag = 0;
- (void) printf("\nSend aborted.\n");
- (void) fflush(stdout);
- longjmp(sendabort, 1);
- } /* abortsend */
-
-
-
- void sendrequest(char *cmd, char *local, char *remote)
- {
- FILE *fin, *dout = NULL;
- void (*oldintr)(int), (*oldintp)(int);
- string str;
- register int c, d;
- struct stat st;
- int filetype;
- int do_reports = 0;
- char *mode;
- register char *bufp;
-
- 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);
- code = -1;
- echo(stdin, 1);
- return;
- }
- 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(local + 1);
- (void) signal(SIGINT, oldintr);
- (void) signal(SIGPIPE, oldintp);
- code = -1;
- return;
- }
- } else {
- filetype = IS_FILE;
- fin = fopen(local, "r");
- if (fin == NULL) {
- Perror(local);
- (void) signal(SIGINT, oldintr);
- code = -1;
- return;
- }
- 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);
- code = -1;
- return;
- }
- file_size = st.st_size;
- }
- if (initconn()) {
- (void) signal(SIGINT, oldintr);
- if (oldintp)
- (void) signal(SIGPIPE, oldintp);
- code = -1;
- close_file(&fin, filetype);
- return;
- }
- 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);
- return;
- }
- } else
- if (command(cmd) != PRELIM) {
- (void) signal(SIGINT, oldintr);
- if (oldintp)
- (void) signal(SIGPIPE, oldintp);
- close_file(&fin, filetype);
- return;
- }
- 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)
- progress_report(0);
- }
- if (c < 0)
- Perror(local);
- if (d <= 0) {
- if (d == 0 && !creating)
- (void) fprintf(stderr, "netout: write returned 0?\n");
- else if (errno != EPIPE)
- Perror("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)
- progress_report(0);
- }
- if (ferror(fin))
- Perror(local);
- if (ferror(dout)) {
- if (errno != EPIPE)
- Perror("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);
- end_progress("sent", local, remote);
- return;
- Abort:
- code = -1;
- echo(stdin, 1);
- if (!cpend)
- return;
- if (data >= 0) {
- (void) close(data);
- data = -1;
- }
- goto Done;
- } /* sendrequest */
-
-
-
- long get_remote_size(char *remote, int filetype)
- {
- int oldverbose;
- long rmt_size;
- string str;
-
- rmt_size = -1; /*
- * Return -1 if we could't get it.
- * Not all sites support SIZE.
- */
-
- if (filetype == IS_FILE) {
- /* Won't make sense for a pipe or stream. */
- (void) sprintf(str, "SIZE %s", remote);
- *reply_string = 0;
- oldverbose = verbose;
- verbose = V_QUIET;
- (void) command(str);
- verbose = oldverbose;
- if (*reply_string != 5) /* 5xx is an error. */
- (void) sscanf(reply_string, "%*d %ld", &rmt_size);
- }
- return rmt_size;
- } /* get_remote_size */
-
-
-
- /*ARGSUSED*/
- void abortrecv(int unused)
- {
- activemcmd = 0;
- abrtflag = 0;
- (void) printf("(abort)\n");
- (void) fflush(stdout);
- longjmp(recvabort, 1);
- } /* abortrecv */
-
-
-
- void recvrequest(char *cmd, char *local, char *remote, char *mode)
- {
- FILE *fout, *din;
- void (*oldintr)(int), (*oldintp)(int);
- int oldverbose, oldtype = 0, is_retr;
- int tcrflag, nfnd;
- char msg;
- string str;
- struct fd_set mask;
- int c, d;
- int filetype, do_reports = 0;
- string remote_dir;
- char *cp;
- #ifdef REDIR
- char *linePtr;
- int nchars;
- string str2;
- #endif
-
- bytes = 0;
- is_retr = strcmp(cmd, "RETR") == 0;
- oldintr = NULL;
- oldintp = NULL;
- tcrflag = /* !crflag && */ is_retr;
-
- /*
- * 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);
- }
- }
-
- if (setjmp(recvabort)) {
- echo(stdin, 1);
- while (cpend) {
- (void) getreply(0);
- }
- if (data >= 0) {
- (void) close(data);
- data = -1;
- }
- if (oldintr)
- (void) signal(SIGINT, oldintr);
- code = -1;
- return;
- }
- oldintr = signal(SIGINT, abortrecv);
-
- if (strcmp(local, "-") == 0)
- filetype = IS_STREAM;
- else if (*local == '|')
- filetype = IS_PIPE;
- else {
- filetype = IS_FILE; /* is_retr ? IS_FILE : IS_STREAM; */
- if (access(local, 2) < 0) {
- char *dir = rindex(local, '/');
-
- if (errno != ENOENT && errno != EACCES) {
- Perror(local);
- (void) signal(SIGINT, oldintr);
- code = -1;
- return;
- }
- /* 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(local);
- (void) signal(SIGINT, oldintr);
- code = -1;
- return;
- }
- }
- }
- }
- if (initconn()) {
- (void) signal(SIGINT, oldintr);
- code = -1;
- return;
- }
- if (!is_retr) {
- if (curtype != TYPE_A) {
- oldtype = curtype;
- oldverbose = verbose;
- if (!debug)
- verbose = V_QUIET;
- setascii(0, NULL);
- verbose = oldverbose;
- }
- }
-
- file_size = -1;
- if (remote) {
- file_size = get_remote_size(remote, filetype);
- (void) sprintf(str, "%s %s", cmd, remote);
- if (command(str) != PRELIM)
- goto nevrmind;
- } else {
- if (command(cmd) != PRELIM) {
- nevrmind: (void) signal(SIGINT, oldintr);
- if (oldtype) {
- if (!debug)
- verbose = V_QUIET;
- if (oldtype == TYPE_I)
- setbinary(0, NULL);
- verbose = oldverbose;
- }
- return;
- }
- }
- din = dataconn("r");
- if (din == NULL)
- goto Abort;
- if (filetype == IS_STREAM) {
- fout = stdout;
- } else if (filetype == IS_PIPE) {
- oldintp = signal(SIGPIPE, SIG_IGN);
- fout = popen(local + 1, "w");
- if (fout == NULL) {
- Perror(local+1);
- goto Abort;
- }
- } else {
- fout = fopen(local, mode);
- if (fout == NULL) {
- Perror(local);
- goto Abort;
- }
- }
- do_reports = NOT_VQUIET && is_retr && filetype == IS_FILE;
- if (do_reports)
- do_reports = start_progress(0, local);
-
- if (setjmp(recvabort))
- goto Abort;
-
- switch (curtype) {
-
- case TYPE_I:
- case TYPE_L:
- errno = d = 0;
- while ((c = read(fileno(din), xferbuf, (int)xferbufsize)) > 0) {
- if ((d = write(fileno(fout), xferbuf, c)) != c)
- break;
- bytes += c;
-
- /* Print progress indicator. */
- if (do_reports)
- progress_report(0);
- }
- if (c < 0) {
- if (errno != EPIPE)
- Perror("netin");
- bytes = -1;
- }
- if (d < c) {
- if (d < 0) {
- if (errno != EPIPE)
- Perror(local);
- } else
- (void) fprintf(stderr, "%s: short write\n", local);
- }
- break;
-
- case TYPE_A:
- #ifdef REDIR
- nchars = 0;
- linePtr = str2;
- #endif
- next_report = xferbufsize;
- while ((c = getc(din)) != EOF) {
- while (c == '\r') {
- bytes++;
- if ((c = getc(din)) != '\n' || tcrflag) {
- if (ferror(fout))
- goto break2;
- (void) putc('\r', fout);
- if (c == '\0') {
- bytes++;
- goto contin2;
- }
- if (c == EOF)
- goto contin2;
- }
- }
- (void) putc(c, fout);
- bytes++;
-
- /* Print progress indicator. */
- if (do_reports && bytes > next_report)
- progress_report(0);
- #ifdef REDIR
- if (nchars < sizeof(str2) - 1) { /* No seg violations, please */
- *linePtr++ = c; /* build redir string */
- nchars++;
- }
- #endif
- contin2:
- #ifdef REDIR
- /* Save the input line in the buffer for recall later. */
- if (c=='\n' && is_ls) {
- register struct lslist *new;
-
- *--linePtr = '\0';
- nchars--;
- new = (struct lslist *) malloc((size_t) sizeof(struct lslist));
- if (new != NULL) {
- if (new->string = malloc(strlen(str2) + 1))
- (void) strcpy(new->string, str2);
- new->next = NULL;
- if (lshead == NULL)
- lshead = lstail = new;
- else {
- lstail->next = new;
- lstail = new;
- }
- }
- /* reset line buffer */
- linePtr = str2;
- nchars = 0;
- } /* ls mode & last char is a newline */
- #else
- ;
- #endif
- } /* while ((c = getc(din)) != EOF) */
- break2:
- if (ferror(din)) {
- if (errno != EPIPE)
- Perror("netin");
- bytes = -1;
- }
- if (ferror(fout)) {
- if (errno != EPIPE)
- Perror(local);
- }
- break;
- } /* end switch (curtype) */
-
- close_file(&fout, filetype);
- (void) signal(SIGINT, oldintr);
- if (oldintp)
- (void) signal(SIGPIPE, oldintp);
- if (din)
- (void) fclose(din);
- (void) getreply(0);
- if (bytes > 0 && is_retr && filetype == IS_FILE)
- end_progress("received", local, remote);
- if (oldtype) {
- if (!debug)
- verbose = V_QUIET;
- if (oldtype == TYPE_I)
- setbinary(0, NULL);
- verbose = oldverbose;
- }
- return;
- Abort:
- echo(stdin, 1);
-
- /* Abort using RFC959 recommended IP,SYNC sequence */
-
- if (oldintp)
- (void) signal(SIGPIPE, oldintr);
- (void) signal(SIGINT,SIG_IGN);
- if (oldtype) {
- if (!debug)
- verbose = V_QUIET;
- if (oldtype == TYPE_I)
- setbinary(0, NULL);
- verbose = oldverbose;
- }
- if (!cpend) {
- code = -1;
- (void) signal(SIGINT,oldintr);
- return;
- }
-
- if (!cout) return;
- (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("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("abort");
- }
- code = -1;
- lostpeer(0);
- }
- if (din && FD_ISSET(fileno(din), &mask)) {
- while ((c = read(fileno(din), xferbuf, xferbufsize)) > 0)
- ;
- }
- if ((c = getreply(0)) == ERROR && code == 552) { /* needed for nic style abort */
- if (data >= 0) {
- (void) close(data);
- data = -1;
- }
- (void) getreply(0);
- }
- (void) getreply(0);
- code = -1;
- if (data >= 0) {
- (void) close(data);
- data = -1;
- }
- close_file(&fout, filetype);
- if (din)
- (void) fclose(din);
- end_progress("received", local, remote);
- (void) signal(SIGINT,oldintr);
- } /* recvrequest */
-
-
-
-
- /*
- * Need to start a listen on the data channel
- * before we send the command, otherwise the
- * server's connect may fail.
- */
-
- initconn(void)
- {
- register char *p, *a;
- int result, len, tmpno = 0;
- int on = 1, rval;
- string str;
- void (*oldintr)(int);
-
- 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("socket");
- if (tmpno)
- sendport = 1;
- rval = 1; goto Return;
- }
- if (!sendport)
- if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
- Perror("setsockopt (reuse address)");
- goto bad;
- }
- if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
- Perror("bind");
- goto bad;
- }
- if (options & SO_DEBUG &&
- setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
- Perror("setsockopt (ignored)");
- len = sizeof (data_addr);
- if (getsockname(data, (char *)&data_addr, &len) < 0) {
- Perror("getsockname");
- goto bad;
- }
- if (listen(data, 1) < 0)
- Perror("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);
-
- s = accept(data, (struct sockaddr *) &from, &fromlen);
- if (s < 0) {
- Perror("accept");
- (void) close(data), data = -1;
- fp = NULL;
- } else {
- (void) close(data);
- data = s;
- fp = fdopen(data, mode);
- }
- return (fp);
- } /* dataconn */
-
- /* eof ftp.c */
-