From 9c1943439765826dd2b8d92447e4d1c684331902 Mon Sep 17 00:00:00 2001 From: Bobbi Webber-Manners Date: Mon, 29 Jun 2020 19:23:53 -0400 Subject: [PATCH] Show system date in status bar. Code cleanup. --- apps/email.c | 174 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 128 insertions(+), 46 deletions(-) diff --git a/apps/email.c b/apps/email.c index 3dd9207..918b8d0 100644 --- a/apps/email.c +++ b/apps/email.c @@ -29,6 +29,28 @@ #define SCROLLBACK 25*80 // How many bytes to go back when paging up #define READSZ 1024 // Size of buffer for copying files +#define BELL 0x07 +#define BACKSPACE 0x08 +#define INVERSE 0x0f +#define RETURN 0x0d +#define NORMAL 0x0e +#define CURDOWN 0x0a +#define HOME 0x19 +#define CLRLINE 0x1a +#define DELETE 0x7f + +/* + * Represents a date and time + */ +struct datetime { + unsigned int year; + unsigned char month; + unsigned char day; + unsigned char hour; + unsigned char minute; + unsigned char ispd25format; + unsigned char nodatetime; +}; char filename[80]; char userentry[80]; @@ -51,9 +73,9 @@ static unsigned char buf[READSZ]; */ void goto_prompt_row(void) { uint8_t i; - putchar(0x19); // HOME + putchar(HOME); for (i = 0; i < PROMPT_ROW - 1; ++i) - putchar(0x0a); // CURSOR DOWN + putchar(CURDOWN); } /* @@ -64,7 +86,7 @@ void error(uint8_t fatal, const char *fmt, ...) { va_list v; if (fatal) { clrscr(); - printf("\n\n%cFATAL ERROR:%c\n\n", 0x0f, 0x0e); + printf("\n\n%cFATAL ERROR:%c\n\n", INVERSE, NORMAL); va_start(v, fmt); vprintf(fmt, v); va_end(v); @@ -73,13 +95,13 @@ void error(uint8_t fatal, const char *fmt, ...) { exit(1); } else { goto_prompt_row(); - putchar(0x1a); // CLEAR LINE + putchar(CLRLINE); va_start(v, fmt); vprintf(fmt, v); va_end(v); printf(" - [Press Any Key]"); cgetc(); - putchar(0x1a); // CLEAR LINE + putchar(CLRLINE); } } @@ -89,7 +111,7 @@ void error(uint8_t fatal, const char *fmt, ...) { void spinner(void) { static char chars[] = "|/-\\"; static uint8_t i = 0; - putchar(0x08); // BACKSPACE + putchar(BACKSPACE); putchar(chars[(i++) % 4]); } @@ -111,6 +133,52 @@ void readconfigfile(void) { fclose(fp); } +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]; + if ((d == 0) && (t == 0)) { + dt->nodatetime = 1; + return; + } + dt->nodatetime = 0; + if (!(t & 0xe000)) { + /* ProDOS 1.0 to 2.4.2 date format */ + dt->year = (d & 0xfe00) >> 9; + dt->month = (d & 0x01e0) >> 5; + dt->day = d & 0x001f; + dt->hour = (t & 0x1f00) >> 8; + dt->minute = t & 0x003f; + dt->ispd25format = 0; + if (dt->year < 40) /* See ProDOS-8 Tech Note 48 */ + dt->year += 2000; + else + dt->year += 1900; + } else { + /* ProDOS 2.5.0+ */ + dt->year = t & 0x0fff; + dt->month = ((t & 0xf000) >> 12) - 1; + dt->day = (d & 0xf800) >> 11; + dt->hour = (d & 0x07c0) >> 6; + dt->minute = d & 0x003f; + dt->ispd25format = 1; + } +} + +void printdatetime(struct datetime *dt) { + if (dt->nodatetime) + fputs("????-??-?? ??:??", stdout); + else { + printf("%04d-%02d-%02d %02d:%02d", + dt->year, dt->month, dt->day, dt->hour, dt->minute); + } +} + +void printsystemdate(void) { + struct datetime dt; + readdatetime((unsigned char*)(0xbf90), &dt); + printdatetime(&dt); +} + /* * Free linked list rooted at headers */ @@ -203,7 +271,7 @@ void printfield(char *s, uint8_t start, uint8_t end) { * Print one line summary of email headers for one message */ void print_one_email_summary(struct emailhdrs *h, uint8_t inverse) { - putchar(inverse ? 0xf : 0xe); // INVERSE or NORMAL + putchar(inverse ? INVERSE : NORMAL); putchar(h->tag == 'T' ? 'T' : ' '); switch(h->status) { case 'N': @@ -224,7 +292,7 @@ void print_one_email_summary(struct emailhdrs *h, uint8_t inverse) { putchar('|'); printfield(h->subject, 0, 39); //putchar('\r'); - putchar(0xe); // NORMAL + putchar(NORMAL); } /* @@ -240,16 +308,24 @@ struct emailhdrs *get_headers(uint16_t n) { return h; } +/* + * Print status bar at the top + */ void status_bar(void) { - putchar(0x19); // HOME + putchar(HOME); + putchar(INVERSE); + fputs(" ", stdout); + printsystemdate(); + putchar(HOME); if (num_msgs == 0) - printf("%c%s [%s] No messages%c", - 0x0f, PROGNAME, curr_mbox, 0x0e); + printf("%c%s [%s] No messages ", INVERSE, PROGNAME, curr_mbox); else - printf("%c%s [%s] %u messages, %u new, %u tagged. Displaying %u-%u%c", - 0x0f, PROGNAME, curr_mbox, total_msgs, total_new, total_tag, first_msg, - first_msg + num_msgs - 1, 0x0e); - printf("\n\n"); + printf("%c[%s] %u msgs, %u new, %u tagged. Showing %u-%u. ", + INVERSE, curr_mbox, total_msgs, total_new, total_tag, first_msg, + first_msg + num_msgs - 1); + putchar(NORMAL); + putchar(CURDOWN); + printf("\n"); } /* @@ -265,11 +341,11 @@ void email_summary(void) { ++i; h = h->next; } - putchar(0x19); // HOME + putchar(HOME); for (i = 0; i < MENU_ROW - 1; ++i) - putchar(0x0a); // CURSOR DOWN - printf("%cUp/K Prev | SPC/RET Read | A)rchive | C)opy | M)ove | D)el | U)ndel | P)urge %c", 0x0f, 0x0e); - printf("%cDn/J Next | S)witch mbox | N)ew mbox| T)ag | W)rite | R)eply | F)wd | Q)uit %c", 0x0f, 0x0e); + putchar(CURDOWN); + printf("%cUp/K Prev | SPC/RET Read | A)rchive | C)opy | M)ove | D)el | U)ndel | P)urge %c", INVERSE, NORMAL); + printf("%cDn/J Next | S)witch mbox | N)ew mbox| T)ag | W)rite | R)eply | F)wd | Q)uit %c", INVERSE, NORMAL); } /* @@ -279,9 +355,9 @@ void email_summary_for(uint16_t n) { struct emailhdrs *h = headers; uint16_t j; h = get_headers(n); - putchar(0x19); // HOME + putchar(HOME); for (j = 0; j < n + 1; ++j) - putchar(0x0a); // CURSOR DOWN + putchar(CURDOWN); print_one_email_summary(h, (n == selection)); } @@ -335,9 +411,9 @@ restart: } if (c == '\r') { if ((*p) == 22) { // Use the CURSOR ROW location - putchar(0x0f); // INVERSE + putchar(INVERSE); printf("[%05lu] SPACE continue reading | B)ack | T)op | H)drs | Q)uit", pos); - putchar(0x0e); // NORMAL + putchar(NORMAL); retry1: c = cgetc(); switch (c) { @@ -371,15 +447,15 @@ retry1: fclose(fp); return; default: - putchar(7); // BELL + putchar(BELL); goto retry1; } clrscr(); } } else if (eof) { - putchar(0x0f); // INVERSE + putchar(INVERSE); printf("[%05lu] *** END *** | B)ack | T)op | H)drs | Q)uit", pos); - putchar(0x0e); // NORMAL + putchar(NORMAL); retry2: c = cgetc(); switch (c) { @@ -411,7 +487,7 @@ retry2: fclose(fp); return; default: - putchar(7); // BELL + putchar(BELL); goto retry2; } clrscr(); @@ -475,6 +551,9 @@ void new_mailbox(char *mbox) { void switch_mailbox(char *mbox) { char prev_mbox[80]; uint8_t err; + // Treat '.' as shortcut for INBOX + if (!strcmp(mbox, ".")) + strcpy(mbox, "INBOX"); strcpy(prev_mbox, curr_mbox); strcpy(curr_mbox, mbox); first_msg = 1; @@ -523,7 +602,7 @@ void purge_deleted(void) { error(ERR_NONFATAL, "Can't delete %s", filename); } goto_prompt_row(); - putchar(0x1a); // CLEAR LINE + putchar(CLRLINE); printf("%u msgs deleted", ++delcount); } else { l = fwrite(h, 1, EMAILHDRS_SZ_ON_DISK, fp2); @@ -732,9 +811,9 @@ void copy_to_mailbox(struct emailhdrs *h, uint16_t idx, return; } } - putchar(0x08); // Erase spinner + putchar(BACKSPACE); putchar(' '); - putchar(0x08); + putchar(BACKSPACE); fclose(fp); fclose(fp2); @@ -788,13 +867,13 @@ char prompt_okay(char *msg) { c = cgetc(); if ((c == 'y') || (c == 'Y') || (c == 'n') || (c == 'N')) break; - putchar(7); // BELL + putchar(BELL); } if ((c == 'y') || (c == 'Y')) c = 1; else c = 0; - putchar(0x1a); // CLEAR LINE + putchar(CLRLINE); return c; } @@ -843,7 +922,7 @@ uint8_t copy_to_mailbox_tagged(char *mbox, uint8_t delete) { if (h->tag == 'T') { h->tag = ' '; // Don't want it tagged in the destination goto_prompt_row(); - putchar(0x1a); // CLEAR LINE + putchar(CLRLINE); printf("%u/%u:", ++tagcount, total_tag); copy_to_mailbox(h, count, mbox, delete, ' '); } @@ -859,6 +938,7 @@ err: * Returns number of chars read. * prompt - Message to display before > prompt * is_file - if 1, restrict chars to those allowed in ProDOS filename + * Returns number of chars read */ uint8_t prompt_for_name(char *prompt, uint8_t is_file) { uint16_t i; @@ -868,22 +948,22 @@ uint8_t prompt_for_name(char *prompt, uint8_t is_file) { i = 0; while (1) { c = cgetc(); - if (is_file && !isalnum(c) && (c != 0x0d) && (c != 0x08) && (c != 0x7f) && (c != '.')) { - putchar(7); // BELL + if (is_file && !isalnum(c) && (c != RETURN) && (c != BACKSPACE) && (c != DELETE) && (c != '.')) { + putchar(BELL); continue; } switch (c) { - case 0x0d: // RETURN KEY + case RETURN: goto done; - case 0x08: // BACKSPACE - case 0x7f: // DELETE + case BACKSPACE: + case DELETE: if (i > 0) { - putchar(0x08); + putchar(BACKSPACE); putchar(' '); - putchar(0x08); + putchar(BACKSPACE); --i; } else - putchar(7); // BELL + putchar(BELL); break; default: putchar(c); @@ -894,7 +974,7 @@ uint8_t prompt_for_name(char *prompt, uint8_t is_file) { } done: userentry[i] = '\0'; - putchar(0x1a); // CLEAR LINE + putchar(CLRLINE); goto_prompt_row(); return i; } @@ -921,11 +1001,13 @@ void create_blank_outgoing() { } fprintf(fp, "From: %s\n", cfg_emailaddr); + prompt_for_name("To", 0); + if (strlen(userentry) == 0) + return; + fprintf(fp, "To: %s\n", userentry); prompt_for_name("Subject", 0); fprintf(fp, "Subject: %s\n", userentry); fprintf(fp, "Date: TODO: put date in here!!\n"); // TODO - prompt_for_name("To", 0); - fprintf(fp, "To: %s\n", userentry); prompt_for_name("cc", 0); fprintf(fp, "cc: %s\n\n", userentry); fclose(fp); @@ -991,7 +1073,7 @@ void keyboard_hdlr(void) { email_summary(); } break; - case 0x0d: // RETURN KEY + case RETURN: case ' ': h = get_headers(selection); if (h) { @@ -1073,7 +1155,7 @@ void keyboard_hdlr(void) { } default: //printf("[%02x]", c); - putchar(7); // BELL + putchar(BELL); } } }