Removed the space between function names and the opening parenthesis.
[mmh] / uip / ftpsbr.c
index 671a533..7d6d72b 100644 (file)
@@ -1,9 +1,10 @@
-
 /*
- * ftpsbr.c -- simple FTP client library
- *
- * $Id$
- */
+** ftpsbr.c -- simple FTP client library
+**
+** This code is Copyright (c) 2002, by the authors of nmh.  See the
+** COPYRIGHT file in the root directory of the nmh distribution for
+** complete copyright information.
+*/
 
 #include <h/mh.h>
 #include <h/mime.h>
@@ -12,8 +13,8 @@
 # include <arpa/ftp.h>
 #endif
 
-#define        v_debug debugsw
-#define        v_verbose verbosw
+#define v_debug debugsw
+#define v_verbose verbosw
 
 static int ftp_fd = NOTOK;
 static int data_fd = NOTOK;
@@ -29,494 +30,491 @@ extern int v_verbose;
 #include <netdb.h>
 #include <errno.h>
 
-#if defined(BIND) && !defined(h_addr)
-# define h_addr        h_addr_list[0]
-#endif
-
-#define        inaddr_copy(hp,sin) \
-    memcpy((char *) &((sin)->sin_addr), (hp)->h_addr, (hp)->h_length)
+#define start_tcp_client(res) \
+       socket(res->ai_family, res->ai_socktype, res->ai_protocol)
 
-#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))
+#define join_tcp_server(fd, sock, len) \
+       connect((fd), (struct sockaddr *) (sock), len)
 
 /*
- * prototypes
- */
-struct hostent *gethostbystring ();
-int ftp_get (char *, char *, char *, char *, char *, char *, int, int);
-int ftp_trans (char *, char *, char *, char *, char *, char *, char *, int, int);
+** prototypes
+*/
+int ftp_get(char *, char *, char *, char *, char *, char *, int, int);
+int ftp_trans(char *, char *, char *, char *, char *, char *, char *,
+               int, int);
 
 /*
- * static prototypes
- */
-static int start_tcp_server (struct sockaddr_in *, int, int, int);
-static void _asnprintf (char *, int, char *, va_list);
-static int ftp_quit (void);
-static int ftp_read (char *, char *, char *, int);
-static int initconn (void);
-static int dataconn (void);
-static int command (int arg1, ...);
-static int vcommand (int, va_list);
-static int getreply (int, int);
+** static prototypes
+*/
+static int start_tcp_server(struct sockaddr_in *, int, int, int);
+static void _asnprintf(char *, int, char *, va_list);
+static int ftp_quit(void);
+static int ftp_read(char *, char *, char *, int);
+static int initconn(void);
+static int dataconn(void);
+static int command(int arg1, ...);
+static int vcommand(int, va_list);
+static int getreply(int, int);
 
 
 static int
-start_tcp_server (struct sockaddr_in *sock, int backlog, int opt1, int opt2)
+start_tcp_server(struct sockaddr_in *sock, int backlog, int opt1, int opt2)
 {
-    int eindex, sd;
+       int eindex, sd;
 
-    if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == NOTOK)
-       return NOTOK;
+       if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == NOTOK)
+               return NOTOK;
 
-    if (bind (sd, (struct sockaddr *) sock, sizeof *sock) == NOTOK) {
-       eindex = errno;
-       close (sd);
-       errno = eindex;
-    } else {
-       listen (sd, backlog);
-    }
+       if (bind(sd, (struct sockaddr *) sock, sizeof *sock) == NOTOK) {
+               eindex = errno;
+               close(sd);
+               errno = eindex;
+       } else {
+               listen(sd, backlog);
+       }
 
-    return sd;
+       return sd;
 }
 
 
 static int __len__;
 
