From 9ba05ef98b16a89fb3b8598d60b551c7811808f6 Mon Sep 17 00:00:00 2001 From: Bobbi Webber-Manners Date: Tue, 7 Jul 2020 19:23:16 -0400 Subject: [PATCH] Added utility for rebuilding EMAIL.DB. Other minor fixes. --- apps/Makefile | 6 +- apps/email.c | 5 + apps/pop65.c | 5 +- apps/rebuild.c | 252 +++++++++++++++++++++++++++++++++++++++++++++++++ apps/smtp65.c | 5 +- 5 files changed, 266 insertions(+), 7 deletions(-) create mode 100644 apps/rebuild.c diff --git a/apps/Makefile b/apps/Makefile index 723bb1e..532e790 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -45,7 +45,7 @@ TCP =\ tweet65 \ pop65-slow -bin: wget65.bin pop65.bin smtp65.bin email.bin +bin: wget65.bin pop65.bin smtp65.bin email.bin rebuild.bin wget65.bin: w5100.c w5100_http.c linenoise.c wget65.bin: IP65LIB = ../ip65/ip65.lib @@ -147,9 +147,11 @@ ip65.dsk: bin java -jar $(AC) -p $@ smtp65.system sys < $(CC65)/apple2enh/util/loader.system # java -jar $(AC) -as $@ wget65 < wget65.bin # java -jar $(AC) -p $@ wget65.system sys < $(CC65)/apple2enh/util/loader.system - java -jar $(AC) -as $@ telnet65 < telnet65.bin +# java -jar $(AC) -as $@ telnet65 < telnet65.bin java -jar $(AC) -as $@ email < email.bin java -jar $(AC) -p $@ email.system sys < $(CC65)/apple2enh/util/loader.system + java -jar $(AC) -as $@ rebuild < rebuild.bin + java -jar $(AC) -p $@ rebuild.system sys < $(CC65)/apple2enh/util/loader.system java -jar $(AC) -p $@ tzone.txt txt < tzone.txt java -jar $(AC) -p $@ pop65.cfg txt < pop65.cfg diff --git a/apps/email.c b/apps/email.c index 3a43528..4e463db 100644 --- a/apps/email.c +++ b/apps/email.c @@ -4,6 +4,8 @@ // Bobbi June, July 2020 ///////////////////////////////////////////////////////////////// +// - TODO: Make an EMAIL.DB rebuilder tool +// - TODO: Get rid of all uses of malloc(). Don't need it. // - TODO: See TODOs further down for error handling // - TODO: Editor for email composition functions @@ -146,6 +148,9 @@ void readconfigfile(void) { fclose(fp); } +/* + * Convert date/time bytes into struct datetime format. + */ void readdatetime(unsigned char time[4], struct datetime *dt) { unsigned int d = time[0] + 256U * time[1]; unsigned int t = time[2] + 256U * time[3]; diff --git a/apps/pop65.c b/apps/pop65.c index 7d4466f..8647dea 100644 --- a/apps/pop65.c +++ b/apps/pop65.c @@ -34,6 +34,7 @@ #define READSZ 1024 // Must be less than NETBUFSZ to fit in buf[] static unsigned char buf[NETBUFSZ+1]; // One extra byte for null terminator +static char linebuf_pad[1]; // One byte of padding make it easier static char linebuf[LINEBUFSZ]; char filename[80]; @@ -316,7 +317,7 @@ int16_t get_line(FILE *fp) { while (1) { for (i = rd; i < buflen; ++i) { linebuf[j++] = buf[i]; - // The following line is safe because j>=1 at this point + // The following line is safe because of linebuf_pad[] if ((linebuf[j - 1] == '\n') && (linebuf[j - 2] == '\r')) { found = 1; break; @@ -474,6 +475,8 @@ void main(void) { uint16_t msg, nummsgs; uint32_t bytes; + linebuf_pad[0] = 0; + videomode(VIDEOMODE_80COL); printf("%c%s POP3%c\n", 0x0f, PROGNAME, 0x0e); diff --git a/apps/rebuild.c b/apps/rebuild.c new file mode 100644 index 0000000..db56a61 --- /dev/null +++ b/apps/rebuild.c @@ -0,0 +1,252 @@ +///////////////////////////////////////////////////////////////// +// Rebuild EMAIL.DB & NEXT.EMAIL files for an existing mailbox +// Bobbi July 2020 +///////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef unsigned long uint32_t; +typedef unsigned int uint16_t; +typedef unsigned char uint8_t; +typedef int int16_t; +#include "email_common.h" + +#define NETBUFSZ 1500+4 // 4 extra bytes for overlap between packets +#define LINEBUFSZ 1000 // According to RFC2822 Section 2.1.1 (998+CRLF) +#define READSZ 1024 // Must be less than NETBUFSZ to fit in buf[] + +static unsigned char buf[NETBUFSZ+1]; // One extra byte for null terminator +static char linebuf[LINEBUFSZ]; + +static char dirname[255]; +static char filename[255]; + +/* + * Keypress before quit + */ +void confirm_exit(void) { + printf("\nPress any key "); + cgetc(); + exit(0); +} + +/* + * Called for all errors + */ +void error_exit() { + confirm_exit(); +} + +/* + * Read a text file a line at a time leaving the line in linebuf[] + * Returns number of chars in the line, or -1 if EOF. + * Converts line endings from CRLF -> CR (Apple ][ style) + */ +int16_t get_line(FILE *fp) { + static uint16_t rd = 0; + static uint16_t buflen = 0; + uint8_t found = 0; + uint16_t j = 0; + uint16_t i; + while (1) { + for (i = rd; i < buflen; ++i) { + linebuf[j++] = buf[i]; + if (linebuf[j - 1] == '\r') { + found = 1; + break; + } + } + if (found) { + rd = i + 1; + return j; + } + buflen = fread(buf, 1, READSZ, fp); + if (buflen == 0) { + rd = 0; + return -1; // Hit EOF before we found EOL + } + rd = 0; + } +} + +/* + * Update EMAIL.DB - quick access database for header info + */ +void update_email_db(struct emailhdrs *h) { + FILE *fp; + sprintf(filename, "%s/EMAIL.DB", dirname); + _filetype = PRODOS_T_BIN; + _auxtype = 0; + fp = fopen(filename, "ab"); + if (!fp) { + printf("Can't open %s\n", filename); + error_exit(); + } + fwrite(h, sizeof(struct emailhdrs), 1, fp); + fclose(fp); +} + +/* + * Write NEXT.EMAIL file with number of next EMAIL.n file to be created + */ +void write_next_email(uint16_t num) { + FILE *fp; + sprintf(filename, "%s/NEXT.EMAIL", dirname); + _filetype = PRODOS_T_TXT; + _auxtype = 0; + fp = fopen(filename, "wb"); + if (!fp) { + printf("2)Can't open %s\n", filename); + fclose(fp); + error_exit(); + } + fprintf(fp, "%u", num); + fclose(fp); +} + +/* + * Copy one header from source->dest, removing '\r' from end + */ +void copyheader(char *dest, char *source, uint16_t len) { + uint16_t i; + memset(dest, ' ', len); + for (i = 0; i < len; ++i) { + if ((*source == '\0') || (*source == '\r')) + return; + *dest++ = *source++; + } +} + +/* + * Repair a mailbox by scanning the messages and rebuilding + * EMAIL.DB and NEXT.EMAIL + */ +void repair_mailbox(void) { + static struct emailhdrs hdrs; + uint16_t msg, chars, headerchars, emailnum, maxemailnum; + uint8_t headers; + FILE *fp; + DIR *dp; + struct dirent *d; + + dp = opendir(dirname); + if (!dp) { + printf("Can't open dir %s\n", dirname); + error_exit(); + } + + sprintf(filename, "%s/EMAIL.DB", dirname); + _filetype = PRODOS_T_BIN; + _auxtype = 0; + fp = fopen(filename, "wb"); + if (!fp) { + closedir(dp); + printf("Can't create %s\n", filename); + error_exit(); + } + fclose(fp); + + sprintf(filename, "%s/NEXT.EMAIL", dirname); + _filetype = PRODOS_T_TXT; + _auxtype = 0; + fp = fopen(filename, "wb"); + if (!fp) { + closedir(dp); + printf("Can't create %s\n", filename); + error_exit(); + } + fclose(fp); + + while (d = readdir(dp)) { + + if (!strncmp(d->d_name, "EMAIL.DB", 8)) + continue; + if (!strncmp(d->d_name, "NEXT.EMAIL", 10)) + continue; + if (strncmp(d->d_name, "EMAIL.", 6)) + continue; + + sscanf(d->d_name, "EMAIL.%u", &emailnum); + if (emailnum > maxemailnum) + maxemailnum = emailnum; + + sprintf(filename, "%s/%s", dirname, d->d_name); + printf("** Processing file %s [%u] ...\n", filename, emailnum); + fp = fopen(filename, "r"); + if (!fp) { + closedir(dp); + printf("Can't open %s\n", filename); + continue; + } + headers = 1; + headerchars = 0; + hdrs.emailnum = emailnum; + hdrs.skipbytes = 0; // Just in case it doesn't get set + hdrs.status = 'N'; + hdrs.tag = ' '; + while ((chars = get_line(fp)) != -1) { + if (headers) { + headerchars += chars; + if (!strncmp(linebuf, "Date: ", 6)) { + copyheader(hdrs.date, linebuf + 6, 39); + hdrs.date[39] = '\0'; + } + if (!strncmp(linebuf, "From: ", 6)) { + copyheader(hdrs.from, linebuf + 6, 79); + hdrs.from[79] = '\0'; + } + if (!strncmp(linebuf, "To: ", 4)) { + copyheader(hdrs.to, linebuf + 4, 79); + hdrs.to[79] = '\0'; + } + if (!strncmp(linebuf, "Cc: ", 4)) { + copyheader(hdrs.cc, linebuf + 4, 79); + hdrs.cc[79] = '\0'; + } + if (!strncmp(linebuf, "Subject: ", 9)) { + copyheader(hdrs.subject, linebuf + 9, 79); + hdrs.subject[79] = '\0'; + } + if (linebuf[0] == '\r') { + headers = 0; + hdrs.skipbytes = headerchars; + } + } + } + fclose(fp); + update_email_db(&hdrs); + } + closedir(dp); + write_next_email(maxemailnum + 1); + printf("Rebuilt %s/EMAIL.DB\n", dirname); + printf("Rebuilt %s/NEXT.EMAIL\n\n", dirname); +} + +void main(void) { + videomode(VIDEOMODE_80COL); + printf("%c%s Rebuild EMAIL.DB Utility%c\n", 0x0f, PROGNAME, 0x0e); + + printf("\nEnter full path to the mailbox to rebuild> "); + fgets(dirname, 128, stdin); + dirname[strlen(dirname) - 1] = '\0'; // Eat '\r' + if (strlen(dirname) == 0) { + printf("\nCancelled\n"); + confirm_exit(); + } + + printf("\nUpdating %s ...\n", dirname); + repair_mailbox(); + + confirm_exit(); +} + diff --git a/apps/smtp65.c b/apps/smtp65.c index 85c1802..a0f955d 100644 --- a/apps/smtp65.c +++ b/apps/smtp65.c @@ -6,8 +6,6 @@ // Bobbi June 2020 ///////////////////////////////////////////////////////////////// -// TODO: Email rebuild mode to recreate mailbox given a directory of messages - #include #include #include @@ -460,8 +458,7 @@ void update_sent_mbox(char *name) { copyheader(hdrs.subject, linebuf + 9, 79); hdrs.subject[79] = '\0'; } - //if (linebuf[0] == '\r') { - if (strlen(linebuf) < 10) { + if (linebuf[0] == '\r') { headers = 0; hdrs.skipbytes = headerchars; }