/* ftpsbr.c - simple FTP client library (why doesn't BSD have one?!?) */ #ifndef lint static char ident[] = "@(#)ftpsbr.c,v 1.1.1.1 1993/01/30 04:41:33 jtc Exp"; #endif #include "../h/mh.h" #include "../h/mhn.h" #ifdef FTP #include #ifdef SVR4 #undef NULLVP /* stdio.h */ #endif #include #include #ifdef __STDC__ #include #else #include #endif #ifdef __STDC__ static int command(int arg1, ...); #else static int command(); #endif static int ftp_quit(), ftp_read(), initconn(), dataconn(), _command(), getreply(); /* DATA */ #define v_debug debugsw #define v_verbose verbosw static int ftp_fd = NOTOK; static int data_fd = NOTOK; static int v_noise; extern int v_debug; extern int v_verbose; /* */ #if defined(SYS5) && defined(AUX) #define u_short ushort #define u_long ulong #endif /* taken from ISODE's compat/internet.c */ #include #include #include #include #if defined(BIND) && !defined(h_addr) #define h_addr h_addr_list[0] #endif #define inaddr_copy(hp,sin) \ bcopy ((hp) -> h_addr, (char *) &((sin) -> sin_addr), (hp) -> h_length) #ifndef DG u_long inet_addr (); #else struct in_addr inet_addr (); #endif static char *empty = NULL; #ifdef h_addr static char *addrs[2] = { NULL }; #endif static struct hostent *gethostbystring (s) char *s; { register struct hostent *h; #ifndef DG static u_long iaddr; #else static struct in_addr iaddr; #endif static struct hostent hs; iaddr = inet_addr (s); #ifndef DG if (iaddr == NOTOK && strcmp (s, "255.255.255.255")) #else if (iaddr.s_addr == NOTOK && strcmp (s, "255.255.255.255")) #endif return gethostbyname (s); h = &hs; h -> h_name = s; h -> h_aliases = ∅ h -> h_addrtype = AF_INET; h -> h_length = sizeof (iaddr); #ifdef h_addr h -> h_addr_list = addrs; bzero ((char *) addrs, sizeof addrs); #endif h -> h_addr = (char *) &iaddr; return h; } /* */ extern int errno; extern int sys_nerr; extern char *sys_errlist[]; #define start_tcp_client(sock,priv) \ socket (AF_INET, SOCK_STREAM, 0) #define join_tcp_server(fd, sock) \ connect ((fd), (struct sockaddr *) (sock), sizeof *(sock)) /* ARGSUSED */ static int start_tcp_server (sock, backlog, opt1, opt2) struct sockaddr_in *sock; int backlog, opt1, opt2; { int eindex, sd; if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == NOTOK) return NOTOK; if (bind (sd, (struct sockaddr *) sock, sizeof *sock) == NOTOK) { eindex = errno; (void) close (sd); errno = eindex; } else (void) listen (sd, backlog); return sd; } static int __len__; #define join_tcp_client(fd,sock) \ accept ((fd), (struct sockaddr *) (sock), \ (__len__ = sizeof *(sock), &__len__)) #define read_tcp_socket read #define write_tcp_socket write #define close_tcp_socket close /* */ static void _asprintf (bp, what, ap) /* fmt, args, ... */ register char *bp; char *what; va_list ap; { register int eindex; char *fmt; eindex = errno; *bp = '\0'; fmt = va_arg (ap, char *); if (fmt) { #ifndef VSPRINTF struct _iobuf iob; #endif #ifndef VSPRINTF #ifdef pyr bzero ((char *) &iob, sizeof iob); iob._file = _NFILE; #endif iob._flag = _IOWRT | _IOSTRG; #if !defined(vax) && !defined(pyr) && !defined(sequent) iob._ptr = (unsigned char *) bp; #else iob._ptr = bp; #endif iob._cnt = BUFSIZ; _doprnt (fmt, ap, &iob); (void) putc ('\0', &iob); #else (void) vsprintf (bp, fmt, ap); #endif bp += strlen (bp); } if (what) { if (*what) { (void) sprintf (bp, " %s: ", what); bp += strlen (bp); } if (0 < eindex && eindex < sys_nerr) (void) strcpy (bp, sys_errlist[eindex]); else (void) sprintf (bp, "Error %d", eindex); bp += strlen (bp); } errno = eindex; } /* */ int ftp_get (host, user, password, cwd, remote, local, ascii, stayopen) char *host, *user, *password, *cwd, *remote, *local; int ascii, stayopen; { int result; if (stayopen <= 0) { result = ftp_quit (); if (host == NULL) return result; } if (ftp_fd == NOTOK) { struct sockaddr_in in_socket; register struct hostent *hp; register struct servent *sp; if ((sp = getservbyname ("ftp", "tcp")) == NULL) { fprintf (stderr, "tcp/ftp: unknown service"); return NOTOK; } if ((hp = gethostbystring (host)) == NULL) { fprintf (stderr, "%s: unknown host\n", host); return NOTOK; } in_socket.sin_family = hp -> h_addrtype; inaddr_copy (hp, &in_socket); in_socket.sin_port = sp -> s_port; if ((ftp_fd = start_tcp_client ((struct sockaddr_in *) NULL, 0)) == NOTOK) { perror (host); return NOTOK; } if (join_tcp_server (ftp_fd, &in_socket) == NOTOK) { perror (host); (void) close_tcp_socket (ftp_fd), ftp_fd = NOTOK; return NOTOK; } (void) getreply (1, 0); if (v_verbose) { fprintf (stdout, "Connected to %s\n", host); (void) fflush (stdout); } if (user) { if ((result = command (0, "USER %s", user)) == CONTINUE) result = command (1, "PASS %s", password); if (result != COMPLETE) { result = NOTOK; goto out; } } if (remote == NULL) return OK; } if (cwd && ((result = command (0, "CWD %s", cwd)) != COMPLETE && result != CONTINUE)) { result = NOTOK; goto out; } if (command (1, ascii ? "TYPE A" : "TYPE I") != COMPLETE) { result = NOTOK; goto out; } result = ftp_read (remote, local, ascii); out: ; if (result != OK || !stayopen) (void) ftp_quit (); return result; } /* */ static int ftp_quit () { int n; if (ftp_fd == NOTOK) return OK; n = command (1, "QUIT"); (void) close_tcp_socket (ftp_fd), ftp_fd = NOTOK; return (n == 0 || n == COMPLETE ? OK : NOTOK); } /* */ static int ftp_read (remote, local, ascii) char *remote, *local; int ascii; { register int cc; int expectingreply = 0; char buffer[BUFSIZ]; FILE *fp; if (initconn () == NOTOK) goto bad; v_noise = v_verbose; if (command (-1, "RETR %s", remote) != PRELIM) goto bad; expectingreply++; if (dataconn () == NOTOK) { bad: ; if (data_fd != NOTOK) (void) close_tcp_socket (data_fd), data_fd = NOTOK; if (expectingreply) (void) getreply (-2, 0); return NOTOK; } if ((fp = fopen (local, "w")) == NULL) { perror (local); goto bad; } if (ascii) { int c; FILE *in; if (!(in = fdopen (data_fd, "r"))) { perror ("fdopen"); goto bad; } while ((c = getc (in)) != EOF) { if (c == '\r') switch (c = getc (in)) { case EOF: case '\0': c = '\r'; break; case '\n': break; default: (void) putc ('\r', fp); break; } if (putc (c, fp) == EOF) { perror ("putc"); (void) fclose (in); data_fd = NOTOK; goto bad; } } (void) fclose (in); data_fd = NOTOK; } else { while ((cc = read_tcp_socket (data_fd, buffer, sizeof buffer)) > 0) if (fwrite (buffer, sizeof *buffer, cc, fp) == 0) { perror ("fwrite"); goto bad; } if (cc < 0) { perror ("read_tcp_socket"); goto bad; } (void) close_tcp_socket (data_fd), data_fd = NOTOK; } (void) fclose (fp); v_noise = v_verbose; return (getreply (1, 0) == COMPLETE ? OK : NOTOK); } /* */ static int initconn () { int len; register char *a, *p; struct sockaddr_in in_socket; if (getsockname (ftp_fd, (struct sockaddr *) &in_socket, (len = sizeof in_socket, &len)) == NOTOK) { perror ("getsockname"); return NOTOK; } in_socket.sin_port = 0; if ((data_fd = start_tcp_server (&in_socket, 1, 0, 0)) == NOTOK) { perror ("start_tcp_server"); return NOTOK; } if (getsockname (data_fd, (struct sockaddr *) &in_socket, (len = sizeof in_socket, &len)) == NOTOK) { perror ("getsockname"); return NOTOK; } a = (char *) &in_socket.sin_addr; p = (char *) &in_socket.sin_port; #define UC(b) (((int) b) & 0xff) if (command (1, "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])) == COMPLETE) return OK; return NOTOK; } /* */ static int dataconn () { int fd; struct sockaddr_in in_socket; if ((fd = join_tcp_client (data_fd, &in_socket)) == NOTOK) { perror ("join_tcp_client"); return NOTOK; } (void) close_tcp_socket (data_fd); data_fd = fd; return OK; } /* */ #ifndef lint #ifdef __STDC__ static int command (int arg1, ...) { int val; va_list ap; va_start (ap, arg1); val = _command (arg1, ap); va_end (ap); return val; } #else static int command (va_alist) va_dcl { int val; va_list ap; va_start (ap); val = _command (va_arg (ap, int), ap); va_end (ap); return val; } #endif static int _command (complete, ap) int complete; va_list ap; { int len; char buffer[BUFSIZ]; if (ftp_fd == NOTOK) return NOTOK; _asprintf (buffer, NULLCP, ap); if (v_debug) fprintf (stderr, "<--- %s\n", buffer); (void) strcat (buffer, "\r\n"); len = strlen (buffer); if (write_tcp_socket (ftp_fd, buffer, len) != len) { perror ("write_tcp_socket"); return NOTOK; } return (getreply (complete, !strcmp (buffer, "QUIT"))); } #else /* VARARGS2 */ static int command (complete, fmt) int complete; char *fmt; { return command (complete, fmt); } #endif /* */ static int getreply (complete, expecteof) int complete, expecteof; { for (;;) { register int code, dig, n; int continuation; register char *bp; char buffer[BUFSIZ]; code = dig = n = continuation = 0; bp = buffer; for (;;) { char c; if (read_tcp_socket (ftp_fd, &c, 1) < 1) { if (expecteof) return OK; perror ("read_tcp_socket"); return DONE; } if (c == '\n') break; *bp++ = c != '\r' ? c : '\0'; dig++; if (dig < 4) { if (isdigit(c)) code = code * 10 + (c - '0'); else /* XXX: naughty FTP... */ if (isspace (c)) continuation++; } else if (dig == 4 && c == '-') continuation++; if (n == 0) n = c; } if (v_debug) fprintf (stderr, "---> %s\n", buffer); if (continuation) continue; n -= '0'; if (v_noise) { fprintf (stdout, "%s\n", buffer); (void) fflush (stdout); v_noise = 0; } else if ((complete == -1 && n != PRELIM) || (complete == 0 && n != CONTINUE && n != COMPLETE) || (complete == 1 && n != COMPLETE)) fprintf (stderr, "%s\n", buffer); return n; } } #endif