3 * ftpsbr.c -- simple FTP client library
11 #ifdef HAVE_ARPA_FTP_H
12 # include <arpa/ftp.h>
15 #define v_debug debugsw
16 #define v_verbose verbosw
18 static int ftp_fd = NOTOK;
19 static int data_fd = NOTOK;
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
32 #if defined(BIND) && !defined(h_addr)
33 # define h_addr h_addr_list[0]
36 #define inaddr_copy(hp,sin) \
37 memcpy((char *) &((sin)->sin_addr), (hp)->h_addr, (hp)->h_length)
39 #define start_tcp_client(sock,priv) \
40 socket (AF_INET, SOCK_STREAM, 0)
42 #define join_tcp_server(fd, sock) \
43 connect ((fd), (struct sockaddr *) (sock), sizeof *(sock))
48 struct hostent *gethostbystring ();
49 int ftp_get (char *, char *, char *, char *, char *, char *, int, int);
50 int ftp_trans (char *, char *, char *, char *, char *, char *, char *, int, int);
55 static int start_tcp_server (struct sockaddr_in *, int, int, int);
56 static void _asnprintf (char *, int, char *, va_list);
57 static int ftp_quit (void);
58 static int ftp_read (char *, char *, char *, int);
59 static int initconn (void);
60 static int dataconn (void);
61 static int command (int arg1, ...);
62 static int vcommand (int, va_list);
63 static int getreply (int, int);
67 start_tcp_server (struct sockaddr_in *sock, int backlog, int opt1, int opt2)
71 if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == NOTOK)
74 if (bind (sd, (struct sockaddr *) sock, sizeof *sock) == NOTOK) {
88 #define join_tcp_client(fd,sock) \
89 accept ((fd), (struct sockaddr *) (sock), \
90 (__len__ = sizeof *(sock), &__len__))
92 #define read_tcp_socket read
93 #define write_tcp_socket write
94 #define close_tcp_socket close
97 _asnprintf (char *bp, int len_bp, char *what, va_list ap)
105 fmt = va_arg (ap, char *);
108 vsnprintf(bp, len_bp, fmt, ap);
118 snprintf (bp, len_bp, " %s: ", what);
123 if ((s = strerror(eindex)))
124 strncpy (bp, s, len_bp);
126 snprintf (bp, len_bp, "Error %d", eindex);
135 ftp_get (char *host, char *user, char *password, char *cwd,
136 char *remote, char *local, int ascii, int stayopen)
138 return ftp_trans (host, user, password, cwd, remote, local,
139 "RETR", ascii, stayopen);
144 ftp_trans (char *host, char *user, char *password, char *cwd, char *remote,
145 char *local, char *cmd, int ascii, int stayopen)
150 result = ftp_quit ();
155 if (ftp_fd == NOTOK) {
156 struct sockaddr_in in_socket;
157 register struct hostent *hp;
158 register struct servent *sp;
160 if ((sp = getservbyname ("ftp", "tcp")) == NULL) {
161 fprintf (stderr, "tcp/ftp: unknown service");
164 if ((hp = gethostbystring (host)) == NULL) {
165 fprintf (stderr, "%s: unknown host\n", host);
168 in_socket.sin_family = hp->h_addrtype;
169 inaddr_copy (hp, &in_socket);
170 in_socket.sin_port = sp->s_port;
172 if ((ftp_fd = start_tcp_client ((struct sockaddr_in *) NULL, 0))
177 if (join_tcp_server (ftp_fd, &in_socket) == NOTOK) {
179 close_tcp_socket (ftp_fd), ftp_fd = NOTOK;
185 fprintf (stdout, "Connected to %s\n", host);
190 if ((result = command (0, "USER %s", user)) == CONTINUE)
191 result = command (1, "PASS %s", password);
192 if (result != COMPLETE) {
202 if (cwd && ((result = command (0, "CWD %s", cwd)) != COMPLETE
203 && result != CONTINUE)) {
208 if (command (1, ascii ? "TYPE A" : "TYPE I") != COMPLETE) {
213 result = ftp_read (remote, local, cmd, ascii);
216 if (result != OK || !stayopen)
231 n = command (1, "QUIT");
232 close_tcp_socket (ftp_fd), ftp_fd = NOTOK;
233 return (n == 0 || n == COMPLETE ? OK : NOTOK);
237 ftp_read (char *remote, char *local, char *cmd, int ascii)
239 int istdio = 0, istore;
241 int expectingreply = 0;
245 if (initconn () == NOTOK)
249 if (command (-1, *remote ? "%s %s" : "%s", cmd, remote) != PRELIM)
253 if (dataconn () == NOTOK) {
257 if (data_fd != NOTOK)
258 close_tcp_socket (data_fd), data_fd = NOTOK;
265 istore = !strcmp (cmd, "STOR");
267 if ((istdio = !strcmp (local, "-")))
268 fp = istore ? stdin : stdout;
270 if ((fp = fopen (local, istore ? "r" : "w")) == NULL) {
280 if (!(out = fdopen (data_fd, "w"))) {
285 while ((c = getc (fp)) != EOF) {
288 if (putc (c, out) == EOF) {
300 while ((cc = fread (buffer, sizeof *buffer, sizeof buffer, fp)) > 0)
301 if (write_tcp_socket (data_fd, buffer, cc) != cc) {
302 perror ("write_tcp_socket");
306 close_tcp_socket (data_fd), data_fd = NOTOK;
314 if (!(in = fdopen (data_fd, "r"))) {
319 while ((c = getc (in)) != EOF) {
321 switch (c = getc (in)) {
335 if (putc (c, fp) == EOF) {
347 while ((cc = read_tcp_socket (data_fd, buffer, sizeof buffer)) > 0)
348 if (fwrite (buffer, sizeof *buffer, cc, fp) == 0) {
353 perror ("read_tcp_socket");
357 close_tcp_socket (data_fd), data_fd = NOTOK;
365 return (getreply (1, 0) == COMPLETE ? OK : NOTOK);
369 #define UC(b) (((int) b) & 0xff)
375 register char *a, *p;
376 struct sockaddr_in in_socket;
378 if (getsockname (ftp_fd, (struct sockaddr *) &in_socket,
379 (len = sizeof(in_socket), &len)) == NOTOK) {
380 perror ("getsockname");
383 in_socket.sin_port = 0;
384 if ((data_fd = start_tcp_server (&in_socket, 1, 0, 0)) == NOTOK) {
385 perror ("start_tcp_server");
389 if (getsockname (data_fd, (struct sockaddr *) &in_socket,
390 (len = sizeof in_socket, &len)) == NOTOK) {
391 perror ("getsockname");
395 a = (char *) &in_socket.sin_addr;
396 p = (char *) &in_socket.sin_port;
398 if (command (1, "PORT %d,%d,%d,%d,%d,%d",
399 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
400 UC(p[0]), UC(p[1])) == COMPLETE)
410 struct sockaddr_in in_socket;
412 if ((fd = join_tcp_client (data_fd, &in_socket)) == NOTOK) {
413 perror ("join_tcp_client");
416 close_tcp_socket (data_fd);
424 command (int arg1, ...)
430 val = vcommand (arg1, ap);
437 vcommand (int complete, va_list ap)
445 _asnprintf (buffer, sizeof(buffer), NULL, ap);
447 fprintf (stderr, "<--- %s\n", buffer);
449 strcat (buffer, "\r\n");
450 len = strlen (buffer);
452 if (write_tcp_socket (ftp_fd, buffer, len) != len) {
453 perror ("write_tcp_socket");
457 return (getreply (complete, !strcmp (buffer, "QUIT")));
462 getreply (int complete, int expecteof)
465 register int code, dig, n;
470 code = dig = n = continuation = 0;
476 if (read_tcp_socket (ftp_fd, &c, 1) < 1) {
480 perror ("read_tcp_socket");
485 *bp++ = c != '\r' ? c : '\0';
490 code = code * 10 + (c - '0');
491 else /* XXX: naughty FTP... */
496 if (dig == 4 && c == '-')
503 fprintf (stderr, "---> %s\n", buffer);
510 fprintf (stdout, "%s\n", buffer);
515 if ((complete == -1 && n != PRELIM)
516 || (complete == 0 && n != CONTINUE && n != COMPLETE)
517 || (complete == 1 && n != COMPLETE))
518 fprintf (stderr, "%s\n", buffer);