mirror of
https://github.com/bobbimanners/emailler.git
synced 2024-05-28 05:41:28 +00:00
Merge branch 'usenet'
This commit is contained in:
commit
62ec27c1f9
|
@ -45,7 +45,7 @@ TCP =\
|
|||
tweet65 \
|
||||
pop65-slow
|
||||
|
||||
bin: wget65.bin pop65.bin smtp65.bin email.bin rebuild.bin edit.bin attacher.bin
|
||||
bin: wget65.bin pop65.bin smtp65.bin email.bin rebuild.bin edit.bin attacher.bin nntp65.bin nntp65.up.bin
|
||||
|
||||
wget65.bin: w5100.c w5100_http.c linenoise.c
|
||||
wget65.bin: IP65LIB = ../ip65/ip65.lib
|
||||
|
@ -59,6 +59,14 @@ smtp65.bin: w5100.c
|
|||
smtp65.bin: IP65LIB = ../ip65/ip65.lib
|
||||
smtp65.bin: A2_DRIVERLIB = ../drivers/ip65_apple2_uther2.lib
|
||||
|
||||
nntp65.bin: w5100.c
|
||||
nntp65.bin: IP65LIB = ../ip65/ip65.lib
|
||||
nntp65.bin: A2_DRIVERLIB = ../drivers/ip65_apple2_uther2.lib
|
||||
|
||||
nntp65.up.bin: w5100.c
|
||||
nntp65.up.bin: IP65LIB = ../ip65/ip65.lib
|
||||
nntp65.up.bin: A2_DRIVERLIB = ../drivers/ip65_apple2_uther2.lib
|
||||
|
||||
date65.bin hfs65.bin tweet65.bin: CL65FLAGS = --start-addr 0x0C00 apple2enh-iobuf-0800.o
|
||||
|
||||
telnet65.com: ATARI_CFG = atrtelnet.cfg
|
||||
|
@ -144,10 +152,16 @@ ip65.dsk: bin
|
|||
java -jar $(AC) -p $@ edithelp2.txt txt < edithelp2.txt
|
||||
java -jar $(AC) -p $@ edit.system sys < $(CC65)/apple2enh/util/loader.system
|
||||
java -jar $(AC) -as $@ email < email.bin
|
||||
java -jar $(AC) -p $@ emailhelp1.txt txt < emailhelp1.txt
|
||||
java -jar $(AC) -p $@ email.cfg txt < email.cfg
|
||||
java -jar $(AC) -p $@ email.system sys < $(CC65)/apple2enh/util/loader.system
|
||||
java -jar $(AC) -as $@ hfs65 < hfs65.bin
|
||||
java -jar $(AC) -p $@ hfs65.system sys < $(CC65)/apple2enh/util/loader.system
|
||||
java -jar $(AC) -p $@ news.cfg txt < news.cfg
|
||||
java -jar $(AC) -as $@ nntp65 < nntp65.bin
|
||||
java -jar $(AC) -p $@ nntp65.system sys < $(CC65)/apple2enh/util/loader.system
|
||||
java -jar $(AC) -as $@ nntp65up < nntp65.up.bin
|
||||
java -jar $(AC) -p $@ nntp65up.system sys < $(CC65)/apple2enh/util/loader.system
|
||||
java -jar $(AC) -as $@ pop65 < pop65.bin
|
||||
java -jar $(AC) -p $@ pop65.system sys < $(CC65)/apple2enh/util/loader.system
|
||||
java -jar $(AC) -as $@ rebuild < rebuild.bin
|
||||
|
|
136
apps/attacher.c
136
apps/attacher.c
|
@ -28,7 +28,7 @@
|
|||
#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[]
|
||||
#define IOBUFSZ 4096
|
||||
#define IOBUFSZ 8192
|
||||
|
||||
unsigned char buf[NETBUFSZ+1]; // One extra byte for null terminator
|
||||
char linebuf[LINEBUFSZ];
|
||||
|
@ -155,12 +155,13 @@ void readconfigfile(void) {
|
|||
|
||||
/*
|
||||
* Read a text file a line at a time
|
||||
* Returns number of chars in the line, or -1 if EOF.
|
||||
* Returns number of chars in the line, or 0 if EOF.
|
||||
* Expects Apple ][ style line endings (CR) and does no conversion
|
||||
* fp - file to read from
|
||||
* writep - Pointer to buffer into which line will be written
|
||||
* n - length of buffer. Longer lines will be truncated and terminated with CR.
|
||||
*/
|
||||
int16_t get_line(FILE *fp, char *writep) {
|
||||
uint16_t get_line(FILE *fp, char *writep, uint16_t n) {
|
||||
static uint16_t rd = 0; // Read
|
||||
static uint16_t end = 0; // End of valid data in buf
|
||||
uint16_t i = 0;
|
||||
|
@ -170,13 +171,18 @@ int16_t get_line(FILE *fp, char *writep) {
|
|||
rd = 0;
|
||||
}
|
||||
if (end == 0)
|
||||
return -1; // EOF
|
||||
writep[i++] = buf[rd++];
|
||||
if (writep[i - 1] == '\r') {
|
||||
writep[i] = '\0';
|
||||
return i;
|
||||
goto done;
|
||||
if (i == n - 1) {
|
||||
writep[i - 1] = '\r';
|
||||
goto done;
|
||||
}
|
||||
writep[i++] = buf[rd++];
|
||||
if (writep[i - 1] == '\r')
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
writep[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -316,7 +322,9 @@ struct tabent {
|
|||
uint32_t size;
|
||||
} *entry;
|
||||
|
||||
#define FILELINES 16
|
||||
// It is best if FILESPERPAGE is a multiple of FILELINES
|
||||
#define FILELINES 16 // Number of lines displayed in file_ui
|
||||
#define FILESPERPAGE 160 // Number of files loaded into iobuf[]
|
||||
|
||||
/*
|
||||
* Draw one line in file chooser UI
|
||||
|
@ -421,6 +429,49 @@ uint16_t online(void) {
|
|||
return entries;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read directory entries and populate table in iobuf[]
|
||||
* for file_ui()
|
||||
* page - page index, each page has FILESPERPAGE entries
|
||||
* page is 0, 1, 2, 3 ...
|
||||
* num_entries - number of entries read
|
||||
* Returns 0 there are more files, 1 if end of directory reached
|
||||
*/
|
||||
uint8_t read_dir(uint8_t page, uint16_t *num_entries) {
|
||||
DIR *dp;
|
||||
struct dirent *ent;
|
||||
struct tabent *entry;
|
||||
uint8_t rc = 0;
|
||||
uint16_t entries = 0, i = 0;
|
||||
entry = (struct tabent*)iobuf;
|
||||
if (page == 0) {
|
||||
strcpy(entry->name, ".."); // Add fake '..' entry
|
||||
entry->type = 0x0f;
|
||||
++entry;
|
||||
++entries;
|
||||
}
|
||||
dp = opendir(".");
|
||||
while (1) {
|
||||
ent = readdir(dp);
|
||||
if (!ent) {
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
if (++i < page * FILESPERPAGE)
|
||||
continue;
|
||||
if (entries >= FILESPERPAGE)
|
||||
break;
|
||||
memcpy(entry->name, ent->d_name, 16);
|
||||
entry->type = ent->d_type;
|
||||
entry->size = ent->d_size;
|
||||
++entry;
|
||||
++entries;
|
||||
}
|
||||
closedir(dp);
|
||||
*num_entries = entries;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* File chooser UI
|
||||
* Leaves file name in userentry[], or empty string if error/cancel
|
||||
|
@ -430,13 +481,14 @@ uint16_t online(void) {
|
|||
*/
|
||||
void file_ui(char *msg1, char *msg2, char *msg3) {
|
||||
struct tabent *entry;
|
||||
DIR *dp;
|
||||
struct dirent *ent;
|
||||
char c;
|
||||
uint16_t entries, current, first;
|
||||
uint8_t toplevel = 0;
|
||||
uint16_t entries;
|
||||
uint8_t end_of_dir;
|
||||
uint16_t first = 0, current = 0;
|
||||
uint8_t toplevel = 0, page = 0;
|
||||
restart:
|
||||
clrscr();
|
||||
cursor(0);
|
||||
gotoxy(0,0);
|
||||
revers(1);
|
||||
cprintf("%s", msg1);
|
||||
|
@ -450,33 +502,10 @@ restart:
|
|||
revers(1);
|
||||
cprintf("%s", (toplevel ? "Volumes" : userentry));
|
||||
revers(0);
|
||||
entries = current = first = 0;
|
||||
if (toplevel) {
|
||||
if (toplevel)
|
||||
entries = online();
|
||||
} else {
|
||||
entry = (struct tabent*)iobuf;
|
||||
strcpy(entry->name, ".."); // Add fake '..' entry
|
||||
entry->type = 0x0f;
|
||||
++entry;
|
||||
++entries;
|
||||
cursor(0);
|
||||
dp = opendir(".");
|
||||
while (1) {
|
||||
ent = readdir(dp);
|
||||
if (!ent)
|
||||
break;
|
||||
memcpy(entry->name, ent->d_name, 16);
|
||||
entry->type = ent->d_type;
|
||||
entry->size = ent->d_size;
|
||||
++entry;
|
||||
++entries;
|
||||
if ((char*)entry > (char*)iobuf + IOBUFSZ - 100) {
|
||||
beep();
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir(dp);
|
||||
}
|
||||
else
|
||||
end_of_dir = read_dir(page, &entries);
|
||||
redraw:
|
||||
file_ui_draw_all(first, current, entries);
|
||||
while (1) {
|
||||
|
@ -485,6 +514,13 @@ redraw:
|
|||
case 0x0b: // Up
|
||||
if (current > 0)
|
||||
--current;
|
||||
else
|
||||
if (page > 0) {
|
||||
--page;
|
||||
current = FILESPERPAGE - 1;
|
||||
first = current - FILELINES + 1;
|
||||
goto restart;
|
||||
}
|
||||
if (current < first) {
|
||||
if (first > FILELINES)
|
||||
first -= FILELINES;
|
||||
|
@ -498,6 +534,11 @@ redraw:
|
|||
case 0x0a: // Down
|
||||
if (current < entries - 1)
|
||||
++current;
|
||||
else if (!end_of_dir) {
|
||||
++page;
|
||||
first = current = 0;
|
||||
goto restart;
|
||||
}
|
||||
if (current >= first + FILELINES) {
|
||||
first += FILELINES;
|
||||
goto redraw;
|
||||
|
@ -520,6 +561,7 @@ redraw:
|
|||
toplevel = 1;
|
||||
else
|
||||
chdir(userentry);
|
||||
first = current = 0;
|
||||
goto restart;
|
||||
} else {
|
||||
if (toplevel) {
|
||||
|
@ -532,13 +574,21 @@ redraw:
|
|||
chdir(userentry);
|
||||
}
|
||||
toplevel = 0;
|
||||
first = current = 0;
|
||||
goto restart;
|
||||
}
|
||||
break;
|
||||
default: // All other file types
|
||||
strcpy(userentry, entry->name);
|
||||
case 0x04: // ASCII text
|
||||
getcwd(userentry, 80);
|
||||
strcat(userentry, "/");
|
||||
strcat(userentry, entry->name);
|
||||
goto done;
|
||||
break;
|
||||
default:
|
||||
getcwd(userentry, 80);
|
||||
strcat(userentry, "/");
|
||||
strcat(userentry, entry->name);
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case ESC:
|
||||
|
@ -587,7 +637,7 @@ void attach(char *fname) {
|
|||
|
||||
printf(" Copying email content ... "); // Space is for spinner to eat
|
||||
size = 0;
|
||||
while ((chars = get_line(fp, linebuf)) != -1) {
|
||||
while ((chars = get_line(fp, linebuf, LINEBUFSZ)) != 0) {
|
||||
size += chars;
|
||||
if (linebuf[0] == '\r')
|
||||
break;
|
||||
|
@ -600,7 +650,7 @@ void attach(char *fname) {
|
|||
fprintf(destfp, "--a2forever\r");
|
||||
fprintf(destfp, "Content-Type: text/plain; charset=US-ASCII\r");
|
||||
fprintf(destfp, "Content-Transfer-Encoding: 7bit\r\r");
|
||||
while ((chars = get_line(fp, linebuf)) != -1) {
|
||||
while ((chars = get_line(fp, linebuf, LINEBUFSZ)) != 0) {
|
||||
size += chars;
|
||||
fputs(linebuf, destfp);
|
||||
spinner(size, 0);
|
||||
|
|
133
apps/edit.c
133
apps/edit.c
|
@ -1558,8 +1558,8 @@ done:
|
|||
void load_email(void) {
|
||||
revers(0);
|
||||
clrscr();
|
||||
snprintf(userentry, 80, "%s/EMAIL.SYSTEM", startdir);
|
||||
exec(userentry, NULL);
|
||||
chdir(startdir);
|
||||
exec("EMAIL.SYSTEM", NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1568,8 +1568,8 @@ void load_email(void) {
|
|||
void load_attacher(void) {
|
||||
revers(0);
|
||||
clrscr();
|
||||
snprintf(userentry, 80, "%s/ATTACHER.SYSTEM", startdir);
|
||||
exec(userentry, filename);
|
||||
chdir(startdir);
|
||||
exec("ATTACHER.SYSTEM", filename);
|
||||
}
|
||||
|
||||
void file_ui(char *, char *, char *); // Forward declaration
|
||||
|
@ -1581,6 +1581,10 @@ void name_file(void); // Forward declaration
|
|||
void save(void) {
|
||||
uint8_t rc;
|
||||
FILE *fp;
|
||||
if (email_mode == 1) {
|
||||
show_error("Read-only file");
|
||||
return;
|
||||
}
|
||||
if (strlen(filename) == 0) {
|
||||
status[1] = 1; // Prompt if save will overwrite existing file
|
||||
name_file();
|
||||
|
@ -1884,7 +1888,7 @@ void init_aux_banks(void) {
|
|||
uint16_t count;
|
||||
clrscr();
|
||||
revers(1);
|
||||
cprintf("EDIT.SYSTEM v1.26 Bobbi 2020");
|
||||
cprintf("EDIT.SYSTEM v1.27 Bobbi 2020");
|
||||
revers(0);
|
||||
cprintf("\n\n\n %u x 64KB aux banks -> %uKB\n", banktbl[0], banktbl[0]*64);
|
||||
for (i = 1; i <= banktbl[0]; ++i) {
|
||||
|
@ -2024,7 +2028,9 @@ struct tabent {
|
|||
uint32_t size;
|
||||
} *entry;
|
||||
|
||||
#define FILELINES 16
|
||||
// It is best if FILESPERPAGE is a multiple of FILELINES
|
||||
#define FILELINES 16 // Number of lines displayed in file_ui
|
||||
#define FILESPERPAGE 160 // Number of files loaded into iobuf[]
|
||||
|
||||
/*
|
||||
* Draw one line in file chooser UI
|
||||
|
@ -2129,6 +2135,49 @@ uint16_t online(void) {
|
|||
return entries;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read directory entries and populate table in iobuf[]
|
||||
* for file_ui()
|
||||
* page - page index, each page has FILESPERPAGE entries
|
||||
* page is 0, 1, 2, 3 ...
|
||||
* num_entries - number of entries read
|
||||
* Returns 0 there are more files, 1 if end of directory reached
|
||||
*/
|
||||
uint8_t read_dir(uint8_t page, uint16_t *num_entries) {
|
||||
DIR *dp;
|
||||
struct dirent *ent;
|
||||
struct tabent *entry;
|
||||
uint8_t rc = 0;
|
||||
uint16_t entries = 0, i = 0;
|
||||
entry = (struct tabent*)iobuf;
|
||||
if (page == 0) {
|
||||
strcpy(entry->name, ".."); // Add fake '..' entry
|
||||
entry->type = 0x0f;
|
||||
++entry;
|
||||
++entries;
|
||||
}
|
||||
dp = opendir(".");
|
||||
while (1) {
|
||||
ent = readdir(dp);
|
||||
if (!ent) {
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
if (++i < page * FILESPERPAGE)
|
||||
continue;
|
||||
if (entries >= FILESPERPAGE)
|
||||
break;
|
||||
memcpy(entry->name, ent->d_name, 16);
|
||||
entry->type = ent->d_type;
|
||||
entry->size = ent->d_size;
|
||||
++entry;
|
||||
++entries;
|
||||
}
|
||||
closedir(dp);
|
||||
*num_entries = entries;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* File chooser UI
|
||||
* Leaves file name in userentry[], or empty string if error/cancel
|
||||
|
@ -2138,13 +2187,15 @@ uint16_t online(void) {
|
|||
*/
|
||||
void file_ui(char *msg1, char *msg2, char *msg3) {
|
||||
struct tabent *entry;
|
||||
DIR *dp;
|
||||
struct dirent *ent;
|
||||
char c;
|
||||
uint16_t entries, current, first;
|
||||
uint8_t toplevel = 0;
|
||||
uint16_t entries;
|
||||
uint8_t end_of_dir;
|
||||
uint16_t first = 0, current = 0;
|
||||
uint8_t toplevel = 0, page = 0;
|
||||
cutbuflen = 0;
|
||||
restart:
|
||||
clrscr();
|
||||
cursor(0);
|
||||
gotoxy(0,0);
|
||||
revers(1);
|
||||
cprintf("%s", msg1);
|
||||
|
@ -2158,34 +2209,10 @@ restart:
|
|||
revers(1);
|
||||
cprintf("%s", (toplevel ? "Volumes" : userentry));
|
||||
revers(0);
|
||||
entries = current = first = 0;
|
||||
cutbuflen = 0;
|
||||
if (toplevel) {
|
||||
if (toplevel)
|
||||
entries = online();
|
||||
} else {
|
||||
entry = (struct tabent*)iobuf;
|
||||
strcpy(entry->name, ".."); // Add fake '..' entry
|
||||
entry->type = 0x0f;
|
||||
++entry;
|
||||
++entries;
|
||||
cursor(0);
|
||||
dp = opendir(".");
|
||||
while (1) {
|
||||
ent = readdir(dp);
|
||||
if (!ent)
|
||||
break;
|
||||
memcpy(entry->name, ent->d_name, 16);
|
||||
entry->type = ent->d_type;
|
||||
entry->size = ent->d_size;
|
||||
++entry;
|
||||
++entries;
|
||||
if ((char*)entry > (char*)iobuf + CUTBUFSZ - 100) {
|
||||
beep();
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir(dp);
|
||||
}
|
||||
else
|
||||
end_of_dir = read_dir(page, &entries);
|
||||
redraw:
|
||||
file_ui_draw_all(first, current, entries);
|
||||
while (1) {
|
||||
|
@ -2194,6 +2221,13 @@ redraw:
|
|||
case 0x0b: // Up
|
||||
if (current > 0)
|
||||
--current;
|
||||
else
|
||||
if (page > 0) {
|
||||
--page;
|
||||
current = FILESPERPAGE - 1;
|
||||
first = current - FILELINES + 1;
|
||||
goto restart;
|
||||
}
|
||||
if (current < first) {
|
||||
if (first > FILELINES)
|
||||
first -= FILELINES;
|
||||
|
@ -2207,6 +2241,11 @@ redraw:
|
|||
case 0x0a: // Down
|
||||
if (current < entries - 1)
|
||||
++current;
|
||||
else if (!end_of_dir) {
|
||||
++page;
|
||||
first = current = 0;
|
||||
goto restart;
|
||||
}
|
||||
if (current >= first + FILELINES) {
|
||||
first += FILELINES;
|
||||
goto redraw;
|
||||
|
@ -2229,6 +2268,7 @@ redraw:
|
|||
toplevel = 1;
|
||||
else
|
||||
chdir(userentry);
|
||||
first = current = 0;
|
||||
goto restart;
|
||||
} else {
|
||||
if (toplevel) {
|
||||
|
@ -2241,6 +2281,7 @@ redraw:
|
|||
chdir(userentry);
|
||||
}
|
||||
toplevel = 0;
|
||||
first = current = 0;
|
||||
goto restart;
|
||||
}
|
||||
break;
|
||||
|
@ -2521,6 +2562,8 @@ int edit(char *fname) {
|
|||
case 0x80 + 'N': // OA-N "Name"
|
||||
case 0x80 + 'n': // OA-n
|
||||
name_file();
|
||||
if (email_mode == 1)
|
||||
email_mode = 3;
|
||||
break;
|
||||
case 0x80 + 'Q': // OA-Q "Quit"
|
||||
case 0x80 + 'q': // OA-q
|
||||
|
@ -2531,7 +2574,8 @@ int edit(char *fname) {
|
|||
load_attacher();
|
||||
// Fall through
|
||||
case 1:
|
||||
if (prompt_okay("Quit to EMAIL") == 0)
|
||||
case 3:
|
||||
if (prompt_okay("Return to EMAIL") == 0)
|
||||
load_email();
|
||||
break;
|
||||
default:
|
||||
|
@ -2751,11 +2795,18 @@ donehelp:
|
|||
*/
|
||||
void usage(void) {
|
||||
printf("Usage: -EDIT.SYSTEM [filename.txt]");
|
||||
printf(" or -EDIT.SYSTEM [-reademail|-compose] filename.txt");
|
||||
printf(" or -EDIT.SYSTEM [-reademail|-email|-news] filename.txt");
|
||||
reconnect_ramdisk();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Command line arguments:
|
||||
* -reademail - Open file read-only. Load EMAIL.SYSTEM on quit.
|
||||
* -email - Prompt for attachments, load ATTACHER.SYSTEM
|
||||
* or EMAIL.SYSTEM on quit
|
||||
* -news - Load EMAIL.SYSTEM on quit
|
||||
*/
|
||||
void main(int argc, char *argv[]) {
|
||||
uint8_t *pp = (uint8_t*)0xbf98;
|
||||
if (!(*pp & 0x02)) {
|
||||
|
@ -2775,8 +2826,10 @@ void main(int argc, char *argv[]) {
|
|||
case 3:
|
||||
if (strcmp(argv[1], "-reademail") == 0)
|
||||
email_mode = 1;
|
||||
else if (strcmp(argv[1], "-compose") == 0)
|
||||
else if (strcmp(argv[1], "-email") == 0)
|
||||
email_mode = 2;
|
||||
else if (strcmp(argv[1], "-news") == 0)
|
||||
email_mode = 3;
|
||||
else
|
||||
usage();
|
||||
edit(argv[2]);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
--------------------------------------------------------------------------------
|
||||
v1.26 }}} EDIT.SYSTEM HELP }}} Page One
|
||||
v1.27 }}} EDIT.SYSTEM HELP }}} Page One
|
||||
--------------------------------------+-----------------------------------------
|
||||
Navigation: | Editing:
|
||||
Cursor keys Move the cursor | [Return] Split line
|
||||
|
|
661
apps/email.c
661
apps/email.c
File diff suppressed because it is too large
Load Diff
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PROGNAME "emai//er v1.11"
|
||||
#define PROGNAME "emai//er v1.99" // Will be 2.0 soon!!
|
||||
|
||||
// Configuration params from EMAIL.CFG
|
||||
char cfg_server[40]; // IP of POP3 server
|
||||
|
|
24
apps/emailhelp1.txt
Normal file
24
apps/emailhelp1.txt
Normal file
|
@ -0,0 +1,24 @@
|
|||
------------------------------------------+-------------------------------------
|
||||
Message Summary Screen | Message Pager
|
||||
[Up] / K Previous message | [Space] Page forward
|
||||
[Down] / J Next message | B Page back
|
||||
[Space] / [Ret] Read current message | T Go to top
|
||||
Q Quit to ProDOS | M MIME mode
|
||||
------------------------------------------+ H Show email headers
|
||||
Message Management | Q Return to summary
|
||||
S Switch mailbox +-------------------------------------
|
||||
N Create new mailbox | emai//er Suite
|
||||
T Tag current message | {-D Set date using DATE65 (NTP)
|
||||
A Archive current/tagged message | {-R Receive email using POP65
|
||||
C Copy current/tagged message | {-S Send OUTBOX using SMTP65
|
||||
M Move current/tagged message | {-E Open current message in EDIT
|
||||
D Mark current message deleted | }-R Receive news using NNTP65
|
||||
U Remove deletion mark | }-S Sent NEWS.OUTBOX with NNTP65UP
|
||||
P Purge messages marked as deleted |
|
||||
------------------------------------------+-------------------------------------
|
||||
Email Composition | News Composition
|
||||
W Write an email message | }-P Post news article
|
||||
R Reply to current message | }-F Follow-up to current article
|
||||
F Forward current message |
|
||||
------------------------------------------+-------------------------------------
|
||||
[ Any Key to Exit Help ]
|
7
apps/news.cfg
Normal file
7
apps/news.cfg
Normal file
|
@ -0,0 +1,7 @@
|
|||
144.76.35.198:119
|
||||
usergoeshere
|
||||
passwordgoeshere
|
||||
/IP65
|
||||
/DATA/EMAIL
|
||||
bobbi.8bit@gmail.com
|
||||
|
684
apps/nntp65.c
Normal file
684
apps/nntp65.c
Normal file
|
@ -0,0 +1,684 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
// NNTP65
|
||||
// Network News Transport Protocol (NNTP) Client for IP65
|
||||
// https://www.ietf.org/rfc/rfc3977.txt
|
||||
// (Based on smtp65.c, which in turn is based on IP65's wget65.c)
|
||||
// Bobbi September 2020
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cc65.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <conio.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <apple2_filetype.h>
|
||||
|
||||
#include "../inc/ip65.h"
|
||||
#include "w5100.h"
|
||||
|
||||
#include "email_common.h"
|
||||
|
||||
#define BELL 7
|
||||
#define BACKSPACE 8
|
||||
|
||||
// Both pragmas are obligatory to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment registers.
|
||||
#pragma optimize (on)
|
||||
#pragma static-locals (on)
|
||||
|
||||
#define NETBUFSZ 1500+4 // 4 extra bytes for overlap between packets
|
||||
#define LINEBUFSZ 2000 /*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_pad[1]; // One byte of padding make it easier
|
||||
static char linebuf[LINEBUFSZ];
|
||||
static char newsgroup[80];
|
||||
static char mailbox[80];
|
||||
|
||||
uint8_t exec_email_on_exit = 0;
|
||||
char filename[80];
|
||||
int len;
|
||||
FILE *fp, *newsgroupsfp, *newnewsgroupsfp;
|
||||
uint32_t filesize;
|
||||
uint16_t nntp_port;
|
||||
|
||||
/*
|
||||
* Keypress before quit
|
||||
*/
|
||||
void confirm_exit(void) {
|
||||
fclose(fp);
|
||||
fclose(newsgroupsfp);
|
||||
fclose(newnewsgroupsfp);
|
||||
w5100_disconnect();
|
||||
printf("\n[Press Any Key]");
|
||||
cgetc();
|
||||
if (exec_email_on_exit) {
|
||||
sprintf(filename, "%s/EMAIL.SYSTEM", cfg_instdir);
|
||||
exec(filename, NULL);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called for all non IP65 errors
|
||||
*/
|
||||
void error_exit() {
|
||||
confirm_exit();
|
||||
}
|
||||
|
||||
/*
|
||||
* Called if IP65 call fails
|
||||
*/
|
||||
void ip65_error_exit(void) {
|
||||
printf("%s\n", ip65_strerror(ip65_error));
|
||||
confirm_exit();
|
||||
}
|
||||
|
||||
/*
|
||||
* Print message to the console, stripping extraneous CRLF stuff
|
||||
* from the end.
|
||||
*/
|
||||
void print_strip_crlf(char *s) {
|
||||
uint8_t i = 0;
|
||||
while ((s[i] != '\0') && (s[i] != '\r') && (s[i] != '\n'))
|
||||
putchar(s[i++]);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
/*
|
||||
* Spinner while downloading files
|
||||
*/
|
||||
void spinner(uint32_t sz, uint8_t final) {
|
||||
static char chars[] = "|/-\\";
|
||||
static char buf[10] = "";
|
||||
static uint8_t i = 0;
|
||||
uint8_t j;
|
||||
for (j = 0; j < strlen(buf); ++j)
|
||||
putchar(BACKSPACE);
|
||||
if (final) {
|
||||
sprintf(buf, " [%lu]\n", sz);
|
||||
printf("%s", buf);
|
||||
strcpy(buf, "");
|
||||
}
|
||||
else {
|
||||
sprintf(buf, "%c %lu", chars[(i++) % 4], sz);
|
||||
printf("%s", buf);
|
||||
}
|
||||
}
|
||||
|
||||
#define DO_SEND 1 // For do_send param
|
||||
#define DONT_SEND 0 // For do_send param
|
||||
#define CMD_MODE 0 // For mode param
|
||||
#define DATA_MODE 1 // For mode param
|
||||
|
||||
// Modified verson of w5100_http_open from w5100_http.c
|
||||
// Sends a TCP message and receives a the first packet of the response.
|
||||
// sendbuf is the buffer to send (null terminated)
|
||||
// recvbuf is the buffer into which the received message will be written
|
||||
// length is the length of recvbuf[]
|
||||
// do_send Do the sending if true, otherwise skip
|
||||
// mode Binary mode for received message, maybe first block of long message
|
||||
bool w5100_tcp_send_recv(char* sendbuf, char* recvbuf, size_t length,
|
||||
uint8_t do_send, uint8_t mode) {
|
||||
|
||||
if (do_send == DO_SEND) {
|
||||
uint16_t snd;
|
||||
uint16_t pos = 0;
|
||||
uint16_t len = strlen(sendbuf);
|
||||
|
||||
if (strncmp(sendbuf, "AUTHINFO PASS", 13) == 0)
|
||||
printf(">AUTHINFO PASS ****\n");
|
||||
else {
|
||||
putchar('>');
|
||||
print_strip_crlf(sendbuf);
|
||||
}
|
||||
|
||||
while (len) {
|
||||
if (input_check_for_abort_key())
|
||||
{
|
||||
printf("User abort\n");
|
||||
w5100_disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
snd = w5100_send_request();
|
||||
if (!snd) {
|
||||
if (!w5100_connected()) {
|
||||
printf("Connection lost\n");
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len < snd)
|
||||
snd = len;
|
||||
|
||||
{
|
||||
// One less to allow for faster pre-increment below
|
||||
const char *dataptr = sendbuf + pos - 1;
|
||||
uint16_t i;
|
||||
for (i = 0; i < snd; ++i) {
|
||||
// The variable is necessary to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment register.
|
||||
char data = *++dataptr;
|
||||
*w5100_data = data;
|
||||
}
|
||||
}
|
||||
|
||||
w5100_send_commit(snd);
|
||||
len -= snd;
|
||||
pos += snd;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == DATA_MODE) {
|
||||
//
|
||||
// Handle article body
|
||||
//
|
||||
uint16_t rcv, written;
|
||||
uint16_t len = 0;
|
||||
uint8_t cont = 1;
|
||||
|
||||
// Backspace to put spinner on same line as RETR
|
||||
for (rcv = 0; rcv < 15; ++rcv)
|
||||
putchar(BACKSPACE);
|
||||
|
||||
filesize = 0;
|
||||
|
||||
// Initialize 4 byte overlap to zero
|
||||
bzero(recvbuf, 4);
|
||||
|
||||
while (cont) {
|
||||
if (input_check_for_abort_key()) {
|
||||
printf("User abort\n");
|
||||
w5100_disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
rcv = w5100_receive_request();
|
||||
if (!rcv) {
|
||||
cont = w5100_connected();
|
||||
if (cont)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rcv > length - len)
|
||||
rcv = length - len;
|
||||
|
||||
{
|
||||
// One less to allow for faster pre-increment below
|
||||
// 4 bytes of overlap between blocks
|
||||
char *dataptr = recvbuf + len + 4 - 1;
|
||||
uint16_t i;
|
||||
for (i = 0; i < rcv; ++i) {
|
||||
// The variable is necessary to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment register.
|
||||
char data = *w5100_data;
|
||||
*++dataptr = data;
|
||||
if (!memcmp(dataptr - 4, "\r\n.\r\n", 5))
|
||||
cont = 0;
|
||||
}
|
||||
}
|
||||
w5100_receive_commit(rcv);
|
||||
len += rcv;
|
||||
|
||||
// Skip 4 byte overlap
|
||||
written = fwrite(recvbuf + 4, 1, len, fp);
|
||||
if (written != len) {
|
||||
printf("Write error");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy 4 bytes of overlap
|
||||
memcpy(recvbuf, recvbuf + len, 4);
|
||||
|
||||
filesize += len;
|
||||
spinner(filesize, 0);
|
||||
len = 0;
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// Handle short single line ASCII text responses
|
||||
// Must fit in recvbuf[]
|
||||
//
|
||||
uint16_t rcv;
|
||||
uint16_t len = 0;
|
||||
uint8_t cont = 1;
|
||||
|
||||
--length; // Leave space for NULL at end in case of buffer overrun
|
||||
|
||||
while (cont) {
|
||||
if (input_check_for_abort_key()) {
|
||||
printf("User abort\n");
|
||||
w5100_disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
rcv = w5100_receive_request();
|
||||
if (!rcv) {
|
||||
cont = w5100_connected();
|
||||
if (cont)
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((length - len) == 0)
|
||||
cont = 0;
|
||||
|
||||
if (rcv > length - len)
|
||||
rcv = length - len;
|
||||
|
||||
{
|
||||
// One less to allow for faster pre-increment below
|
||||
// 4 bytes of overlap between blocks
|
||||
char *dataptr = recvbuf + len - 1;
|
||||
uint16_t i;
|
||||
for (i = 0; i < rcv; ++i) {
|
||||
// The variable is necessary to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment register.
|
||||
char data = *w5100_data;
|
||||
*++dataptr = data;
|
||||
if (!memcmp(dataptr - 1, "\r\n", 2))
|
||||
cont = 0;
|
||||
}
|
||||
}
|
||||
w5100_receive_commit(rcv);
|
||||
len += rcv;
|
||||
}
|
||||
recvbuf[len + 1] = '\0';
|
||||
putchar('<');
|
||||
print_strip_crlf(recvbuf);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check expected string from server
|
||||
*/
|
||||
uint8_t expect(char *buf, char *s) {
|
||||
if (strncmp(buf, s, strlen(s)) != 0) {
|
||||
printf("\nExpected '%s' got '%s'\n", s, buf);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read parms from NEWS.CFG
|
||||
*/
|
||||
void readconfigfile(void) {
|
||||
char *colon;
|
||||
fp = fopen("NEWS.CFG", "r");
|
||||
if (!fp) {
|
||||
puts("Can't open config file NEWS.CFG");
|
||||
error_exit();
|
||||
}
|
||||
fscanf(fp, "%s", cfg_server);
|
||||
fscanf(fp, "%s", cfg_user);
|
||||
fscanf(fp, "%s", cfg_pass);
|
||||
fscanf(fp, "%s", cfg_instdir);
|
||||
fscanf(fp, "%s", cfg_emaildir);
|
||||
fclose(fp);
|
||||
|
||||
colon = strchr(cfg_server, ':');
|
||||
if (!colon)
|
||||
nntp_port = 110;
|
||||
else {
|
||||
nntp_port = atoi(colon + 1);
|
||||
*colon = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a text file a line at a time
|
||||
* Returns number of chars in the line, or 0 if EOF.
|
||||
* Expects CRLF line endings (CRLF) and converts to Apple II (CR) convention
|
||||
* fp - file to read from
|
||||
* writep - Pointer to buffer into which line will be written
|
||||
* n - length of buffer. Longer lines will be truncated and terminated with CR.
|
||||
*/
|
||||
uint16_t get_line(FILE *fp, char *writep, uint16_t n) {
|
||||
static uint16_t rd = 0; // Read
|
||||
static uint16_t end = 0; // End of valid data in buf
|
||||
uint16_t i = 0;
|
||||
while (1) {
|
||||
if (rd == end) {
|
||||
end = fread(buf, 1, READSZ, fp);
|
||||
rd = 0;
|
||||
}
|
||||
if (end == 0)
|
||||
goto done;
|
||||
writep[i++] = buf[rd++];
|
||||
if (i == n - 1) {
|
||||
writep[i - 1] = '\r';
|
||||
goto done;
|
||||
}
|
||||
// The following line is safe because of linebuf_pad[]
|
||||
if ((writep[i - 1] == '\n') && (writep[i - 2] == '\r')) {
|
||||
writep[i - 1] = '\0'; // Remove LF
|
||||
return i - 1;
|
||||
}
|
||||
}
|
||||
done:
|
||||
writep[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update EMAIL.DB - quick access database for header info
|
||||
*/
|
||||
void update_email_db(char *mbox, struct emailhdrs *h) {
|
||||
FILE *fp;
|
||||
sprintf(filename, "%s/%s/EMAIL.DB", cfg_emaildir, mbox);
|
||||
_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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write NEXT.EMAIL file with number of next EMAIL.n file to be created
|
||||
*/
|
||||
#if 0
|
||||
void write_next_email(uint16_t num) {
|
||||
sprintf(filename, "%s/INBOX/NEXT.EMAIL", cfg_emaildir);
|
||||
_filetype = PRODOS_T_TXT;
|
||||
_auxtype = 0;
|
||||
fp = fopen(filename, "wb");
|
||||
if (!fp) {
|
||||
printf("Can't open %s\n", filename);
|
||||
fclose(fp);
|
||||
error_exit();
|
||||
}
|
||||
fprintf(fp, "%u", num);
|
||||
fclose(fp);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Update mailbox
|
||||
* Copy messages from spool dir to mailbox and find headers of interest
|
||||
* (Date, From, Subject)
|
||||
*/
|
||||
void update_mailbox(char *mbox) {
|
||||
static struct emailhdrs hdrs;
|
||||
struct dirent *d;
|
||||
uint16_t msg, chars, headerchars;
|
||||
uint8_t headers;
|
||||
FILE *destfp;
|
||||
DIR *dp;
|
||||
sprintf(filename, "%s/NEWS.SPOOL", cfg_emaildir);
|
||||
dp = opendir(filename);
|
||||
while (d = readdir(dp)) {
|
||||
strcpy(linebuf, "");
|
||||
sprintf(filename, "%s/NEWS.SPOOL/%s", cfg_emaildir, d->d_name);
|
||||
fp = fopen(filename, "r");
|
||||
if (!fp) {
|
||||
printf("Can't open %s\n", filename);
|
||||
closedir(dp);
|
||||
error_exit();
|
||||
}
|
||||
hdrs.emailnum = msg = atoi(&(d->d_name[5]));
|
||||
sprintf(filename, "%s/%s/EMAIL.%u", cfg_emaildir, mbox, msg);
|
||||
puts(filename);
|
||||
_filetype = PRODOS_T_TXT;
|
||||
_auxtype = 0;
|
||||
destfp = fopen(filename, "wb");
|
||||
if (!destfp) {
|
||||
printf("Can't open %s\n", filename);
|
||||
closedir(dp);
|
||||
error_exit();
|
||||
}
|
||||
headers = 1;
|
||||
headerchars = 0;
|
||||
hdrs.skipbytes = 0; // Just in case it doesn't get set
|
||||
hdrs.status = 'N';
|
||||
hdrs.tag = ' ';
|
||||
hdrs.date[0] = hdrs.from[0] = hdrs.cc[0] = hdrs.subject[0] = '\0';
|
||||
// Store News:newsgroup in TO field
|
||||
strcpy(filename, "News:");
|
||||
strcat(filename, newsgroup);
|
||||
copyheader(hdrs.to, filename, 79);
|
||||
while ((chars = get_line(fp, linebuf, LINEBUFSZ)) != 0) {
|
||||
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';
|
||||
}
|
||||
// Store Organization in CC field
|
||||
if (!strncmp(linebuf, "Organization: ", 14)) {
|
||||
copyheader(hdrs.cc, linebuf + 14, 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;
|
||||
}
|
||||
}
|
||||
fputs(linebuf, destfp);
|
||||
}
|
||||
fclose(fp);
|
||||
fclose(destfp);
|
||||
update_email_db(mbox, &hdrs);
|
||||
|
||||
sprintf(filename, "%s/NEWS.SPOOL/NEWS.%u", cfg_emaildir, msg);
|
||||
if (unlink(filename))
|
||||
printf("Can't delete %s\n", filename);
|
||||
}
|
||||
closedir(dp);
|
||||
}
|
||||
|
||||
void main(int argc, char *argv[]) {
|
||||
uint32_t nummsgs, lownum, highnum, msgnum, msg;
|
||||
char sendbuf[80];
|
||||
uint8_t eth_init = ETH_INIT_DEFAULT;
|
||||
|
||||
if ((argc == 2) && (strcmp(argv[1], "EMAIL") == 0))
|
||||
exec_email_on_exit = 1;
|
||||
|
||||
linebuf_pad[0] = 0;
|
||||
|
||||
videomode(VIDEOMODE_80COL);
|
||||
printf("%c%s NNTP - Receive News Articles%c\n", 0x0f, PROGNAME, 0x0e);
|
||||
|
||||
printf("\nReading NEWS.CFG -");
|
||||
readconfigfile();
|
||||
printf(" Ok");
|
||||
|
||||
printf("\nReading NEWSGROUPS.CFG - ");
|
||||
sprintf(filename, "%s/NEWSGROUPS.CFG", cfg_emaildir);
|
||||
newsgroupsfp = fopen(filename, "r");
|
||||
if (!newsgroupsfp) {
|
||||
printf("\nCan't read %s\n", filename);
|
||||
error_exit();
|
||||
}
|
||||
|
||||
printf("Ok\nCreating NEWSGROUPS.NEW - ");
|
||||
sprintf(filename, "%s/NEWSGROUPS.NEW", cfg_emaildir);
|
||||
_filetype = PRODOS_T_TXT;
|
||||
_auxtype = 0;
|
||||
newnewsgroupsfp = fopen(filename, "wb");
|
||||
if (!newnewsgroupsfp) {
|
||||
printf("\nCan't open %s\n", filename);
|
||||
error_exit();
|
||||
}
|
||||
|
||||
{
|
||||
int file;
|
||||
printf("Ok\nSetting slot - ");
|
||||
file = open("ethernet.slot", O_RDONLY);
|
||||
if (file != -1) {
|
||||
read(file, ð_init, 1);
|
||||
close(file);
|
||||
eth_init &= ~'0';
|
||||
}
|
||||
}
|
||||
|
||||
printf("%d\nInitializing %s - ", eth_init, eth_name);
|
||||
if (ip65_init(eth_init)) {
|
||||
ip65_error_exit();
|
||||
}
|
||||
|
||||
// Abort on Ctrl-C to be consistent with Linenoise
|
||||
abort_key = 0x83;
|
||||
|
||||
printf("Ok\nObtaining IP address - ");
|
||||
if (dhcp_init()) {
|
||||
ip65_error_exit();
|
||||
}
|
||||
|
||||
// Copy IP config from IP65 to W5100
|
||||
w5100_config(eth_init);
|
||||
|
||||
printf("Ok\nConnecting to %s (%u) - ", cfg_server, nntp_port);
|
||||
|
||||
if (!w5100_connect(parse_dotted_quad(cfg_server), nntp_port)) {
|
||||
printf("Fail\n");
|
||||
error_exit();
|
||||
}
|
||||
|
||||
printf("Ok\n\n");
|
||||
|
||||
if (!w5100_tcp_send_recv(sendbuf, buf, NETBUFSZ, DONT_SEND, CMD_MODE)) {
|
||||
error_exit();
|
||||
}
|
||||
if (expect(buf, "20")) // "200" if posting is allowed / "201" if no posting
|
||||
error_exit();
|
||||
|
||||
sprintf(sendbuf, "AUTHINFO USER %s\r\n", cfg_user);
|
||||
if (!w5100_tcp_send_recv(sendbuf, buf, NETBUFSZ, DO_SEND, CMD_MODE)) {
|
||||
error_exit();
|
||||
}
|
||||
if (expect(buf, "381")) // Username accepted
|
||||
error_exit();
|
||||
|
||||
sprintf(sendbuf, "AUTHINFO PASS %s\r\n", cfg_pass);
|
||||
if (!w5100_tcp_send_recv(sendbuf, buf, NETBUFSZ, DO_SEND, CMD_MODE)) {
|
||||
error_exit();
|
||||
}
|
||||
if (expect(buf, "281")) // Authentication successful
|
||||
error_exit();
|
||||
|
||||
while (1) {
|
||||
msg = fscanf(newsgroupsfp, "%s %s %ld", newsgroup, mailbox, &msgnum);
|
||||
if (strcmp(newsgroup, "0") == 0)
|
||||
break;
|
||||
if ((msg == 0) || (msg == EOF))
|
||||
break;
|
||||
printf("*************************************************************\n");
|
||||
printf("* NEWSGROUP: %s\n", newsgroup);
|
||||
printf("* MAILBOX: %s\n", mailbox);
|
||||
printf("* START MSG: %ld\n", msgnum);
|
||||
printf("*************************************************************\n");
|
||||
|
||||
sprintf(sendbuf, "GROUP %s\r\n", newsgroup);
|
||||
if (!w5100_tcp_send_recv(sendbuf, buf, NETBUFSZ, DO_SEND, CMD_MODE)) {
|
||||
error_exit();
|
||||
}
|
||||
if (strncmp(buf, "411", 3) == 0) {
|
||||
putchar(BELL);
|
||||
printf("** Non-existent newsgroup %s\n", newsgroup);
|
||||
continue;
|
||||
}
|
||||
|
||||
sscanf(buf, "211 %lu %lu %lu", &nummsgs, &lownum, &highnum);
|
||||
printf(" Approx. %lu messages, numbered from %lu to %lu\n", nummsgs, lownum, highnum);
|
||||
|
||||
if (msgnum == 0)
|
||||
msgnum = highnum - 100; // If 0 is specified grab 100 messages to start
|
||||
|
||||
if (msgnum < lownum)
|
||||
msgnum = lownum;
|
||||
|
||||
for (msg = msgnum; msg <= highnum; ++msg) {
|
||||
sprintf(sendbuf, "STAT %ld\r\n", msgnum);
|
||||
if (!w5100_tcp_send_recv(sendbuf, buf, NETBUFSZ, DO_SEND, CMD_MODE)) {
|
||||
error_exit();
|
||||
}
|
||||
if (strncmp(buf, "220", 3)) // Message number exists
|
||||
break;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (!w5100_tcp_send_recv("NEXT\r\n", buf, NETBUFSZ, DO_SEND, CMD_MODE)) {
|
||||
error_exit();
|
||||
}
|
||||
if (strncmp(buf, "223", 3) != 0)
|
||||
break; // No more messages in group
|
||||
sscanf(buf, "223 %ld", &msg);
|
||||
sprintf(filename, "%s/NEWS.SPOOL/NEWS.%lu", cfg_emaildir, msg);
|
||||
_filetype = PRODOS_T_TXT;
|
||||
_auxtype = 0;
|
||||
fp = fopen(filename, "wb");
|
||||
if (!fp) {
|
||||
printf("Can't create %s\n", filename);
|
||||
error_exit();
|
||||
}
|
||||
printf("\n** Retrieving article %lu/%lu from %s\n", msg, highnum, newsgroup);
|
||||
if (!w5100_tcp_send_recv("ARTICLE\r\n", buf, NETBUFSZ, DO_SEND, DATA_MODE)) {
|
||||
error_exit();
|
||||
}
|
||||
spinner(filesize, 1); // Cleanup spinner
|
||||
fclose(fp);
|
||||
}
|
||||
printf("Updating NEWSGROUPS.NEW (%s:%ld) ...\n", newsgroup, msg);
|
||||
fprintf(newnewsgroupsfp, "%s %s %ld\n", newsgroup, mailbox, msg);
|
||||
printf("Updating mailbox %s ...\n", mailbox);
|
||||
update_mailbox(mailbox);
|
||||
}
|
||||
|
||||
fclose(newsgroupsfp);
|
||||
fclose(newnewsgroupsfp);
|
||||
|
||||
sprintf(filename, "%s/NEWSGROUPS.CFG", cfg_emaildir);
|
||||
if (unlink(filename)) {
|
||||
printf("Can't delete %s\n", filename);
|
||||
error_exit();
|
||||
}
|
||||
sprintf(linebuf, "%s/NEWSGROUPS.NEW", cfg_emaildir);
|
||||
if (rename(linebuf, filename)) {
|
||||
printf("Can't rename %s to %s\n", linebuf, filename);
|
||||
error_exit();
|
||||
}
|
||||
|
||||
// Ignore any error - can be a race condition where other side
|
||||
// disconnects too fast and we get an error
|
||||
w5100_tcp_send_recv("QUIT\r\n", buf, NETBUFSZ, DO_SEND, CMD_MODE);
|
||||
|
||||
printf("Disconnecting\n");
|
||||
w5100_disconnect();
|
||||
|
||||
confirm_exit();
|
||||
}
|
706
apps/nntp65.up.c
Normal file
706
apps/nntp65.up.c
Normal file
|
@ -0,0 +1,706 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
// NNTP65.UP
|
||||
// Network News Transport Protocol (NNTP) Client for IP65
|
||||
// https://www.ietf.org/rfc/rfc3977.txt
|
||||
// (Based on smtp65.c, which in turn is based on IP65's wget65.c)
|
||||
// Bobbi September 2020
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cc65.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <conio.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <apple2_filetype.h>
|
||||
|
||||
#include "../inc/ip65.h"
|
||||
#include "w5100.h"
|
||||
|
||||
#include "email_common.h"
|
||||
|
||||
#define BELL 7
|
||||
#define BACKSPACE 8
|
||||
#define NORMAL 0x0e
|
||||
#define INVERSE 0x0f
|
||||
#define CLRLINE 0x1a
|
||||
|
||||
// Both pragmas are obligatory to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment registers.
|
||||
#pragma optimize (on)
|
||||
#pragma static-locals (on)
|
||||
|
||||
#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 linebuf[LINEBUFSZ];
|
||||
|
||||
uint8_t exec_email_on_exit = 0;
|
||||
char filename[80];
|
||||
int len;
|
||||
FILE *fp;
|
||||
uint32_t filesize;
|
||||
uint16_t nntp_port;
|
||||
|
||||
/*
|
||||
* Keypress before quit
|
||||
*/
|
||||
void confirm_exit(void) {
|
||||
printf("\n[Press Any Key]");
|
||||
cgetc();
|
||||
if (exec_email_on_exit) {
|
||||
sprintf(filename, "%s/EMAIL.SYSTEM", cfg_instdir);
|
||||
exec(filename, NULL);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called for all non IP65 errors
|
||||
*/
|
||||
void error_exit() {
|
||||
confirm_exit();
|
||||
}
|
||||
|
||||
/*
|
||||
* Called if IP65 call fails
|
||||
*/
|
||||
void ip65_error_exit(void) {
|
||||
printf("%s\n", ip65_strerror(ip65_error));
|
||||
confirm_exit();
|
||||
}
|
||||
|
||||
/*
|
||||
* Print message to the console, stripping extraneous CRLF stuff
|
||||
* from the end.
|
||||
*/
|
||||
void print_strip_crlf(char *s) {
|
||||
uint8_t i = 0;
|
||||
while ((s[i] != '\0') && (s[i] != '\r') && (s[i] != '\n'))
|
||||
putchar(s[i++]);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
/*
|
||||
* Spinner while uploading files
|
||||
*/
|
||||
void spinner(uint32_t sz, uint8_t final) {
|
||||
static char chars[] = "|/-\\";
|
||||
static char buf[10] = "";
|
||||
static uint8_t i = 0;
|
||||
uint8_t j;
|
||||
for (j = 0; j < strlen(buf); ++j)
|
||||
putchar(BACKSPACE);
|
||||
if (final) {
|
||||
sprintf(buf, " [%lu]\n", sz);
|
||||
printf("%s", buf);
|
||||
strcpy(buf, "");
|
||||
}
|
||||
else {
|
||||
sprintf(buf, "%c %lu", chars[(i++) % 4], sz);
|
||||
printf("%s", buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a text file a line at a time
|
||||
* Returns number of chars in the line, or 0 if EOF.
|
||||
* Expects Apple ][ style line endings (CR) and does no conversion
|
||||
* fp - file to read from
|
||||
* reset - if 1 then just reset the buffer and return
|
||||
* writep - Pointer to buffer into which line will be written
|
||||
* n - length of buffer. Longer lines will be truncated and terminated with CR.
|
||||
*/
|
||||
uint16_t get_line(FILE *fp, uint8_t reset, char *writep, uint16_t n) {
|
||||
static uint16_t rd = 0; // Read
|
||||
static uint16_t end = 0; // End of valid data in buf
|
||||
uint16_t i = 0;
|
||||
if (reset) {
|
||||
rd = end = 0;
|
||||
return 0;
|
||||
}
|
||||
while (1) {
|
||||
if (rd == end) {
|
||||
end = fread(buf, 1, READSZ, fp);
|
||||
rd = 0;
|
||||
}
|
||||
if (end == 0)
|
||||
goto done;
|
||||
if (i == n - 1) {
|
||||
writep[i - 1] = '\r';
|
||||
goto done;
|
||||
}
|
||||
writep[i++] = buf[rd++];
|
||||
if (writep[i - 1] == '\r')
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
writep[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
#define DO_SEND 1 // For do_send param
|
||||
#define DONT_SEND 0 // For do_send param
|
||||
#define CMD_MODE 0 // For mode param
|
||||
#define DATA_MODE 1 // For mode param
|
||||
|
||||
// Modified verson of w5100_http_open from w5100_http.c
|
||||
// Sends a TCP message and receives a the first packet of the response.
|
||||
// sendbuf is the buffer to send (null terminated)
|
||||
// recvbuf is the buffer into which the received message will be written
|
||||
// length is the length of recvbuf[]
|
||||
// do_send Do the sending if true, otherwise skip
|
||||
// mode Binary mode for sent message, pump data from disk file fp
|
||||
bool w5100_tcp_send_recv(char* sendbuf, char* recvbuf, size_t length,
|
||||
uint8_t do_send, uint8_t mode) {
|
||||
|
||||
if (do_send == DO_SEND) {
|
||||
|
||||
if (mode == DATA_MODE) {
|
||||
//
|
||||
// Handle sending of email body
|
||||
//
|
||||
uint16_t pos = 0;
|
||||
uint8_t cont = 1;
|
||||
uint16_t snd;
|
||||
int16_t len;
|
||||
|
||||
filesize = 0;
|
||||
len = get_line(fp, 1, linebuf, LINEBUFSZ); // Reset buffer
|
||||
|
||||
while (cont) {
|
||||
|
||||
len = get_line(fp, 0, linebuf, LINEBUFSZ - 1);
|
||||
pos = 0;
|
||||
|
||||
if (len == 0) {
|
||||
strcpy(linebuf, "\r\n.\r\n");
|
||||
len = 5;
|
||||
cont = 0;
|
||||
} else {
|
||||
linebuf[len++] = '\n'; // CR -> CRLF
|
||||
linebuf[len] = '\0';
|
||||
filesize += len;
|
||||
}
|
||||
|
||||
while (len) {
|
||||
if (input_check_for_abort_key())
|
||||
{
|
||||
printf("User abort\n");
|
||||
w5100_disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
snd = w5100_send_request();
|
||||
if (!snd) {
|
||||
if (!w5100_connected()) {
|
||||
printf("Connection lost\n");
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len < snd)
|
||||
snd = len;
|
||||
|
||||
{
|
||||
// One less to allow for faster pre-increment below
|
||||
const char *dataptr = linebuf + pos - 1;
|
||||
uint16_t i;
|
||||
for (i = 0; i < snd; ++i) {
|
||||
// The variable is necessary to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment register.
|
||||
char data = *++dataptr;
|
||||
*w5100_data = data;
|
||||
}
|
||||
}
|
||||
|
||||
w5100_send_commit(snd);
|
||||
len -= snd;
|
||||
pos += snd;
|
||||
}
|
||||
spinner(filesize, 0);
|
||||
}
|
||||
spinner(filesize, 1);
|
||||
|
||||
} else {
|
||||
//
|
||||
// Handle short ASCII text transmissions
|
||||
//
|
||||
uint16_t snd;
|
||||
uint16_t pos = 0;
|
||||
uint16_t len = strlen(sendbuf);
|
||||
|
||||
if (strncmp(sendbuf, "AUTHINFO PASS", 13) == 0)
|
||||
printf(">AUTHINFO PASS ****\n");
|
||||
else {
|
||||
putchar('>');
|
||||
print_strip_crlf(sendbuf);
|
||||
}
|
||||
|
||||
while (len) {
|
||||
if (input_check_for_abort_key())
|
||||
{
|
||||
printf("User abort\n");
|
||||
w5100_disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
snd = w5100_send_request();
|
||||
if (!snd) {
|
||||
if (!w5100_connected()) {
|
||||
printf("Connection lost\n");
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len < snd)
|
||||
snd = len;
|
||||
|
||||
{
|
||||
// One less to allow for faster pre-increment below
|
||||
const char *dataptr = sendbuf + pos - 1;
|
||||
uint16_t i;
|
||||
for (i = 0; i < snd; ++i) {
|
||||
// The variable is necessary to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment register.
|
||||
char data = *++dataptr;
|
||||
*w5100_data = data;
|
||||
}
|
||||
}
|
||||
|
||||
w5100_send_commit(snd);
|
||||
len -= snd;
|
||||
pos += snd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
//
|
||||
// Handle short single packet ASCII text responses
|
||||
// Must fit in recvbuf[]
|
||||
//
|
||||
uint16_t rcv;
|
||||
uint16_t len = 0;
|
||||
uint8_t cont = 1;
|
||||
|
||||
--length; // Leave space for NULL at end in case of buffer overrun
|
||||
|
||||
while (cont) {
|
||||
if (input_check_for_abort_key()) {
|
||||
printf("User abort\n");
|
||||
w5100_disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
rcv = w5100_receive_request();
|
||||
if (!rcv) {
|
||||
cont = w5100_connected();
|
||||
if (cont)
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((length - len) == 0)
|
||||
cont = 0;
|
||||
|
||||
if (rcv > length - len)
|
||||
rcv = length - len;
|
||||
|
||||
{
|
||||
// One less to allow for faster pre-increment below
|
||||
char *dataptr = recvbuf + len - 1;
|
||||
uint16_t i;
|
||||
for (i = 0; i < rcv; ++i) {
|
||||
// The variable is necessary to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment register.
|
||||
char data = *w5100_data;
|
||||
*++dataptr = data;
|
||||
if (!memcmp(dataptr - 1, "\r\n", 2))
|
||||
cont = 0;
|
||||
}
|
||||
}
|
||||
w5100_receive_commit(rcv);
|
||||
len += rcv;
|
||||
}
|
||||
recvbuf[len + 1] = '\0';
|
||||
putchar('<');
|
||||
print_strip_crlf(recvbuf);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check expected string from server
|
||||
* Returns 0 if expected, 1 otherwise
|
||||
*/
|
||||
uint8_t expect(char *buf, char *s) {
|
||||
if (strncmp(buf, s, strlen(s)) != 0) {
|
||||
printf("\nExpected '%s' got '%s'\n", s, buf);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read parms from NEWS.CFG
|
||||
*/
|
||||
void readconfigfile(void) {
|
||||
char *colon;
|
||||
fp = fopen("NEWS.CFG", "r");
|
||||
if (!fp) {
|
||||
puts("Can't open config file NEWS.CFG");
|
||||
error_exit();
|
||||
}
|
||||
fscanf(fp, "%s", cfg_server);
|
||||
fscanf(fp, "%s", cfg_user);
|
||||
fscanf(fp, "%s", cfg_pass);
|
||||
fscanf(fp, "%s", cfg_instdir);
|
||||
fscanf(fp, "%s", cfg_emaildir);
|
||||
fscanf(fp, "%s", cfg_emailaddr);
|
||||
fclose(fp);
|
||||
|
||||
colon = strchr(cfg_server, ':');
|
||||
if (!colon)
|
||||
nntp_port = 110;
|
||||
else
|
||||
nntp_port = atoi(colon + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update EMAIL.DB - quick access database for header info
|
||||
*/
|
||||
void update_email_db(struct emailhdrs *h) {
|
||||
FILE *fp;
|
||||
sprintf(filename, "%s/NEWS.SENT/EMAIL.DB", cfg_emaildir);
|
||||
_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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write NEXT.EMAIL file with number of next EMAIL.n file to be created
|
||||
*/
|
||||
void write_next_email(uint16_t num) {
|
||||
sprintf(filename, "%s/NEWS.SENT/NEXT.EMAIL", cfg_emaildir);
|
||||
_filetype = PRODOS_T_TXT;
|
||||
_auxtype = 0;
|
||||
fp = fopen(filename, "wb");
|
||||
if (!fp) {
|
||||
printf("Can't open %s\n", filename);
|
||||
fclose(fp);
|
||||
error_exit();
|
||||
}
|
||||
fprintf(fp, "%u", num);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update NEWS.SENT when a message has been sent
|
||||
* Copy a messages from OUTBOX to SENT and find headers of interest
|
||||
* (Date, From, To, BCC, Subject)
|
||||
* filename - Filename in OUTBOX for message just sent
|
||||
*/
|
||||
void update_sent_mbox(char *name) {
|
||||
static struct emailhdrs hdrs;
|
||||
uint16_t nextemail, chars, headerchars;
|
||||
uint8_t headers;
|
||||
FILE *destfp;
|
||||
sprintf(filename, "%s/NEWS.SENT/NEXT.EMAIL", cfg_emaildir);
|
||||
fp = fopen(filename, "r");
|
||||
if (!fp) {
|
||||
nextemail = 1;
|
||||
write_next_email(nextemail);
|
||||
} else {
|
||||
fscanf(fp, "%u", &nextemail);
|
||||
fclose(fp);
|
||||
}
|
||||
strcpy(linebuf, "");
|
||||
sprintf(filename, "%s/NEWS.OUTBOX/%s", cfg_emaildir, name);
|
||||
fp = fopen(filename, "r");
|
||||
if (!fp) {
|
||||
printf("Can't open %s\n", filename);
|
||||
error_exit();
|
||||
}
|
||||
hdrs.emailnum = nextemail;
|
||||
sprintf(filename, "%s/NEWS.SENT/EMAIL.%u", cfg_emaildir, nextemail++);
|
||||
puts(filename);
|
||||
_filetype = PRODOS_T_TXT;
|
||||
_auxtype = 0;
|
||||
destfp = fopen(filename, "wb");
|
||||
if (!destfp) {
|
||||
printf("Can't open %s\n", filename);
|
||||
fclose(fp);
|
||||
error_exit();
|
||||
}
|
||||
headers = 1;
|
||||
headerchars = 0;
|
||||
hdrs.skipbytes = 0; // Just in case it doesn't get set
|
||||
hdrs.status = 'N';
|
||||
hdrs.tag = ' ';
|
||||
get_line(fp, 1, linebuf, LINEBUFSZ); // Reset buffer
|
||||
while ((chars = get_line(fp, 0, linebuf, LINEBUFSZ)) != 0) {
|
||||
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, "Newsgroups: ", 12)) {
|
||||
strcpy(filename, "News:");
|
||||
strcat(filename, linebuf + 12);
|
||||
copyheader(hdrs.to, filename, 79);
|
||||
hdrs.to[79] = '\0';
|
||||
}
|
||||
if (!strncmp(linebuf, "Organization: ", 14)) {
|
||||
copyheader(hdrs.cc, linebuf + 14, 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;
|
||||
}
|
||||
}
|
||||
fputs(linebuf, destfp);
|
||||
}
|
||||
fclose(fp);
|
||||
fclose(destfp);
|
||||
update_email_db(&hdrs);
|
||||
write_next_email(nextemail);
|
||||
}
|
||||
|
||||
void main(int argc, char *argv[]) {
|
||||
static char sendbuf[80];
|
||||
uint8_t linecount;
|
||||
DIR *dp;
|
||||
struct dirent *d;
|
||||
char c;
|
||||
uint8_t eth_init = ETH_INIT_DEFAULT, connected = 0;
|
||||
|
||||
if ((argc == 2) && (strcmp(argv[1], "EMAIL") == 0))
|
||||
exec_email_on_exit = 1;
|
||||
|
||||
videomode(VIDEOMODE_80COL);
|
||||
printf("%c%s NNTP Post News Article(s)%c\n", 0x0f, PROGNAME, 0x0e);
|
||||
|
||||
printf("\nReading NEWS.CFG -");
|
||||
readconfigfile();
|
||||
printf(" Ok");
|
||||
|
||||
{
|
||||
int file;
|
||||
|
||||
printf("\nSetting slot - ");
|
||||
file = open("ethernet.slot", O_RDONLY);
|
||||
if (file != -1) {
|
||||
read(file, ð_init, 1);
|
||||
close(file);
|
||||
eth_init &= ~'0';
|
||||
}
|
||||
}
|
||||
|
||||
printf("%d\nInitializing %s - ", eth_init, eth_name);
|
||||
if (ip65_init(eth_init)) {
|
||||
ip65_error_exit();
|
||||
}
|
||||
|
||||
// Abort on Ctrl-C to be consistent with Linenoise
|
||||
abort_key = 0x83;
|
||||
|
||||
printf("Ok\nObtaining IP address - ");
|
||||
if (dhcp_init()) {
|
||||
ip65_error_exit();
|
||||
}
|
||||
printf("Ok\n");
|
||||
|
||||
// Copy IP config from IP65 to W5100
|
||||
w5100_config(eth_init);
|
||||
|
||||
sprintf(filename, "%s/NEWS.OUTBOX", cfg_emaildir);
|
||||
dp = opendir(filename);
|
||||
if (!dp) {
|
||||
printf("Can't open dir %s\n", filename);
|
||||
error_exit();
|
||||
}
|
||||
|
||||
while (d = readdir(dp)) {
|
||||
|
||||
sprintf(filename, "%s/NEWS.OUTBOX/%s", cfg_emaildir, d->d_name);
|
||||
fp = fopen(filename, "rb");
|
||||
if (!fp) {
|
||||
printf("Can't open %s\n", d->d_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip special files
|
||||
if (!strncmp(d->d_name, "EMAIL.DB", 8))
|
||||
goto skiptonext;
|
||||
if (!strncmp(d->d_name, "NEXT.EMAIL", 10))
|
||||
goto skiptonext;
|
||||
|
||||
printf("\n** Processing file %s ...\n", d->d_name);
|
||||
|
||||
linecount = 0;
|
||||
|
||||
while (1) {
|
||||
if ((get_line(fp, 0, linebuf, LINEBUFSZ) == 0) || (linecount == 20))
|
||||
break;
|
||||
++linecount;
|
||||
if (!strncmp(linebuf, "Newsgroups: ", 12))
|
||||
printf("%s", linebuf);
|
||||
if (!strncmp(linebuf, "Subject: ", 9))
|
||||
printf("%s", linebuf);
|
||||
}
|
||||
|
||||
printf("\n%cS)end message | H)old message in NEWS.OUTBOX | D)elete message from NEWS.OUTBOX%c",
|
||||
INVERSE, NORMAL);
|
||||
while (1) {
|
||||
c = cgetc();
|
||||
switch (c) {
|
||||
case 'S':
|
||||
case 's':
|
||||
goto sendmessage;
|
||||
case 'H':
|
||||
case 'h':
|
||||
printf("\n Holding message\n");
|
||||
fclose(fp);
|
||||
goto skiptonext;
|
||||
case 'D':
|
||||
case 'd':
|
||||
printf("\nSure? (y/n)");
|
||||
while (1) {
|
||||
c = cgetc();
|
||||
switch (c) {
|
||||
case 'Y':
|
||||
case 'y':
|
||||
putchar(CLRLINE);
|
||||
printf("\n Deleting message\n");
|
||||
fclose(fp);
|
||||
goto unlink;
|
||||
case 'N':
|
||||
case 'n':
|
||||
putchar(CLRLINE);
|
||||
printf("\n Holding message\n");
|
||||
fclose(fp);
|
||||
goto skiptonext;
|
||||
default:
|
||||
putchar(BELL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
putchar(BELL);
|
||||
}
|
||||
}
|
||||
|
||||
sendmessage:
|
||||
|
||||
if (!connected) {
|
||||
printf("\nConnecting to %s (%u) - ", cfg_server, nntp_port);
|
||||
|
||||
if (!w5100_connect(parse_dotted_quad(cfg_server), nntp_port)) {
|
||||
printf("Fail\n");
|
||||
error_exit();
|
||||
}
|
||||
|
||||
printf("Ok\n\n");
|
||||
|
||||
if (!w5100_tcp_send_recv(sendbuf, buf, NETBUFSZ, DONT_SEND, CMD_MODE)) {
|
||||
error_exit();
|
||||
}
|
||||
if (expect(buf, "200 ")) // "200" if posting is allowed
|
||||
error_exit();
|
||||
|
||||
sprintf(sendbuf, "AUTHINFO USER %s\r\n", cfg_user);
|
||||
if (!w5100_tcp_send_recv(sendbuf, buf, NETBUFSZ, DO_SEND, CMD_MODE)) {
|
||||
error_exit();
|
||||
}
|
||||
if (expect(buf, "381")) // Username accepted
|
||||
error_exit();
|
||||
|
||||
sprintf(sendbuf, "AUTHINFO PASS %s\r\n", cfg_pass);
|
||||
if (!w5100_tcp_send_recv(sendbuf, buf, NETBUFSZ, DO_SEND, CMD_MODE)) {
|
||||
error_exit();
|
||||
}
|
||||
if (expect(buf, "281")) // Authentication successful
|
||||
error_exit();
|
||||
|
||||
connected = 1;
|
||||
}
|
||||
|
||||
if (!w5100_tcp_send_recv("POST\r\n", buf, NETBUFSZ, DO_SEND, CMD_MODE)) {
|
||||
error_exit();
|
||||
}
|
||||
if (expect(buf, "340"))
|
||||
error_exit();
|
||||
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
if (!w5100_tcp_send_recv(sendbuf, buf, NETBUFSZ, DO_SEND, DATA_MODE)) {
|
||||
error_exit();
|
||||
}
|
||||
expect(buf, "240");
|
||||
|
||||
fclose(fp);
|
||||
|
||||
printf("Updating NEWS.SENT mailbox ...\n");
|
||||
update_sent_mbox(d->d_name);
|
||||
|
||||
printf("Removing from NEWS.OUTBOX ...\n");
|
||||
sprintf(filename, "%s/NEWS.OUTBOX/%s", cfg_emaildir, d->d_name);
|
||||
|
||||
unlink:
|
||||
if (unlink(filename))
|
||||
printf("Can't remove %s\n", filename);
|
||||
|
||||
skiptonext:
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
}
|
||||
closedir(dp);
|
||||
|
||||
// Ignore any error - can be a race condition where other side
|
||||
// disconnects too fast and we get an error
|
||||
if (connected) {
|
||||
w5100_tcp_send_recv("QUIT\r\n", buf, NETBUFSZ, DO_SEND, CMD_MODE);
|
||||
printf("Disconnecting\n");
|
||||
w5100_disconnect();
|
||||
} else
|
||||
printf("\n** No messages were sent **\n");
|
||||
|
||||
confirm_exit();
|
||||
}
|
69
apps/pop65.c
69
apps/pop65.c
|
@ -48,6 +48,8 @@ uint16_t pop_port;
|
|||
* Keypress before quit
|
||||
*/
|
||||
void confirm_exit(void) {
|
||||
fclose(fp);
|
||||
w5100_disconnect();
|
||||
printf("\n[Press Any Key]");
|
||||
cgetc();
|
||||
if (exec_email_on_exit) {
|
||||
|
@ -225,7 +227,7 @@ bool w5100_tcp_send_recv(char* sendbuf, char* recvbuf, size_t length,
|
|||
if (written != len) {
|
||||
printf("Write error");
|
||||
fclose(fp);
|
||||
error_exit();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy 4 bytes of overlap
|
||||
|
@ -237,12 +239,16 @@ bool w5100_tcp_send_recv(char* sendbuf, char* recvbuf, size_t length,
|
|||
}
|
||||
} else {
|
||||
//
|
||||
// Handle short single packet ASCII text responses
|
||||
// Handle short single line ASCII text responses
|
||||
// Must fit in recvbuf[]
|
||||
//
|
||||
uint16_t rcv;
|
||||
uint16_t len = 0;
|
||||
uint8_t cont = 1;
|
||||
|
||||
while (1) {
|
||||
--length; // Leave space for NULL at end in case of buffer overrun
|
||||
|
||||
while (cont) {
|
||||
if (input_check_for_abort_key()) {
|
||||
printf("User abort\n");
|
||||
w5100_disconnect();
|
||||
|
@ -250,30 +256,35 @@ bool w5100_tcp_send_recv(char* sendbuf, char* recvbuf, size_t length,
|
|||
}
|
||||
|
||||
rcv = w5100_receive_request();
|
||||
if (rcv)
|
||||
break;
|
||||
if (!w5100_connected()) {
|
||||
printf("Connection lost\n");
|
||||
return false;
|
||||
if (!rcv) {
|
||||
cont = w5100_connected();
|
||||
if (cont)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (rcv > length - len)
|
||||
rcv = length - len;
|
||||
if ((length - len) == 0)
|
||||
cont = 0;
|
||||
|
||||
{
|
||||
// One less to allow for faster pre-increment below
|
||||
char *dataptr = recvbuf + len - 1;
|
||||
uint16_t i;
|
||||
for (i = 0; i < rcv; ++i) {
|
||||
// The variable is necessary to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment register.
|
||||
char data = *w5100_data;
|
||||
*++dataptr = data;
|
||||
if (rcv > length - len)
|
||||
rcv = length - len;
|
||||
|
||||
{
|
||||
// One less to allow for faster pre-increment below
|
||||
char *dataptr = recvbuf + len - 1;
|
||||
uint16_t i;
|
||||
for (i = 0; i < rcv; ++i) {
|
||||
// The variable is necessary to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment register.
|
||||
char data = *w5100_data;
|
||||
*++dataptr = data;
|
||||
if (!memcmp(dataptr - 1, "\r\n", 2))
|
||||
cont = 0;
|
||||
}
|
||||
}
|
||||
w5100_receive_commit(rcv);
|
||||
len += rcv;
|
||||
}
|
||||
recvbuf[len + 1] = '\0';
|
||||
putchar('<');
|
||||
print_strip_crlf(recvbuf);
|
||||
}
|
||||
|
@ -285,7 +296,7 @@ bool w5100_tcp_send_recv(char* sendbuf, char* recvbuf, size_t length,
|
|||
*/
|
||||
void expect(char *buf, char *s) {
|
||||
if (strncmp(buf, s, strlen(s)) != 0) {
|
||||
printf("\nExpected '%s' got '%s\n", s, buf);
|
||||
printf("\nExpected '%s' got '%s'\n", s, buf);
|
||||
error_exit();
|
||||
}
|
||||
}
|
||||
|
@ -321,12 +332,13 @@ void readconfigfile(void) {
|
|||
|
||||
/*
|
||||
* Read a text file a line at a time
|
||||
* Returns number of chars in the line, or -1 if EOF.
|
||||
* Returns number of chars in the line, or 0 if EOF.
|
||||
* Expects CRLF line endings (CRLF) and converts to Apple II (CR) convention
|
||||
* fp - file to read from
|
||||
* writep - Pointer to buffer into which line will be written
|
||||
* n - length of buffer. Longer lines will be truncated and terminated with CR.
|
||||
*/
|
||||
int16_t get_line(FILE *fp, char *writep) {
|
||||
uint16_t get_line(FILE *fp, char *writep, uint16_t n) {
|
||||
static uint16_t rd = 0; // Read
|
||||
static uint16_t end = 0; // End of valid data in buf
|
||||
uint16_t i = 0;
|
||||
|
@ -336,7 +348,11 @@ int16_t get_line(FILE *fp, char *writep) {
|
|||
rd = 0;
|
||||
}
|
||||
if (end == 0)
|
||||
return -1; // EOF
|
||||
goto done;
|
||||
if (i == n - 1) {
|
||||
writep[i - 1] = '\r';
|
||||
goto done;
|
||||
}
|
||||
writep[i++] = buf[rd++];
|
||||
// The following line is safe because of linebuf_pad[]
|
||||
if ((writep[i - 1] == '\n') && (writep[i - 2] == '\r')) {
|
||||
|
@ -344,6 +360,9 @@ int16_t get_line(FILE *fp, char *writep) {
|
|||
return i - 1;
|
||||
}
|
||||
}
|
||||
done:
|
||||
writep[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -436,7 +455,7 @@ void update_inbox(uint16_t nummsgs) {
|
|||
hdrs.skipbytes = 0; // Just in case it doesn't get set
|
||||
hdrs.status = 'N';
|
||||
hdrs.tag = ' ';
|
||||
while ((chars = get_line(fp, linebuf)) != -1) {
|
||||
while ((chars = get_line(fp, linebuf, LINEBUFSZ)) != 0) {
|
||||
if (headers) {
|
||||
headerchars += chars;
|
||||
if (!strncmp(linebuf, "Date: ", 6)) {
|
||||
|
|
|
@ -45,13 +45,13 @@ void error_exit() {
|
|||
|
||||
/*
|
||||
* Read a text file a line at a time
|
||||
* Returns number of chars in the line, or -1 if EOF.
|
||||
* Returns number of chars in the line, or 0 if EOF.
|
||||
* Expects Apple ][ style line endings (CR) and does no conversion
|
||||
* fp - file to read from
|
||||
* writep - Pointer to buffer into which line will be written
|
||||
* pos - position in file is updated via this pointer
|
||||
* n - length of buffer. Longer lines will be truncated and terminated with CR.
|
||||
*/
|
||||
int16_t get_line(FILE *fp, char *writep) {
|
||||
uint16_t get_line(FILE *fp, char *writep, uint16_t n) {
|
||||
static uint16_t rd = 0; // Read
|
||||
static uint16_t end = 0; // End of valid data in buf
|
||||
uint16_t i = 0;
|
||||
|
@ -61,13 +61,18 @@ int16_t get_line(FILE *fp, char *writep) {
|
|||
rd = 0;
|
||||
}
|
||||
if (end == 0)
|
||||
return -1; // EOF
|
||||
writep[i++] = buf[rd++];
|
||||
if (writep[i - 1] == '\r') {
|
||||
writep[i] = '\0';
|
||||
return i;
|
||||
goto done;
|
||||
if (i == n - 1) {
|
||||
writep[i - 1] = '\r';
|
||||
goto done;
|
||||
}
|
||||
writep[i++] = buf[rd++];
|
||||
if (writep[i - 1] == '\r')
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
writep[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -188,7 +193,7 @@ void repair_mailbox(void) {
|
|||
hdrs.skipbytes = 0; // Just in case it doesn't get set
|
||||
hdrs.status = 'R';
|
||||
hdrs.tag = ' ';
|
||||
while ((chars = get_line(fp, linebuf)) != -1) {
|
||||
while ((chars = get_line(fp, linebuf, LINEBUFSZ)) != 0) {
|
||||
if (headers) {
|
||||
headerchars += chars;
|
||||
if (!strncmp(linebuf, "Date: ", 6)) {
|
||||
|
|
148
apps/smtp65.c
148
apps/smtp65.c
|
@ -23,7 +23,11 @@
|
|||
|
||||
#include "email_common.h"
|
||||
|
||||
#define BELL 7
|
||||
#define BACKSPACE 8
|
||||
#define NORMAL 0x0e
|
||||
#define INVERSE 0x0f
|
||||
#define CLRLINE 0x1a
|
||||
|
||||
// Both pragmas are obligatory to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment registers.
|
||||
|
@ -106,13 +110,14 @@ void spinner(uint32_t sz, uint8_t final) {
|
|||
|
||||
/*
|
||||
* Read a text file a line at a time
|
||||
* Returns number of chars in the line, or -1 if EOF.
|
||||
* Returns number of chars in the line, or 0 if EOF.
|
||||
* Expects Apple ][ style line endings (CR) and does no conversion
|
||||
* fp - file to read from
|
||||
* reset - if 1 then just reset the buffer and return
|
||||
* writep - Pointer to buffer into which line will be written
|
||||
* n - length of buffer. Longer lines will be truncated and terminated with CR.
|
||||
*/
|
||||
int16_t get_line(FILE *fp, uint8_t reset, char *writep) {
|
||||
uint16_t get_line(FILE *fp, uint8_t reset, char *writep, uint16_t n) {
|
||||
static uint16_t rd = 0; // Read
|
||||
static uint16_t end = 0; // End of valid data in buf
|
||||
uint16_t i = 0;
|
||||
|
@ -126,13 +131,18 @@ int16_t get_line(FILE *fp, uint8_t reset, char *writep) {
|
|||
rd = 0;
|
||||
}
|
||||
if (end == 0)
|
||||
return -1; // EOF
|
||||
writep[i++] = buf[rd++];
|
||||
if (writep[i - 1] == '\r') {
|
||||
writep[i] = '\0';
|
||||
return i;
|
||||
goto done;
|
||||
if (i == n - 1) {
|
||||
writep[i - 1] = '\r';
|
||||
goto done;
|
||||
}
|
||||
writep[i++] = buf[rd++];
|
||||
if (writep[i - 1] == '\r')
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
writep[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
#define DO_SEND 1 // For do_send param
|
||||
|
@ -159,17 +169,17 @@ bool w5100_tcp_send_recv(char* sendbuf, char* recvbuf, size_t length,
|
|||
uint16_t pos = 0;
|
||||
uint8_t cont = 1;
|
||||
uint16_t snd;
|
||||
int16_t len;
|
||||
uint16_t len;
|
||||
|
||||
filesize = 0;
|
||||
len = get_line(fp, 1, linebuf); // Reset buffer
|
||||
len = get_line(fp, 1, linebuf, LINEBUFSZ); // Reset buffer
|
||||
|
||||
while (cont) {
|
||||
|
||||
len = get_line(fp, 0, linebuf);
|
||||
len = get_line(fp, 0, linebuf, LINEBUFSZ - 1);
|
||||
pos = 0;
|
||||
|
||||
if (len == -1) {
|
||||
if (len == 0) {
|
||||
strcpy(linebuf, "\r\n.\r\n");
|
||||
len = 5;
|
||||
cont = 0;
|
||||
|
@ -221,7 +231,7 @@ bool w5100_tcp_send_recv(char* sendbuf, char* recvbuf, size_t length,
|
|||
|
||||
} else {
|
||||
//
|
||||
// Handle short single packet ASCII text transmissions
|
||||
// Handle short ASCII text transmissions
|
||||
//
|
||||
uint16_t snd;
|
||||
uint16_t pos = 0;
|
||||
|
@ -272,11 +282,15 @@ bool w5100_tcp_send_recv(char* sendbuf, char* recvbuf, size_t length,
|
|||
{
|
||||
//
|
||||
// Handle short single packet ASCII text responses
|
||||
// Must fit in recvbuf[]
|
||||
//
|
||||
uint16_t rcv;
|
||||
uint16_t len = 0;
|
||||
uint8_t cont = 1;
|
||||
|
||||
while(1) {
|
||||
--length; // Leave space for NULL at end in case of buffer overrun
|
||||
|
||||
while (cont) {
|
||||
if (input_check_for_abort_key()) {
|
||||
printf("User abort\n");
|
||||
w5100_disconnect();
|
||||
|
@ -284,30 +298,35 @@ bool w5100_tcp_send_recv(char* sendbuf, char* recvbuf, size_t length,
|
|||
}
|
||||
|
||||
rcv = w5100_receive_request();
|
||||
if (rcv)
|
||||
break;
|
||||
if (!w5100_connected()) {
|
||||
printf("Connection lost\n");
|
||||
return false;
|
||||
if (!rcv) {
|
||||
cont = w5100_connected();
|
||||
if (cont)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (rcv > length - len)
|
||||
rcv = length - len;
|
||||
if ((length - len) == 0)
|
||||
cont = 0;
|
||||
|
||||
{
|
||||
// One less to allow for faster pre-increment below
|
||||
char *dataptr = recvbuf + len - 1;
|
||||
uint16_t i;
|
||||
for (i = 0; i < rcv; ++i) {
|
||||
// The variable is necessary to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment register.
|
||||
char data = *w5100_data;
|
||||
*++dataptr = data;
|
||||
if (rcv > length - len)
|
||||
rcv = length - len;
|
||||
|
||||
{
|
||||
// One less to allow for faster pre-increment below
|
||||
char *dataptr = recvbuf + len - 1;
|
||||
uint16_t i;
|
||||
for (i = 0; i < rcv; ++i) {
|
||||
// The variable is necessary to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment register.
|
||||
char data = *w5100_data;
|
||||
*++dataptr = data;
|
||||
if (!memcmp(dataptr - 1, "\r\n", 2))
|
||||
cont = 0;
|
||||
}
|
||||
}
|
||||
w5100_receive_commit(rcv);
|
||||
len += rcv;
|
||||
}
|
||||
recvbuf[len + 1] = '\0';
|
||||
putchar('<');
|
||||
print_strip_crlf(recvbuf);
|
||||
}
|
||||
|
@ -320,7 +339,7 @@ bool w5100_tcp_send_recv(char* sendbuf, char* recvbuf, size_t length,
|
|||
*/
|
||||
uint8_t expect(char *buf, char *s) {
|
||||
if (strncmp(buf, s, strlen(s)) != 0) {
|
||||
printf("\nExpected '%s' got '%s\n", s, buf);
|
||||
printf("\nExpected '%s' got '%s'\n", s, buf);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -446,8 +465,8 @@ void update_sent_mbox(char *name) {
|
|||
hdrs.skipbytes = 0; // Just in case it doesn't get set
|
||||
hdrs.status = 'N';
|
||||
hdrs.tag = ' ';
|
||||
get_line(fp, 1, linebuf); // Reset buffer
|
||||
while ((chars = get_line(fp, 0, linebuf)) != -1) {
|
||||
get_line(fp, 1, linebuf, LINEBUFSZ); // Reset buffer
|
||||
while ((chars = get_line(fp, 0, linebuf, LINEBUFSZ)) != 0) {
|
||||
if (headers) {
|
||||
headerchars += chars;
|
||||
if (!strncmp(linebuf, "Date: ", 6)) {
|
||||
|
@ -488,7 +507,7 @@ void main(int argc, char *argv[]) {
|
|||
uint8_t linecount;
|
||||
DIR *dp;
|
||||
struct dirent *d;
|
||||
char *p, *q;
|
||||
char *p, *q, c;
|
||||
uint8_t eth_init = ETH_INIT_DEFAULT, connected = 0;
|
||||
|
||||
if ((argc == 2) && (strcmp(argv[1], "EMAIL") == 0))
|
||||
|
@ -558,7 +577,7 @@ void main(int argc, char *argv[]) {
|
|||
strcpy(recipients, "");
|
||||
|
||||
while (1) {
|
||||
if ((get_line(fp, 0, linebuf) == -1) || (linecount == 20)) {
|
||||
if ((get_line(fp, 0, linebuf, LINEBUFSZ) == 0) || (linecount == 20)) {
|
||||
if (strlen(recipients) == 0) {
|
||||
printf("No recipients (To or Cc) in %s. Skipping msg.\n", d->d_name);
|
||||
goto skiptonext;
|
||||
|
@ -567,6 +586,7 @@ void main(int argc, char *argv[]) {
|
|||
}
|
||||
++linecount;
|
||||
if (!strncmp(linebuf, "To: ", 4) || (!strncmp(linebuf, "cc: ",4))) {
|
||||
printf("%s", linebuf);
|
||||
linebuf[strlen(linebuf) - 1] = '\0'; // Chop off \r
|
||||
if (strlen(linebuf + 4) > 0) {
|
||||
if (strlen(recipients) > 0)
|
||||
|
@ -574,10 +594,55 @@ void main(int argc, char *argv[]) {
|
|||
strcat(recipients, linebuf + 4);
|
||||
}
|
||||
}
|
||||
if (!strncmp(linebuf, "Subject: ", 9))
|
||||
printf("%s", linebuf);
|
||||
}
|
||||
|
||||
printf("\n%cS)end message | H)old message in OUTBOX | D)elete message from OUTBOX %c",
|
||||
INVERSE, NORMAL);
|
||||
while (1) {
|
||||
c = cgetc();
|
||||
switch (c) {
|
||||
case 'S':
|
||||
case 's':
|
||||
goto sendmessage;
|
||||
case 'H':
|
||||
case 'h':
|
||||
printf("\n Holding message\n");
|
||||
fclose(fp);
|
||||
goto skiptonext;
|
||||
case 'D':
|
||||
case 'd':
|
||||
printf("\nSure? (y/n)");
|
||||
while (1) {
|
||||
c = cgetc();
|
||||
switch (c) {
|
||||
case 'Y':
|
||||
case 'y':
|
||||
putchar(CLRLINE);
|
||||
printf("\n Deleting message\n");
|
||||
fclose(fp);
|
||||
goto unlink;
|
||||
case 'N':
|
||||
case 'n':
|
||||
putchar(CLRLINE);
|
||||
printf("\n Holding message\n");
|
||||
fclose(fp);
|
||||
goto skiptonext;
|
||||
default:
|
||||
putchar(BELL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
putchar(BELL);
|
||||
}
|
||||
}
|
||||
|
||||
sendmessage:
|
||||
|
||||
if (!connected) {
|
||||
printf("Connecting to %s - ", cfg_smtp_server);
|
||||
printf("\nConnecting to %s - ", cfg_smtp_server);
|
||||
|
||||
if (!w5100_connect(parse_dotted_quad(cfg_smtp_server), smtp_port)) {
|
||||
printf("Fail\n");
|
||||
|
@ -661,6 +726,8 @@ void main(int argc, char *argv[]) {
|
|||
|
||||
printf("Removing from OUTBOX ...\n");
|
||||
sprintf(filename, "%s/OUTBOX/%s", cfg_emaildir, d->d_name);
|
||||
|
||||
unlink:
|
||||
if (unlink(filename))
|
||||
printf("Can't remove %s\n", filename);
|
||||
|
||||
|
@ -672,11 +739,12 @@ skiptonext:
|
|||
|
||||
// Ignore any error - can be a race condition where other side
|
||||
// disconnects too fast and we get an error
|
||||
if (connected)
|
||||
if (connected) {
|
||||
w5100_tcp_send_recv("QUIT\r\n", buf, NETBUFSZ, DO_SEND, CMD_MODE);
|
||||
|
||||
printf("Disconnecting\n");
|
||||
w5100_disconnect();
|
||||
printf("Disconnecting\n");
|
||||
w5100_disconnect();
|
||||
} else
|
||||
printf("\n** No messages were sent **\n");
|
||||
|
||||
confirm_exit();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user