Index: h/netsec.h
==================================================================
--- h/netsec.h
+++ h/netsec.h
@@ -164,12 +164,12 @@
  * errstr	- Error size
  *
  * Returns number of bytes read, or -1 on error.
  */
 
-ssize_t netsec_read(netsec_context *ns_context, void *buffer, size_t size,
-		    char **errstr);
+ssize_t netsec_read(netsec_context *ns_context, char *buffer, size_t size,
+		    size_t *retlen, char **errstr);
 
 /*
  * Write data to the network; if encryption is being performed, we will
  * do it.  Data may be buffered; use netsec_flush() to flush any outstanding
  * data to the network.

Index: sbr/netsec.c
==================================================================
--- sbr/netsec.c
+++ sbr/netsec.c
@@ -372,14 +372,13 @@
  * Read data from the network.  Basically, return anything in our buffer,
  * otherwise fill from the network.
  */
 
 ssize_t
-netsec_read(netsec_context *nsc, void *buffer, size_t size, char **errstr)
+netsec_read(netsec_context *nsc, char *buffer, size_t size,
+	    size_t *retlen, char **errstr)
 {
-    int retlen;
-
     /*
      * If our buffer is empty, then we should fill it now
      */
 
     if (nsc->ns_inbuflen == 0) {
@@ -390,15 +389,15 @@
     /*
      * netsec_fillread only returns if the buffer is full, so we can
      * assume here that this has something in it.
      */
 
-    retlen = min(size, nsc->ns_inbuflen);
+    *retlen = min(size, nsc->ns_inbuflen);
 
-    memcpy(buffer, nsc->ns_inptr, retlen);
+    memcpy(buffer, nsc->ns_inptr, *retlen);
 
-    if (retlen == (int) nsc->ns_inbuflen) {
+    if (*retlen == nsc->ns_inbuflen) {
 	/*
 	 * We've emptied our buffer, so reset everything.
 	 */
 	nsc->ns_inptr = nsc->ns_inbuffer;
 	nsc->ns_inbuflen = 0;

Index: uip/inc.c
==================================================================
--- uip/inc.c
+++ uip/inc.c
@@ -934,9 +934,9 @@
 }
 
 static int
 pop_action (char *s)
 {
-    fprintf (pf, "%s\n", s);
-    stop += strlen (s) + 1;
+    fprintf (pf, "%s", s);
+    stop += strlen (s);
     return 0;  /* Is return value used?  This was missing before 1999-07-15. */
 }

Index: uip/popsbr.c
==================================================================
--- uip/popsbr.c
+++ uip/popsbr.c
@@ -489,12 +489,17 @@
 
 static int
 traverse (int (*action)(char *), const char *fmt, ...)
 {
     int result, snoopstate;
+    size_t len, unused, inoffset, slen, count;
     va_list ap;
     char buffer[sizeof(response)];
+    size_t buflen;
+    char *errstr, *ptr, *sptr, *tptr;
+    boolean checkline = true;
+    boolean needdata = true;
 
     va_start(ap, fmt);
     result = vcommand (fmt, ap);
     va_end(ap);
 
@@ -503,25 +508,94 @@
     strncpy (buffer, response, sizeof(buffer));
 
     if ((snoopstate = netsec_get_snoop(nsc)))
 	netsec_set_snoop(nsc, 0);
 
-    for (;;)
-	switch (multiline ()) {
-	    case NOTOK: 
+    unused = sizeof(buffer);
+    inoffset = 0;
+    buflen = 0;
+    for (;;) {
+	if (needdata) {
+	    result = netsec_read(nsc, buffer + inoffset, unused, &len, &errstr);
+	    if (result != OK) {
+		strncpy(response, errstr, sizeof(response));
+		response[sizeof(response) - 1] = '\0';
+		free(errstr);
 		netsec_set_snoop(nsc, snoopstate);
 		return NOTOK;
-
-	    case DONE: 
-		strncpy (response, buffer, sizeof(response));
-		netsec_set_snoop(nsc, snoopstate);
+	    }
+	    tptr = buffer;
+	    buflen += len;
+	    needdata = false;
+	}
+	if (checkline) {
+	    if (buflen >= LEN(TRM) + 2 &&
+		strncmp(TRM "\r\n", tptr, LEN(TRM) + 2) == 0)
 		return OK;
-
-	    case OK: 
+	    if (buflen >= LEN(TRM TRM) &&
+		strncmp(TRM TRM, tptr, LEN(TRM TRM)) == 0) {
+		tptr += LEN(TRM);
+		buflen -= LEN(TRM);
+	    }
+	}
+	ptr = tptr;
+	checkline = false;
+	count = 0;
+	while (count < buflen) {
+	    count++;
+	    if (*ptr++ == '\n') {
+		sptr = tptr;
+		if (count > 1 && *(ptr - 2) == '\r') {
+		    *--ptr = '\0';
+		    checkline = true;
+		}
+		*--ptr = '\n'; ptr++;
+		slen = ptr - tptr;
+		strncpy(response, sptr, slen);
+		response[slen] = '\0';
+		buflen -= count;
+		tptr += count;
 		(*action) (response);
 		break;
+	    }
+	}
+	if (checkline) {
+	    if (buflen > 0) {
+		if (buflen < LEN(TRM) + 2 || buflen < LEN(TRM TRM)) {
+		    needdata = true;
+		    inoffset = buflen;
+		    unused = sizeof(buffer) - buflen;
+		    memmove(buffer, tptr, buflen);
+		}
+	    } else {
+		needdata = true;
+		inoffset = 0;
+		unused = sizeof(buffer);
+	    }
+	    continue;
+	}
+	if (count == buflen) {
+	    sptr = tptr;
+	    if (buflen > 1 && tptr[buflen - 1] == '\r') {
+		ptr--;
+	    }
+	    slen = ptr - tptr;
+	    strncpy(response, sptr, slen);
+	    response[slen] = '\0';
+	    buflen -= slen;
+	    (*action) (response);
+	    if (buflen > 0) {
+		inoffset = buflen;
+		unused = sizeof(buffer) - buflen;
+		memmove(buffer, buffer + slen, buflen);
+	    } else {
+		inoffset = 0;
+		unused = sizeof(buffer);
+	    }
+	    needdata = true;
 	}
+    }
 }
 
 
 int
 pop_dele (int msgno)

