Thus said Ken Hornstein on Mon, 21 Nov 2022 21:41:34 -0500:

> netsec_read() is  supposed to  RETURN the number  of bytes  read, just
> like read() does (that's why it's return value is prototyped ssize_t).
> But it just returns OK on success.

Attached is the previous patch remade against master. It also includes a
bug fix  against the  previous that  I noticed  while testing;  a simple
off-by-one error  when checking  for \r at  the end of  a line.  I again
tested it with my  6 sample messages that gave angst  to inc earlier and
they work fine now (that's how I noticed the off-by-one error).

I'm running a similar patch on my nmh 1.7.1 installation and will report
any problems that I find in "production".

Suggestions?

Andy
diff --git a/h/netsec.h b/h/netsec.h
index 6c69c82c..42370fa7 100644
--- a/h/netsec.h
+++ b/h/netsec.h
@@ -166,8 +166,8 @@ char *netsec_readline(netsec_context *ns_context, size_t *length,
  * 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, unsigned char *buffer,
+		    size_t size, char **errstr);
 
 /*
  * Write data to the network; if encryption is being performed, we will
diff --git a/sbr/netsec.c b/sbr/netsec.c
index bf0ff9cf..c5f478e2 100644
--- a/sbr/netsec.c
+++ b/sbr/netsec.c
@@ -382,9 +382,10 @@ netsec_set_timeout(netsec_context *nsc, int timeout)
  */
 
 ssize_t
-netsec_read(netsec_context *nsc, void *buffer, size_t size, char **errstr)
+netsec_read(netsec_context *nsc, unsigned char *buffer, size_t size, 
+	    char **errstr)
 {
-    int retlen;
+    ssize_t retlen;
 
     /*
      * If our buffer is empty, then we should fill it now
@@ -415,7 +416,7 @@ netsec_read(netsec_context *nsc, void *buffer, size_t size, char **errstr)
 	nsc->ns_inbuflen -= size;
     }
 
-    return OK;
+    return retlen;
 }
 
 /*
diff --git a/uip/inc.c b/uip/inc.c
index dd0a646d..ddbc13cb 100644
--- a/uip/inc.c
+++ b/uip/inc.c
@@ -900,7 +900,7 @@ pop_action(void *closure, char *s)
     int n;
 
     pc = closure;
-    n = fprintf(pc->mailout, "%s\n", s);
+    n = fprintf(pc->mailout, "%s", s);
     if (n < 0)
         return NOTOK;
     pc->written += n; /* Count linefeed too. */
diff --git a/uip/popsbr.c b/uip/popsbr.c
index 8a064ff5..d96dde22 100644
--- a/uip/popsbr.c
+++ b/uip/popsbr.c
@@ -565,8 +565,13 @@ static int
 traverse (int (*action)(void *, char *), void *closure, 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;
+    bool checkline = true;
+    bool needdata = true;
 
     va_start(ap, fmt);
     result = vcommand (fmt, ap);
@@ -579,21 +584,94 @@ traverse (int (*action)(void *, char *), void *closure, const char *fmt, ...)
     if ((snoopstate = netsec_get_snoop(nsc)))
 	netsec_set_snoop(nsc, 0);
 
+    unused = sizeof(buffer);
+    inoffset = 0;
+    buflen = 0;
     for (;;) {
-        result = multiline();
-        if (result == OK) {
-            result = (*action)(closure, response);
-            if (result == OK)
-                continue;
-        } else if (result == DONE) {
-            strncpy(response, buffer, sizeof(response));
-            result = OK;
-        }
-        break;
+	if (needdata) {
+	    len = netsec_read(nsc, buffer + inoffset, unused, &errstr);
+	    if (len < 0) {
+		strncpy(response, errstr, sizeof(response));
+		response[sizeof(response) - 1] = '\0';
+		free(errstr);
+		netsec_set_snoop(nsc, snoopstate);
+		return NOTOK;
+	    }
+	    tptr = buffer;
+	    buflen += len;
+	    needdata = false;
+	}
+	if (checkline) {
+	    if (buflen >= LEN(TRM) + 2 &&
+		strncmp(TRM "\r\n", tptr, LEN(TRM) + 2) == 0)
+		return 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) (closure, 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 > 0 && tptr[buflen - 1] == '\r')
+		ptr--;
+	    slen = ptr - tptr;
+	    strncpy(response, sptr, slen);
+	    response[slen] = '\0';
+	    buflen -= slen;
+	    (*action) (closure, response);
+	    if (buflen > 0) {
+		inoffset = buflen;
+		unused = sizeof(buffer) - buflen;
+		memmove(buffer, tptr + slen, buflen);
+	    } else {
+		inoffset = 0;
+		unused = sizeof(buffer);
+	    }
+	    needdata = true;
+	} else {
+	    return NOTOK;
+	}
     }
 
     netsec_set_snoop(nsc, snoopstate);
-    return result;
+    return NOTOK;
 }
 
 

Reply via email to