EMAIL: Allow attachment filename / path to be manually overriden when saving

This commit is contained in:
Bobbi Webber-Manners 2020-09-07 00:48:19 -04:00
parent e0d1bdac82
commit 9d1364f83b
2 changed files with 76 additions and 23 deletions

View File

@ -756,24 +756,45 @@ uint8_t word_wrap_line(FILE *fp, char **s, uint8_t cols, char mode) {
return (*s ? 1 : 0); // Caller should invoke again return (*s ? 1 : 0); // Caller should invoke again
} }
uint8_t prompt_for_name(char *, uint8_t); // Forward declaration
/* /*
* OK to d/l attachment? * OK to d/l attachment?
*/ */
char prompt_okay_attachment(char *filename) { char prompt_okay_attachment(char *filename) {
char c; char c;
printf("Okay to download %s? (y/n) >", filename);
while (1) { while (1) {
printf("ProDOS filename: %s\n", filename);
printf("%c A)ccept | S)kip | R)ename%c\n", INVERSE, NORMAL);
c = cgetc(); c = cgetc();
if ((c == 'y') || (c == 'Y') || (c == 'n') || (c == 'N')) switch (c) {
case 'A':
case 'a':
return 1;
break; break;
putchar(BELL); case 'S':
case 's':
return 0;
break;
case 'R':
case 'r':
c = wherey();
if (prompt_for_name("Save As", 2) == 255) {
gotoxy(0, c);
break; // ESC pressed
}
if (strlen(userentry) > 0) {
if (userentry[0] == '/')
strcpy(filename, userentry);
else
snprintf(filename, 80, "%s/ATTACHMENTS/%s", cfg_emaildir, userentry);
}
gotoxy(0, c);
break;
default:
putchar(BELL);
}
} }
putchar(RETURN); // Go to col 0
putchar(CURUP);
putchar(CLRLINE);
if ((c == 'y') || (c == 'Y'))
return 1;
else
return 0; return 0;
} }
@ -792,6 +813,10 @@ void sanitize_filename(char *s) {
} }
if (isalnum(c) || c == '.' || c == '/') if (isalnum(c) || c == '.' || c == '/')
s[j++] = c; s[j++] = c;
if (j == 15) {
s[j] = '\0';
break;
}
} }
} }
@ -890,8 +915,9 @@ void email_pager(struct emailhdrs *h) {
FILE *sbackfp = NULL; FILE *sbackfp = NULL;
const int8_t *b = b64dec - 43; const int8_t *b = b64dec - 43;
FILE *attachfp; FILE *attachfp;
uint16_t linecount, chars; uint16_t linecount, chars, skipbytes;
uint8_t mime_enc, mime_binary, mime_hasfile, eof, screennum, maxscreennum; uint8_t mime_enc, mime_binary, mime_hasfile, eof,
screennum, maxscreennum, attnum;
char c, *readp, *writep; char c, *readp, *writep;
clrscr2(); clrscr2();
snprintf(filename, 80, "%s/%s/EMAIL.%u", cfg_emaildir, curr_mbox, h->emailnum); snprintf(filename, 80, "%s/%s/EMAIL.%u", cfg_emaildir, curr_mbox, h->emailnum);
@ -913,6 +939,7 @@ restart:
mime_enc = ENC_7BIT; mime_enc = ENC_7BIT;
mime_binary = 0; mime_binary = 0;
mime_hasfile = 0; mime_hasfile = 0;
attnum = 0;
if (sbackfp) if (sbackfp)
fclose(sbackfp); fclose(sbackfp);
_filetype = PRODOS_T_BIN; _filetype = PRODOS_T_BIN;
@ -938,6 +965,13 @@ restart:
fputs("\nSubject: ", stdout); fputs("\nSubject: ", stdout);
printfield(h->subject, 0, 70); printfield(h->subject, 0, 70);
fputs("\n\n", stdout); fputs("\n\n", stdout);
// We do not need all the email headers for the summary screen right now.
// Freeing them can release up to nearly 8KB. The caller rebuilds the
// summary info by calling read_email_db().
skipbytes = h->skipbytes;
free_headers_list();
get_line(fp, 1, linebuf, &pos); // Reset buffer get_line(fp, 1, linebuf, &pos); // Reset buffer
while (1) { while (1) {
if (!readp) if (!readp)
@ -987,21 +1021,29 @@ restart:
} }
} else if (strstr(writep, "filename=")) { } else if (strstr(writep, "filename=")) {
mime_hasfile = 1; mime_hasfile = 1;
snprintf(filename, 80, "%s/ATTACHMENTS/%s", snprintf(filename, 80, "%s", strstr(writep, "filename=") + 9);
cfg_emaildir, strstr(writep, "filename=") + 9); printf("%cAttachment %u %c\n",
INVERSE, ++attnum, NORMAL);
printf(" MIME filename: %s", filename);
sanitize_filename(filename); sanitize_filename(filename);
snprintf(userentry, 80, "%s/ATTACHMENTS/%s",
cfg_emaildir, filename);
strcpy(filename, userentry);
prompt_dl:
if (prompt_okay_attachment(filename)) { if (prompt_okay_attachment(filename)) {
printf("** Attachment -> %s ", filename); printf("*** Attachment -> %s ", filename);
attachfp = fopen(filename, "wb"); attachfp = fopen(filename, "wb");
if (!attachfp) if (!attachfp) {
printf("\n** Can't open %s ", filename); printf("\n*** Can't open %s %d\n", filename, errno);
goto prompt_dl;
}
} else } else
attachfp = NULL; attachfp = NULL;
} else if ((mime == 3) && (!strncmp(writep, "\r", 1))) { } else if ((mime == 3) && (!strncmp(writep, "\r", 1))) {
mime = 4; mime = 4;
if (!attachfp && mime_hasfile) { if (!attachfp && mime_hasfile) {
mime_enc = ENC_SKIP; // Skip over MIME parts user chose to skip mime_enc = ENC_SKIP; // Skip over MIME parts user chose to skip
printf("** Skipping %s ", filename); printf("*** Skipping %s ", filename);
} else if (!attachfp && mime_binary) { } else 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
printf("\n"); printf("\n");
@ -1060,7 +1102,7 @@ restart:
} }
} }
endscreen: endscreen:
if ((*cursorrow == 22) || eof) { if (!mime_hasfile && ((*cursorrow == 22) || eof)) {
printf("\n%c[%07lu] %s | B)ack | T)op | H)drs | M)IME | Q)uit%c", printf("\n%c[%07lu] %s | B)ack | T)op | H)drs | M)IME | Q)uit%c",
INVERSE, INVERSE,
pos, pos,
@ -1098,7 +1140,7 @@ retry:
case 'T': case 'T':
case 't': case 't':
mime = 0; mime = 0;
pos = h->skipbytes; pos = skipbytes;
fseek(fp, pos, SEEK_SET); fseek(fp, pos, SEEK_SET);
goto restart; goto restart;
break; break;
@ -1132,7 +1174,7 @@ retry:
break; break;
} }
} while (linebuf[0] != '\r'); } while (linebuf[0] != '\r');
pos = h->skipbytes; pos = skipbytes;
fseek(fp, pos, SEEK_SET); fseek(fp, pos, SEEK_SET);
goto restart; goto restart;
case 'Q': case 'Q':
@ -1369,6 +1411,7 @@ uint8_t parse_from_addr(char *p, char *q) {
* Returns number of chars read. * Returns number of chars read.
* prompt - Message to display before > prompt * prompt - Message to display before > prompt
* is_file - if 1, restrict chars to those allowed in ProDOS filename * is_file - if 1, restrict chars to those allowed in ProDOS filename
* if 2, restrict chars to those allowed in ProDOS path
* Returns number of chars read, or 255 if ESC pressed * Returns number of chars read, or 255 if ESC pressed
*/ */
uint8_t prompt_for_name(char *prompt, uint8_t is_file) { uint8_t prompt_for_name(char *prompt, uint8_t is_file) {
@ -1379,8 +1422,12 @@ uint8_t prompt_for_name(char *prompt, uint8_t is_file) {
i = 0; i = 0;
while (1) { while (1) {
c = cgetc(); c = cgetc();
if (is_file && !isalnum(c) && (c != RETURN) && (c != BACKSPACE) && if ((is_file > 0) && !isalnum(c) && (c != RETURN) && (c != BACKSPACE) &&
(c != DELETE) && (c != ESC) && (c != '.')) { (c != DELETE) && (c != ESC) && (c != '.') && (c != '/')) {
putchar(BELL);
continue;
}
if ((is_file == 1) && (c == '/')) {
putchar(BELL); putchar(BELL);
continue; continue;
} }
@ -1962,6 +2009,7 @@ void keyboard_hdlr(void) {
h->status = 'R'; // Mark email read h->status = 'R'; // Mark email read
write_updated_headers(h, get_db_index()); write_updated_headers(h, get_db_index());
email_pager(h); email_pager(h);
read_email_db(first_msg, 0, 0); // email_pager() deletes the headers
email_summary(); email_summary();
} }
break; break;
@ -2097,6 +2145,11 @@ void main(void) {
error(ERR_FATAL, "Need 80 cols"); error(ERR_FATAL, "Need 80 cols");
if ((*pp & 0x30) != 0x30) if ((*pp & 0x30) != 0x30)
error(ERR_FATAL, "Need 128K"); error(ERR_FATAL, "Need 128K");
// Clear system bit map
for (pp = (uint8_t*)0xbf58; pp <= (uint8_t*)0xbf6f; ++pp)
*pp = 0;
videomode(VIDEOMODE_80COL); videomode(VIDEOMODE_80COL);
readconfigfile(); readconfigfile();
reverse = 0; reverse = 0;

View File

@ -6,7 +6,7 @@
#include <stdint.h> #include <stdint.h>
#define PROGNAME "emai//er v1.05" #define PROGNAME "emai//er v1.06"
// Configuration params from EMAIL.CFG // Configuration params from EMAIL.CFG
char cfg_server[40]; // IP of POP3 server char cfg_server[40]; // IP of POP3 server