home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 June
/
SIMTEL_0692.cdr
/
msdos
/
ddjmag
/
ddj8904.arc
/
PROTO
< prev
next >
Wrap
Text File
|
1989-03-27
|
19KB
|
634 lines
_C PROGRAMMING COLUMN_
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 <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <mem.h>
#include <ctype.h>
#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 <stdio.h>
#include <conio.h>
#include <ctype.h>
#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 <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <mem.h>
#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);
}