Updates to email_pager() / wrap_line_mime() are *mostly* working now

This commit is contained in:
Bobbi Webber-Manners 2020-07-20 22:20:40 -04:00
parent c4c80165c2
commit 4231d627b9

View File

@ -620,45 +620,29 @@ void putline(FILE *fp, char *s) {
} }
/* /*
* Perform word wrapping, for a line of text, which may contain embedded '\r' * Perform word wrapping for a line of plain text. For each call, this function
* carriage returns, perform word-wrapping. For each call, this function will * will output one line of text (or a partial line if there is not enough input).
* output one line of text (or a partial line if there is not enough input).
* fp - File handle to use for output. * fp - File handle to use for output.
* s - Pointer to pointer to input buffer. If all text is consumed, this is * s - Pointer to pointer to input buffer. If all text is consumed, this is
* set to NULL. If there is text left in the buffer to be consumed then * set to NULL. If there is text left in the buffer to be consumed then
* the pointer will be advanced to point to the next text to process. * the pointer will be advanced to point to the next text to process.
* mime - Set to 1 if we are wrapping content which was decoded from
* Quoted-Printable or Base64. In this case line does not necessarily
* end in EOL.
*/ */
void word_wrap_line(FILE *fp, char **s, uint8_t mime) { void word_wrap_line_plaintext(FILE *fp, char **s) {
static uint8_t col = 0; // Keeps track of screen column static uint8_t col = 0; // Keeps track of screen column
char *ss = *s; char *ss = *s;
char *ret = strchr(ss, '\r');
uint16_t l = strlen(ss); uint16_t l = strlen(ss);
char *nextline = NULL; char *nextline = NULL;
uint16_t i; uint16_t i;
if (ret) { if (col + l <= 80) { // Fits on this line
if (l >= (ret - ss) + 1) // If '\r' is not at the end ...
nextline = ss + (ret - ss) + 1; // Keep track of next line(s)
l = ret - ss;
}
if ((!mime && (col + l <= 80)) ||
(mime && ret && (col + l) <= 80)) { // Fits on this line
// if (col + l <= 80) { // Fits on this line
col += l; col += l;
putline(fp, ss); putline(fp, ss);
if (ret) { col = 0;
col = 0; if (col + l != 80)
if (col + l != 80) fputc('\r', fp);
fputc('\r', fp); *s = NULL;
}
*s = nextline;
return; return;
} }
i = 80 - col; // Doesn't fit, need to break i = 80 - col; // Doesn't fit, need to break
if (i > l)
i = l;
while ((ss[--i] != ' ') && (i > 0)); while ((ss[--i] != ' ') && (i > 0));
if (i == 0) { // No space character found if (i == 0) { // No space character found
if (col == 0) // Doesn't fit on full line if (col == 0) // Doesn't fit on full line
@ -677,6 +661,85 @@ void word_wrap_line(FILE *fp, char **s, uint8_t mime) {
*s = ss + i + 1; *s = ss + i + 1;
} }
/*
* Perform word wrapping, for a line of MIME decoded text, which may contain
* multiple embedded '\r' carriage returns, or no carriage return at all.
* fp - File handle to use for output.
* s - Pointer to pointer to input buffer. If all text is consumed, this is
* set to NULL. If there is text left in the buffer to be consumed then
* the pointer will be advanced to point to the next text to process.
* Returns 1 if the caller should invoke the routine again before obtaining
* more input, or 0 if there is nothing more to do or caller needs to get more
* input before next call.
*/
uint8_t word_wrap_line_mime(FILE *fp, char **s) {
static uint8_t col = 0; // Keeps track of screen column
char *ss = *s;
char *ret = strchr(ss, '\r');
uint16_t l = strlen(ss);
char *nextline = NULL;
uint16_t i;
if (l == 0)
return 0; // Need more input to proceed
//printf("word_wrap_line_mine l=%d\n", l);
if (ret) {
//printf("RET l=%d rhs=%d\n", l, (ret - ss) + 1);
if (l > (ret - ss) + 1) // If '\r' is not at the end ...
nextline = ss + (ret - ss) + 1; // Keep track of next line(s)
l = ret - ss;
}
if (ret) {
//printf("RET");
if ((col + l) <= 80) { // Fits on this line
//printf("FITS\n");
col += l;
putline(fp, ss);
if (ret) {
col = 0;
if (col + l != 80)
fputc('\r', fp);
}
//printf("\nnextline=%p\n", nextline);
*s = nextline;
return (*s ? 1 : 0); // Caller should invoke again
}
//printf("NOFIT");
i = 80 - col; // Doesn't fit, need to break
if (i > l)
i = l;
while ((ss[--i] != ' ') && (i > 0));
if (i == 0) { // No space character found
//printf("NOSPC\n");
if (col == 0) // Doesn't fit on full line
for (i = 0; i < 80; ++i) { // Truncate @80 chars
fputc(ss[i], fp);
*s = ss + l + 1;
} else // There is stuff on this line already
fputc('\r', fp); // Try a blank line
col = 0;
return (ret ? (*s ? 0 : 1) : 0); // If EOL, caller should invoke again
}
} else {
//printf("NORET");
// No EOL
i = 80 - col; // Doesn't fit, need to break
if (i > l)
i = l;
while ((ss[--i] != ' ') && (i > 0));
if (i == 0) { // No space character found
//printf("NOSPC\n");
return 0; // Need more input to proceed
}
}
//printf("SPC %d\n", i);
ss[i] = '\0'; // Space was found, split line
putline(fp, ss);
fputc('\r', fp);
col = 0;
*s = ss + i + 1;
return (*s ? 1 : 0); // Caller should invoke again
}
/* /*
* OK to d/l attachment? * OK to d/l attachment?
*/ */
@ -792,7 +855,7 @@ void email_pager(struct emailhdrs *h) {
FILE *attachfp; FILE *attachfp;
uint16_t linecount, chars; uint16_t linecount, chars;
uint8_t mime_enc, mime_binary, eof, screennum, maxscreennum; uint8_t mime_enc, mime_binary, eof, screennum, maxscreennum;
char c, *readp; char c, *readp, *writep;
clrscr2(); clrscr2();
sprintf(filename, "%s/%s/EMAIL.%u", cfg_emaildir, curr_mbox, h->emailnum); sprintf(filename, "%s/%s/EMAIL.%u", cfg_emaildir, curr_mbox, h->emailnum);
fp = fopen(filename, "rb"); fp = fopen(filename, "rb");
@ -808,6 +871,7 @@ restart:
eof = 0; eof = 0;
linecount = 0; linecount = 0;
readp = linebuf; readp = linebuf;
writep = linebuf;
attachfp = NULL; attachfp = NULL;
if (sbackfp) if (sbackfp)
fclose(sbackfp); fclose(sbackfp);
@ -836,11 +900,15 @@ restart:
fputs("\n\n", stdout); fputs("\n\n", stdout);
get_line(fp, 1, linebuf, &pos); // Reset buffer get_line(fp, 1, linebuf, &pos); // Reset buffer
while (1) { while (1) {
readp = linebuf; if (!readp)
if (get_line(fp, 0, readp, &pos) == -1) readp = linebuf;
if (!writep)
writep = linebuf;
//printf("READ W=%p R=%p\n", writep, readp);
if (get_line(fp, 0, writep, &pos) == -1)
eof = 1; eof = 1;
++linecount; ++linecount;
if ((mime >= 1) && (!strncmp(readp, "--", 2))) { if ((mime >= 1) && (!strncmp(writep, "--", 2))) {
if (attachfp) if (attachfp)
fclose(attachfp); fclose(attachfp);
if ((mime == 4) && mime_binary) { if ((mime == 4) && mime_binary) {
@ -851,33 +919,33 @@ restart:
mime = 2; mime = 2;
mime_enc = ENC_7BIT; mime_enc = ENC_7BIT;
mime_binary = 0; mime_binary = 0;
readp = NULL; // Read next line from disk readp = writep = NULL;
} else if ((mime < 4) && (mime >= 2)) { } else if ((mime < 4) && (mime >= 2)) {
if (!strncasecmp(readp, "Content-Type: ", 14)) { if (!strncasecmp(writep, "Content-Type: ", 14)) {
if (!strncmp(readp + 14, "text/plain", 10)) { if (!strncmp(writep + 14, "text/plain", 10)) {
mime = 3; mime = 3;
} else if (!strncmp(readp + 14, "text/html", 9)) { } else if (!strncmp(writep + 14, "text/html", 9)) {
printf("\n<Not showing HTML>\n"); printf("\n<Not showing HTML>\n");
mime = 1; mime = 1;
} else { } else {
mime_binary = 1; mime_binary = 1;
mime = 3; mime = 3;
} }
} else if (!strncasecmp(readp, "Content-Transfer-Encoding: ", 27)) { } else if (!strncasecmp(writep, "Content-Transfer-Encoding: ", 27)) {
mime = 3; mime = 3;
if (!strncmp(readp + 27, "7bit", 4)) if (!strncmp(writep + 27, "7bit", 4))
mime_enc = ENC_7BIT; mime_enc = ENC_7BIT;
else if (!strncmp(readp + 27, "quoted-printable", 16)) else if (!strncmp(writep + 27, "quoted-printable", 16))
mime_enc = ENC_QP; mime_enc = ENC_QP;
else if (!strncmp(readp + 27, "base64", 6)) else if (!strncmp(writep + 27, "base64", 6))
mime_enc = ENC_B64; mime_enc = ENC_B64;
else { else {
printf("** Unsupp encoding %s\n", readp + 27); printf("** Unsupp encoding %s\n", writep + 27);
mime = 1; mime = 1;
} }
} else if (strstr(readp, "filename=")) { } else if (strstr(writep, "filename=")) {
sprintf(filename, "%s/ATTACHMENTS/%s", sprintf(filename, "%s/ATTACHMENTS/%s",
cfg_emaildir, strstr(readp, "filename=") + 9); cfg_emaildir, strstr(writep, "filename=") + 9);
sanitize_filename(filename); sanitize_filename(filename);
if (prompt_okay_attachment(filename)) { if (prompt_okay_attachment(filename)) {
printf("** Attachment -> %s ", filename); printf("** Attachment -> %s ", filename);
@ -886,115 +954,125 @@ restart:
printf("\n** Can't open %s ", filename); printf("\n** Can't open %s ", filename);
} else } else
attachfp = NULL; attachfp = NULL;
} else if ((mime == 3) && (!strncmp(readp, "\r", 1))) { } else if ((mime == 3) && (!strncmp(writep, "\r", 1))) {
mime = 4; mime = 4;
if (!attachfp && mime_binary) { if (!attachfp && mime_binary) {
mime_enc = ENC_SKIP; // Skip over binary MIME parts with no filename mime_enc = ENC_SKIP; // Skip over binary MIME parts with no filename
fputs("Skipping ", stdout); fputs("Skipping ", stdout);
} }
} }
readp = NULL; // Read next line from disk readp = writep = NULL;
} else if (mime == 4) { } else if (mime == 4) {
switch (mime_enc) { switch (mime_enc) {
case ENC_QP: case ENC_QP:
chars = decode_quoted_printable(readp); chars = decode_quoted_printable(writep);
break; break;
case ENC_B64: case ENC_B64:
chars = decode_base64(readp); chars = decode_base64(writep);
break; break;
case ENC_SKIP: case ENC_SKIP:
readp = NULL; // Read next line from disk readp = writep = NULL;
break; break;
} }
if (mime_binary && !(linecount % 10)) if (mime_binary && !(linecount % 10))
spinner(); spinner();
} }
do { if (readp) {
if (readp) { if (mime == 0) {
if (mime == 0) while (readp)
word_wrap_line(stdout, &readp, 0); word_wrap_line_plaintext(stdout, &readp);
if (mime == 1) writep = NULL;
readp = NULL; }
if (mime == 4) { if (mime == 1) {
if (mime_binary) { readp = writep = NULL;
if (attachfp) }
fwrite(readp, 1, chars, attachfp); if (mime == 4) {
readp = 0; if (mime_binary) {
} else { if (attachfp)
word_wrap_line(stdout, &readp, 0 /* 1 */); fwrite(readp, 1, chars, attachfp);
} readp = writep = NULL;
} else {
//while (word_wrap_line_mime(stdout, &readp));
do {
c = word_wrap_line_mime(stdout, &readp);
cgetc(); //DEBUG
} while (c == 1);
if (readp)
writep += chars;
else
writep = NULL;
} }
} }
if ((*cursorrow == 22) || eof) { }
printf("\n%c[%05lu] %s | B)ack | T)op | H)drs | M)IME | Q)uit%c", if ((*cursorrow == 22) || eof) {
INVERSE, printf("\n%c[%05lu] %s | B)ack | T)op | H)drs | M)IME | Q)uit%c",
pos, INVERSE,
(eof ? " ** END ** " : "SPACE continue reading"), pos,
NORMAL); (eof ? " ** END ** " : "SPACE continue reading"),
if (sbackfp) { NORMAL);
save_screen_to_scrollback(sbackfp); if (sbackfp) {
++screennum; save_screen_to_scrollback(sbackfp);
++maxscreennum; ++screennum;
} ++maxscreennum;
}
retry: retry:
c = cgetc(); c = cgetc();
switch (c) { switch (c) {
case ' ': case ' ':
if (sbackfp && (screennum < maxscreennum)) { if (sbackfp && (screennum < maxscreennum)) {
load_screen_from_scrollback(sbackfp, ++screennum); load_screen_from_scrollback(sbackfp, ++screennum);
goto retry; goto retry;
} else { } else {
if (eof) { if (eof) {
putchar(BELL);
goto retry;
}
}
break;
case 'B':
case 'b':
if (sbackfp && (screennum > 1)) {
load_screen_from_scrollback(sbackfp, --screennum);
goto retry;
} else {
putchar(BELL); putchar(BELL);
goto retry; goto retry;
} }
break; }
case 'T':
case 't':
mime = 0;
pos = h->skipbytes;
fseek(fp, pos, SEEK_SET);
goto restart;
break;
case 'H':
case 'h':
mime = 0;
pos = 0;
fseek(fp, pos, SEEK_SET);
goto restart;
break; break;
case 'M': case 'B':
case 'm': case 'b':
mime = 1; if (sbackfp && (screennum > 1)) {
pos = h->skipbytes; load_screen_from_scrollback(sbackfp, --screennum);
fseek(fp, pos, SEEK_SET); goto retry;
goto restart; } else {
case 'Q':
case 'q':
if (attachfp)
fclose(attachfp);
if (sbackfp)
fclose(sbackfp);
fclose(fp);
return;
default:
putchar(BELL); putchar(BELL);
goto retry; goto retry;
} }
clrscr2(); break;
case 'T':
case 't':
mime = 0;
pos = h->skipbytes;
fseek(fp, pos, SEEK_SET);
goto restart;
break;
case 'H':
case 'h':
mime = 0;
pos = 0;
fseek(fp, pos, SEEK_SET);
goto restart;
break;
case 'M':
case 'm':
mime = 1;
pos = h->skipbytes;
fseek(fp, pos, SEEK_SET);
goto restart;
case 'Q':
case 'q':
if (attachfp)
fclose(attachfp);
if (sbackfp)
fclose(sbackfp);
fclose(fp);
return;
default:
putchar(BELL);
goto retry;
} }
} while (readp); clrscr2();
}
} }
} }