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 HAVE_ARPA_FTP_H
13 # include <arpa/ftp.h>
16 #define v_debug debugsw
17 #define v_verbose verbosw
19 static int ftp_fd = NOTOK;
20 static int data_fd = NOTOK;
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
33 #define start_tcp_client(res) \
34 socket(res->ai_family, res->ai_socktype, res->ai_protocol)
36 #define join_tcp_server(fd, sock, len) \
37 connect((fd), (struct sockaddr *) (sock), len)
42 int ftp_get(char *, char *, char *, char *, char *, char *, int, int);
43 int ftp_trans(char *, char *, char *, char *, char *, char *, char *,
49 static int start_tcp_server(struct sockaddr_in *, int, int, int);
50 static void _asnprintf(char *, int, char *, va_list);
51 static int ftp_quit(void);
52 static int ftp_read(char *, char *, char *, int);
53 static int initconn(void);
54 static int dataconn(void);
55 static int command(int arg1, ...);
56 static int vcommand(int, va_list);
57 static int getreply(int, int);
61 start_tcp_server(struct sockaddr_in *sock, int backlog, int opt1, int opt2)
65 if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == NOTOK)
68 if (bind(sd, (struct sockaddr *) sock, sizeof *sock) == NOTOK) {
82 #define join_tcp_client(fd,sock) \
83 accept((fd), (struct sockaddr *) (sock), \
84 (__len__ = sizeof *(sock), &__len__))
86 #define read_tcp_socket read
87 #define write_tcp_socket write
88 #define close_tcp_socket close
91 _asnprintf(char *bp, int len_bp, char *what, va_list ap)
99 fmt = va_arg(ap, char *);
102 vsnprintf(bp, len_bp, fmt, ap);
112 snprintf(bp, len_bp, " %s: ", what);
117 if ((s = strerror(eindex)))
118 strncpy(bp, s, len_bp);
120 snprintf(bp, len_bp, "Error %d", eindex);
129 ftp_get(char *host, char *user, char *password, char *cwd,
130 char *remote, char *local, int ascii, int stayopen)
132 return ftp_trans(host, user, password, cwd, remote, local,
133 "RETR", ascii, stayopen);
138 ftp_trans(char *host, char *user, char *password, char *cwd, char *remote,
139 char *local, char *cmd, int ascii, int stayopen)
149 if (ftp_fd == NOTOK) {
150 struct addrinfo hints, *res;
152 memset(&hints, 0, sizeof(hints));
154 hints.ai_flags = AI_ADDRCONFIG;
156 hints.ai_family = PF_INET;
157 hints.ai_socktype = SOCK_STREAM;
159 result = getaddrinfo(host, "ftp", &hints, &res);
162 fprintf(stderr, "%s/ftp: %s\n",
163 host, gai_strerror(result));
167 if ((ftp_fd = start_tcp_client(res)) == NOTOK) {
172 if (join_tcp_server(ftp_fd, res->ai_addr, res->ai_addrlen)
176 close_tcp_socket(ftp_fd), ftp_fd = NOTOK;
183 fprintf(stdout, "Connected to %s\n", host);
188 if ((result = command (0, "USER %s", user))
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) {
298 while ((cc = fread(buffer, sizeof *buffer,
299 sizeof buffer, fp)) > 0)
300 if (write_tcp_socket(data_fd, buffer, cc)
302 perror("write_tcp_socket");
306 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) {
345 while ((cc = read_tcp_socket(data_fd, buffer,
347 if (fwrite(buffer, sizeof *buffer, cc, fp)
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');
492 /* XXX: naughty FTP... */
495 if (dig == 4 && c == '-')
502 fprintf(stderr, "---> %s\n", buffer);
509 fprintf(stdout, "%s\n", buffer);
513 if ((complete == -1 && n != PRELIM)
514 || (complete == 0 && n != CONTINUE && n != COMPLETE)
515 || (complete == 1 && n != COMPLETE))
516 fprintf(stderr, "%s\n", buffer);