home *** CD-ROM | disk | FTP | other *** search
- _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);
- }
-
-