2 * ftpsbr.c -- simple FTP client library
4 * This code is Copyright (c) 2002, by the authors of nmh. See the
5 * COPYRIGHT file in the root directory of the nmh distribution for
6 * complete copyright information.
12 #ifdef notdef_lyndon_posix
14 * Does this get included indirectly? Let's find out. It's not
15 * part of Posix. Mail lyndon@orthanc.ca if this breaks your build.
17 # include <arpa/ftp.h>
20 #define v_debug debugsw
21 #define v_verbose verbosw
23 static int ftp_fd = NOTOK;
24 static int data_fd = NOTOK;
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
37 #define start_tcp_client(res) \
38 socket (res->ai_family, res->ai_socktype, res->ai_protocol)
40 #define join_tcp_server(fd, sock, len) \
41 connect ((fd), (struct sockaddr *) (sock), len)
46 int ftp_get (char *, char *, char *, char *, char *, char *, int, int);
47 int ftp_trans (char *, char *, char *, char *, char *, char *, char *, int, int);
52 static int start_tcp_server (struct sockaddr_in *, int, int, int);
53 static void _asnprintf (char *, int, char *, va_list);
54 static int ftp_quit (void);
55 static int ftp_read (char *, char *, char *, int);
56 static int initconn (void);
57 static int dataconn (void);
58 static int command (int arg1, ...);
59 static int vcommand (int, va_list);
60 static int getreply (int, int);
64 start_tcp_server (struct sockaddr_in *sock, int backlog, int opt1, int opt2)
68 if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == NOTOK)
71 if (bind (sd, (struct sockaddr *) sock, sizeof *sock) == NOTOK) {
85 #define join_tcp_client(fd,sock) \
86 accept ((fd), (struct sockaddr *) (sock), \
87 (__len__ = sizeof *(sock), &__len__))
89 #define read_tcp_socket read
90 #define write_tcp_socket write
91 #define close_tcp_socket close
94 _asnprintf (char *bp, int len_bp, char *what, va_list ap)
102 fmt = va_arg (ap, char *);
105 vsnprintf(bp, len_bp, fmt, ap);
115 snprintf (bp, len_bp, " %s: ", what);
120 if ((s = strerror(eindex)))
121 strncpy (bp, s, len_bp);
123 snprintf (bp, len_bp, "Error %d", eindex);
132 ftp_get (char *host, char *user, char *password, char *cwd,
133 char *remote, char *local, int ascii, int stayopen)
135 return ftp_trans (host, user, password, cwd, remote, local,
136 "RETR", ascii, stayopen);
141 ftp_trans (char *host, char *user, char *password, char *cwd, char *remote,
142 char *local, char *cmd, int ascii, int stayopen)
147 result = ftp_quit ();
152 if (ftp_fd == NOTOK) {
153 struct addrinfo hints, *res;
155 memset(&hints, 0, sizeof(hints));
157 hints.ai_flags = AI_ADDRCONFIG;
159 hints.ai_family = PF_INET;
160 hints.ai_socktype = SOCK_STREAM;
162 result = getaddrinfo(host, "ftp", &hints, &res);
165 fprintf(stderr, "%s/ftp: %s\n", host, gai_strerror(result));
169 if ((ftp_fd = start_tcp_client (res)) == NOTOK) {
174 if (join_tcp_server (ftp_fd, res->ai_addr, res->ai_addrlen) == NOTOK) {
177 close_tcp_socket (ftp_fd), ftp_fd = NOTOK;
184 fprintf (stdout, "Connected to %s\n", host);
189 if ((result = command (0, "USER %s", user)) == CONTINUE)
190 result = command (1, "PASS %s", password);
191 if (result != COMPLETE) {
201 if (cwd && ((result = command (0, "CWD %s", cwd)) != COMPLETE
202 && result != CONTINUE)) {
207 if (command (1, ascii ? "TYPE A" : "TYPE I") != COMPLETE) {
212 result = ftp_read (remote, local, cmd, ascii);
215 if (result != OK || !stayopen)
230 n = command (1, "QUIT");
231 close_tcp_socket (ftp_fd), ftp_fd = NOTOK;
232 return (n == 0 || n == COMPLETE ? OK : NOTOK);
236 ftp_read (char *remote, char *local, char *cmd, int ascii)
238 int istdio = 0, istore;
240 int expectingreply = 0;
244 if (initconn () == NOTOK)
248 if (command (-1, *remote ? "%s %s" : "%s", cmd, remote) != PRELIM)
252 if (dataconn () == NOTOK) {
256 if (data_fd != NOTOK)
257 close_tcp_socket (data_fd), data_fd = NOTOK;
264 istore = !strcmp (cmd, "STOR");
266 if ((istdio = !strcmp (local, "-")))
267 fp = istore ? stdin : stdout;
269 if ((fp = fopen (local, istore ? "r" : "w")) == NULL) {
279 if (!(out = fdopen (data_fd, "w"))) {
284 while ((c = getc (fp)) != EOF) {
287 if (putc (c, out) == EOF) {
299 while ((cc = fread (buffer, sizeof *buffer, sizeof buffer, fp)) > 0)
300 if (write_tcp_socket (data_fd, buffer, cc) != cc) {
301 perror ("write_tcp_socket");
305 close_tcp_socket (data_fd), data_fd = NOTOK;
313 if (!(in = fdopen (data_fd, "r"))) {
318 while ((c = getc (in)) != EOF) {
320 switch (c = getc (in)) {
334 if (putc (c, fp) == EOF) {
346 while ((cc = read_tcp_socket (data_fd, buffer, sizeof buffer)) > 0)
347 if (fwrite (buffer, sizeof *buffer, cc, fp) == 0) {
352 perror ("read_tcp_socket");
356 close_tcp_socket (data_fd), data_fd = NOTOK;
364 return (getreply (1, 0) == COMPLETE ? OK : NOTOK);
368 #define UC(b) (((int) b) & 0xff)
374 register char *a, *p;
375 struct sockaddr_in in_socket;
377 if (getsockname (ftp_fd, (struct sockaddr *) &in_socket,
378 (len = sizeof(in_socket), &len)) == NOTOK) {
379 perror ("getsockname");
382 in_socket.sin_port = 0;
383 if ((data_fd = start_tcp_server (&in_socket, 1, 0, 0)) == NOTOK) {
384 perror ("start_tcp_server");
388 if (getsockname (data_fd, (struct sockaddr *) &in_socket,
389 (len = sizeof in_socket, &len)) == NOTOK) {
390 perror ("getsockname");
394 a = (char *) &in_socket.sin_addr;
395 p = (char *) &in_socket.sin_port;
397 if (command (1, "PORT %d,%d,%d,%d,%d,%d",
398 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
399 UC(p[0]), UC(p[1])) == COMPLETE)
409 struct sockaddr_in in_socket;
411 if ((fd = join_tcp_client (data_fd, &in_socket)) == NOTOK) {
412 perror ("join_tcp_client");
415 close_tcp_socket (data_fd);
423 command (int arg1, ...)
429 val = vcommand (arg1, ap);
436 vcommand (int complete, va_list ap)
444 _asnprintf (buffer, sizeof(buffer), NULL, ap);
446 fprintf (stderr, "<--- %s\n", buffer);
448 strcat (buffer, "\r\n");
449 len = strlen (buffer);
451 if (write_tcp_socket (ftp_fd, buffer, len) != len) {
452 perror ("write_tcp_socket");
456 return (getreply (complete, !strcmp (buffer, "QUIT")));
461 getreply (int complete, int expecteof)
464 register int code, dig, n;
469 code = dig = n = continuation = 0;
475 if (read_tcp_socket (ftp_fd, &c, 1) < 1) {
479 perror ("read_tcp_socket");
484 *bp++ = c != '\r' ? c : '\0';
489 code = code * 10 + (c - '0');
490 else /* XXX: naughty FTP... */
495 if (dig == 4 && c == '-')
502 fprintf (stderr, "---> %s\n", buffer);
509 fprintf (stdout, "%s\n", buffer);
514 if ((complete == -1 && n != PRELIM)
515 || (complete == 0 && n != CONTINUE && n != COMPLETE)
516 || (complete == 1 && n != COMPLETE))
517 fprintf (stderr, "%s\n", buffer);