-#define        join_tcp_client(fd,sock) \
-       accept ((fd), (struct sockaddr *) (sock), \
+#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
+#define read_tcp_socket read
+#define write_tcp_socket write
+#define close_tcp_socket close
 
 static void
-_asnprintf (char *bp, int len_bp, char *what, va_list ap)
+_asnprintf(char *bp, int len_bp, char *what, va_list ap)
 {
-    int eindex, len;
-    char *fmt;
+       int eindex, len;
+       char *fmt;
 
-    eindex = errno;
+       eindex = errno;
 
-    *bp = '\0';
-    fmt = va_arg (ap, char *);
+       *bp = '\0';
+       fmt = va_arg(ap, char *);
 
-    if (fmt) {
-       vsnprintf(bp, len_bp, fmt, ap);
-       len = strlen(bp);
-       bp += len;
-       len_bp -= len;
-    }
+       if (fmt) {
+               vsnprintf(bp, len_bp, fmt, ap);
+               len = strlen(bp);
+               bp += len;
+               len_bp -= len;
+       }
 
-    if (what) {
-       char *s;
+       if (what) {
+               char *s;
 
-       if (*what) {
-           snprintf (bp, len_bp, " %s: ", what);
-           len = strlen (bp);
-           bp += len;
-           len_bp -= len;
+               if (*what) {
+                       snprintf(bp, len_bp, " %s: ", what);
+                       len = strlen(bp);
+                       bp += len;
+                       len_bp -= len;
+               }
+               if ((s = strerror(eindex)))
+                       strncpy(bp, s, len_bp);
+               else
+                       snprintf(bp, len_bp, "Error %d", eindex);
+               bp += strlen(bp);
        }
-       if ((s = strerror(eindex)))
-           strncpy (bp, s, len_bp);
-       else
-           snprintf (bp, len_bp, "Error %d", eindex);
-       bp += strlen (bp);
-    }
 
-    errno = eindex;
+       errno = eindex;
 }
 
 
 int
-ftp_get (char *host, char *user, char *password, char *cwd,
-         char *remote, char *local, int ascii, int stayopen)
+ftp_get(char *host, char *user, char *password, char *cwd,
+                char *remote, char *local, int ascii, int stayopen)
 {
-    return ftp_trans (host, user, password, cwd, remote, local,
-                      "RETR", ascii, stayopen);
+       return ftp_trans(host, user, password, cwd, remote, local,
+               "RETR", ascii, stayopen);
 }
 
 
 int
-ftp_trans (char *host, char *user, char *password, char *cwd, char *remote,
-           char *local, char *cmd, int ascii, int stayopen)
+ftp_trans(char *host, char *user, char *password, char *cwd, char *remote,
+       char *local, char *cmd, int ascii, int stayopen)
 {
-    int        result;
+       int result;
 
-    if (stayopen <= 0) {
-       result = ftp_quit ();
-       if (host == NULL)
-           return 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 (ftp_fd == NOTOK) {
+               struct addrinfo hints, *res;
 
-       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);
-           close_tcp_socket (ftp_fd), ftp_fd = NOTOK;
-           return NOTOK;
-       }
-       getreply (1, 0);
+               memset(&hints, 0, sizeof(hints));
+#ifdef AI_ADDRCONFIG
+               hints.ai_flags = AI_ADDRCONFIG;
+#endif
+               hints.ai_family = PF_INET;
+               hints.ai_socktype = SOCK_STREAM;
+
+               result = getaddrinfo(host, "ftp", &hints, &res);
+
+               if (result) {
+                       fprintf(stderr, "%s/ftp: %s\n",
+                                       host, gai_strerror(result));
+                       return NOTOK;
+               }
 
-       if (v_verbose) {
-           fprintf (stdout, "Connected to %s\n", host);
-           fflush (stdout);
+               if ((ftp_fd = start_tcp_client(res)) == NOTOK) {
+                       perror(host);
+                       freeaddrinfo(res);
+                       return NOTOK;
+               }
+               if (join_tcp_server(ftp_fd, res->ai_addr, res->ai_addrlen)
+                               == NOTOK) {
+                       perror(host);
+                       freeaddrinfo(res);
+                       close_tcp_socket(ftp_fd), ftp_fd = NOTOK;
+                       return NOTOK;
+               }
+               freeaddrinfo(res);
+               getreply(1, 0);
+
+               if (v_verbose) {
+                       fprintf(stdout, "Connected to %s\n", host);
+                       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 (user) {
-           if ((result = command (0, "USER %s", user)) == CONTINUE)
-               result = command (1, "PASS %s", password);
-           if (result != COMPLETE) {
+       if (cwd && ((result = command (0, "CWD %s", cwd)) != COMPLETE
+                       && result != CONTINUE)) {
                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;
-    }
+       if (command(1, ascii ? "TYPE A" : "TYPE I") != COMPLETE) {
+               result = NOTOK;
+               goto out;
+       }
 
-    result = ftp_read (remote, local, cmd, ascii);
+       result = ftp_read(remote, local, cmd, ascii);
 
 out: ;
-    if (result != OK || !stayopen)
-       ftp_quit ();
+       if (result != OK || !stayopen)
+               ftp_quit();
 
-    return result;
+       return result;
 }
 
 
 static int
-ftp_quit (void)
+ftp_quit(void)
 {
-    int        n;
+       int n;
 
-    if (ftp_fd == NOTOK)
-       return OK;
+       if (ftp_fd == NOTOK)
+               return OK;
 
-    n = command (1, "QUIT");
-    close_tcp_socket (ftp_fd), ftp_fd = NOTOK;
-    return (n == 0 || n == COMPLETE ? OK : NOTOK);
+       n = command(1, "QUIT");
+       close_tcp_socket(ftp_fd), ftp_fd = NOTOK;
+       return (n == 0 || n == COMPLETE ? OK : NOTOK);
 }
 
 static int
-ftp_read (char *remote, char *local, char *cmd, int ascii)
+ftp_read(char *remote, char *local, char *cmd, int ascii)
 {
-    int        istdio = 0, istore;
-    register int cc;
-    int        expectingreply = 0;
-    char buffer[BUFSIZ];
-    FILE *fp = NULL;
+       int istdio = 0, istore;
+       register int cc;
+       int expectingreply = 0;
+       char buffer[BUFSIZ];
+       FILE *fp = NULL;
 
-    if (initconn () == NOTOK)
-       goto bad;
+       if (initconn() == NOTOK)
+               goto bad;
 
-    v_noise = v_verbose;
-    if (command (-1, *remote ? "%s %s" : "%s", cmd, remote) != PRELIM)
-       goto bad;
+       v_noise = v_verbose;
+       if (command(-1, *remote ? "%s %s" : "%s", cmd, remote) != PRELIM)
+               goto bad;
 
-    expectingreply++;
-    if (dataconn () == NOTOK) {
+       expectingreply++;
+       if (dataconn() == NOTOK) {
 bad: ;
-        if (fp && !istdio)
-           fclose (fp);
-       if (data_fd != NOTOK)
-           close_tcp_socket (data_fd), data_fd = NOTOK;
-       if (expectingreply)
-           getreply (-2, 0);
+               if (fp && !istdio)
+                       fclose(fp);
+               if (data_fd != NOTOK)
+                       close_tcp_socket(data_fd), data_fd = NOTOK;
+               if (expectingreply)
+                       getreply(-2, 0);
+
+               return NOTOK;
+       }
 
-       return NOTOK;
-    }
+       istore = !strcmp(cmd, "STOR");
 
-    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 ((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 (istore) {
-       if (ascii) {
-           int c;
-           FILE *out;
+                       if (!(out = fdopen(data_fd, "w"))) {
+                               perror("fdopen");
+                               goto bad;
+                       }
 
-           if (!(out = fdopen (data_fd, "w"))) {
-               perror ("fdopen");
-               goto bad;
-           }
-
-           while ((c = getc (fp)) != EOF) {
-               if (c == '\n')
-                   putc ('\r', out);
-               if (putc (c, out) == EOF) {
-                   perror ("putc");
-                   fclose (out);
-                   data_fd = NOTOK;
-                   goto bad;
-               }
-           }
+                       while ((c = getc(fp)) != EOF) {
+                               if (c == '\n')
+                                       putc('\r', out);
+                               if (putc(c, out) == EOF) {
+                                       perror("putc");
+                                       fclose(out);
+                                       data_fd = NOTOK;
+                                       goto bad;
+                               }
+                       }
 
-           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;
+                       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;
+                               }
+
+                       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;
+                       }
 
-           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:
-                           putc ('\r', fp);
-                           break;
+                       while ((c = getc(in)) != EOF) {
+                               if (c == '\r')
+                                       switch (c = getc(in)) {
+                                               case EOF:
+                                               case '\0':
+                                                       c = '\r';
+                                                       break;
+
+                                               case '\n':
+                                                       break;
+
+                                               default:
+                                                       putc('\r', fp);
+                                                       break;
+                                               }
+
+                               if (putc(c, fp) == EOF) {
+                                       perror("putc");
+                                       fclose(in);
+                                       data_fd = NOTOK;
+                                       goto bad;
+                               }
                        }
 
-               if (putc (c, fp) == EOF) {
-                   perror ("putc");
-                   fclose (in);
-                   data_fd = NOTOK;
-                   goto bad;
-               }
-           }
+                       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;
+                       }
 
-           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;
+                       close_tcp_socket(data_fd), data_fd = NOTOK;
                }
-           if (cc < 0) {
-               perror ("read_tcp_socket");
-               goto bad;
-           }
-
-           close_tcp_socket (data_fd), data_fd = NOTOK;
        }
-    }
 
-    if (!istdio)
-       fclose (fp);
+       if (!istdio)
+               fclose(fp);
 
-    v_noise = v_verbose;
-    return (getreply (1, 0) == COMPLETE ? OK : NOTOK);
+       v_noise = v_verbose;
+       return (getreply(1, 0) == COMPLETE ? OK : NOTOK);
 }
 
 
-#define        UC(b) (((int) b) & 0xff)
+#define UC(b) (((int) b) & 0xff)
 
 static int
-initconn (void)
+initconn(void)
 {
-    int        len;
-    register char *a, *p;
-    struct sockaddr_in in_socket;
+       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(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;
-    }
+       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;
+       a = (char *) &in_socket.sin_addr;
+       p = (char *) &in_socket.sin_port;
 
-    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;
+       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;
+       return NOTOK;
 }
 
 static int
-dataconn (void)
+dataconn(void)
 {
-    int        fd;
-    struct sockaddr_in in_socket;
-    
-    if ((fd = join_tcp_client (data_fd, &in_socket)) == NOTOK) {
-       perror ("join_tcp_client");
-       return NOTOK;
-    }
-    close_tcp_socket (data_fd);
-    data_fd = fd;
+       int fd;
+       struct sockaddr_in in_socket;
+
+       if ((fd = join_tcp_client(data_fd, &in_socket)) == NOTOK) {
+               perror("join_tcp_client");
+               return NOTOK;
+       }
+       close_tcp_socket(data_fd);
+       data_fd = fd;
 
-    return OK;
+       return OK;
 }
 
 
 static int
-command (int arg1, ...)
+command(int arg1, ...)
 {
-    int        val;
-    va_list ap;
+       int val;
+       va_list ap;
 
-    va_start (ap, arg1);
-    val = vcommand (arg1, ap);
-    va_end (ap);
+       va_start(ap, arg1);
+       val = vcommand(arg1, ap);
+       va_end(ap);
 
-    return val;
+       return val;
 }
 
 static int
-vcommand (int complete, va_list ap)
+vcommand(int complete, va_list ap)
 {
-    int        len;
-    char buffer[BUFSIZ];
+       int len;
+       char buffer[BUFSIZ];
 
-    if (ftp_fd == NOTOK)
-       return NOTOK;
+       if (ftp_fd == NOTOK)
+               return NOTOK;
 
-    _asnprintf (buffer, sizeof(buffer), NULL, ap);
-    if (v_debug)
-       fprintf (stderr, "<--- %s\n", buffer);
+       _asnprintf(buffer, sizeof(buffer), NULL, ap);
+       if (v_debug)
+               fprintf(stderr, "<--- %s\n", buffer);
 
-    strcat (buffer, "\r\n");
-    len = strlen (buffer);
+       strcat(buffer, "\r\n");
+       len = strlen(buffer);
 
-    if (write_tcp_socket (ftp_fd, buffer, len) != len) {
-       perror ("write_tcp_socket");
-       return NOTOK;
-    }
+       if (write_tcp_socket(ftp_fd, buffer, len) != len) {
+               perror("write_tcp_socket");
+               return NOTOK;
+       }
 
-    return (getreply (complete, !strcmp (buffer, "QUIT")));
+       return(getreply(complete, !strcmp(buffer, "QUIT")));
 }
 
 
 static int
-getreply (int complete, int expecteof)
+getreply(int complete, int expecteof)
 {
-    for (;;) {
-       register int code, dig, n;
-       int continuation;
-       register char *bp;
-       char buffer[BUFSIZ];
+       for (;;) {
+               register int code, dig, n;
+               int continuation;
+               register char *bp;
+               char buffer[BUFSIZ];
 
-       code = dig = n = continuation = 0;
-       bp = buffer;
+               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;
-       }
+               for (;;) {
+                       unsigned char c;
 
-       if (v_debug)
-           fprintf (stderr, "---> %s\n", buffer);
-       if (continuation)
-           continue;
+                       if (read_tcp_socket(ftp_fd, &c, 1) < 1) {
+                               if (expecteof)
+                                       return OK;
 
-       n -= '0';
+                               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 if (isspace(c))
+                                       /* XXX: naughty FTP... */
+                                       continuation++;
+                       } else
+                               if (dig == 4 && c == '-')
+                                       continuation++;
+                       if (n == 0)
+                               n = c;
+               }
 
-       if (v_noise) {
-           fprintf (stdout, "%s\n", buffer);
-           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);
+               if (v_debug)
+                       fprintf(stderr, "---> %s\n", buffer);
+               if (continuation)
+                       continue;
+
+               n -= '0';
 
-       return n;
-    }
+               if (v_noise) {
+                       fprintf(stdout, "%s\n", buffer);
+                       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;
+       }
 }