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;
}