Mercurial > hg > Applications > mh
view uip/ftpsbr.c @ 0:bce86c4163a3
Initial revision
author | kono |
---|---|
date | Mon, 18 Apr 2005 23:46:02 +0900 |
parents | |
children | a6481689f99c |
line wrap: on
line source
/* ftpsbr.c - simple FTP client library (why doesn't BSD have one?!?) */ #ifndef lint static char ident[] = "@(#)$Id$"; #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 #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) struct hostent *gethostbystring (); /* */ #ifdef __CYGWIN32__ #include <errno.h> #endif extern int errno; #if !defined(BSD44) && !defined(__GNU_LIBRARY__) extern int sys_nerr; extern char *sys_errlist[]; #endif #ifdef __NetBSD__ /* XXX */ #include <errno.h> #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; { return ftp_trans (host, user, password, cwd, remote, local, "RETR", ascii, stayopen); } /* */ int ftp_trans (host, user, password, cwd, remote, local, cmd, ascii, stayopen) char *host, *user, *password, *cwd, *remote, *local, *cmd; 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, cmd, 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, cmd, ascii) char *remote, *local, *cmd; int ascii; { int istdio = 0, istore; register int cc; int expectingreply = 0; char buffer[BUFSIZ]; FILE *fp = NULL; if (initconn () == NOTOK) goto bad; v_noise = v_verbose; if (command (-1, *remote ? "%s %s" : "%s", cmd, remote) != PRELIM) goto bad; expectingreply++; if (dataconn () == NOTOK) { bad: ; if (fp && !istdio) (void) fclose (fp); if (data_fd != NOTOK) (void) close_tcp_socket (data_fd), data_fd = NOTOK; if (expectingreply) (void) getreply (-2, 0); return NOTOK; } istore = !strcmp (cmd, "STOR"); if (istdio = !strcmp (local, "-")) fp = istore ? stdin : stdout; else if ((fp = fopen (local, istore ? "r" : "w")) == NULL) { perror (local); goto bad; } if (istore) { if (ascii) { int c; FILE *out; if (!(out = fdopen (data_fd, "w"))) { perror ("fdopen"); goto bad; } while ((c = getc (fp)) != EOF) { if (c == '\n') (void) putc ('\r', out); if (putc (c, out) == EOF) { perror ("putc"); (void) fclose (out); data_fd = NOTOK; goto bad; } } (void) fclose (out); data_fd = NOTOK; } else { while ((cc = fread (buffer, sizeof *buffer, sizeof buffer, fp)) >0) if (write_tcp_socket (data_fd, buffer, cc) != cc) { perror ("write_tcp_socket"); goto bad; } (void) close_tcp_socket (data_fd), data_fd = NOTOK; } } else { 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; } } if (!istdio) (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 = va_arg (ap, int); val = _command (val, 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