4.4BSD/usr/src/contrib/mh-6.8/uip/ftpsbr.c
/* ftpsbr.c - simple FTP client library (why doesn't BSD have one?!?) */
#ifndef lint
static char ident[] = "@(#)$Id: ftpsbr.c,v 1.10 1992/12/03 16:50:27 jromine Exp $";
#endif
#include "../h/mh.h"
#include "../h/mhn.h"
#ifdef FTP
#include <ctype.h>
#ifdef SVR4
#undef NULLVP /* stdio.h */
#endif
#include <stdio.h>
#include <arpa/ftp.h>
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#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 <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#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;
#ifndef BSD44
extern int sys_nerr;
extern char *sys_errlist[];
#endif
#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