Improvements to EMAIL.DB format. Don't delete headers, just hide them.

This commit is contained in:
Bobbi Webber-Manners 2020-06-25 14:23:38 -04:00
parent 71cfe5f60b
commit b3b556b440
3 changed files with 93 additions and 79 deletions

View File

@ -1,8 +1,8 @@
//
/////////////////////////////////////////////////////////////////
// Simple Email User Agent
// Bobbi June 2020
// Handles INBOX in the format created by POP65
//
// Bobbi June 2020
/////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
@ -10,6 +10,9 @@
#include <conio.h>
#include <string.h>
#define EMAIL_C
#include "email_common.h"
#define SCROLLBACK 25*80
char filename[80];
@ -18,23 +21,6 @@ struct emailhdrs *headers;
uint16_t selection, prevselection;
uint16_t num_msgs;
// Configuration params from POP65.CFG
char cfg_server[80]; // IP of POP3 server
char cfg_user[80]; // Username
char cfg_pass[80]; // Password
char cfg_spooldir[80]; // ProDOS directory to spool email to
char cfg_inboxdir[80]; // ProDOS directory for email inbox
// Represents the email headers for one message
struct emailhdrs {
char date[80];
char from[80];
char to[80];
char cc[80];
char subject[80];
struct emailhdrs *next;
};
/*
* Keypress before quit
*/
@ -71,7 +57,7 @@ void readconfigfile(void) {
}
/*
* Read EMAIL.DB
* Read EMAIL.DB and populate linked list rooted at headers
*/
void read_email_db(void) {
struct emailhdrs *curr = NULL, *prev = NULL;
@ -116,9 +102,9 @@ 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(uint16_t num, struct emailhdrs *h, uint8_t inverse) {
void print_one_email_summary(struct emailhdrs *h, uint8_t inverse) {
putchar(inverse ? 0xf : 0xe); // INVERSE or NORMAL
printf("%02d|", num);
printf("%02d|", h->emailnum);
printfield(h->date, 0, 16);
putchar('|');
printfield(h->from, 0, 20);
@ -129,7 +115,7 @@ void print_one_email_summary(uint16_t num, struct emailhdrs *h, uint8_t inverse)
}
/*
* Get emailhdrs for nth email
* Get emailhdrs for nth email in list of headers
*/
struct emailhdrs *get_headers(uint16_t n) {
uint16_t i = 1;
@ -149,14 +135,14 @@ void email_summary(void) {
struct emailhdrs *h = headers;
clrscr();
while (h) {
print_one_email_summary(i, h, (i == selection));
print_one_email_summary(h, (i == selection));
++i;
h = h->next;
}
}
/*
* Show email summary for nth email message
* Show email summary for nth email message in list of headers
*/
void email_summary_for(uint16_t n) {
struct emailhdrs *h = headers;
@ -165,7 +151,7 @@ void email_summary_for(uint16_t n) {
putchar(0x19); // HOME
for (j = 0; j < n - 1; ++j)
putchar(0x0a); // CURSOR DOWN
print_one_email_summary(n, h, (n == selection));
print_one_email_summary(h, (n == selection));
}
/*
@ -185,7 +171,7 @@ void email_pager(void) {
uint8_t line, eof;
char c;
clrscr();
sprintf(filename, "%s/EMAIL.%u", cfg_inboxdir, selection);
sprintf(filename, "%s/EMAIL.%u", cfg_inboxdir, h->emailnum);
fp = fopen(filename, "rb");
if (!fp) {
printf("Can't open %s\n", filename);
@ -193,6 +179,8 @@ void email_pager(void) {
cgetc();
return;
}
pos = h->skipbytes;
fseek(fp, pos, SEEK_SET); // Skip over headers
restart:
clrscr();
line = 6;
@ -221,7 +209,7 @@ restart:
++line;
if (line == 22) {
putchar(0x0f); // INVERSE
printf("[%05lu] SPACE continue reading | B)ack | T)op | Q)uit", pos);
printf("[%05lu] SPACE continue reading | B)ack | T)op | H)drs | Q)uit", pos);
putchar(0x0e); // NORMAL
retry1:
c = cgetc();
@ -231,7 +219,7 @@ retry1:
case 'B':
case 'b':
if (pos < (uint32_t)(SCROLLBACK)) {
pos = 0;
pos = h->skipbytes;
fseek(fp, pos, SEEK_SET);
goto restart;
} else {
@ -241,10 +229,16 @@ retry1:
break;
case 'T':
case 't':
pos = 0;
pos = h->skipbytes;
fseek(fp, pos, SEEK_SET);
goto restart;
break;
case 'H':
case 'h':
pos = 0;
fseek(fp, pos, SEEK_SET);
goto restart;
break;
case 'Q':
case 'q':
fclose(fp);
@ -258,7 +252,7 @@ retry1:
}
} else if (eof) {
putchar(0x0f); // INVERSE
printf("[%05lu] *** END *** | B)ack | T)op | Q)uit", pos);
printf("[%05lu] *** END *** | B)ack | T)op | H)drs | Q)uit", pos);
putchar(0x0e); // NORMAL
retry2:
c = cgetc();
@ -266,7 +260,7 @@ retry2:
case 'B':
case 'b':
if (pos < (uint32_t)(SCROLLBACK)) {
pos = 0;
pos = h->skipbytes;
fseek(fp, pos, SEEK_SET);
goto restart;
} else {
@ -276,6 +270,12 @@ retry2:
break;
case 'T':
case 't':
pos = h->skipbytes;
fseek(fp, pos, SEEK_SET);
goto restart;
break;
case 'H':
case 'h':
pos = 0;
fseek(fp, pos, SEEK_SET);
goto restart;

27
apps/email_common.h Normal file
View File

@ -0,0 +1,27 @@
/////////////////////////////////////////////////////////////////
// EMAIL_COMMON.H
// Definitions shared between pop65.c and email.c
// Bobbi June 2020
/////////////////////////////////////////////////////////////////
// Configuration params from POP65.CFG
char cfg_server[80]; // IP of POP3 server
char cfg_user[80]; // Username
char cfg_pass[80]; // Password
char cfg_spooldir[80]; // ProDOS directory to spool email to
char cfg_inboxdir[80]; // ProDOS directory for email inbox
// Represents the email headers for one message
struct emailhdrs {
uint16_t emailnum; // Name of file is EMAIL.n (n=emailnum)
uint16_t skipbytes; // How many bytes to skip over the headers
char date[40];
char from[80];
char to[80];
char cc[80];
char subject[80];
#ifdef EMAIL_C
struct emailhdrs *next; // Used in email.c only for linked list
#endif
};

View File

@ -6,7 +6,6 @@
// Bobbi June 2020
/////////////////////////////////////////////////////////////////
#include <dio.h>
#include <cc65.h>
#include <errno.h>
#include <ctype.h>
@ -16,14 +15,14 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <device.h>
#include "../inc/ip65.h"
#include "w5100.h"
#include "w5100_http.h"
#include "linenoise.h"
#include "email_common.h"
#define BACKSPACE 8
// Both pragmas are obligatory to have cc65 generate code
@ -34,36 +33,19 @@
#define NETBUFSZ 1500
#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 padding[1] = {0}; // Having an extra byte before linebuf[] helps
static char linebuf[LINEBUFSZ];
char filename[80];
int len;
FILE *fp;
static unsigned char buf[NETBUFSZ+1]; // One extra byte for null terminator
static char linebuf[LINEBUFSZ];
char filename[80];
int len;
FILE *fp;
uint32_t filesize;
// Configuration params from POP65.CFG
char cfg_server[80]; // IP of POP3 server
char cfg_user[80]; // Username
char cfg_pass[80]; // Password
char cfg_spooldir[80]; // ProDOS directory to spool email to
char cfg_inboxdir[80]; // ProDOS directory for email inbox
// Represents the email headers for one message
struct emailhdrs {
char date[80];
char from[80];
char to[80];
char cc[80];
char subject[80];
};
/*
* Keypress before quit
*/
void confirm_exit(void)
{
void confirm_exit(void) {
printf("\nPress any key ");
cgetc();
exit(0);
@ -72,16 +54,14 @@ void confirm_exit(void)
/*
* Called for all non IP65 errors
*/
void error_exit()
{
void error_exit() {
confirm_exit();
}
/*
* Called if IP65 call fails
*/
void ip65_error_exit(void)
{
void ip65_error_exit(void) {
printf("%s\n", ip65_strerror(ip65_error));
confirm_exit();
}
@ -225,6 +205,8 @@ bool w5100_tcp_send_recv(char* sendbuf, char* recvbuf, size_t length,
*++dataptr = data;
// TODO -- check we are not looking before start of recvbuf here!!
// TODO -- this doesn't handle the case where the sequence is split across
// packets!!!
if (!memcmp(dataptr - 4, "\r\n.\r\n", 5))
cont = 0;
}
@ -317,10 +299,10 @@ void readconfigfile(void) {
/*
* Read a text file a line at a time leaving the line in linebuf[]
* Returns 1 if line read, 0 if EOF.
* Returns number of chars in the line, or -1 if EOF.
* Converts line endings from CRLF -> CR (Apple ][ style)
*/
uint8_t get_line(FILE *fp) {
int16_t get_line(FILE *fp) {
static uint16_t rd = 0;
static uint16_t buflen = 0;
uint8_t found = 0;
@ -329,21 +311,21 @@ uint8_t get_line(FILE *fp) {
while (1) {
for (i = rd; i < buflen; ++i) {
linebuf[j++] = buf[i];
if ((linebuf[j-1] == '\n') && (linebuf[j-2] == '\r')) {
// The following line is safe because j>=1 at this point
if ((linebuf[j - 1] == '\n') && (linebuf[j - 2] == '\r')) {
found = 1;
break;
}
}
if (found) {
rd = i + 1;
linebuf[j-1] = '\0'; // Remove LF from end
j = 0;
return 1;
linebuf[j - 1] = '\0'; // Remove LF from end
return j - 2;
}
buflen = fread(buf, 1, READSZ, fp);
if (buflen == 0) {
rd = 0;
return 0; // Hit EOF before we found EOL
return -1; // Hit EOF before we found EOL
}
rd = 0;
}
@ -399,7 +381,7 @@ void write_next_email(uint16_t num) {
*/
void update_inbox(uint16_t nummsgs) {
static struct emailhdrs hdrs;
uint16_t nextemail, msg;
uint16_t nextemail, msg, chars, headerchars;
uint8_t headers;
FILE *destfp;
sprintf(filename, "%s/NEXT.EMAIL", cfg_inboxdir);
@ -419,6 +401,7 @@ void update_inbox(uint16_t nummsgs) {
printf("Can't open %s\n", filename);
error_exit();
}
hdrs.emailnum = nextemail;
sprintf(filename, "%s/EMAIL.%u", cfg_inboxdir, nextemail++);
puts(filename);
destfp = fopen(filename, "wb");
@ -428,10 +411,13 @@ void update_inbox(uint16_t nummsgs) {
error_exit();
}
headers = 1;
while (get_line(fp)) {
headerchars = 0;
hdrs.skipbytes = 0; // Just in case it doesn't get set
while ((chars = get_line(fp)) != -1) {
if (headers) {
headerchars += chars + 1; // Don't forget the LF we deleted
if (!strncmp(linebuf, "Date: ", 6)) {
copyheader(hdrs.date, linebuf + 6, 79);
copyheader(hdrs.date, linebuf + 6, 39);
hdrs.date[79] = '\0';
}
if (!strncmp(linebuf, "From: ", 6)) {
@ -450,10 +436,13 @@ void update_inbox(uint16_t nummsgs) {
copyheader(hdrs.subject, linebuf + 9, 79);
hdrs.subject[79] = '\0';
}
if (linebuf[0] == '\r')
//if (linebuf[0] == '\r') {
if (strlen(linebuf) < 10) {
headers = 0;
} else
fputs(linebuf, destfp);
hdrs.skipbytes = headerchars;
}
}
fputs(linebuf, destfp);
}
fclose(fp);
fclose(destfp);
@ -468,8 +457,6 @@ void main(void) {
uint16_t msg, nummsgs;
uint32_t bytes;
padding[0] = 0; // To shut up warning
videomode(VIDEOMODE_80COL);
printf("\nReading POP65.CFG -");
readconfigfile();