Category : Files from Magazines
Archive   : DDJ0489.ZIP
Filename : PROTO
by Al Stevens
[LISTING ONE]
/* ------- the hook to the phone directory ---------- */
extern void phdirectory(void);
static void (*phone_directory)(void) = phdirectory;
/* ------- the hook to script processors ---------- */
void (*script_processor)(void);
/* ------- hooks to file transfer protocols --------- */
extern int select_protocol(void);
static int (*select_transfer_protocol)(void) = select_protocol;
/* ----- up to five upload function pointers ----- */
void upload_xmodem(FILE *);
void upload_kermit(FILE *);
static void (*up_protocol[5])(FILE *file_pointer) = {
upload_ASCII, upload_xmodem, upload_kermit,NULL,NULL
};
/* ----- up to five download function pointers ----- */
void download_xmodem(FILE *);
void download_kermit(FILE *);
static void (*down_protocol[5])(FILE *file_pointer) = {
download_ASCII, download_xmodem, download_kermit,NULL,NULL
};
[LISTING TWO]
/* --------- phonedir.c ---------- */
#include
#include
#include
#include
#include
#include
#include "window.h"
#include "entry.h"
#include "help.h"
#include "modem.h"
#define DIRECTORY "phone.dir"
#define MAX_ENTRIES 50
#define WRITEDIR F2
#define MODIFYDIR F3
void phdirectory(void);
char scriptfile[13];
static void get_directory(void);
static void put_directory(void);
static int dirproc(int, int);
static void bld_default(int);
static void build_dir(int);
static int enter_directory(int);
static void select_directory(int);
char *prompt_line(char *, int, char *);
void reset_prompt(char *, int);
static int edit_directory(void);
static int direrror(int);
static void field_terminate(FIELD *fld, int termchar);
extern int PARITY,STOPBITS,WORDLEN,BAUD;
extern char PHONENO[];
extern char spaces[];
extern struct wn wkw; /* the directory window structure */
extern void (*phone_directory)() = phdirectory;
/* -------- phone directory file record ------------ */
struct {
char ol_name[21]; /* callee's name */
char ol_phone[24]; /* phone number */
char ol_parity[8]; /* none/odd/even */
char ol_stopbits[4]; /* 1 or 2 */
char ol_wordlen[3]; /* 7 or 8 */
char ol_baud[6]; /* 110,150,300,600,1200,2400 */
char ol_script[9]; /* name of script file */
} pd;
static char hdr[] =
" Name "
"Phone Number "
"Parity Stop Len Baud Script";
static char select_prompt[] =
"\030\031\021\304\331:Select Esc:Return "
"F2:Write Directory F3:Modify "
"Ins:Insert Del:Delete";
static char enter_prompt[] =
" F2:Write Changes to Directory "
" Esc:Ignore Entry F1:Help";
static char *pds[MAX_ENTRIES+1];
static int pct;
static FILE *fp;
static char nmmask[] = "____________________";
static char phmask[] = "____________________";
static char prmask[] = "____";
static char sbmask[] = "_";
static char wlmask[] = "_";
static char bdmask[] = "____";
static char scmask[] = "________";
/* ------- data entry template for the directory ------- */
FIELD directory_template[] = {
{3, 16, 1, pd.ol_name, nmmask, "name"},
{4, 16, 1, pd.ol_phone, phmask, "phone"},
{5, 16, 1, pd.ol_parity, prmask, "parity"},
{6, 16, 1, pd.ol_stopbits, sbmask, "stopbits"},
{7, 16, 1, pd.ol_wordlen, wlmask, "wordlen"},
{8, 16, 1, pd.ol_baud, bdmask, "baud"},
{9, 16, 1, pd.ol_script, scmask, "script"},
{0}
};
/* -------- data entry error messages --------- */
static char *ermsgs[] = {
"Parity must be None, Odd, or Even",
"Stop Bits must 1 or 2",
"Word Length must be 7 or 8",
"Baud Rate must be 110,150,300,600,1200,2400"
};
/* ------ manage the telephone directory ------ */
void phdirectory(void)
{
int s = 1;
char *ttl, *sel;
set_help("directry");
ttl = prompt_line(hdr, 1, NULL);
sel = prompt_line(select_prompt, 25, NULL);
establish_window(1,2,80,24,TEXTFG,TEXTBG,TRUE);
get_directory();
text_window(pds, 1);
while (pct &&
(s=select_window(s,SELECTFG,SELECTBG,dirproc))!=0)
if (pct && pds[s-1] != spaces+1) {
select_directory(s-1);
break;
}
delete_window();
reset_prompt(sel, 25);
reset_prompt(ttl, 1);
}
/* -------- select the directory entry for the dialer ------- */
static void select_directory(int n)
{
char *cp = scriptfile;
movmem(pds[n], &pd, sizeof pd);
strncpy(PHONENO, pd.ol_phone, 20);
BAUD = atoi(pd.ol_baud);
STOPBITS = *pd.ol_stopbits - '0';
WORDLEN = *pd.ol_wordlen - '0';
PARITY = (*pd.ol_wordlen == 'N' ? 0 :
*pd.ol_wordlen == 'O' ? 1 : 2);
establish_window(30,11,50,13,HELPFG,HELPBG,TRUE);
gotoxy(2,2);
cputs("Initializing Modem");
initmodem();
delete_window();
setmem(scriptfile, sizeof scriptfile, '\0');
strncpy(scriptfile, pd.ol_script, 8);
while (*cp && *cp != ' ')
cp++;
strcpy(cp, ".scr");
}
/* ------ read the phone directory ----------- */
static void get_directory(void)
{
if (pct == 0 && (fp = fopen(DIRECTORY, "r")) != NULL) {
while (fread(&pd, sizeof pd, 1, fp) != 0) {
build_dir(pct++);
if (pct == MAX_ENTRIES)
break;
}
pds[pct++] = spaces+1;
pds[pct] = NULL;
fclose(fp);
}
if (pct == 0)
dirproc(INS, 1);
}
/* ------- build a default phone directory entry -------- */
static void bld_default(int n)
{
static char *prs[] = {"None", "Odd ", "Even"};
setmem(&pd, sizeof pd-1, ' ');
strncpy(pd.ol_parity, prs[PARITY], 4);
*pd.ol_stopbits = STOPBITS + '0';
*pd.ol_wordlen = WORDLEN + '0';
sprintf(pd.ol_baud, "%4d", BAUD);
pd.ol_baud[4] = ' ';
build_dir(n);
}
/* --------- build a directory entry for display ----------- */
static void build_dir(int n)
{
if ((pds[n] = malloc(sizeof pd)) != NULL)
movmem(&pd, pds[n], sizeof pd);
}
/* ------- write the phone directory ---------- */
static void put_directory(void)
{
int i;
fp = fopen(DIRECTORY, "w");
for (i = 0; i < pct; i++)
if (pds[i] != spaces+1)
fwrite(pds[i], sizeof pd, 1, fp);
fclose(fp);
}
/* ---------- process a directory entry ------------- */
static int dirproc(int c, int lineno)
{
int i, j;
switch (c) {
case DEL:
if (pds[lineno-1] != spaces+1) {
free(pds[lineno-1]);
for (j = lineno-1; j < pct; j++)
pds[j] = pds[j+1];
if (--pct) {
text_window(pds, wkw.wtop);
for (i = pct+2; i <= wkw.wtop+wkw.ht; i++)
writeline(2, i, spaces+1);
if (lineno-1 == pct)
--lineno;
}
else
clear_window();
}
break;
case INS:
if (pct == MAX_ENTRIES)
break;
i = pct;
if (i)
while (i >= lineno) {
pds[i] = pds[i-1];
--i;
}
bld_default(i);
pct++;
case MODIFYDIR:
if (pds[lineno-1] != spaces+1) {
movmem(pds[lineno-1], &pd, sizeof pd);
enter_directory(lineno-1);
}
break;
case WRITEDIR:
put_directory();
break;
}
wkw.wy = lineno - wkw.wtop + 1;
return (pct == 0);
}
/* ------- data entry for a directory record ---------- */
static int enter_directory(int lineno)
{
int s = 1;
char *p = prompt_line(enter_prompt, 25, NULL);
establish_window(20,5,56,15,ENTRYFG,ENTRYBG,TRUE);
window_title(" Telephone Directory Entry ");
gotoxy(3,3), cputs("Name:");
gotoxy(3,4), cputs("Phone:");
gotoxy(3,5), cputs("Parity:");
gotoxy(3,6), cputs("Stop Bits:");
gotoxy(3,7), cputs("Word Length:");
gotoxy(3,8), cputs("Baud Rate:");
gotoxy(3,9), cputs("Script:");
field_terminate(directory_template, '\0');
while (s != WRITEDIR && s != ESC) {
s = data_entry(directory_template, FALSE, s);
if (s == WRITEDIR)
s = edit_directory();
}
field_terminate(directory_template, ' ');
*(((char *)(&pd)) + sizeof pd - 1) = '\0';
delete_window();
reset_prompt(p, 25);
if (s == WRITEDIR) {
movmem(&pd, pds[lineno], sizeof pd);
put_directory();
}
text_window(pds,wkw.wtop ? wkw.wtop : 1);
return (s != ESC);
}
/* -------- validate the directory entry -------- */
static int edit_directory(void)
{
int i;
static int bds[] = {110,150,300,600,1200,2400};
*pd.ol_parity = toupper(*pd.ol_parity);
if (*pd.ol_parity != 'N' &&
*pd.ol_parity != 'O' &&
*pd.ol_parity != 'E')
return direrror(3);
if (*pd.ol_stopbits != '1' && *pd.ol_stopbits != '2')
return direrror(4);
if (*pd.ol_wordlen != '7' && *pd.ol_wordlen != '8')
return direrror(5);
for (i = 0; i < 6; i++)
if (atoi(pd.ol_baud) == bds[i])
break;
if (i == 6)
return direrror(6);
return WRITEDIR;
}
/* ------- post a directory entry error ---------- */
static int direrror(int n)
{
error_message(ermsgs[n-3]);
return n;
}
/* -------- set field terminators to null or space ------- */
static void field_terminate(FIELD *fld, int termchar)
{
for (;fld->frow;fld++)
*(fld->fbuff+strlen(fld->fmask)) = termchar;
}
[LISTING THREE]
/* ------------- protocol.c --------------- */
#include
#include
#include
#include "window.h"
#include "help.h"
#include "menu.h"
static char *prots[] = {
" ASCII",
" Xmodem",
" Kermit",
NULL
};
/* ----- translate A,X,K keystrokes for protocol menu ----- */
static int protkey(int ky, int lnno)
{
ky = tolower(ky);
return ky=='a' ? 1 : ky=='x' ? 2 : ky=='k' ? 3 : ERROR;
}
/* --- file transfer protocol for uploads and downloads --- */
int select_protocol(void)
{
extern MENU *mn;
MENU *holdmn;
static int rtn = 0;
holdmn = mn;
mn = NULL;
set_help("protocol");
establish_window(25,7,55,11,MENUFG,MENUBG,TRUE);
window_title(" Select Transfer Protocol ");
text_window(prots, 1);
rtn = select_window(rtn?rtn:1,SELECTFG,SELECTBG,protkey);
delete_window();
mn = holdmn;
return rtn ? rtn-1 : 0;
}
/* ---- These are stubs, to be replaced later ---- */
void upload_kermit(FILE *fd)
{
error_message("Upload KERMIT not implemented");
}
void download_kermit(FILE *fd)
{
error_message("Download KERMIT not implemented");
}
[LISTING FOUR]
/* -------------- xmodem.c --------------- */
#include
#include
#include
#include
#include "window.h"
#include "serial.h"
#define RETRIES 12
#define CRCTRIES 2
#define PADCHAR 0x1a
#define SOH 1
#define EOT 4
#define ACK 6
#define NAK 0x15
#define CAN 0x18
#define CRC 'C'
/* -------- external data ---------- */
extern int TIMEOUT;
extern int WORDLEN;
extern int xonxoff_enabled;
/* --------- local data ------------ */
static int tries; /* retry counter */
static char bf [130]; /* i/o buffer */
/* -------- prototypes ------------- */
extern int keyhit(void);
static void receive_error(int, int);
static void xmodem_msg(char *);
static void test_wordlen(void);
unsigned compute_crc(char *, int);
/* --------- error messages ----------- */
static char *errs[] = {
"Timed Out ",
"Invalid SOH ",
"Invalid block # ",
"Invalid chksum/crc"
};
/* ---------- upload with xmodem protocol ------------- */
void upload_xmodem(FILE *fd)
{
int i, chksum, eof = FALSE, ans = 0, ln, crcout = 0;
unsigned crc;
char bno = 1;
xonxoff_enabled = FALSE;
establish_window(20,10,52,14,MENUFG,MENUBG,TRUE);
window_title("XMODEM Upload (CHKSUM)");
tries = 0;
test_wordlen();
/* ----- wait for the go-ahead from the receiver ------ */
TIMEOUT = 6;
while (tries++ < RETRIES && crcout != NAK && crcout != CRC)
crcout = readcomm();
if (crcout == CRC)
window_title(" XMODEM Upload (CRC) ");
TIMEOUT = 10;
/* -------- send the file to the receiver ----------- */
while (tries < RETRIES &&
!eof && ans != CAN && !timed_out()) {
/* ---- read the next data block ----- */
setmem(bf, 128, PADCHAR);
if ((ln = fread(bf, 1, 128, fd)) < 128)
eof = TRUE;
if (ln == 0)
break;
gotoxy(2, 2);
cprintf("Block %d ",bno);
chksum = 0;
if (keyhit())
if (getch() == ESC) {
writecomm(CAN);
break;
}
writecomm(SOH); /* SOH */
writecomm(bno); /* block number */
writecomm(~bno); /* 1s complement */
/* ------- send the data block ------ */
for (i = 0; i < 128; i++) {
writecomm(bf[i]);
chksum += bf[i]; /* checksum calculation */
}
/* -- send error-correcting value (chksum or crc) -- */
if (crcout == NAK)
writecomm(chksum & 255);
else {
crc = compute_crc(bf, 130);
writecomm((crc >> 8) & 255);
writecomm(crc & 255);
}
/* ----- read ACK, NAK, or CAN from receiver ----- */
ans = readcomm();
if (ans == ACK) {
bno++;
tries = 0;
gotoxy(2, 4);
cprintf(" ");
}
if (ans == NAK) {
eof = FALSE;
gotoxy(2, 4);
cprintf("%2d tries", ++tries);
/* ---- position to previous block ----- */
if (fseek(fd, -128L, 1) == -1)
fseek(fd, 0L, 0);
}
}
if (eof) {
writecomm(EOT); /* send the EOT */
readcomm(); /* wait for an ACK */
xmodem_msg("Transfer Completed");
}
else
xmodem_msg("Transfer Aborted");
xonxoff_enabled = TRUE;
}
/* ---------- download with xmodem protocol ------------- */
void download_xmodem(FILE *fd)
{
int blk=0, soh= 0, bn, nbn, i, crcin = TRUE, fst = TRUE;
unsigned chksum, cs, cs1;
xonxoff_enabled = FALSE;
establish_window(20,10,52,14,MENUFG,MENUBG,TRUE);
window_title("XMODEM Download (CHKSUM)");
/* - send Cs then NAKs until the sender starts sending - */
tries = 0;
test_wordlen();
TIMEOUT = 6;
while (soh != SOH && tries < RETRIES) {
crcin = (tries++ < CRCTRIES);
writecomm(crcin ? CRC : NAK);
soh = readcomm();
if (!timed_out() && soh != SOH)
sleep(6);
}
if (crcin)
window_title(" XMODEM Download (CRC) ");
while (tries < RETRIES) {
if (timed_out())
receive_error(0, NAK);
/* -- Receive the data and build the file -- */
gotoxy(2,2);
cprintf("Block %d ", blk + 1);
if (!fst) {
TIMEOUT = 10;
soh = readcomm();
if (timed_out())
continue;
if (soh == CAN)
break;
if (soh == EOT) {
writecomm(ACK);
break;
}
}
fst = FALSE;
TIMEOUT = 1;
bn = readcomm(); /* block number */
nbn = readcomm(); /* 1's complement */
chksum = 0;
/* ---- data block ----- */
for (i = 0; i < 128; i++) {
*(bf + i) = readcomm();
if (timed_out())
break;
chksum = (chksum + (*(bf + i)) & 255) & 255;
}
if (timed_out())
continue;
/* ---- checksum or crc from sender ---- */
cs = readcomm() & 255;
if (crcin) {
cs1 = readcomm() & 255;
cs = (cs << 8) + cs1;
}
if (timed_out())
continue;
if (soh != SOH) { /* check the SOH */
receive_error(1, NAK);
continue;
}
/* --- same as previous block number? --- */
if (bn == blk)
fseek(fd, -128L, 1);
/* --- no, next sequential block number? --- */
else if (bn != blk + 1) {
receive_error(2, CAN);
break;
}
blk = bn;
/* --- test the block # 1s complement --- */
if ((nbn & 255) != (~blk & 255)) {
receive_error(2, NAK);
continue;
}
if (crcin)
chksum = compute_crc(bf, 130);
/* --- test chksum or crc vs one sent --- */
if (cs != chksum) {
receive_error(6, NAK);
continue;
}
soh = bn = nbn = cs = 0;
tries = 0;
/* --- write the block to disk --- */
fwrite(bf, 128, 1, fd);
if (keyhit())
if (getch() == ESC) {
writecomm(CAN);
break;
}
writecomm(ACK);
}
if (soh == EOT)
xmodem_msg("Transfer Complete");
else
xmodem_msg("Transfer Aborted");
TIMEOUT = 10;
xonxoff_enabled = TRUE;
}
/* ------------- send a nak ------------ */
static void receive_error(erno, rtn)
{
++tries;
if (TIMEOUT == 1) {
gotoxy(2,4);
cprintf("%s (%d tries)", errs[erno], tries);
}
writecomm(rtn);
}
/* ------ test for valid word length -------- */
static void test_wordlen(void)
{
if (WORDLEN != 8) {
gotoxy(2,4);
cprintf("Must be 8 Data Bits");
tries = RETRIES;
}
}
/* --------- final message about xmodem transfer -------- */
static void xmodem_msg(char *s)
{
gotoxy(2,3);
cprintf(s);
putch(BELL);
sleep(3);
delete_window();
}
/* --------- compute the crc ------------ */
unsigned compute_crc(char *bf, int len)
{
int i;
long crc = 0;
while (len--) {
crc |= (*bf++) & 255;
for (i = 0; i < 8; i++) {
crc <<= 1;
if (crc & 0x1000000L)
crc ^= 0x102100L;
}
}
return (unsigned) (crc >> 8);
}
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/