home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 September
/
Simtel20_Sept92.cdr
/
msdos
/
ddjmag
/
ddj8903.arc
/
STEVENS.LST
< prev
Wrap
File List
|
1989-02-10
|
22KB
|
759 lines
_C PROGRAMMING COLUMN_
by Al Stevens
[LISTING ONE]
/* ------ smallcom.c ---------- */
#include <conio.h>
#include <stdio.h>
#include <mem.h>
#include <string.h>
#include <ctype.h>
#include <dos.h>
#include <stdlib.h>
#include "window.h"
#include "editor.h"
#include "menu.h"
#include "entry.h"
#include "serial.h"
#include "modem.h"
#include "help.h"
#define ANSWERTIMEOUT 60
#define MAXSTRINGS 15
#define carrier() (inp(MODEMSTATUS) & 0x80)
#define LOGFILE "smallcom.log"
#define HELPFILE "smallcom.hlp"
#define CFGFILE "smallcom.cfg"
#define ALT_P 153
#define ALT_C 174
#define CTRL_C 3
#define WILDCARD '?'
static union REGS rg;
static FILE *logfp, *uploadfp, *downloadfp, *cfg;
static int running=1,connected,answering,savebaud;
int filecount;
extern int direct_connection, TIMEOUT, inserting;
extern char spaces[];
extern struct wn wkw;
extern MENU *mn;
/* ---------- prototypes ----------- */
void fileedit(char *);
static void displaycount(void);
static void smallmenu(int);
static void logserial(int);
static int upload(int, int);
static int download(int, int);
static int call(int, int);
static int directory(int, int);
static int comeditor(int, int);
static answer(int, int);
static directcon(int, int);
static int loginput(int, int);
static int hangup(int, int);
static int quit(int, int);
static int prm(int, int);
static void loadp(void);
static int savep(int, int);
static void set_parameters(void);
static int get_filename(char *);
static void notice(char *);
static void statusline(void);
static void putch_window(int);
void upload_ASCII(FILE *);
void download_ASCII(FILE *);
int keyhit(void);
char *prompt_line(char *, int, char *);
void reset_prompt(char *, int);
static int testcarrier(void);
static int waitforconnect(void);
static void initcom(void);
int waitforresult(void);
int waitforstring(char **, int, int);
static void waitforcall(void);
static void resetline(void);
/* ------- the hook to the phone directory ---------- */
static void (*phone_directory)(void) = NULL;
/* ------- the hook to script processors ---------- */
void (*script_processor)(void); /* filled in by directory */
/* ------- hooks to file transfer protocols --------- */
static int (*select_transfer_protocol)(void) = NULL;
/* ----- up to five upload function pointers ----- */
static void (*up_protocol[5])(FILE *file_pointer) = {
upload_ASCII, NULL, NULL, NULL, NULL
};
/* ----- up to five download function pointers ----- */
static void (*down_protocol[5])(FILE *file_pointer) = {
download_ASCII, NULL, NULL, NULL, NULL
};
/* --------- Files menu ------------ */
static char *fselcs[] = {
"Log Input On/Off",
"Upload a File",
"Download a File",
"Quit",
NULL
};
static char *fhelps[] = {"log","upload","download","quitcom"};
/* ----------- Connect menu -------------- */
static char *cselcs[] = {
"Place Call",
"Answer Call",
"Hang up",
"Direct Connection",
NULL
};
static char *chelps[] = {"call","answer","hangup","direct"};
/* ---------- Parameters menu --------------- */
static char *pselcs[] = {
"Com Port: ",
"Baud Rate: ",
"Data Bits: ",
"Stop Bit(s): ",
"Parity: ",
"Mode of Dialing: ",
"Write Parameters",
NULL
};
static char *phelps[] = {"port","baud","wordlen","stopbits",
"parity","dialmode","writecfg"};
/* ---------- menu selection function tables ----------- */
static int (*ffuncs[])() = {loginput,upload,download,quit};
static int (*cfuncs[])() = {call,answer,hangup,directcon};
static int (*pfuncs[])() = {prm,prm,prm,prm,prm,prm,savep};
static int (*efuncs[])() = {comeditor};
static int (*dfuncs[])() = {directory};
/* ------ horizontal prompt messages ---------- */
char fdesc[]="Message File Operations";
char cdesc[]="Connections to Remote Processor";
char pdesc[]="Set Communications Parameters for Program Start";
char edesc[]="Edit a Text File";
char ddesc[]="The SMALLCOM Telephone Directory";
/* ------- horizontal menu bar ----------- */
static MENU cmn [] = {
{"File", fdesc, fselcs, fhelps, "ludq", ffuncs, 0},
{"Connect", cdesc, cselcs, chelps, "pahd", cfuncs, 0},
{"Parameters", pdesc, pselcs, phelps, "cbdspmw", pfuncs, 0},
{"Editor", edesc, NULL, NULL, "e", efuncs, 0},
{"Directory", ddesc, NULL, NULL, "d", dfuncs, 0},
{NULL}
};
/* ------ filename data entry template and buffer ------- */
static char filename[65], filemask[65];
static FIELD fn_template[] = {
{2,14,1,filename,filemask,NULL},
{0}
};
/* ------ modem result codes ------- */
static char *results[] = {
"\r\nOK\r\n",
"\r\nCONNECT\r\n",
"\r\nRING\r\n",
"\r\nNO CARRIER\r\n",
"\r\nERROR\r\n",
"\r\nCONNECT 1200\r\n",
"\r\nNO DIALTONE\r\n",
"\r\nBUSY\r\n",
"\r\nNO ANSWER\r\n",
"\r\n\r\n",
"\r\nCONNECT 2400\r\n",
NULL
};
extern int COMPORT,PARITY,STOPBITS,WORDLEN,BAUD;
extern char DIAL[], PHONENO[];
/* ================ MAIN ================== */
void main(void)
{
int c;
char *mb;
inserting = FALSE;
load_help(HELPFILE);
loadp();
savebaud = BAUD;
set_parameters();
clear_screen();
mb = display_menubar(cmn);
establish_window(1,2,80,24,TEXTFG,TEXTBG,TRUE);
statusline();
initcom();
gotoxy(2,2);
while (running) {
set_help("smallcom");
testcarrier();
if (keyhit()) {
switch (c = getkey()) {
case F10: smallmenu(0); break;
case ALT_F: smallmenu(1); break;
case ALT_C: smallmenu(2); break;
case ALT_P: smallmenu(3); break;
case ALT_E: smallmenu(4); break;
case ALT_D: smallmenu(5); break;
case CTRL_C:clear_window();
wkw.wx = wkw.wy = 0;
gotoxy(2,2);
break;
case ESC: quit(1,1);
break;
default: if (!(c & 0x80) && connected) {
if (answering
|| direct_connection)
logserial(c=='\r'?'\n':c);
writecomm(c);
if (c == '\r')
writecomm('\n');
}
break;
}
}
if (input_char_ready()) {
logserial(c = readcomm());
if (answering)
writecomm(c);
}
}
if (connected)
hangup(1,1);
release_modem();
restore_menubar(mb);
delete_window();
clear_screen();
}
/* ---------- execute the SMALLCOM menu --------- */
static void smallmenu(int n)
{
window(1,25,80,25);
gotoxy(1,1);
cprintf(spaces);
putch(' ');
current_window();
menu_select(cmn, n);
set_parameters();
statusline();
gotoxy(wkw.wx+2, wkw.wy+2);
}
/* ------ Call menu command ------ */
static int call(hs, vs)
{
if (!connected) {
notice("Dialing");
placecall();
sleep(4);
delete_window();
if ((connected = waitforconnect()) == FALSE) {
statusline();
initmodem();
}
else if (script_processor)
(*script_processor)();
}
return TRUE;
}
/* --------- Direct Connection menu command --------- */
static int directcon(hs, vs)
{
direct_connection ^= 1;
connected |= direct_connection;
return TRUE;
}
/* ------- Hangup menu command ------- */
static int hangup(hs, vs)
{
if (connected) {
notice("Hanging up");
resetline();
delete_window();
}
return TRUE;
}
/* --------- Quit menu command --------- */
static int quit(hs, vs)
{
int c = 0;
notice("Exit to DOS? ");
c = getkey();
delete_window();
running = (tolower(c) != 'y');
return TRUE;
}
/* -------- Log Input menu command -------- */
static int loginput(hs, vs)
{
if (logfp == NULL)
logfp = fopen(LOGFILE, "ab");
else {
fclose(logfp);
logfp = NULL;
}
return TRUE;
}
/* ---------- Upload file menu command ---------- */
static int upload(hs, vs)
{
int pr = 0;
if (!connected) {
error_message("Not connected");
return FALSE;
}
if (uploadfp == NULL) {
setmem(filename, sizeof filename - 1, ' ');
setmem(filemask, sizeof filemask - 1, '_');
if (get_filename(" Upload what file? ") != ESC) {
if ((uploadfp = fopen(filename, "rb")) == NULL)
error_message("Cannot open file");
else {
statusline();
if (select_transfer_protocol)
pr = (*select_transfer_protocol)();
(*up_protocol[pr])(uploadfp);
fclose(uploadfp);
uploadfp = NULL;
}
}
}
return TRUE;
}
/* ------ upload a file with ASCII transfer protocol ----- */
void upload_ASCII(FILE *fp)
{
int c;
while ((c = fgetc(fp)) != EOF) {
writecomm(c);
displaycount();
if (input_char_ready())
logserial(readcomm());
if (keyhit())
if (getch() == ESC)
break;
if (!testcarrier())
break;
}
filecount = 0;
if (connected)
writecomm(EOF);
}
/* ---------- Download file menu command ---------- */
static int download(hs, vs)
{
int pr = 0, save_timeout;
if (!connected) {
error_message("Not connected");
return FALSE;
}
setmem(filename, sizeof filename - 1, ' ');
setmem(filemask, sizeof filemask - 1, '_');
if (get_filename(" Download what file? ") != ESC) {
downloadfp = fopen(filename, "wb");
statusline();
if (select_transfer_protocol)
pr = (*select_transfer_protocol)();
save_timeout = TIMEOUT;
TIMEOUT = 60;
(*down_protocol[pr])(downloadfp);
TIMEOUT = save_timeout;
fclose(downloadfp);
downloadfp = NULL;
}
return TRUE;
}
/* ----- download a file with ASCII transfer protocol ----- */
void download_ASCII(FILE *fp)
{
int c = 0;
while (TRUE) {
if (keyhit()) {
if ((c = getkey()) == ESC)
break;
writecomm(c);
if (!answering)
logserial(readcomm());
}
c = readcomm() & 127;
if (c == 0 || c == 0x7f)
break;
fputc(c, fp);
displaycount();
if (!testcarrier())
break;
}
}
/* --- echo modem input and write to the log if selected --- */
static void logserial(int c)
{
putch_window(c);
if (logfp)
fputc(c, logfp);
}
/* -------- read a file name ------------- */
static int get_filename(char *ttl)
{
int rtn;
establish_window(1,23,80,25,ENTRYFG,ENTRYBG,TRUE);
window_title(ttl);
gotoxy(3,2);
cputs("File name:");
rtn = data_entry(fn_template, TRUE, 1);
delete_window();
return rtn;
}
/* -------- small message ------------ */
static void notice(char *s)
{
int lf = (80-strlen(s))/2-1;
int rt = lf+strlen(s)+2;
establish_window(lf,11,rt,13,HELPFG,HELPBG,TRUE);
gotoxy(2,2);
cputs(s);
}
/* ---- comm and modem parameter menu commands ----- */
static int prm(hs, vs)
{
switch (vs) {
case 1: COMPORT ^= 3; /* flip between 1 and 2 */
break;
case 2: BAUD *= 2; /* 110,150,300, */
if (BAUD == 220) /* 600,1200,2400 */
BAUD = 150;
if (BAUD == 4800)
BAUD = 110;
break;
case 3: WORDLEN ^= 0xf; /* flip between 7 and 8 */
break;
case 4: STOPBITS ^= 3; /* flip between 1 and 2 */
break;
case 5: if (++PARITY == 3) /* 0, 1, 2 */
PARITY = 0;
break;
case 6: DIAL[3] = DIAL[3] == 'T' ? 'P' : 'T';
break;
default:
break;
}
set_parameters();
return FALSE;
}
/* ------ post the parameters into the menu display ------- */
static void set_parameters(void)
{
static char *pars[] = {"None", " Odd", "Even"};
static char *mode[] = {"Pulse", " Tone"};
pselcs[0][strlen(pselcs[0])-1] = '0' + COMPORT;
sprintf(&pselcs[1][strlen(pselcs[1])-4],"%4d",BAUD);
pselcs[2][strlen(pselcs[2])-1] = '0' + WORDLEN;
pselcs[3][strlen(pselcs[3])-1] = '0' + STOPBITS;
sprintf(&pselcs[4][strlen(pselcs[4])-4],"%s",pars[PARITY]);
sprintf(&pselcs[5][strlen(pselcs[5])-5],"%s",
mode[DIAL[3]=='T']);
}
/* ------- load the configuration file ---------- */
static void loadp(void)
{
if ((cfg = fopen(CFGFILE, "r")) != NULL) {
fscanf(cfg,"%d %d %d %d %d %c %s",
&COMPORT,&PARITY,&STOPBITS,&WORDLEN,&BAUD,&DIAL[3],
&PHONENO[0]);
fclose(cfg);
}
}
/* ---------- Write Parameters menu command ---------- */
static int savep(hs, vs)
{
cfg = fopen(CFGFILE, "w");
fprintf(cfg, "%d %d %d %d %d %c %s",
COMPORT,PARITY,STOPBITS,WORDLEN,BAUD,DIAL[3],PHONENO);
fclose(cfg);
initcom();
return FALSE;
}
/* --------- Editor menu command --------------- */
static int comeditor(hs, vs)
{
extern int MAXLINES, inserting;
MAXLINES = 800;
mn = NULL;
fileedit("");
inserting = FALSE;
insert_line();
return TRUE;
}
/* --------- Directory menu command --------------- */
static int directory(hs, vs)
{
if (phone_directory) {
mn = NULL;
(*phone_directory)();
}
return TRUE;
}
/* ----------- display a status line ----------- */
static void statusline(void)
{
char stat[81];
static char *st = NULL;
sprintf(stat,
" %s Line %s %s %s %-12.12s %-14.14s F10:Menu",
(connected ? " On" : "Off"),
(direct_connection ? "Direct" : " "),
(logfp ? "Logging" : " "),
((answering & !connected)
? "Answering " :
uploadfp ? "Uploading " :
downloadfp ? "Downloading" : " "),
(uploadfp||downloadfp ? filename : " "),
*PHONENO ? PHONENO : "No Phone #");
st = prompt_line(stat, 25, st);
}
/* ------- write the file count into the status line ------- */
static void displaycount(void)
{
filecount++;
if ((filecount % 10) == 0) {
window(1,25,80,25);
textcolor(MENUFG);
textbackground(MENUBG);
gotoxy(50,1);
cprintf("%5d", filecount);
current_window();
gotoxy(wkw.wx+2, wkw.wy+2);
}
}
/* ----- write a one-liner prompt saving video memory ----- */
char *prompt_line(char *s, int y, char *t)
{
if (t == NULL)
if ((t = malloc(160)) != NULL)
gettext(1,y,80,y,t);
window(1,y,80,y);
textcolor(MENUFG);
textbackground(MENUBG);
gotoxy(1,1);
cprintf(spaces);
putch(' ');
gotoxy(1,1);
cprintf(s);
current_window();
return t;
}
/* ------- reset the one-liner prompt line --------- */
void reset_prompt(char *s, int y)
{
puttext(1,y,80,y,s);
free(s);
}
/* -------- write a character to the user's window -------- */
static void putch_window(int c)
{
gotoxy(wkw.wx+2, wkw.wy+2);
switch (c) {
case '\t': while (wkw.wx % 4)
putch_window(' ');
break;
case '\b': if (wkw.wx)
--wkw.wx;
break;
default: putch(c);
wkw.wx++;
if (wkw.wx < wkw.wd-2)
break;
case '\n': if (wkw.wy < wkw.ht-1)
wkw.wy++;
else {
scroll_window(1);
writeline(2, wkw.wy+2, spaces+1);
}
case '\r': wkw.wx = 0;
break;
}
gotoxy(wkw.wx+2, wkw.wy+2);
}
/* ------------ wait for a call ------------ */
static void waitforcall(void)
{
answercall();
if ((connected = answering = waitforconnect()) == FALSE) {
statusline();
initmodem();
}
}
/* ---- wait for a line connection, reset baud rate ---- */
static int waitforconnect(void)
{
extern int BAUD;
int baud = 0;
while (baud == 0)
switch (waitforresult()) {
case 1: baud = 300; break; /* CONNECT */
case 5: baud = 1200; break; /* CONNECT 1200 */
case 10: baud = 2400; break; /* CONNECT 2400 */
case 0: /* OK */
case 2: break; /* RING */
case 3: /* NO CARRIER */
case 4: /* ERROR */
case 7: /* BUSY */
case 8: /* NO ANSWER */
case -1: baud = -1; break; /* time-out */
default: break; /* anything else */
}
if (baud != -1 && baud != BAUD) {
savebaud = BAUD;
BAUD = baud;
initcomport();
}
return (baud != -1);
}
/* ---- wait for a modem result (0-10). -1 if timed out ---- */
int waitforresult(void)
{
return waitforstring(results, ANSWERTIMEOUT, 0);
}
/* --------- wait for a string from the serial port -------- */
int waitforstring(char *tbl[], int wait, int wildcard)
{
int c, i, done = FALSE;
char *sr[MAXSTRINGS];
for (i = 0; tbl[i] != NULL; i++)
sr[i] = tbl[i];
while (!done) {
set_timer(wait);
while (!input_char_ready()) {
if (timed_out())
return -1;
if (keyhit())
if ((c = getkey()) == ESC)
return -1;
}
logserial(c = readcomm());
for (i = 0; tbl[i] != NULL; i++) {
if (c==*(sr[i]) ||
(wildcard && *(sr[i])==wildcard)) {
if (*(++(sr[i])) == '\0') {
done = TRUE;
break;
}
}
else
sr[i] = tbl[i];
}
}
return i;
}
/* ----- initialize from serial and modem parameters ----- */
static void initcom(void)
{
notice("Initializing Modem");
initmodem();
delete_window();
}
/* ----- test carrier detect -------- */
static int testcarrier(void)
{
if (!direct_connection && connected && carrier() == FALSE)
resetline();
return connected;
}
/* ------ disconnect and reestablish the serial port ------ */
static void resetline(void)
{
answering = connected = FALSE;
statusline();
disconnect();
BAUD = savebaud;
initcomport();
}
/* --------- answer a call ----------- */
static int answer(hs, vs)
{
answering = 1;
statusline();
gotoxy(wkw.wx+2, wkw.wy+2);
waitforcall();
return TRUE;
}
#if COMPILER==TURBOC
/* --------- use bios to test for a keystroke -------- */
int keyhit(void)
{
rg.h.ah = 1;
int86(0x16, &rg, &rg);
return ((rg.x.flags & 0x40) == 0);
}
#endif
[LISTING TWO]
smallcom (serial.h,modem.h,editor.h,window.h,menu.h,entry.h,help.h)
editshel (editor.h, menu.h, entry.h, help.h, window.h)
editor (editor.h, window.h)
help (help.h, window.h)
modem (serial.h, modem.h)
serial (serial.h)
entry (entry.h, window.h)
menu (menu.h, window.h)
window (window.h)
[LISTING THREE]
#
# SMALLCOM.MAK: make file for SMALLCOM.EXE with Microsoft C/MASM
#
.c.obj:
cl /DMSOFT=1 /DTURBOC=2 /DCOMPILER=MSOFT -c -W3 -Gs -AC $*.c
smallcom.obj : smallcom.c serial.h modem.h menu.h entry.h \
help.h window.h
modem.obj : modem.c serial.h modem.h
serial.obj : serial.c serial.h
entry.obj : entry.c entry.h window.h
menu.obj : menu.c menu.h window.h
help.obj : help.c help.h window.h
editshel.obj : editshel.c editor.h menu.h entry.h help.h \
window.h
editor.obj : editor.c editor.h window.h
window.obj : window.c window.h
microsft.obj : microsft.c
vpeek.obj : vpeek.asm
masm /MX vpeek;
keyhit.obj : keyhit.asm
masm /MX keyhit;
smallcom.exe : smallcom.obj modem.obj serial.obj editor.obj \
editshel.obj entry.obj menu.obj help.obj \
window.obj keyhit.obj vpeek.obj microsft.obj
link @smallcom.lnk
[LISTING FOUR]
smallcom+
modem+
serial+
entry+
menu+
editor+
editshel+
help+
window+
vpeek+
keyhit+
microsft
smallcom
nul
\lib\clibce