mirror of
https://github.com/bobbimanners/emailler.git
synced 2024-05-28 20:41:33 +00:00
Compare commits
44 Commits
emailler-v
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
9fdedd46bb | ||
|
9fa090f34d | ||
|
95615458aa | ||
|
d8d532fd72 | ||
|
7c402facc7 | ||
|
7bb47d4b85 | ||
|
d015ca310c | ||
|
e102d732b0 | ||
|
6106701fa8 | ||
|
077bddc9f1 | ||
|
e123dc2dbc | ||
|
675073a6c9 | ||
|
4e482b14cb | ||
|
ef07cc8b88 | ||
|
c2b4773e1c | ||
|
305c7bcf34 | ||
|
6e9c751f53 | ||
|
6613ec218c | ||
|
44c46943b0 | ||
|
52f6b664e4 | ||
|
9c4baa170d | ||
|
e943e0cca1 | ||
|
80bf13eb69 | ||
|
004c2cb1dc | ||
|
85f6fab6a9 | ||
|
6919adb9be | ||
|
6b1cde52c1 | ||
|
d7ec996cc8 | ||
|
ba19bc4f57 | ||
|
19ffeb1c8a | ||
|
f63fe7829f | ||
|
677137e851 | ||
|
332a5bb7e1 | ||
|
07bc9b40d8 | ||
|
432de5ad21 | ||
|
82835c508d | ||
|
733edc18c5 | ||
|
3f9ad451e2 | ||
|
84bcdc2043 | ||
|
e8c726f2fb | ||
|
89e5de0374 | ||
|
2ca9e4769e | ||
|
080d952737 | ||
|
1655c60f93 |
|
@ -82,7 +82,7 @@ Install the packages with root privs on the Pi:
|
|||
```
|
||||
sudo apt update
|
||||
sudo apt upgrade
|
||||
sudo apt install postfix postfix-pcre
|
||||
sudo apt install postfix postfix-pcre libsasl2-modules
|
||||
sudo apt install dovecot-common dovecot-pop3d
|
||||
sudo apt install fetchmail
|
||||
```
|
||||
|
@ -134,7 +134,7 @@ We will modify a number of configuration files:
|
|||
- `/etc/postfix/sasl/sasl_passwd`
|
||||
- `/etc/postfix/sasl/sasl_passwd.db`
|
||||
|
||||
Once Dovecot has been configured, the service may be controlled as follows:
|
||||
Once Postfix has been configured, the service may be controlled as follows:
|
||||
- `systemctl start postfix` - start service.
|
||||
- `systemctl stop postfix` - stop service.
|
||||
- `systemctl status postfix` - status of service.
|
||||
|
@ -179,6 +179,10 @@ My home network is 192.168.10.0/24, so I added it here:
|
|||
`mynetworks = 192.168.10.0/24 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128`.
|
||||
You should adjust this line to match your own LAN subnet.
|
||||
|
||||
I had an issue where the Pi was unable to connect to Google's SMTP server.
|
||||
It turned out it was trying to use IPv6, so I forced IPv4 as follows:
|
||||
`inet_protocols = ipv4`
|
||||
|
||||
Finally I added the following block of settings to enabled SASL authentication
|
||||
when talking to Gmail:
|
||||
|
||||
|
@ -245,7 +249,7 @@ mynetworks = 192.168.10.0/24 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
|
|||
mailbox_size_limit = 0
|
||||
recipient_delimiter = +
|
||||
inet_interfaces = all
|
||||
inet_protocols = all
|
||||
inet_protocols = ipv4
|
||||
|
||||
# Enable SASL authentication
|
||||
smtp_sasl_auth_enable = yes
|
||||
|
|
43
README-print65.md
Normal file
43
README-print65.md
Normal file
|
@ -0,0 +1,43 @@
|
|||
# Apple II Email and Usenet News Suite
|
||||
|
||||
<p align="center"><img src="img/emailler-logo.png" alt="emai//er-logo" height="200px"></p>
|
||||
|
||||
[Back to Main emai//er Docs](README.md#detailed-documentation-for-email-functions)
|
||||
|
||||
## `PRINT65.SYSTEM`
|
||||
|
||||
<!-- <p align="center"><img src="img/SMTP65.jpg" alt="SMTP65" height="400px"></p> -->
|
||||
|
||||
`PRINT65.SYSTEM` is a utility for printing to a network-connected printer using the Hewlett Packard Jetdirect protocol. It requires an Uthernet-II ethernet card and will not work with other interfaces without modification, because it uses the W5100 hardware TCP/IP stack.
|
||||
|
||||
Before running `PRINT65.SYSTEM` for the first time, use `EDIT.SYSTEM` to create a configuration file called `PRINT.CFG`. This file consists of a single line specifying the IP address of the network printer to use, optionally followed by a colon and a port number. If the port number is omitted it defaults to 9100. For example:
|
||||
|
||||
```
|
||||
192.168.10.4:9100
|
||||
```
|
||||
|
||||
`PRINT65.SYSTEM` performs the following tasks:
|
||||
|
||||
- If no filename was provided on the command line, prompt for the filename to print
|
||||
- Detect Uthernet-II
|
||||
- Obtain IP address using DHCP
|
||||
- Connect to Jetdirect printer
|
||||
- Open file
|
||||
- Send file contents to printer over TCP/IP
|
||||
- Close file
|
||||
- Disconnect
|
||||
|
||||
### Using Command Line Argument to Specify the File to Print
|
||||
|
||||
`PRINT65.SYSTEM` supports command line arguments in a way that is compatible with the Davex shell (and possibily other environments.) In Davex you can print a file as follows:
|
||||
|
||||
```
|
||||
print65.system /path/to/my/file
|
||||
```
|
||||
|
||||
### HP Jetdirect
|
||||
|
||||
Most HP printers support Jetdirect. I am using an HP Photosmart 7520 which supports the Jetdirect protocol on port 9100 over it's wifi connection. Jetdirect defaults to a simple plain text mode, which we exploit here to print in 80 column text mode.
|
||||
|
||||
[Back to Main emai//er Docs](README.md#detailed-documentation-for-email-functions)
|
||||
|
|
@ -27,14 +27,14 @@ Here is an example config file (with passwords replaced with `****` for obvious
|
|||
Bobbi
|
||||
****
|
||||
/H1/IP65
|
||||
/DATA/EMAIL
|
||||
/H1/DOCUMENTS/EMAIL
|
||||
bobbi.8bit@gmail.com
|
||||
```
|
||||
|
||||
The lines are as follows, in order:
|
||||
|
||||
1) IP address of the NNTP server, optionally followed by a colon and then the TCP port number. If the colon and port number are omitted, port 119 is the default.
|
||||
2) Username to use when connecting to NNTP.
|
||||
2) Username to use when connecting to NNTP. If your NNTP server does not need authentication then use '-' for the username and password.
|
||||
3) Password to use when connecting to NNTP.
|
||||
4) ProDOS path of the directory where the email executables are installed.
|
||||
5) ProDOS path to the root of the email folder tree. Mailboxes will be created and managed under this root path.
|
||||
|
|
|
@ -31,6 +31,7 @@ Emai//er is implemented as a number of ProDOS executables, each of which perform
|
|||
- `ATTACHER.SYSTEM` is used for creating multi-part MIME messages with attached files.
|
||||
- `REBUILD.SYSTEM` is a utility for rebuilding mailbox databases, should they become corrupted. This can also be used for bulk import of messages.
|
||||
- `DATE65.SYSTEM` is a Network Time Protocol (NTP) client which can be used for setting the system time and date if you do not have a real time clock.
|
||||
- `PRINT65.SYSTEM` allows text file to be printed to a network-attached printer that supports the Hewlett Packard Jetdirect protocol.
|
||||
|
||||
The following diagram shows the various executables that form the emai//er suite and how they execute one another. Note how `EMAIL.SYSTEM` serves as the hub from which all the other programs may be invoked.
|
||||
|
||||
|
@ -68,6 +69,10 @@ Recommended optional hardware:
|
|||
|
||||
Emai//er has been extensively tested using ProDOS 2.4.2. However, it should not be a problem to run it under other versions of ProDOS.
|
||||
|
||||
## Uthernet-II Slot
|
||||
|
||||
The default slot is 5. If you have your card in another slot then create a file called `ethernet.slot` using `EDIT.SYSTEM` with your slot number on the first line.
|
||||
|
||||
## Transport Level Security (TLS)
|
||||
|
||||
One problem faced by any retrocomputing project of this type is that Transport Layer Security (TLS) is endemic on today's Internet. While this is great for security, the encryption algorithms are not feasible to implement on a 6502-based system. In order to bridge the plain text world of the Apple II to today's encrypted Internet, I have set up a Raspberry Pi using several common open source packages as a gateway.
|
||||
|
@ -105,6 +110,7 @@ Please refer to the linked documents for detailed instructions on how to configu
|
|||
- [Receiving Email with `POP65.SYSTEM`](README-pop65.md)
|
||||
- [Sending Email with `SMTP65.SYSTEM`](README-smtp65.md)
|
||||
- [Rebuilding Mailboxes with `REBUILD.SYSTEM`](README-rebuild.md)
|
||||
- [Printing Files with `PRINT65.SYSTEM`](README-print65.md)
|
||||
|
||||
## Detailed Documentation for Usenet Functions
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ TCP =\
|
|||
tweet65 \
|
||||
pop65-slow
|
||||
|
||||
bin: wget65.bin pop65.bin smtp65.bin email.bin rebuild.bin edit.bin attacher.bin nntp65.bin nntp65.up.bin
|
||||
bin: wget65.bin pop65.bin smtp65.bin email.bin rebuild.bin edit.bin attacher.bin nntp65.bin nntp65.up.bin print65.bin
|
||||
|
||||
wget65.bin: w5100.c w5100_http.c linenoise.c
|
||||
wget65.bin: IP65LIB = ../ip65/ip65.lib
|
||||
|
@ -67,6 +67,10 @@ nntp65.up.bin: w5100.c
|
|||
nntp65.up.bin: IP65LIB = ../ip65/ip65.lib
|
||||
nntp65.up.bin: A2_DRIVERLIB = ../drivers/ip65_apple2_uther2.lib
|
||||
|
||||
print65.bin: w5100.c
|
||||
print65.bin: IP65LIB = ../ip65/ip65.lib
|
||||
print65.bin: A2_DRIVERLIB = ../drivers/ip65_apple2_uther2.lib
|
||||
|
||||
email.bin: gettime.s
|
||||
|
||||
date65.bin hfs65.bin tweet65.bin: CL65FLAGS = --start-addr 0x0C00 apple2enh-iobuf-0800.o
|
||||
|
@ -166,6 +170,8 @@ ip65.dsk: 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 $@ print65 < print65.bin
|
||||
java -jar $(AC) -p $@ print65.system sys < $(CC65)/apple2enh/util/loader.system
|
||||
java -jar $(AC) -as $@ rebuild < rebuild.bin
|
||||
java -jar $(AC) -p $@ rebuild.system sys < $(CC65)/apple2enh/util/loader.system
|
||||
java -jar $(AC) -as $@ smtp65 < smtp65.bin
|
||||
|
|
|
@ -335,6 +335,8 @@ struct tabent {
|
|||
*/
|
||||
void file_ui_draw(uint16_t i, uint16_t first, uint16_t selected, uint16_t entries) {
|
||||
struct tabent *entry;
|
||||
if (i < first)
|
||||
return;
|
||||
gotoxy(5, i - first + 6);
|
||||
if (i < entries) {
|
||||
entry = (struct tabent*)iobuf + i;
|
||||
|
@ -395,14 +397,10 @@ void file_ui_draw_all(uint16_t first, uint16_t selected, uint16_t entries) {
|
|||
}
|
||||
|
||||
/*
|
||||
* Perform ProDOS MLI ON_LINE call to
|
||||
* write all online volume names into iobuf[]
|
||||
* Return the number of entries
|
||||
* Asm code for online()
|
||||
*/
|
||||
uint16_t online(void) {
|
||||
uint16_t entries = 0;
|
||||
struct tabent *entry;
|
||||
uint8_t i, j, len;
|
||||
#pragma optimize (push, off)
|
||||
void onlineasm(void) {
|
||||
__asm__("lda #$00"); // All devices
|
||||
__asm__("sta mliparam + 1");
|
||||
__asm__("lda #<%v", iobuf); // iobuf LSB
|
||||
|
@ -413,6 +411,19 @@ uint16_t online(void) {
|
|||
__asm__("lda #$c5"); // ON_LINE
|
||||
__asm__("ldx #$02"); // Two parms
|
||||
__asm__("jsr callmli");
|
||||
}
|
||||
#pragma optimize (pop)
|
||||
|
||||
/*
|
||||
* Perform ProDOS MLI ON_LINE call to
|
||||
* write all online volume names into iobuf[]
|
||||
* Return the number of entries
|
||||
*/
|
||||
uint16_t online(void) {
|
||||
uint16_t entries = 0;
|
||||
struct tabent *entry;
|
||||
uint8_t i, j, len;
|
||||
onlineasm();
|
||||
entry = (struct tabent*)iobuf;
|
||||
for (i = 0; i < 16; ++i) {
|
||||
len = iobuf[256 + i * 16] & 0x0f;
|
||||
|
|
91
apps/edit.c
91
apps/edit.c
|
@ -419,37 +419,44 @@ void goto_prompt_row(void) {
|
|||
gotoxy(0, PROMPT_ROW);
|
||||
}
|
||||
|
||||
#define MAX_DISP_FILENAME 35 /* Max display space for filename */
|
||||
|
||||
/*
|
||||
* Refresh the status line at the bottom of the screen
|
||||
*/
|
||||
void update_status_line(void) {
|
||||
uint8_t nofile = 0;
|
||||
uint8_t l;
|
||||
|
||||
static char selmsg1[] = ": Go to end of selection, then [Return]";
|
||||
static char selmsg2[] = ": Go to target, then [Return] to ";
|
||||
uint8_t no_name = 0;
|
||||
static char dispfname[MAX_DISP_FILENAME + 1];
|
||||
static char disppartnum[8 + 1];
|
||||
|
||||
goto_prompt_row();
|
||||
|
||||
if (strlen(filename) == 0) {
|
||||
strcpy(filename, "<scratch>");
|
||||
nofile = 1;
|
||||
no_name = 1;
|
||||
}
|
||||
if (status[2] == 0)
|
||||
strcpy(disppartnum, "");
|
||||
else
|
||||
snprintf(disppartnum, 8, ":Part%u", status[2]);
|
||||
l = strlen(filename) + strlen(disppartnum);
|
||||
if (l <= MAX_DISP_FILENAME) {
|
||||
strcpy(dispfname, filename);
|
||||
} else {
|
||||
strcpy(dispfname, filename + (l - MAX_DISP_FILENAME));
|
||||
dispfname[0] = dispfname[1] = dispfname[2] = '.';
|
||||
}
|
||||
strcat(dispfname, disppartnum);
|
||||
revers(1);
|
||||
switch (mode) {
|
||||
case SEL_NONE:
|
||||
if (status[2] == 0) {
|
||||
cprintf("OA-? Help | [%03u] %c File:%s %2uKB free",
|
||||
l_auxbank, status[0] ? '*' : ' ', filename,
|
||||
(FREESPACE() + 512) / 1024);
|
||||
l = 44 - strlen(filename);
|
||||
} else {
|
||||
snprintf(userentry, 80, "%s Part:%u", filename, status[2]);
|
||||
cprintf("OA-? Help | [%03u] %c File:%s %2uKB free",
|
||||
l_auxbank, status[0] ? '*' : ' ', userentry,
|
||||
(FREESPACE() + 512) / 1024);
|
||||
l = 45 - strlen(userentry);
|
||||
}
|
||||
cprintf("OA-? Help | [%03u] %c %s",
|
||||
l_auxbank, status[0] ? '*' : ' ', dispfname);
|
||||
l = 49 - strlen(dispfname);
|
||||
cclear(l);
|
||||
cprintf("| Free:%2uKB", (FREESPACE() + 512) / 1024);
|
||||
l = 0;
|
||||
break;
|
||||
case SEL_SELECT:
|
||||
cprintf("Select: OA-[Space] to end");
|
||||
|
@ -464,27 +471,23 @@ void update_status_line(void) {
|
|||
l = 80 - 23;
|
||||
break;
|
||||
case SRCH3:
|
||||
if (status[2] == 0) {
|
||||
cprintf("OA-? Help | [%03u] %c File:%s %2uKB free | Not Found",
|
||||
l_auxbank, status[0] ? '*' : ' ', filename, (FREESPACE() + 512) / 1024);
|
||||
l = 44 - 12 - strlen(filename);
|
||||
} else {
|
||||
snprintf(userentry, 80, "%s Part:%u", filename, status[2]);
|
||||
cprintf("OA-? Help | [%03u] %c File:%s %2uKB free | Not Found",
|
||||
l_auxbank, status[0] ? '*' : ' ', userentry,
|
||||
(FREESPACE() + 512) / 1024);
|
||||
l = 45 - 12 - strlen(userentry);
|
||||
}
|
||||
cprintf("OA-? Help | [%03u] %c %s",
|
||||
l_auxbank, status[0] ? '*' : ' ', dispfname);
|
||||
l = 49 - 12 - strlen(dispfname);
|
||||
cclear(l);
|
||||
cprintf("| Free:%2uKB | NOT FOUND", (FREESPACE() + 512) / 1024);
|
||||
beep();
|
||||
beep();
|
||||
l = 0;
|
||||
break;
|
||||
}
|
||||
cclear(l);
|
||||
if (l > 0)
|
||||
cclear(l);
|
||||
revers(0);
|
||||
|
||||
if (nofile)
|
||||
strcpy(filename, "");
|
||||
|
||||
gotoxy(curscol, cursrow);
|
||||
cursor(1);
|
||||
if (no_name)
|
||||
strcpy(filename, "");
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -763,7 +766,7 @@ void spinner(uint32_t sz, uint8_t saving, uint8_t copymode) {
|
|||
(saving ? "Saving" : "Opening"), filename, chars[(i++) % 4], sz);
|
||||
revers(1);
|
||||
cprintf("%s", buf);
|
||||
cclear(79 - strlen(buf));
|
||||
cclear(80 - strlen(buf));
|
||||
revers(0);
|
||||
}
|
||||
|
||||
|
@ -1627,8 +1630,8 @@ uint8_t finish_search_replace(uint16_t pos, uint8_t r, uint8_t ask) {
|
|||
uint8_t i;
|
||||
mode = SEL_NONE;
|
||||
jump_pos(pos);
|
||||
startsel = gapend + 1;
|
||||
endsel = gapend + 1 + strlen(search);
|
||||
// startsel = gapend + 1;
|
||||
// endsel = gapend + 1 + strlen(search);
|
||||
draw_screen();
|
||||
if (r == 0) { // Replace mode
|
||||
if (ask) {
|
||||
|
@ -1651,7 +1654,7 @@ uint8_t finish_search_replace(uint16_t pos, uint8_t r, uint8_t ask) {
|
|||
cursor_right();
|
||||
return 1; // Continue
|
||||
}
|
||||
startsel = endsel = 65535U;
|
||||
// startsel = endsel = 65535U;
|
||||
return 0; // Do not continue
|
||||
}
|
||||
|
||||
|
@ -1727,8 +1730,8 @@ void disconnect_ramdisk(void) {
|
|||
uint16_t *s3d2 = (uint16_t*)0xbf26; // s3d2 driver vector
|
||||
if (*s0d1 != *s3d2)
|
||||
check_ramdisk(3 + (2 - 1) * 8); // s3d2
|
||||
if (*s0d1 != *s3d1)
|
||||
check_ramdisk(3 + (1 - 1) * 8); // s3d1
|
||||
// if (*s0d1 != *s3d1)
|
||||
// check_ramdisk(3 + (1 - 1) * 8); // s3d1
|
||||
if (*s0d1 == *s3d2) {
|
||||
s3d2dev = 0;
|
||||
goto s3d1; // No /RAM
|
||||
|
@ -1744,6 +1747,8 @@ void disconnect_ramdisk(void) {
|
|||
*s3d2 = *s0d1;
|
||||
--(*devcnt);
|
||||
s3d1:
|
||||
return;
|
||||
#if 0
|
||||
if (*s0d1 == *s3d1) {
|
||||
s3d1dev = 0;
|
||||
return; // No /RAM3
|
||||
|
@ -1758,6 +1763,7 @@ s3d1:
|
|||
s3d1vec = *s3d1;
|
||||
*s3d1 = *s0d1;
|
||||
--(*devcnt);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1805,6 +1811,7 @@ void reconnect_ramdisk(void) {
|
|||
printf("Unable to reconnect S3D2");
|
||||
}
|
||||
s3d1:
|
||||
# if 0
|
||||
if (s3d1dev) {
|
||||
*s3d1 = s3d1vec;
|
||||
++(*devcnt);
|
||||
|
@ -1825,6 +1832,7 @@ s3d1:
|
|||
beep();
|
||||
printf("Unable to reconnect S3D1");
|
||||
}
|
||||
#endif
|
||||
done:
|
||||
return;
|
||||
}
|
||||
|
@ -1888,7 +1896,7 @@ void init_aux_banks(void) {
|
|||
uint16_t count;
|
||||
clrscr();
|
||||
revers(1);
|
||||
cprintf("EDIT.SYSTEM v1.27 Bobbi 2020");
|
||||
cprintf("EDIT.SYSTEM v1.30 Bobbi 2021");
|
||||
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) {
|
||||
|
@ -2041,6 +2049,8 @@ struct tabent {
|
|||
*/
|
||||
void file_ui_draw(uint16_t i, uint16_t first, uint16_t selected, uint16_t entries) {
|
||||
struct tabent *entry;
|
||||
if (i < first)
|
||||
return;
|
||||
gotoxy(5, i - first + 6);
|
||||
if (i < entries) {
|
||||
entry = (struct tabent*)iobuf + i;
|
||||
|
@ -2628,6 +2638,7 @@ int edit(char *fname) {
|
|||
}
|
||||
break;
|
||||
case 0x80 + '?': // OA-? "Help"
|
||||
case 0x80 + '/': // OA-/ "Help"
|
||||
help1:
|
||||
help(1);
|
||||
c = cgetc();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
--------------------------------------------------------------------------------
|
||||
v1.27 }}} EDIT.SYSTEM HELP }}} Page One
|
||||
v1.30 }}} EDIT.SYSTEM HELP }}} Page One
|
||||
--------------------------------------+-----------------------------------------
|
||||
Navigation: | Editing:
|
||||
Cursor keys Move the cursor | [Return] Split line
|
||||
|
|
233
apps/email.c
233
apps/email.c
|
@ -1,7 +1,7 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
// emai//er - Simple Email User Agent vaguely inspired by Elm
|
||||
// Handles INBOX in the format created by POP65
|
||||
// Bobbi June 2020 - May 2021
|
||||
// Bobbi June 2020 - June 2021
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdio.h>
|
||||
|
@ -22,8 +22,9 @@
|
|||
// Program constants
|
||||
#define MSGS_PER_PAGE 19 // Number of messages shown on summary screen
|
||||
#define PROMPT_ROW 24 // Row that data entry prompt appears on
|
||||
#define LINEBUFSZ 1000 // According to RFC2822 Section 2.1.1 (998+CRLF)
|
||||
#define READSZ 512 // Size of buffer for copying files
|
||||
#define LINEBUFSZ 1024 // Max line 1000 according to RFC2822 Sect 2.1.1
|
||||
// We use 1024 because this is also used for scrollback
|
||||
|
||||
// Characters
|
||||
#define BELL 0x07
|
||||
|
@ -88,8 +89,7 @@ struct datetime {
|
|||
|
||||
static char filename[80];
|
||||
static char userentry[80];
|
||||
static char linebuf[LINEBUFSZ];
|
||||
static char halfscreen[0x0400];
|
||||
static uint8_t linebuf[LINEBUFSZ];
|
||||
static FILE *fp;
|
||||
static struct emailhdrs *headers;
|
||||
static uint16_t selection = 1;
|
||||
|
@ -553,7 +553,7 @@ uint8_t hexdigit(char c) {
|
|||
* p - Pointer to buffer to decode. Results written in place.
|
||||
* Returns number of bytes decoded
|
||||
*/
|
||||
uint16_t decode_quoted_printable(uint8_t *p) {
|
||||
uint16_t decode_quoted_printable(uint8_t *p, uint8_t isheader) {
|
||||
uint16_t i = 0, j = 0;
|
||||
uint8_t c;
|
||||
while (c = p[i]) {
|
||||
|
@ -564,7 +564,7 @@ uint16_t decode_quoted_printable(uint8_t *p) {
|
|||
c = 16 * hexdigit(p[i + 1]) + hexdigit(p[i + 2]);
|
||||
p[j++] = c;
|
||||
i += 3;
|
||||
} else if (c == '?')
|
||||
} else if ((c == '?') && isheader)
|
||||
break;
|
||||
else {
|
||||
p[j++] = c;
|
||||
|
@ -589,18 +589,19 @@ void printfield(char *s, uint8_t start, uint8_t end) {
|
|||
#pragma code-name (pop)
|
||||
|
||||
/*
|
||||
* Decode Subject header which may be encoded Quoted-Printable or Base64
|
||||
* Decode Subject or From header which may be encoded
|
||||
* Quoted-Printable or Base64
|
||||
* p - pointer to subject header content
|
||||
* Decoded (and sanitized) text is returned in linebuf[]
|
||||
*/
|
||||
void decode_subject(char *p) {
|
||||
void decode_qp_header(char *p) {
|
||||
uint8_t i = 0, j = 0;
|
||||
if (strncasecmp(p, "=?utf-8?", 8) == 0) {
|
||||
strcpy(linebuf, p + 10); // Skip '=?UTF-8?x?'
|
||||
if (p[8] == 'B')
|
||||
decode_base64(linebuf);
|
||||
else
|
||||
decode_quoted_printable(linebuf);
|
||||
decode_quoted_printable(linebuf, 1);
|
||||
while (linebuf[i]) {
|
||||
if ((linebuf[i] <= 127) && (linebuf[i] >= 32))
|
||||
linebuf[j++] = linebuf[i];
|
||||
|
@ -633,9 +634,10 @@ void print_one_email_summary(struct emailhdrs *h, uint8_t inverse) {
|
|||
putchar('|');
|
||||
printfield(h->date, 0, 16);
|
||||
putchar('|');
|
||||
printfield(h->from, 0, 20);
|
||||
decode_qp_header(h->from);
|
||||
printfield(linebuf, 0, 20);
|
||||
putchar('|');
|
||||
decode_subject(h->subject);
|
||||
decode_qp_header(h->subject);
|
||||
printfield(linebuf, 0, 39);
|
||||
putchar(NORMAL);
|
||||
}
|
||||
|
@ -923,6 +925,21 @@ void sanitize_filename(char *s) {
|
|||
|
||||
enum aux_ops {FROMAUX, TOAUX};
|
||||
|
||||
/*
|
||||
* Asm code for copyaux()
|
||||
*/
|
||||
#pragma optimize (push, off)
|
||||
void copyauxasm(enum aux_ops dir) {
|
||||
if (dir == TOAUX)
|
||||
__asm__("sec"); // Copy main->aux
|
||||
else
|
||||
__asm__("clc"); // Copy aux->main
|
||||
__asm__("sta $c000"); // Turn off 80STORE
|
||||
__asm__("jsr $c311"); // AUXMOVE
|
||||
__asm__("sta $c001"); // Turn on 80STORE
|
||||
}
|
||||
#pragma optimize (pop)
|
||||
|
||||
/*
|
||||
* Aux memory copy routine
|
||||
*/
|
||||
|
@ -933,72 +950,58 @@ void copyaux(char *src, char *dst, uint16_t len, enum aux_ops dir) {
|
|||
*a1 = src;
|
||||
*a2 = src + len - 1; // AUXMOVE moves length+1 bytes!!
|
||||
*a4 = dst;
|
||||
if (dir == TOAUX)
|
||||
__asm__("sec"); // Copy main->aux
|
||||
else
|
||||
__asm__("clc"); // Copy aux->main
|
||||
__asm__("sta $c000"); // Turn off 80STORE
|
||||
__asm__("jsr $c311"); // AUXMOVE
|
||||
__asm__("sta $c001"); // Turn on 80STORE
|
||||
copyauxasm(dir);
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the current screen to the scrollback file
|
||||
* We preserve linebuf[] by copying it to aux 0x0800, and recover
|
||||
* it at the end. This saves us having an additional 1KB buffer.
|
||||
*/
|
||||
void save_screen_to_scrollback(FILE *fp) {
|
||||
copyaux(linebuf, (void*)0x800, 1024, TOAUX); // Preserve linebuf[]
|
||||
if (fwrite((void*)0x0400, 0x0400, 1, fp) != 1) { // Even cols
|
||||
error(ERR_NONFATAL, sb_err);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
copyaux((void*)0x400, halfscreen, 0x400, FROMAUX);
|
||||
if (fwrite(halfscreen, 0x0400, 1, fp) != 1) { // Odd cols
|
||||
copyaux((void*)0x400, linebuf, 0x400, FROMAUX);
|
||||
if (fwrite(linebuf, 0x0400, 1, fp) != 1) { // Odd cols
|
||||
error(ERR_NONFATAL, sb_err);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
copyaux((void*)0x800, linebuf, 1024, FROMAUX); // Recover linebuf[]
|
||||
}
|
||||
|
||||
/*
|
||||
* Load a screen from the scrollback file
|
||||
* Screens are numbered 1, 2, 3 ...
|
||||
* Does not trash the screen holes, which must be preserved!
|
||||
* We preserve linebuf[] by copying it to aux 0x0800, and recover
|
||||
* it at the end. This saves us having an additional 1KB buffer.
|
||||
*/
|
||||
void load_screen_from_scrollback(FILE *fp, uint8_t screen) {
|
||||
uint8_t i;
|
||||
copyaux(linebuf, (void*)0x800, 1024, TOAUX); // Preserve linebuf[]
|
||||
if (fseek(fp, (screen - 1) * 0x0800, SEEK_SET) ||
|
||||
(fread(halfscreen, 0x0400, 1, fp) != 1)) { // Even cols
|
||||
(fread(linebuf, 0x0400, 1, fp) != 1)) { // Even cols
|
||||
error(ERR_NONFATAL, sb_err);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
for (i = 0; i < 8; ++i)
|
||||
memcpy((char*)0x400 + i * 0x80, halfscreen + i * 0x80, 0x078);
|
||||
if (fread(halfscreen, 0x0400, 1, fp) != 1) { // Odd cols
|
||||
memcpy((char*)0x400 + i * 0x80, linebuf + i * 0x80, 0x078);
|
||||
if (fread(linebuf, 0x0400, 1, fp) != 1) { // Odd cols
|
||||
error(ERR_NONFATAL, sb_err);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
for (i = 0; i < 8; ++i)
|
||||
copyaux(halfscreen + i * 0x80, (char*)0x400 + i * 0x80, 0x078, TOAUX);
|
||||
copyaux(linebuf + i * 0x80, (char*)0x400 + i * 0x80, 0x078, TOAUX);
|
||||
if (fseek(fp, 0, SEEK_END)) {
|
||||
error(ERR_NONFATAL, sb_err);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if text at p is a MIME boundary.
|
||||
* p is assumed to point to start of line.
|
||||
* Valid MIME boundaries start with "--", then have a char sequence
|
||||
* with no spaces, then CR
|
||||
*/
|
||||
uint8_t is_mime_boundary(char *p) {
|
||||
if (strncmp(p, "--", 2)) // Must start with "--"
|
||||
return 0;
|
||||
p += 2;
|
||||
do {
|
||||
if (*p == ' ') // Can not contain ' '
|
||||
return 0;
|
||||
++p;
|
||||
} while (*p && (*p != '\r'));
|
||||
return 1;
|
||||
done:
|
||||
copyaux((void*)0x800, linebuf, 1024, FROMAUX); // Recover linebuf[]
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1023,6 +1026,65 @@ enum mime_enc mime_encoding(char *s) {
|
|||
return ENC_SKIP;
|
||||
}
|
||||
|
||||
/*
|
||||
* Support three levels of nesting
|
||||
*/
|
||||
static char mime_boundaries[3][71];
|
||||
static uint8_t mime_idx;
|
||||
|
||||
/*
|
||||
* linebuf[] is expected to contain the Content-Type: header
|
||||
* Parse it and obtain the MIME boundary, write it to buf[]
|
||||
* Returns 1 if boundary was found or if there is no room for more
|
||||
* boundaries to be stored, 0 if boundary was not found.
|
||||
*
|
||||
* Three levels of nesting are supported, to avoid mime_boundaries[]
|
||||
* chewing up too much memory.
|
||||
*/
|
||||
uint8_t mime_get_boundary(void) {
|
||||
char *p, *q;
|
||||
if (mime_idx > 2)
|
||||
return 1; // No point in trying if nested too deep
|
||||
p = strstr(linebuf, "boundary=");
|
||||
if (p) {
|
||||
q = strstr(p + 9, "\r"); // Terminated by EOL ..
|
||||
if (!q)
|
||||
q = strstr(p + 9, ";"); // .. or by semicolon
|
||||
if (q) {
|
||||
if (*(p + 9) == '\"') {
|
||||
// Trim quotes, if present
|
||||
strncpy(mime_boundaries[mime_idx], p + 10, q - p - 10);
|
||||
mime_boundaries[mime_idx][q - p - 11] = '\0';
|
||||
} else {
|
||||
strncpy(mime_boundaries[mime_idx], p + 9, q - p - 9);
|
||||
mime_boundaries[mime_idx][q - p - 9] = '\0';
|
||||
}
|
||||
//printf("Boundary: %s\n", mime_boundaries[mime_idx]);
|
||||
++mime_idx;
|
||||
}
|
||||
return 1; // Got boundary
|
||||
}
|
||||
return 0; // Did not get boundary
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if text at p is a MIME boundary.
|
||||
* Uses the MIME boundaries stored in mime_boundaries[]
|
||||
* p is assumed to point to start of line.
|
||||
*/
|
||||
uint8_t is_mime_boundary(char *p) {
|
||||
uint8_t i;
|
||||
if (strncmp(p, "--", 2)) // Must start with "--"
|
||||
return 0;
|
||||
p += 2;
|
||||
for (i = 0; i < mime_idx; ++i) {
|
||||
// Match boundary followed by '\r' or "--" (or anything else, actually)
|
||||
if (strncmp(mime_boundaries[i], p, strlen(mime_boundaries[i])) == 0)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display email with simple pager functionality
|
||||
* Includes support for decoding MIME headers
|
||||
|
@ -1057,6 +1119,7 @@ void email_pager(struct emailhdrs *h) {
|
|||
pos = hh.skipbytes;
|
||||
fseek(fp, pos, SEEK_SET); // Skip over headers
|
||||
mime_enc = ENC_7BIT;
|
||||
mime_idx = 0;
|
||||
restart:
|
||||
eof = 0;
|
||||
linecount = 0;
|
||||
|
@ -1081,7 +1144,8 @@ restart:
|
|||
fputs("Date: ", stdout);
|
||||
printfield(hh.date, 0, 39);
|
||||
fputs("\nFrom: ", stdout);
|
||||
printfield(hh.from, 0, 70);
|
||||
decode_qp_header(hh.from);
|
||||
printfield(linebuf, 0, 70);
|
||||
if (strncmp(hh.to, "News:", 5) == 0) {
|
||||
fputs("\nNewsgrp: ", stdout);
|
||||
printfield(&(hh.to[5]), 0, 70);
|
||||
|
@ -1098,7 +1162,7 @@ restart:
|
|||
}
|
||||
}
|
||||
fputs("\nSubject: ", stdout);
|
||||
decode_subject(hh.subject);
|
||||
decode_qp_header(hh.subject);
|
||||
printfield(linebuf, 0, 70);
|
||||
fputs("\n\n", stdout);
|
||||
get_line(fp, 1, linebuf, LINEBUFSZ, &pos); // Reset buffer
|
||||
|
@ -1133,8 +1197,8 @@ restart:
|
|||
printf("\n<Not showing HTML>\n");
|
||||
mime = 1;
|
||||
} else {
|
||||
mime = 2 + mime_get_boundary(); // 3 if boundary, 2 otherwise
|
||||
mime_binary = 1;
|
||||
mime = 3;
|
||||
}
|
||||
} else if (!strncasecmp(writep, cte, 27)) {
|
||||
mime = 3;
|
||||
|
@ -1172,12 +1236,14 @@ prompt_dl:
|
|||
mime_enc = ENC_SKIP; // Skip over binary MIME parts with no filename
|
||||
printf("\n");
|
||||
}
|
||||
} else if (mime == 2) {
|
||||
mime = 2 + mime_get_boundary(); // 3 if boundary, 2 otherwise
|
||||
}
|
||||
readp = writep = NULL;
|
||||
} else if (mime == 4) {
|
||||
switch (mime_enc) {
|
||||
case ENC_QP:
|
||||
chars = decode_quoted_printable(writep);
|
||||
chars = decode_quoted_printable(writep, 0);
|
||||
break;
|
||||
case ENC_B64:
|
||||
chars = decode_base64(writep);
|
||||
|
@ -1269,8 +1335,10 @@ retry:
|
|||
get_line(fp, 1, linebuf, LINEBUFSZ, &pos); // Reset buffer
|
||||
do {
|
||||
get_line(fp, 0, linebuf, LINEBUFSZ, &pos);
|
||||
if (!strncasecmp(linebuf, ct, 14))
|
||||
mime = 4;
|
||||
if (!strncasecmp(linebuf, ct, 14)) {
|
||||
mime = 3 + mime_get_boundary(); // 4 if boundary, 3 otherwise
|
||||
continue;
|
||||
}
|
||||
if (!strncasecmp(linebuf, cte, 27)) {
|
||||
mime = 4;
|
||||
mime_enc = mime_encoding(linebuf);
|
||||
|
@ -1278,6 +1346,11 @@ retry:
|
|||
mime = 0;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (mime == 3) { // We have Content-Type but no boundary yet
|
||||
mime_get_boundary();
|
||||
mime = 4;
|
||||
}
|
||||
} while (linebuf[0] != '\r');
|
||||
pos = hh.skipbytes;
|
||||
|
@ -1575,7 +1648,7 @@ esc_pressed:
|
|||
* Adds 'Re: ' to subject line unless it is already there
|
||||
*/
|
||||
void prefix_subject(FILE *f, char *subject, char *prefix) {
|
||||
decode_subject(subject);
|
||||
decode_qp_header(subject);
|
||||
fprintf(f, "Subject: %s%s\r",
|
||||
(strncmp(subject, prefix, strlen(prefix)) ? prefix : ""), linebuf);
|
||||
}
|
||||
|
@ -1613,16 +1686,18 @@ uint8_t write_email_headers(FILE *fp1, FILE *fp2, struct emailhdrs *h,
|
|||
if (mode == 'R') {
|
||||
truncate_header(h->date, buf, 40);
|
||||
fprintf(fp2, "On %s, ", buf);
|
||||
truncate_header(h->from, buf, 80);
|
||||
decode_qp_header(h->from);
|
||||
truncate_header(linebuf, buf, 80);
|
||||
fprintf(fp2, "%s wrote:\r\r", buf);
|
||||
} else {
|
||||
fprintf(fp2, "-------- Forwarded Message --------\r");
|
||||
decode_subject(h->subject);
|
||||
decode_qp_header(h->subject);
|
||||
truncate_header(linebuf, buf, 80);
|
||||
fprintf(fp2, "Subject: %s\r", buf);
|
||||
truncate_header(h->date, buf, 40);
|
||||
fprintf(fp2, "Date: %s\r", buf);
|
||||
truncate_header(h->from, buf, 80);
|
||||
decode_qp_header(h->from);
|
||||
truncate_header(linebuf, buf, 80);
|
||||
fprintf(fp2, "From: %s\r", buf);
|
||||
truncate_header(h->to, buf, 80);
|
||||
fprintf(fp2, "To: %s\r\r", buf);
|
||||
|
@ -1721,19 +1796,22 @@ char prompt_okay(char *msg) {
|
|||
*/
|
||||
void get_email_body(struct emailhdrs *h, FILE *f, char mode) {
|
||||
uint16_t chars;
|
||||
char c, *readp, *writep;
|
||||
uint8_t c, *readp, *writep;
|
||||
uint32_t pos = 0;
|
||||
const int8_t *b = b64dec - 43;
|
||||
uint8_t mime = 0, mime_enc = ENC_7BIT, mime_binary = 0;
|
||||
uint8_t mime = 0, mime_enc = ENC_7BIT, mime_binary, mime_hasfile;
|
||||
fseek(fp, pos, SEEK_SET);
|
||||
get_line(fp, 1, linebuf, LINEBUFSZ, &pos); // Reset buffer
|
||||
mime_idx = 0;
|
||||
do {
|
||||
spinner();
|
||||
get_line(fp, 0, linebuf, LINEBUFSZ, &pos);
|
||||
if (!strncasecmp(linebuf, mime_ver, 17))
|
||||
mime = 1;
|
||||
if (!strncasecmp(linebuf, ct, 14))
|
||||
mime = 4;
|
||||
if (!strncasecmp(linebuf, ct, 14)) {
|
||||
mime = 3 + mime_get_boundary(); // 4 if boundary, 3 otherwise
|
||||
continue;
|
||||
}
|
||||
if (!strncasecmp(linebuf, cte, 27)) {
|
||||
mime = 4;
|
||||
mime_enc = mime_encoding(linebuf);
|
||||
|
@ -1741,6 +1819,11 @@ void get_email_body(struct emailhdrs *h, FILE *f, char mode) {
|
|||
error(ERR_NONFATAL, unsupp_enc, linebuf + 27);
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (mime == 3) { // We have Content-Type but no boundary yet
|
||||
mime_get_boundary();
|
||||
mime = 4;
|
||||
}
|
||||
} while (linebuf[0] != '\r');
|
||||
pos = h->skipbytes;
|
||||
|
@ -1748,8 +1831,10 @@ void get_email_body(struct emailhdrs *h, FILE *f, char mode) {
|
|||
readp = linebuf;
|
||||
writep = linebuf;
|
||||
mime_binary = 0;
|
||||
mime_hasfile = 0;
|
||||
get_line(fp, 1, linebuf, LINEBUFSZ, &pos); // Reset buffer
|
||||
while (1) {
|
||||
spinner();
|
||||
if (!readp)
|
||||
readp = linebuf;
|
||||
if (!writep)
|
||||
|
@ -1757,22 +1842,20 @@ void get_email_body(struct emailhdrs *h, FILE *f, char mode) {
|
|||
if (get_line(fp, 0, writep, (LINEBUFSZ - (writep - linebuf)), &pos) == 0)
|
||||
break;
|
||||
if ((mime >= 1) && is_mime_boundary(writep)) {
|
||||
if ((mime == 4) && !mime_binary) // End of Text/Plain MIME section
|
||||
break;
|
||||
mime = 2;
|
||||
mime_enc = ENC_7BIT;
|
||||
mime_binary = 0;
|
||||
mime_hasfile = 0;
|
||||
readp = writep = NULL;
|
||||
} else if ((mime < 4) && (mime >= 2)) {
|
||||
if (!strncasecmp(writep, ct, 14)) {
|
||||
if (!strncmp(writep + 14, "text/plain", 10)) {
|
||||
mime = 3;
|
||||
} else if (!strncmp(writep + 14, "text/html", 9)) {
|
||||
printf("\n<Not showing HTML>\n");
|
||||
mime = 1;
|
||||
} else {
|
||||
mime = 2 + mime_get_boundary(); // 3 if boundary, 2 otherwise
|
||||
mime_binary = 1;
|
||||
mime = 3;
|
||||
}
|
||||
} else if (!strncasecmp(writep, cte, 27)) {
|
||||
mime = 3;
|
||||
|
@ -1781,16 +1864,20 @@ void get_email_body(struct emailhdrs *h, FILE *f, char mode) {
|
|||
printf(unsupp_enc, writep + 27);
|
||||
mime = 1;
|
||||
}
|
||||
} else if (strstr(writep, "filename=")) {
|
||||
mime_hasfile = 1;
|
||||
} else if ((mime == 3) && (!strncmp(writep, "\r", 1))) {
|
||||
mime = 4;
|
||||
if (mime_binary)
|
||||
mime_enc = ENC_SKIP; // Skip over binary MIME parts
|
||||
} else if (mime == 2) {
|
||||
mime = 2 + mime_get_boundary(); // 3 if boundary, 2 otherwise
|
||||
}
|
||||
readp = writep = NULL;
|
||||
} else if (mime == 4) {
|
||||
switch (mime_enc) {
|
||||
case ENC_QP:
|
||||
chars = decode_quoted_printable(writep);
|
||||
chars = decode_quoted_printable(writep, 0);
|
||||
break;
|
||||
case ENC_B64:
|
||||
chars = decode_base64(writep);
|
||||
|
@ -1801,7 +1888,7 @@ void get_email_body(struct emailhdrs *h, FILE *f, char mode) {
|
|||
}
|
||||
}
|
||||
if (readp) {
|
||||
if ((mime == 0) || ((mime == 4) && !mime_binary)) {
|
||||
if ((mime == 0) || ((mime == 4) && !mime_hasfile)) {
|
||||
do {
|
||||
c = word_wrap_line(f, &readp, 78, mode);
|
||||
} while (c == 1);
|
||||
|
@ -1976,7 +2063,7 @@ uint16_t get_db_index(void) {
|
|||
* on the current message. If they are, prompt the user and, if affirmative,
|
||||
* iterate through the tagged messages calling copy_to_mailbox() on each.
|
||||
*/
|
||||
uint8_t copy_to_mailbox_tagged(char *mbox, uint8_t delete) {
|
||||
uint8_t copy_to_mailbox_tagged(char *mbox, char mode, uint8_t delete) {
|
||||
uint16_t count = 0, tagcount = 0;
|
||||
struct emailhdrs *h;
|
||||
uint16_t l;
|
||||
|
@ -1985,7 +2072,8 @@ uint8_t copy_to_mailbox_tagged(char *mbox, uint8_t delete) {
|
|||
copy_to_mailbox(h, get_db_index(), mbox, delete, ' ');
|
||||
return 0;
|
||||
}
|
||||
snprintf(filename, 80, "%u tagged - ", total_tag);
|
||||
snprintf(filename, 80, "%s %u tagged - ",
|
||||
(mode == 'C' ? "Copy" : (mode == 'M' ? "Move" : "Archive")), total_tag);
|
||||
if (!prompt_okay(filename))
|
||||
return 0;
|
||||
h = (struct emailhdrs*)malloc(sizeof(struct emailhdrs));
|
||||
|
@ -2265,7 +2353,7 @@ void keyboard_hdlr(void) {
|
|||
if (h) {
|
||||
c = prompt_for_name("Copy to mbox", 1);
|
||||
if ((c != 0) && (c != 255))
|
||||
copy_to_mailbox_tagged(userentry, 0);
|
||||
copy_to_mailbox_tagged(userentry, 'C', 0);
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
|
@ -2273,14 +2361,14 @@ void keyboard_hdlr(void) {
|
|||
if (h) {
|
||||
c = prompt_for_name("Move to mbox", 1);
|
||||
if ((c != 0) && (c != 255))
|
||||
copy_to_mailbox_tagged(userentry, 1);
|
||||
copy_to_mailbox_tagged(userentry, 'M', 1);
|
||||
}
|
||||
break;
|
||||
case 'a':
|
||||
case 'A':
|
||||
if (h) {
|
||||
goto_prompt_row();
|
||||
copy_to_mailbox_tagged("RECEIVED", 1);
|
||||
copy_to_mailbox_tagged("RECEIVED", 'A', 1);
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
|
@ -2353,6 +2441,7 @@ void keyboard_hdlr(void) {
|
|||
load_app(APP_SMTP);
|
||||
break;
|
||||
case 0x80 + '?': // OA-? "Help"
|
||||
case 0x80 + '/': // OA-/ "Help"
|
||||
help(1);
|
||||
c = cgetc();
|
||||
email_summary();
|
||||
|
|
|
@ -4,7 +4,7 @@ passwordgoeshere
|
|||
NODELETE
|
||||
192.168.10.2:25
|
||||
apple2.local
|
||||
/IP65
|
||||
/DATA/EMAIL
|
||||
/H1/IP65
|
||||
/H1/DOCUMENTS/EMAIL
|
||||
bobbi.8bit@gmail.com
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
// EMAIL_COMMON.H
|
||||
// Definitions shared between pop65.c and email.c
|
||||
// Bobbi June 2020
|
||||
// Bobbi August 2021
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PROGNAME "emai//er v2.1.4"
|
||||
#define PROGNAME "emai//er v2.1.14"
|
||||
|
||||
// Configuration params from EMAIL.CFG
|
||||
char cfg_server[40]; // IP of POP3 server
|
||||
|
|
|
@ -42,7 +42,7 @@ void send(unsigned char flags, const char* str, ...)
|
|||
}
|
||||
|
||||
va_start(args, str);
|
||||
send_size += vsnprintf(send_buffer + send_size, sizeof(send_buffer) - send_size, str, args);
|
||||
send_size += vsnprintf((char*)send_buffer + send_size, sizeof(send_buffer) - send_size, str, args);
|
||||
va_end(args);
|
||||
|
||||
if (flags & SEND_LAST || sizeof(send_buffer) - send_size < 1024 / 4)
|
||||
|
@ -309,9 +309,9 @@ int main(void)
|
|||
{
|
||||
read(file, ð_init, 1);
|
||||
close(file);
|
||||
eth_init &= ~'0';
|
||||
eth_init &= 7;
|
||||
}
|
||||
printf("- %d", eth_init);
|
||||
printf("- %u", eth_init);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ int ifttt_trigger(const char* key, const char* event,
|
|||
return -1;
|
||||
}
|
||||
|
||||
len = url_download(url, download, sizeof(download));
|
||||
len = url_download(url, (uint8_t*)download, sizeof(download));
|
||||
|
||||
if (len < 12)
|
||||
{
|
||||
|
|
|
@ -78,15 +78,15 @@ struct linenoiseState {
|
|||
int history_index; /* The history index we are currently editing. */
|
||||
};
|
||||
|
||||
enum KEY_ACTION{
|
||||
CTRL_A = 1, /* Ctrl+a */
|
||||
CTRL_B = 2, /* Ctrl-b */
|
||||
CTRL_C = 3, /* Ctrl-c */
|
||||
CTRL_D = 4, /* Ctrl-d */
|
||||
CTRL_E = 5, /* Ctrl-e */
|
||||
CTRL_F = 6, /* Ctrl-f */
|
||||
CTRL_N = 14, /* Ctrl-n */
|
||||
CTRL_P = 16 /* Ctrl-p */
|
||||
enum KEY_ACTION {
|
||||
CTRL_A = 1, /* Ctrl+a */
|
||||
CTRL_B = 2, /* Ctrl-b */
|
||||
CTRL_C = 3, /* Ctrl-c */
|
||||
CTRL_D = 4, /* Ctrl-d */
|
||||
CTRL_E = 5, /* Ctrl-e */
|
||||
CTRL_F = 6, /* Ctrl-f */
|
||||
CTRL_N = 14, /* Ctrl-n */
|
||||
CTRL_P = 16 /* Ctrl-p */
|
||||
};
|
||||
|
||||
static void refreshLine(struct linenoiseState *l);
|
||||
|
@ -102,14 +102,16 @@ static int getColumns() {
|
|||
return cols;
|
||||
}
|
||||
|
||||
#ifdef __APPLE2__
|
||||
#pragma code-name (push, "LC")
|
||||
#endif
|
||||
|
||||
/* Beep, used for completion when there is nothing to complete or when all
|
||||
* the choices were already shown. */
|
||||
static void linenoiseBeep(void) {
|
||||
#ifdef __APPLE2__
|
||||
unsigned char x = wherex();
|
||||
#endif
|
||||
putchar('\a');
|
||||
#ifdef __APPLE2__
|
||||
gotox(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ============================== Completion ================================ */
|
||||
|
@ -123,6 +125,10 @@ static void freeCompletions(linenoiseCompletions *lc) {
|
|||
free(lc->cvec);
|
||||
}
|
||||
|
||||
#ifdef __APPLE2__
|
||||
#pragma code-name (push, "LC")
|
||||
#endif
|
||||
|
||||
/* This is an helper function for linenoiseEdit() and is called when the
|
||||
* user types the <tab> key in order to complete the string currently in the
|
||||
* input.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
144.76.35.198:119
|
||||
usergoeshere
|
||||
passwordgoeshere
|
||||
/IP65
|
||||
/DATA/EMAIL
|
||||
/H1/IP65
|
||||
/H1/DOCUMENTS/EMAIL
|
||||
bobbi.8bit@gmail.com
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#define BELL 7
|
||||
#define BACKSPACE 8
|
||||
|
||||
#define LOGFILE "NNTP65.LOG"
|
||||
|
||||
// Both pragmas are obligatory to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment registers.
|
||||
#pragma optimize (on)
|
||||
|
@ -327,7 +329,7 @@ void readconfigfile(void) {
|
|||
|
||||
colon = strchr(cfg_server, ':');
|
||||
if (!colon)
|
||||
nntp_port = 110;
|
||||
nntp_port = 119;
|
||||
else {
|
||||
nntp_port = atoi(colon + 1);
|
||||
*colon = '\0';
|
||||
|
@ -559,7 +561,8 @@ void update_mailbox(char *mbox) {
|
|||
update_email_db(mbox, &hdrs);
|
||||
puts("");
|
||||
|
||||
sprintf(filename, "%s/NEWS.SPOOL/NEWS.%u", cfg_emaildir, msg);
|
||||
//sprintf(filename, "%s/NEWS.SPOOL/NEWS.%u", cfg_emaildir, msg);
|
||||
sprintf(filename, "%s/NEWS.SPOOL/%s", cfg_emaildir, d->d_name);
|
||||
if (unlink(filename))
|
||||
printf("Can't delete %s\n", filename);
|
||||
}
|
||||
|
@ -568,7 +571,9 @@ void update_mailbox(char *mbox) {
|
|||
|
||||
void main(int argc, char *argv[]) {
|
||||
uint32_t nummsgs, lownum, highnum, msgnum, msg;
|
||||
uint16_t msgcount, i;
|
||||
char sendbuf[80];
|
||||
FILE *logfp;
|
||||
uint8_t eth_init = ETH_INIT_DEFAULT;
|
||||
|
||||
if ((argc == 2) && (strcmp(argv[1], "EMAIL") == 0))
|
||||
|
@ -632,11 +637,12 @@ void main(int argc, char *argv[]) {
|
|||
}
|
||||
|
||||
// Copy IP config from IP65 to W5100
|
||||
w5100_config(eth_init);
|
||||
w5100_init(eth_init);
|
||||
w5100_config();
|
||||
|
||||
printf("Ok\nConnecting to %s (%u) - ", cfg_server, nntp_port);
|
||||
|
||||
if (!w5100_connect(parse_dotted_quad(cfg_server), nntp_port)) {
|
||||
if (!w5100_connect_addr(parse_dotted_quad(cfg_server), nntp_port)) {
|
||||
printf("Fail\n");
|
||||
error_exit();
|
||||
}
|
||||
|
@ -649,19 +655,28 @@ void main(int argc, char *argv[]) {
|
|||
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();
|
||||
// Skip authentication?
|
||||
if (strcmp(cfg_user, "-") != 0) {
|
||||
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();
|
||||
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();
|
||||
}
|
||||
if (expect(buf, "281")) // Authentication successful
|
||||
error_exit();
|
||||
|
||||
// Make empty log file
|
||||
_filetype = PRODOS_T_TXT;
|
||||
_auxtype = 0;
|
||||
logfp = fopen(LOGFILE, "w");
|
||||
fclose(logfp);
|
||||
|
||||
while (1) {
|
||||
msg = fscanf(newsgroupsfp, "%s %s %ld", newsgroup, mailbox, &msgnum);
|
||||
|
@ -703,6 +718,7 @@ void main(int argc, char *argv[]) {
|
|||
break;
|
||||
}
|
||||
|
||||
msgcount = 0;
|
||||
while (1) {
|
||||
if (!w5100_tcp_send_recv("NEXT\r\n", buf, NETBUFSZ, DO_SEND, CMD_MODE)) {
|
||||
error_exit();
|
||||
|
@ -724,11 +740,23 @@ void main(int argc, char *argv[]) {
|
|||
}
|
||||
spinner(filesize, 1); // Cleanup spinner
|
||||
fclose(fp);
|
||||
++msgcount;
|
||||
}
|
||||
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);
|
||||
|
||||
_filetype = PRODOS_T_TXT;
|
||||
_auxtype = 0;
|
||||
logfp = fopen(LOGFILE, "a");
|
||||
if (logfp) {
|
||||
fprintf(logfp, " %s", newsgroup);
|
||||
for (i = 0; i < (30 - strlen(newsgroup)); ++i)
|
||||
fputc(' ', logfp);
|
||||
fprintf(logfp, "%5u messages retrieved to mailbox %s\n", msgcount, mailbox);
|
||||
fclose(logfp);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(newsgroupsfp);
|
||||
|
@ -752,5 +780,17 @@ void main(int argc, char *argv[]) {
|
|||
printf("Disconnecting\n");
|
||||
w5100_disconnect();
|
||||
|
||||
logfp = fopen(LOGFILE, "r");
|
||||
if (logfp) {
|
||||
puts("\nNNTP65 Session Summary:\n");
|
||||
i = fgetc(logfp);
|
||||
while (!feof(logfp)) {
|
||||
putchar(i);
|
||||
i = fgetc(logfp);
|
||||
}
|
||||
fclose(logfp);
|
||||
puts("");
|
||||
}
|
||||
|
||||
confirm_exit();
|
||||
}
|
||||
|
|
|
@ -369,7 +369,7 @@ void readconfigfile(void) {
|
|||
|
||||
colon = strchr(cfg_server, ':');
|
||||
if (!colon)
|
||||
nntp_port = 110;
|
||||
nntp_port = 119;
|
||||
else
|
||||
nntp_port = atoi(colon + 1);
|
||||
}
|
||||
|
@ -548,7 +548,8 @@ void main(int argc, char *argv[]) {
|
|||
printf("Ok\n");
|
||||
|
||||
// Copy IP config from IP65 to W5100
|
||||
w5100_config(eth_init);
|
||||
w5100_init(eth_init);
|
||||
w5100_config();
|
||||
|
||||
sprintf(filename, "%s/NEWS.OUTBOX", cfg_emaildir);
|
||||
dp = opendir(filename);
|
||||
|
@ -577,7 +578,7 @@ void main(int argc, char *argv[]) {
|
|||
linecount = 0;
|
||||
|
||||
while (1) {
|
||||
if ((get_line(fp, 0, linebuf, LINEBUFSZ) == 0) || (linecount == 20))
|
||||
if ((get_line(fp, 0, linebuf, LINEBUFSZ) == 0) || (linecount == 20) || (linebuf[0] == '\r'))
|
||||
break;
|
||||
++linecount;
|
||||
if (!strncmp(linebuf, "Newsgroups: ", 12))
|
||||
|
@ -632,7 +633,7 @@ sendmessage:
|
|||
if (!connected) {
|
||||
printf("\nConnecting to %s (%u) - ", cfg_server, nntp_port);
|
||||
|
||||
if (!w5100_connect(parse_dotted_quad(cfg_server), nntp_port)) {
|
||||
if (!w5100_connect_addr(parse_dotted_quad(cfg_server), nntp_port)) {
|
||||
printf("Fail\n");
|
||||
error_exit();
|
||||
}
|
||||
|
@ -645,19 +646,22 @@ sendmessage:
|
|||
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();
|
||||
// Skip authentication?
|
||||
if (strcmp(cfg_user, "-") != 0) {
|
||||
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();
|
||||
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();
|
||||
}
|
||||
if (expect(buf, "281")) // Authentication successful
|
||||
error_exit();
|
||||
|
||||
connected = 1;
|
||||
}
|
||||
|
|
|
@ -534,17 +534,19 @@ void main(int argc, char *argv[]) {
|
|||
// Abort on Ctrl-C to be consistent with Linenoise
|
||||
abort_key = 0x83;
|
||||
|
||||
w5100_init(eth_init);
|
||||
|
||||
printf("Ok\nObtaining IP address - ");
|
||||
if (dhcp_init()) {
|
||||
ip65_error_exit();
|
||||
}
|
||||
|
||||
// Copy IP config from IP65 to W5100
|
||||
w5100_config(eth_init);
|
||||
w5100_config();
|
||||
|
||||
printf("Ok\nConnecting to %s - ", cfg_server);
|
||||
|
||||
if (!w5100_connect(parse_dotted_quad(cfg_server), pop_port)) {
|
||||
if (!w5100_connect_addr(parse_dotted_quad(cfg_server), pop_port)) {
|
||||
printf("Fail\n");
|
||||
error_exit();
|
||||
}
|
||||
|
|
313
apps/print65.c
Normal file
313
apps/print65.c
Normal file
|
@ -0,0 +1,313 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
// PRINT65
|
||||
// Print files over the network to an HP Jetdirect printer
|
||||
// Bobbi June 2021
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#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];
|
||||
|
||||
static uint8_t exec_email_on_exit = 0;
|
||||
static char filename[256];
|
||||
static FILE *fp;
|
||||
static uint32_t filesize;
|
||||
static uint16_t jetdirect_port;
|
||||
|
||||
/*
|
||||
* Keypress before quit
|
||||
*/
|
||||
void confirm_exit(void) {
|
||||
printf("\n[Press Any Key]");
|
||||
cgetc();
|
||||
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
|
||||
|
||||
// Read file handle fp and send message over TCP
|
||||
bool w5100_tcp_send() {
|
||||
|
||||
//
|
||||
// Handle sending of email body
|
||||
//
|
||||
uint16_t pos = 0;
|
||||
uint8_t cont = 1;
|
||||
uint16_t snd;
|
||||
uint16_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");
|
||||
len = 2;
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read parms from PRINT.CFG
|
||||
*/
|
||||
void readconfigfile(void) {
|
||||
char *colon;
|
||||
fp = fopen("PRINT.CFG", "r");
|
||||
if (!fp) {
|
||||
puts("Can't open config file PRINT.CFG");
|
||||
error_exit();
|
||||
}
|
||||
fscanf(fp, "%s", cfg_server);
|
||||
fclose(fp);
|
||||
|
||||
colon = strchr(cfg_server, ':');
|
||||
if (!colon)
|
||||
jetdirect_port = 9100;
|
||||
else {
|
||||
jetdirect_port = atoi(colon + 1);
|
||||
*colon = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
void main(int argc, char *argv[]) {
|
||||
uint8_t eth_init = ETH_INIT_DEFAULT, connected = 0;
|
||||
|
||||
videomode(VIDEOMODE_80COL);
|
||||
printf("%c%s PRINT%c\n", 0x0f, PROGNAME, 0x0e);
|
||||
|
||||
puts("\nThis utility allows printing to a network-connected printer");
|
||||
puts("using the HP Jetdirect protocol.\n");
|
||||
if (argc == 2) {
|
||||
strcpy(filename, argv[1]);
|
||||
} else {
|
||||
printf("\nFilename to print >");
|
||||
scanf("%s", filename);
|
||||
puts("");
|
||||
}
|
||||
|
||||
readconfigfile();
|
||||
|
||||
{
|
||||
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_init(eth_init);
|
||||
w5100_config();
|
||||
|
||||
fp = fopen(filename, "rb");
|
||||
if (!fp) {
|
||||
printf("Can't open %s\n", filename);
|
||||
error_exit();
|
||||
}
|
||||
|
||||
if (!connected) {
|
||||
printf("\nConnecting to %s:%d - ", cfg_server, jetdirect_port);
|
||||
|
||||
if (!w5100_connect_addr(parse_dotted_quad(cfg_server), jetdirect_port)) {
|
||||
printf("Fail\n");
|
||||
error_exit();
|
||||
}
|
||||
|
||||
printf("Ok\n\n");
|
||||
|
||||
}
|
||||
printf("Sending to printer ");
|
||||
if (!w5100_tcp_send()) {
|
||||
error_exit();
|
||||
}
|
||||
fclose(fp);
|
||||
printf("Disconnecting\n");
|
||||
w5100_disconnect();
|
||||
|
||||
confirm_exit();
|
||||
}
|
||||
|
|
@ -163,6 +163,9 @@ void repair_mailbox(void) {
|
|||
}
|
||||
fclose(fp);
|
||||
|
||||
maxemailnum = 0;
|
||||
minemailnum = 65535;
|
||||
|
||||
printf("** Scanning directory %s\n", dirname);
|
||||
|
||||
while (d = readdir(dp)) {
|
||||
|
@ -180,6 +183,11 @@ void repair_mailbox(void) {
|
|||
}
|
||||
closedir(dp);
|
||||
|
||||
if (maxemailnum < minemailnum) {
|
||||
printf("** No messages in this directory\n");
|
||||
error_exit();
|
||||
}
|
||||
|
||||
printf("** Will process EMAIL.%u to EMAIL.%u\n", minemailnum, maxemailnum);
|
||||
for (emailnum = minemailnum; emailnum <= maxemailnum; ++emailnum) {
|
||||
sprintf(filename, "%s/EMAIL.%u", dirname, emailnum);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
ca65 setmac.s
|
||||
ld65 setmac.o -t none -o setmac.system\#ff2000
|
||||
ld65 setmac.o -t none -o SETMAC.SYSTEM\#FF2000
|
||||
cp ../ip65.dsk ip65.po
|
||||
cadius replacefile ip65.po /IP65 setmac.system\#ff2000
|
||||
cadius replacefile ip65.po /IP65 SETMAC.SYSTEM\#FF2000
|
||||
scp ip65.po pi@pi-eth:~/virtual-1.po
|
||||
|
||||
|
|
|
@ -547,7 +547,8 @@ void main(int argc, char *argv[]) {
|
|||
printf("Ok\n");
|
||||
|
||||
// Copy IP config from IP65 to W5100
|
||||
w5100_config(eth_init);
|
||||
w5100_init(eth_init);
|
||||
w5100_config();
|
||||
|
||||
sprintf(filename, "%s/OUTBOX", cfg_emaildir);
|
||||
dp = opendir(filename);
|
||||
|
@ -577,7 +578,7 @@ void main(int argc, char *argv[]) {
|
|||
strcpy(recipients, "");
|
||||
|
||||
while (1) {
|
||||
if ((get_line(fp, 0, linebuf, LINEBUFSZ) == 0) || (linecount == 20)) {
|
||||
if ((get_line(fp, 0, linebuf, LINEBUFSZ) == 0) || (linecount == 20) || (linebuf[0] == '\r')) {
|
||||
if (strlen(recipients) == 0) {
|
||||
printf("No recipients (To or Cc) in %s. Skipping msg.\n", d->d_name);
|
||||
goto skiptonext;
|
||||
|
@ -644,7 +645,7 @@ sendmessage:
|
|||
if (!connected) {
|
||||
printf("\nConnecting to %s - ", cfg_smtp_server);
|
||||
|
||||
if (!w5100_connect(parse_dotted_quad(cfg_smtp_server), smtp_port)) {
|
||||
if (!w5100_connect_addr(parse_dotted_quad(cfg_smtp_server), smtp_port)) {
|
||||
printf("Fail\n");
|
||||
error_exit();
|
||||
}
|
||||
|
|
|
@ -152,9 +152,9 @@ int main(void)
|
|||
{
|
||||
read(file, ð_init, 1);
|
||||
close(file);
|
||||
eth_init &= ~'0';
|
||||
eth_init &= 7;
|
||||
}
|
||||
printf("- %d\n", eth_init);
|
||||
printf("- %u\n", eth_init);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
96
apps/w5100.c
96
apps/w5100.c
|
@ -65,12 +65,8 @@ static uint16_t addr_mask [2];
|
|||
|
||||
static void set_addr(uint16_t addr)
|
||||
{
|
||||
// The variables are necessary to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment registers.
|
||||
uint8_t addr_hi = addr >> 8;
|
||||
uint8_t addr_lo = addr;
|
||||
*w5100_addr_hi = addr_hi;
|
||||
*w5100_addr_lo = addr_lo;
|
||||
*w5100_addr_hi = addr >> 8;
|
||||
*w5100_addr_lo = addr;
|
||||
}
|
||||
|
||||
static uint8_t get_byte(uint16_t addr)
|
||||
|
@ -91,54 +87,44 @@ static uint16_t get_word(uint16_t addr)
|
|||
{
|
||||
set_addr(addr);
|
||||
|
||||
{
|
||||
// The variables are necessary to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment registers.
|
||||
uint8_t data_hi = *w5100_data;
|
||||
uint8_t data_lo = *w5100_data;
|
||||
return data_hi << 8 | data_lo;
|
||||
}
|
||||
return *w5100_data << 8 | *w5100_data;
|
||||
}
|
||||
|
||||
static void set_word(uint16_t addr, uint16_t data)
|
||||
{
|
||||
set_addr(addr);
|
||||
|
||||
{
|
||||
// The variables are necessary to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment registers.
|
||||
uint8_t data_hi = data >> 8;
|
||||
uint8_t data_lo = data;
|
||||
*w5100_data = data_hi;
|
||||
*w5100_data = data_lo;
|
||||
}
|
||||
*w5100_data = data >> 8;
|
||||
*w5100_data = data;
|
||||
}
|
||||
|
||||
static void set_quad(uint16_t addr, uint32_t data)
|
||||
{
|
||||
set_addr(addr);
|
||||
|
||||
{
|
||||
// The variables are necessary to have cc65 generate code
|
||||
// suitable to access the W5100 auto-increment registers.
|
||||
uint8_t data_1 = data;
|
||||
uint8_t data_2 = data >> 8;
|
||||
uint8_t data_3 = data >> 16;
|
||||
uint8_t data_4 = data >> 24;
|
||||
*w5100_data = data_1;
|
||||
*w5100_data = data_2;
|
||||
*w5100_data = data_3;
|
||||
*w5100_data = data_4;
|
||||
}
|
||||
*w5100_data = data;
|
||||
*w5100_data = data >> 8;
|
||||
*w5100_data = data >> 16;
|
||||
*w5100_data = data >> 24;
|
||||
}
|
||||
|
||||
void w5100_config(uint8_t eth_init)
|
||||
bool w5100_init(uint8_t eth_init)
|
||||
{
|
||||
w5100_mode = (uint8_t*)(eth_init << 4 | 0xC084);
|
||||
w5100_addr_hi = w5100_mode + 1;
|
||||
w5100_addr_lo = w5100_mode + 2;
|
||||
w5100_data = w5100_mode + 3;
|
||||
|
||||
// PPP Link Control Protocol Request Timer Register defaults to 0x28
|
||||
// on a real W5100. However, AppleWin features a virtual W5100 that
|
||||
// supports DNS offloading. On that virtual W5100, the (otherwise
|
||||
// anyhow unused) register defaults to 0x00 as detection mechanism.
|
||||
// https://github.com/a2retrosystems/uthernet2/wiki/Virtual-W5100-with-DNS
|
||||
return get_byte(0x0028) == 0x00;
|
||||
}
|
||||
|
||||
void w5100_config(void)
|
||||
{
|
||||
#ifdef SINGLE_SOCKET
|
||||
|
||||
// IP65 is inhibited so disable the W5100 Ping Block Mode.
|
||||
|
@ -193,14 +179,14 @@ void w5100_config(uint8_t eth_init)
|
|||
}
|
||||
}
|
||||
|
||||
bool w5100_connect(uint32_t addr, uint16_t port)
|
||||
static bool w5100_connect(uint16_t port)
|
||||
{
|
||||
// Socket x Mode Register: TCP
|
||||
set_byte(SOCK_REG(0x00), 0x01);
|
||||
|
||||
// Socket x Source Port Register
|
||||
set_word(SOCK_REG(0x04), ip65_random_word());
|
||||
|
||||
// Socket x Destination Port Register
|
||||
set_word(SOCK_REG(0x10), port);
|
||||
|
||||
// Socket x Command Register: OPEN
|
||||
set_byte(SOCK_REG(0x01), 0x01);
|
||||
|
||||
|
@ -213,12 +199,6 @@ bool w5100_connect(uint32_t addr, uint16_t port)
|
|||
}
|
||||
}
|
||||
|
||||
// Socket x Destination IP Address Register
|
||||
set_quad(SOCK_REG(0x0C), addr);
|
||||
|
||||
// Socket x Destination Port Register
|
||||
set_word(SOCK_REG(0x10), port);
|
||||
|
||||
// Socket x Command Register: CONNECT
|
||||
set_byte(SOCK_REG(0x01), 0x04);
|
||||
|
||||
|
@ -238,6 +218,34 @@ bool w5100_connect(uint32_t addr, uint16_t port)
|
|||
}
|
||||
}
|
||||
|
||||
bool w5100_connect_addr(uint32_t addr, uint16_t port)
|
||||
{
|
||||
// Socket x Mode Register: TCP, Use No Delayed ACK
|
||||
set_byte(SOCK_REG(0x00), 0x21);
|
||||
|
||||
// Socket x Destination IP Address Register
|
||||
set_quad(SOCK_REG(0x0C), addr);
|
||||
|
||||
return w5100_connect(port);
|
||||
}
|
||||
|
||||
bool w5100_connect_name(const char* name, uint8_t length, uint16_t port)
|
||||
{
|
||||
// Socket x Mode Register: TCP, Use No Delayed ACK, Use DNS Offloading
|
||||
set_byte(SOCK_REG(0x00), 0x29);
|
||||
|
||||
// Socket x DNS name length
|
||||
set_byte(SOCK_REG(0x2A), length);
|
||||
|
||||
// Socket x DNS name chars
|
||||
while (length--)
|
||||
{
|
||||
*w5100_data = *name++;
|
||||
}
|
||||
|
||||
return w5100_connect(port);
|
||||
}
|
||||
|
||||
bool w5100_connected(void)
|
||||
{
|
||||
// Socket x Status Register: SOCK_ESTABLISHED ?
|
||||
|
|
16
apps/w5100.h
16
apps/w5100.h
|
@ -46,13 +46,23 @@ void w5100_data_commit(bool do_send, uint16_t size);
|
|||
// to be sent to the server.
|
||||
extern volatile uint8_t* w5100_data;
|
||||
|
||||
// Initialize this module after the IP65 TCP/IP stack has been initialized.
|
||||
// Return true if the (virtual) W5100 supports DNS Offloading.
|
||||
// https://github.com/a2retrosystems/uthernet2/wiki/Virtual-W5100-with-DNS
|
||||
bool w5100_init(uint8_t eth_init);
|
||||
|
||||
// Configure W5100 Ethernet controller with additional information from IP65
|
||||
// after the IP65 TCP/IP stack has been configured.
|
||||
void w5100_config(uint8_t eth_init);
|
||||
void w5100_config(void);
|
||||
|
||||
// Connect to server with IP address <server_addr> on TCP port <server_port>.
|
||||
// Connect to server with IP address <addr> on TCP port <port>.
|
||||
// Return true if the connection is established, return false otherwise.
|
||||
bool w5100_connect(uint32_t addr, uint16_t port);
|
||||
bool w5100_connect_addr(uint32_t addr, uint16_t port);
|
||||
|
||||
// Connect to server with name <name>, <length> on TCP port <port> using
|
||||
// DNS Offloading.
|
||||
// Return true if the connection is established, return false otherwise.
|
||||
bool w5100_connect_name(const char* name, uint8_t length, uint16_t port);
|
||||
|
||||
// Check if still connected to server.
|
||||
// Return true if the connection is established, return false otherwise.
|
||||
|
|
|
@ -39,16 +39,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#pragma optimize (on)
|
||||
#pragma static-locals (on)
|
||||
|
||||
bool w5100_http_open(uint32_t addr, uint16_t port, const char* selector,
|
||||
char* buffer, size_t length)
|
||||
static bool w5100_http_open(const char* selector, char* buffer, size_t length)
|
||||
{
|
||||
printf("Connecting to %s:%d ", dotted_quad(addr), port);
|
||||
|
||||
if (!w5100_connect(addr, port))
|
||||
{
|
||||
printf("- Connect failed\n");
|
||||
return false;
|
||||
}
|
||||
register volatile uint8_t *data = w5100_data;
|
||||
|
||||
printf("- Ok\n\nSending request ");
|
||||
{
|
||||
|
@ -82,15 +75,11 @@ bool w5100_http_open(uint32_t addr, uint16_t port, const char* selector,
|
|||
}
|
||||
|
||||
{
|
||||
// One less to allow for faster pre-increment below
|
||||
const char *dataptr = selector + pos - 1;
|
||||
const char *dataptr = selector + pos;
|
||||
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;
|
||||
*data = *dataptr++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,17 +121,13 @@ bool w5100_http_open(uint32_t addr, uint16_t port, const char* selector,
|
|||
}
|
||||
|
||||
{
|
||||
// One less to allow for faster pre-increment below
|
||||
char *dataptr = buffer + len - 1;
|
||||
char *dataptr = buffer + len;
|
||||
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;
|
||||
*dataptr++ = *data;
|
||||
|
||||
if (!memcmp(dataptr - 3, "\r\n\r\n", 4))
|
||||
if (!memcmp(dataptr - 4, "\r\n\r\n", 4))
|
||||
{
|
||||
rcv = i + 1;
|
||||
body = true;
|
||||
|
@ -183,3 +168,31 @@ bool w5100_http_open(uint32_t addr, uint16_t port, const char* selector,
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool w5100_http_open_addr(uint32_t addr, uint16_t port, const char* selector,
|
||||
char* buffer, size_t length)
|
||||
{
|
||||
printf("Connecting to %s:%d ", dotted_quad(addr), port);
|
||||
|
||||
if (!w5100_connect_addr(addr, port))
|
||||
{
|
||||
printf("- Connect failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return w5100_http_open(selector, buffer, length);
|
||||
}
|
||||
|
||||
bool w5100_http_open_name(const char* name, uint8_t name_length, uint16_t port,
|
||||
const char* selector, char* buffer, size_t buffer_length)
|
||||
{
|
||||
printf("Connecting to port %d ", port);
|
||||
|
||||
if (!w5100_connect_name(name, name_length, port))
|
||||
{
|
||||
printf("- Connect failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return w5100_http_open(selector, buffer, buffer_length);
|
||||
}
|
||||
|
|
|
@ -37,12 +37,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// Connect to server with IP address <server_addr> on TCP port <server_port>,
|
||||
// then HTTP GET <selector> and consume HTTP response header. Provide feedback
|
||||
// on progress to the user via STDOUT. After returning from w5100_http_open()
|
||||
// the connection is ready to consume the HTTP body.
|
||||
// Connect to server with IP address <addr> on TCP port <port>, then HTTP GET
|
||||
// <selector> and consume HTTP response header. Provide feedback on progress
|
||||
// to the user via STDOUT. After returning from w5100_http_open_addr(), the
|
||||
// connection is ready to consume the HTTP body.
|
||||
// Return true if the connection is established, return false otherwise.
|
||||
bool w5100_http_open(uint32_t addr, uint16_t port, const char* selector,
|
||||
char* buffer, size_t length);
|
||||
bool w5100_http_open_addr(uint32_t addr, uint16_t port, const char* selector,
|
||||
char* buffer, size_t length);
|
||||
|
||||
// Connect to server with name <name>, <name_length> on TCP port <port> using
|
||||
// DNS Offloading, then HTTP GET <selector> and consume HTTP response header.
|
||||
// Provide feedback on progress to the user via STDOUT. After returning from
|
||||
// w5100_http_open_name(), the connection is ready to consume the HTTP body.
|
||||
// Return true if the connection is established, return false otherwise.
|
||||
bool w5100_http_open_name(const char* name, uint8_t name_length, uint16_t port,
|
||||
const char* selector, char* buffer, size_t buffer_length);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -241,6 +241,7 @@ void exit_on_key(void)
|
|||
|
||||
void write_file(const char *name)
|
||||
{
|
||||
register volatile uint8_t *data = w5100_data;
|
||||
uint16_t i;
|
||||
int file;
|
||||
uint16_t rcv;
|
||||
|
@ -277,14 +278,10 @@ void write_file(const char *name)
|
|||
}
|
||||
|
||||
{
|
||||
// One less to allow for faster pre-increment below
|
||||
char *dataptr = buffer + len - 1;
|
||||
char *dataptr = buffer + len;
|
||||
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;
|
||||
*dataptr++ = *data;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,6 +315,7 @@ void write_file(const char *name)
|
|||
|
||||
void write_device(char device)
|
||||
{
|
||||
register volatile uint8_t *data = w5100_data;
|
||||
uint16_t i;
|
||||
dhandle_t dio;
|
||||
uint16_t rcv;
|
||||
|
@ -383,8 +381,7 @@ void write_device(char device)
|
|||
rcv = sizeof(buffer) - len;
|
||||
}
|
||||
|
||||
// One less to allow for faster pre-increment below
|
||||
dataptr = buffer + len - 1;
|
||||
dataptr = buffer + len;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -394,16 +391,12 @@ void write_device(char device)
|
|||
rcv = 0x100 - len % 0x100;
|
||||
}
|
||||
|
||||
// One less to allow for faster pre-increment below
|
||||
dataptr = buffer + (skew[len / 0x100] << 8 | len % 0x100) - 1;
|
||||
dataptr = buffer + (skew[len / 0x100] << 8 | len % 0x100);
|
||||
}
|
||||
|
||||
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;
|
||||
*dataptr++ = *data;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -442,6 +435,7 @@ int main(int, char *argv[])
|
|||
uint16_t i;
|
||||
char *arg;
|
||||
char device;
|
||||
bool Offload_DNS;
|
||||
uint8_t eth_init = ETH_INIT_DEFAULT;
|
||||
|
||||
if (doesclrscrafterexit())
|
||||
|
@ -475,11 +469,11 @@ int main(int, char *argv[])
|
|||
{
|
||||
read(file, ð_init, 1);
|
||||
close(file);
|
||||
eth_init &= ~'0';
|
||||
eth_init &= 7;
|
||||
}
|
||||
}
|
||||
|
||||
printf("- %d\n\nInitializing %s ", eth_init, eth_name);
|
||||
printf("- %u\n\nInitializing %s ", eth_init, eth_name);
|
||||
if (ip65_init(eth_init))
|
||||
{
|
||||
ip65_error_exit();
|
||||
|
@ -488,15 +482,20 @@ int main(int, char *argv[])
|
|||
// Abort on Ctrl-C to be consistent with Linenoise
|
||||
abort_key = 0x83;
|
||||
|
||||
printf("- Ok\n\nObtaining IP address ");
|
||||
if (dhcp_init())
|
||||
Offload_DNS = w5100_init(eth_init);
|
||||
|
||||
if (!Offload_DNS)
|
||||
{
|
||||
ip65_error_exit();
|
||||
printf("- Ok\n\nObtaining IP address ");
|
||||
if (dhcp_init())
|
||||
{
|
||||
ip65_error_exit();
|
||||
}
|
||||
}
|
||||
printf("- Ok\n\n");
|
||||
|
||||
// Copy IP config from IP65 to W5100
|
||||
w5100_config(eth_init);
|
||||
w5100_config();
|
||||
|
||||
load_argument("wget.urls");
|
||||
while (true)
|
||||
|
@ -504,7 +503,7 @@ int main(int, char *argv[])
|
|||
arg = get_argument(1, "URL", url_completion);
|
||||
|
||||
printf("\n\nProcessing URL ");
|
||||
if (!url_parse(arg))
|
||||
if (!url_parse(arg, !Offload_DNS))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -657,9 +656,21 @@ int main(int, char *argv[])
|
|||
save_argument("wget.files");
|
||||
|
||||
printf("\n\n");
|
||||
if (!w5100_http_open(url_ip, url_port, url_selector, buffer, sizeof(buffer)))
|
||||
if (Offload_DNS)
|
||||
{
|
||||
return EXIT_FAILURE;
|
||||
if (!w5100_http_open_name(url_host, strlen(url_host) - 4, url_port,
|
||||
url_selector, buffer, sizeof(buffer)))
|
||||
{
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!w5100_http_open_addr(url_ip, url_port,
|
||||
url_selector, buffer, sizeof(buffer)))
|
||||
{
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (device)
|
||||
|
|
|
@ -1,23 +1,21 @@
|
|||
# For assembler programs
|
||||
# ----------------------
|
||||
# c64rrnet.lib : C64 with RR-Net (or clone)
|
||||
# c64eth64.lib : C64 with ETH64
|
||||
# c64combo.lib : C64 with RR-Net or ETH64
|
||||
# a2uther.lib : Apple ][ with Uthernet (default slot: #3)
|
||||
# a2lancegs.lib : Apple ][ with LANceGS (default slot: #3)
|
||||
# a2uther2.lib : Apple ][ with Uthernet II (default slot: #3)
|
||||
# a2combo.lib : Apple ][ with Uthernet or LANceGS or Uthernet II (default slot: #3)
|
||||
# atrdragon.lib : ATARI 8-bit with Dragon Cart
|
||||
# atrdracarys.lib : ATARI 8-bit with Dracarys (default PBI device ID: #8)
|
||||
# atrcombo.lib : ATARI 8-bit with Dragon Cart or Dracarys (default PBI device ID: #8)
|
||||
# vic20rrnet.lib : VIC20 with RR-Net (or clone)
|
||||
# c64rrnet.lib : C64 with RR-Net (or clone)
|
||||
# c64eth64.lib : C64 with ETH64
|
||||
# c64combo.lib : C64 with RR-Net or ETH64
|
||||
# a2uther.lib : Apple ][ with Uthernet (default slot: #3)
|
||||
# a2uther2.lib : Apple ][ with Uthernet II (default slot: #3)
|
||||
# a2lancegs.lib : Apple ][ with LANceGS (default slot: #3)
|
||||
# a2combo.lib : Apple ][ with Uthernet or Uthernet II or LANceGS (default slot: #3)
|
||||
# atrdragon.lib : ATARI 8-bit with Dragon Cart
|
||||
# vic20rrnet.lib : VIC20 with RR-Net (or clone)
|
||||
|
||||
# For C programs
|
||||
# --------------
|
||||
# ip65_c64.lib : C64 with RR-Net or ETH64
|
||||
# ip65_apple2.lib : Apple ][ with Uthernet or LANceGS or Uthernet II (default slot: #3)
|
||||
# ip65_atari.lib : ATARI 8-bit with Dragon Cart or Dracarys (default PBI device ID: #8)
|
||||
# ip65_atarixl.lib : ATARI XL with Dragon Cart or Dracarys (default PBI device ID: #8)
|
||||
# ip65_apple2.lib : Apple ][ with Uthernet or Uthernet II or LANceGS (default slot: #3)
|
||||
# ip65_atari.lib : ATARI 8-bit with Dragon Cart
|
||||
# ip65_atarixl.lib : ATARI XL with Dragon Cart
|
||||
|
||||
DRIVERS=\
|
||||
c64rrnet.lib \
|
||||
|
@ -25,14 +23,12 @@ DRIVERS=\
|
|||
c64combo.lib \
|
||||
ip65_c64.lib \
|
||||
a2uther.lib \
|
||||
a2lancegs.lib \
|
||||
a2uther2.lib \
|
||||
a2lancegs.lib \
|
||||
a2combo.lib \
|
||||
ip65_apple2.lib \
|
||||
ip65_apple2_uther2.lib \
|
||||
atrdragon.lib \
|
||||
atrdracarys.lib \
|
||||
atrcombo.lib \
|
||||
ip65_atari.lib \
|
||||
ip65_atarixl.lib \
|
||||
vic20rrnet.lib
|
||||
|
@ -118,9 +114,9 @@ rr-net.o uthernet.o dragoncart.o vic20-rr-net.o: cs8900a.s
|
|||
|
||||
eth64.o lancegs.o: lan91c96.s
|
||||
|
||||
uthernet2.o dracarys.o: w5100.s
|
||||
uthernet2.o: w5100.s
|
||||
|
||||
c64combo.o a2combo.o atrcombo.o: ethernetcombo.s
|
||||
c64combo.o a2combo.o: ethernetcombo.s
|
||||
|
||||
c64rrnet.lib: rr-net.o $(CS8900AOBJS) c64init.o $(C64OBJS)
|
||||
|
||||
|
@ -132,10 +128,10 @@ ip65_c64.lib: rr-net.o eth64.o c64combo.o c64init.o $(C64_OBJS)
|
|||
|
||||
a2uther.lib: uthernet.o $(CS8900AOBJS) a2init.o $(A2OBJS)
|
||||
|
||||
a2lancegs.lib: lancegs.o $(LAN91C96OBJS) a2init.o $(A2OBJS)
|
||||
|
||||
a2uther2.lib: uthernet2.o $(W5100OBJS) a2init.o $(A2OBJS)
|
||||
|
||||
a2lancegs.lib: lancegs.o $(LAN91C96OBJS) a2init.o $(A2OBJS)
|
||||
|
||||
a2combo.lib: uthernet.o lancegs.o uthernet2.o a2combo.o a2init.o $(A2OBJS)
|
||||
|
||||
ip65_apple2.lib: uthernet.o lancegs.o uthernet2.o a2combo.o a2init.o $(A2_OBJS)
|
||||
|
@ -144,13 +140,9 @@ ip65_apple2_uther2.lib: uthernet2.o $(W5100OBJS) a2init.o $(A2_OBJS)
|
|||
|
||||
atrdragon.lib: dragoncart.o $(CS8900AOBJS) atrinit.o $(ATROBJS)
|
||||
|
||||
atrdracarys.lib: dracarys.o $(W5100OBJS) atrinit.o $(ATROBJS)
|
||||
ip65_atari.lib: dragoncart.o $(CS8900AOBJS) atrinit.o $(ATR_OBJS)
|
||||
|
||||
atrcombo.lib: dragoncart.o dracarys.o atrcombo.o atrinit.o $(ATROBJS)
|
||||
|
||||
ip65_atari.lib: dragoncart.o dracarys.o atrcombo.o atrinit.o $(ATR_OBJS)
|
||||
|
||||
ip65_atarixl.lib: dragoncart.o dracarys.o atrcombo.o atrinit.o $(ATRXL_OBJS)
|
||||
ip65_atarixl.lib: dragoncart.o $(CS8900AOBJS) atrinit.o $(ATRXL_OBJS)
|
||||
|
||||
vic20rrnet.lib: vic20-rr-net.o $(CS8900AOBJS) vic20init.o $(VIC20OBJS)
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
.exportzp eth_init_default = 5 ; Apple 2 default slot
|
||||
.exportzp eth_init_default = 3 ; Apple 2 default slot
|
||||
|
|
|
@ -1 +1 @@
|
|||
.exportzp eth_init_default = 8 ; PBI default device ID
|
||||
.exportzp eth_init_default = 0
|
||||
|
|
|
@ -132,7 +132,7 @@ set_name:
|
|||
eth_init:
|
||||
sta eth_init_value
|
||||
|
||||
.if .defined (__APPLE2__) .or .defined (__ATARI__)
|
||||
.if .defined (__APPLE2__)
|
||||
ldax #_w5100
|
||||
jsr patch_wrapper
|
||||
ldax #_w5100_name
|
||||
|
|
|
@ -41,12 +41,7 @@
|
|||
|
||||
; Ethernet address
|
||||
mac: .byte $00, $08, $DC ; OUI of WIZnet
|
||||
.ifdef __APPLE2__
|
||||
.byte $A2, $A2, $A2
|
||||
.endif
|
||||
.ifdef __ATARI__
|
||||
.byte $A8, $A8, $A8
|
||||
.endif
|
||||
|
||||
; Buffer attributes
|
||||
bufaddr:.res 2 ; Address
|
||||
|
@ -91,8 +86,6 @@ tmp := tmp4 ; Temporary value
|
|||
|
||||
;=====================================================================
|
||||
|
||||
.ifdef __APPLE2__
|
||||
|
||||
.rodata
|
||||
|
||||
fixup: .byte fixup02-fixup01, fixup03-fixup02, fixup04-fixup03
|
||||
|
@ -155,54 +148,6 @@ init:
|
|||
bcs :- ; Always
|
||||
:
|
||||
|
||||
.endif
|
||||
|
||||
;=====================================================================
|
||||
|
||||
.ifdef __ATARI__
|
||||
|
||||
.rodata
|
||||
|
||||
pdtab: .byte %00000001
|
||||
.byte %00000010
|
||||
.byte %00000100
|
||||
.byte %00001000
|
||||
.byte %00010000
|
||||
.byte %00100000
|
||||
.byte %01000000
|
||||
.byte %10000000
|
||||
|
||||
;---------------------------------------------------------------------
|
||||
|
||||
.bss
|
||||
|
||||
pdbit: .res 1
|
||||
|
||||
;---------------------------------------------------------------------
|
||||
|
||||
mode := $D1F0
|
||||
addr := $D1F1
|
||||
data := $D1F3
|
||||
|
||||
pdvs := $D1FF ; parallel device select
|
||||
shpdvs := $0248 ; shadow parallel device select
|
||||
|
||||
;---------------------------------------------------------------------
|
||||
|
||||
.code
|
||||
|
||||
init:
|
||||
; Convert parallel device ID (1-8) to parallel device bit
|
||||
tay
|
||||
lda pdtab-1,y
|
||||
sta pdbit
|
||||
|
||||
; Select parallel device
|
||||
sta shpdvs
|
||||
sta pdvs
|
||||
|
||||
.endif
|
||||
|
||||
;=====================================================================
|
||||
|
||||
; Indirect Bus I/F mode, Address Auto-Increment
|
||||
|
@ -287,13 +232,6 @@ fixup14:sta data
|
|||
;---------------------------------------------------------------------
|
||||
|
||||
poll:
|
||||
.ifdef __ATARI__
|
||||
; Select parallel device
|
||||
lda pdbit
|
||||
sta shpdvs
|
||||
sta pdvs
|
||||
.endif
|
||||
|
||||
; Check for completion of previous command
|
||||
; Socket 0 Command Register: = 0 ?
|
||||
jsr set_addrcmdreg0
|
||||
|
@ -401,13 +339,6 @@ send:
|
|||
sta adv
|
||||
stx adv+1
|
||||
|
||||
.ifdef __ATARI__
|
||||
; Select parallel device
|
||||
lda pdbit
|
||||
sta shpdvs
|
||||
sta pdvs
|
||||
.endif
|
||||
|
||||
; Set parameters for transmitting data
|
||||
lda #>$4000 ; Socket 0 TX Base Address
|
||||
ldx #$01 ; Write
|
||||
|
|
14
inc/ip65.h
14
inc/ip65.h
|
@ -7,9 +7,7 @@
|
|||
// Ethernet driver initialization parameter values
|
||||
//
|
||||
#if defined(__APPLE2__)
|
||||
#define ETH_INIT_DEFAULT 5 // Apple II slot number
|
||||
#elif defined(__ATARI__)
|
||||
#define ETH_INIT_DEFAULT 8 // ATARI PBI device ID
|
||||
#define ETH_INIT_DEFAULT 3 // Apple II slot number
|
||||
#else
|
||||
#define ETH_INIT_DEFAULT 0 // Unused
|
||||
#endif
|
||||
|
@ -294,16 +292,18 @@ bool __fastcall__ tftp_upload_from_memory(uint32_t server, const char* name,
|
|||
//
|
||||
// On success the variables url_ip, url_port and url_selector (see below) are valid.
|
||||
//
|
||||
// Inputs: url: Zero (or ctrl char) terminated string containing the URL
|
||||
// Inputs: url: Zero (or ctrl char) terminated string containing the URL
|
||||
// resolve: Resolve host in URL
|
||||
// Output: true if an error occured, false otherwise
|
||||
//
|
||||
bool __fastcall__ url_parse(const char* url);
|
||||
bool __fastcall__ url_parse(const char* url, bool resolve);
|
||||
|
||||
// Access to parsed HTTP URL
|
||||
//
|
||||
// Access to the three items below is only valid after url_parse returned false.
|
||||
// Access to the four items below is only valid after url_parse returned false.
|
||||
//
|
||||
extern uint32_t url_ip; // IP address of host in URL
|
||||
extern char* url_host; // Zero terminated string containing host in URL + "\r\n\r\n"
|
||||
extern uint32_t url_ip; // IP address of host in URL (only if 'resolve' is true)
|
||||
extern uint16_t url_port; // Port number of URL
|
||||
extern char* url_selector; // Zero terminated string containing selector part of URL
|
||||
|
||||
|
|
16
ip65/dhcp.s
16
ip65/dhcp.s
|
@ -85,6 +85,7 @@ dhcp_message_sent_count: .res 1
|
|||
dhcp_timer: .res 1
|
||||
dhcp_loop_count: .res 1
|
||||
dhcp_break_polling_loop: .res 1
|
||||
dhcp_ip: .res 4
|
||||
|
||||
; DHCP constants
|
||||
BOOTREQUEST = 1
|
||||
|
@ -315,9 +316,9 @@ dhcp_in:
|
|||
cmp dhcp_inp+dhcp_yiaddr ; is the first byte in the assigned address 0?
|
||||
bne :+
|
||||
rts ; if so, it's a bogus response - ignore
|
||||
: ldx #4 ; copy the our new IP address
|
||||
: ldx #3 ; copy the new IP address
|
||||
: lda dhcp_inp+dhcp_yiaddr,x
|
||||
sta cfg_ip,x
|
||||
sta dhcp_ip,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
|
@ -423,7 +424,7 @@ send_dhcprequest:
|
|||
ldx #4 ; option length is 4
|
||||
stx output_buffer+dhcp_options+4
|
||||
dex
|
||||
: lda cfg_ip,x
|
||||
: lda dhcp_ip,x
|
||||
sta output_buffer+dhcp_options+5,x
|
||||
dex
|
||||
bpl :-
|
||||
|
@ -449,9 +450,16 @@ send_dhcprequest:
|
|||
|
||||
ldax #output_buffer
|
||||
jsr udp_send
|
||||
bcs :+ ; if we didn't send the message we probably need to wait for an ARP reply to come back.
|
||||
bcs :++ ; if we didn't send the message we probably need to wait for an ARP reply to come back.
|
||||
|
||||
lda #dhcp_bound ; technically, we should wait till we get a DHCPACK message. but we'll assume success
|
||||
sta dhcp_state
|
||||
ldx #3 ; set the new IP address
|
||||
: lda dhcp_ip,x
|
||||
sta cfg_ip,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
: rts
|
||||
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ url_download:
|
|||
sty url_selector
|
||||
ldy url_download_buffer+1
|
||||
sty url_selector+1
|
||||
ldy #1
|
||||
jsr url_parse_buffer
|
||||
bcc resource_download
|
||||
rts
|
||||
|
|
|
@ -65,7 +65,7 @@ _udp_recv_src_port:
|
|||
ldx udp_inp+udp_src_port
|
||||
rts
|
||||
|
||||
_udp_send:
|
||||
_udp_send:
|
||||
stax udp_send_src_port
|
||||
jsr popax
|
||||
stax udp_send_dest_port
|
||||
|
|
21
ip65/url.s
21
ip65/url.s
|
@ -13,6 +13,7 @@
|
|||
.import parse_integer
|
||||
.import dns_ip
|
||||
|
||||
.export url_host
|
||||
.export url_ip
|
||||
.export url_port
|
||||
.export url_selector
|
||||
|
@ -26,7 +27,8 @@ search_string = ptr1
|
|||
.bss
|
||||
|
||||
url_string: .res 2
|
||||
url_ip: .res 4 ; will be set with ip address of host in url
|
||||
url_host: .res 2 ; will be set with hostname + CRLFCRLF
|
||||
url_ip: .res 4 ; will be set with ip address of host in url (if resolve)
|
||||
url_port: .res 2 ; will be set with port number of url
|
||||
url_selector: .res 2 ; will be set with address of selector part of URL
|
||||
url_type: .res 1
|
||||
|
@ -35,6 +37,7 @@ search_string = ptr1
|
|||
url_type_gopher = 1
|
||||
url_type_http = 2
|
||||
|
||||
resolve: .res 1
|
||||
src_ptr: .res 1
|
||||
dest_ptr: .res 1
|
||||
|
||||
|
@ -46,28 +49,33 @@ search_string = ptr1
|
|||
; inputs:
|
||||
; AX = address of URL string
|
||||
; any control character (i.e. <$20) is treated as 'end of string', e.g. a CR or LF, as well as $00
|
||||
; Y = do resolve hostname
|
||||
; outputs:
|
||||
; sec if a malformed url, otherwise:
|
||||
; url_ip = ip address of host in url
|
||||
; url_port = port number of url
|
||||
; url_selector = address of selector part of URL
|
||||
url_parse:
|
||||
sty resolve
|
||||
ldy #<output_buffer
|
||||
sty url_selector
|
||||
ldy #>output_buffer
|
||||
sty url_selector+1
|
||||
ldy resolve
|
||||
|
||||
; parses a URL into a form that makes it easy to retrieve the specified resource
|
||||
; caution - the resulting selector part of URL must fit into the provided buffer !!!
|
||||
; inputs:
|
||||
; AX = address of URL string
|
||||
; any control character (i.e. <$20) is treated as 'end of string', e.g. a CR or LF, as well as $00
|
||||
; Y = do resolve hostname
|
||||
; url_selector = points to a buffer that selector part of URL will be placed into
|
||||
; outputs:
|
||||
; sec if a malformed url, otherwise:
|
||||
; url_ip = ip address of host in url
|
||||
; url_port = port number of url
|
||||
url_parse_buffer:
|
||||
sty resolve
|
||||
stax url_string
|
||||
ldy #url_type_http
|
||||
sty url_type
|
||||
|
@ -109,6 +117,8 @@ lda #url_type_gopher
|
|||
; now pointing at hostname
|
||||
bcs @exit_with_error
|
||||
@no_protocol_specifier:
|
||||
ldy resolve
|
||||
beq @no_resolve
|
||||
jsr dns_set_hostname
|
||||
bcs @exit_with_sec
|
||||
jsr dns_resolve
|
||||
|
@ -125,6 +135,7 @@ lda #url_type_gopher
|
|||
|
||||
jsr skip_to_hostname
|
||||
|
||||
@no_resolve:
|
||||
; skip over next colon
|
||||
ldax #colon
|
||||
jsr parser_skip_next
|
||||
|
@ -212,11 +223,17 @@ lda #url_type_gopher
|
|||
jsr skip_to_hostname
|
||||
; AX now pointing at hostname
|
||||
stax ptr1
|
||||
|
||||
clc
|
||||
lda url_selector
|
||||
sta ptr2
|
||||
adc dest_ptr
|
||||
sta url_host
|
||||
pla
|
||||
sta ptr2+1
|
||||
|
||||
adc #0
|
||||
sta url_host+1
|
||||
|
||||
lda #0
|
||||
sta src_ptr
|
||||
|
||||
|
|
10
ip65/url_c.s
10
ip65/url_c.s
|
@ -1,22 +1,32 @@
|
|||
.include "../inc/common.inc"
|
||||
|
||||
.export _url_parse
|
||||
.export _url_host
|
||||
.export _url_ip
|
||||
.export _url_port
|
||||
.export _url_selector
|
||||
|
||||
.import url_parse
|
||||
.import url_host
|
||||
.import url_ip
|
||||
.import url_port
|
||||
.import url_selector
|
||||
|
||||
.import popax
|
||||
.importzp tmp1
|
||||
|
||||
_url_parse:
|
||||
sta tmp1
|
||||
jsr popax
|
||||
ldy tmp1
|
||||
jsr url_parse
|
||||
ldx #$00
|
||||
txa
|
||||
rol
|
||||
rts
|
||||
|
||||
_url_host := url_host
|
||||
|
||||
_url_ip := url_ip
|
||||
|
||||
_url_port := url_port
|
||||
|
|
BIN
releases/emailler-2.1.0.po
Normal file
BIN
releases/emailler-2.1.0.po
Normal file
Binary file not shown.
BIN
releases/emailler-2.1.1.po
Normal file
BIN
releases/emailler-2.1.1.po
Normal file
Binary file not shown.
BIN
releases/emailler-2.1.10.po
Normal file
BIN
releases/emailler-2.1.10.po
Normal file
Binary file not shown.
BIN
releases/emailler-2.1.11.po
Normal file
BIN
releases/emailler-2.1.11.po
Normal file
Binary file not shown.
BIN
releases/emailler-2.1.12.po
Normal file
BIN
releases/emailler-2.1.12.po
Normal file
Binary file not shown.
BIN
releases/emailler-2.1.13.po
Normal file
BIN
releases/emailler-2.1.13.po
Normal file
Binary file not shown.
BIN
releases/emailler-2.1.14.po
Normal file
BIN
releases/emailler-2.1.14.po
Normal file
Binary file not shown.
BIN
releases/emailler-2.1.2.po
Normal file
BIN
releases/emailler-2.1.2.po
Normal file
Binary file not shown.
BIN
releases/emailler-2.1.3.po
Normal file
BIN
releases/emailler-2.1.3.po
Normal file
Binary file not shown.
BIN
releases/emailler-2.1.4.po
Normal file
BIN
releases/emailler-2.1.4.po
Normal file
Binary file not shown.
BIN
releases/emailler-2.1.5.po
Normal file
BIN
releases/emailler-2.1.5.po
Normal file
Binary file not shown.
BIN
releases/emailler-2.1.6.po
Normal file
BIN
releases/emailler-2.1.6.po
Normal file
Binary file not shown.
BIN
releases/emailler-2.1.7.po
Normal file
BIN
releases/emailler-2.1.7.po
Normal file
Binary file not shown.
BIN
releases/emailler-2.1.8.po
Normal file
BIN
releases/emailler-2.1.8.po
Normal file
Binary file not shown.
BIN
releases/emailler-2.1.9.po
Normal file
BIN
releases/emailler-2.1.9.po
Normal file
Binary file not shown.
|
@ -17,15 +17,14 @@ else ifeq ($(eth),sm)
|
|||
A2DRIVERLIB = ../drivers/a2lancegs.lib
|
||||
else ifeq ($(eth),wn)
|
||||
A2DRIVERLIB = ../drivers/a2uther2.lib
|
||||
ATRDRIVERLIB = ../drivers/atrdracarys.lib
|
||||
else
|
||||
C64DRIVERLIB = ../drivers/c64combo.lib
|
||||
A2DRIVERLIB = ../drivers/a2combo.lib
|
||||
ATRDRIVERLIB = ../drivers/atrcombo.lib
|
||||
ATRDRIVERLIB = ../drivers/atrdragon.lib
|
||||
VICDRIVERLIB = ../drivers/vic20rrnet.lib
|
||||
endif
|
||||
|
||||
# See http://vice-emu.sourceforge.net/
|
||||
# See https://vice-emu.sourceforge.net/
|
||||
C1541 ?= c1541
|
||||
|
||||
# See https://applecommander.github.io/
|
||||
|
@ -112,32 +111,28 @@ vt100.com: ATARI_CFG = ../apps/atrtelnet.cfg
|
|||
%.o: %.c
|
||||
|
||||
%.prg: %.o ip65 drivers
|
||||
ld65 -o $*.prg -C c64.cfg -m $*.c64.map -vm $< $(IP65LIB) $(C64DRIVERLIB) c64.lib
|
||||
ld65 -o $*.prg -C c64.cfg -m $*.prg.map -vm $< $(IP65LIB) $(C64DRIVERLIB) c64.lib
|
||||
|
||||
%.bin: %.o ip65 drivers
|
||||
ld65 -o $*.bin -C apple2.cfg -m $*.a2.map -vm $< $(IP65LIB) $(A2DRIVERLIB) apple2.lib
|
||||
ld65 -o $*.bin -C apple2.cfg -m $*.bin.map -vm $< $(IP65LIB) $(A2DRIVERLIB) apple2.lib
|
||||
|
||||
%.com: %.o ip65 drivers
|
||||
ld65 -o $*.com -C $(ATARI_CFG) -m $*.atr.map -vm $< $(IP65LIB) $(ATRDRIVERLIB) atari.lib
|
||||
ld65 -o $*.com -C $(ATARI_CFG) -m $*.com.map -vm $< $(IP65LIB) $(ATRDRIVERLIB) atari.lib
|
||||
|
||||
%.vicprg: %.o ip65 drivers
|
||||
ld65 -o $*.vicprg -C vic20-32k.cfg -m $*.vic.map -vm $< $(IP65LIB) $(VICDRIVERLIB) vic20.lib
|
||||
ld65 -o $*.vicprg -C vic20-32k.cfg -m $*.vicprg.map -vm $< $(IP65LIB) $(VICDRIVERLIB) vic20.lib
|
||||
|
||||
%.prg: %.c ip65 drivers
|
||||
cl65 -o $*.prg -O -t c64 -m $*.c64.map -vm $< $(wildcard $**.s) $(IP65LIB) ../drivers/ip65_c64.lib
|
||||
rm $*.o
|
||||
cl65 -o $*.prg -O -t c64 -m $*.prg.map -vm $< $(wildcard $**.s) $(IP65LIB) ../drivers/ip65_c64.lib
|
||||
|
||||
%.bin: %.c ip65 drivers
|
||||
cl65 -o $*.bin -O -t apple2 -m $*.a2.map -vm $< $(wildcard $**.s) $(IP65LIB) ../drivers/ip65_apple2.lib
|
||||
rm $*.o
|
||||
cl65 -o $*.bin -O -t apple2 -m $*.bin.map -vm $< $(wildcard $**.s) $(IP65LIB) ../drivers/ip65_apple2.lib
|
||||
|
||||
%.com: %.c ip65 drivers
|
||||
cl65 -o $*.com -O -t atari -m $*.atr.map -vm $< $(wildcard $**.s) $(IP65LIB) ../drivers/ip65_atari.lib
|
||||
rm $*.o
|
||||
cl65 -o $*.com -O -t atari -m $*.com.map -vm $< $(wildcard $**.s) $(IP65LIB) ../drivers/ip65_atari.lib
|
||||
|
||||
%.xl.com: %.c ip65 drivers
|
||||
cl65 -o $*.xl.com -O -t atarixl -m $*.atrxl.map -vm $< $(wildcard $**.s) $(IP65LIB) ../drivers/ip65_atarixl.lib
|
||||
rm $*.o
|
||||
cl65 -o $*.xl.com -O -t atarixl -m $*.xl.com.map -vm $< $(wildcard $**.s) $(IP65LIB) ../drivers/ip65_atarixl.lib
|
||||
|
||||
ip65test.d64: prg
|
||||
$(C1541) -format ip65,00 d64 $@
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
.import url_port
|
||||
.import url_selector
|
||||
.import url_resource_type
|
||||
.import url_parse
|
||||
.import url_download
|
||||
.import url_download_buffer
|
||||
.import url_download_buffer_length
|
||||
|
|
|
@ -100,6 +100,7 @@ test_url_parse:
|
|||
jsr print
|
||||
jsr print_cr
|
||||
ldax temp_url_ptr
|
||||
ldy #1
|
||||
jsr url_parse
|
||||
bcc :+
|
||||
jmp print_errorcode
|
||||
|
|
Loading…
Reference in New Issue
Block a user