www.pudn.com > commutil.zip > DIAL.CPP
// ******************************************************************** //
// //
// DIAL.CPP //
// Copyright (c) 1993, Michael Holmes and Bob Flanders //
// C++ Communication Utilities //
// //
// Chapter 7: Receiving a FAX //
// Last changed in chapter 5 //
// //
// This file contains the functions that are under Alt-Dial //
// on the main menu. These functions manage the modem Hangup //
// function and the Phonebook edit and dial functions. //
// //
// ******************************************************************** //
/* ******************************************************************** *
*
* hangup() -- hangup the modem by lowering the DTR signal
*
* ******************************************************************** */
int hangup(int c, int r) // column and row for window
{
Window msg_win(c, r, // define temporary window
c + 27, r + 3, // ..to hold message
menu_cn, menu_cr); // ..using system colors
msg_win.Open(double_line); // open window with a border
msg_win.Display(hangup_msg); // ..display message
comm->DTR(1500L); // cycle the DTR line
msg_win.Display(hangup_done); // give completion message
wait_ms(500L); // ..and wait a half-second
return(0); // ..and return to caller
}
/* ******************************************************************** *
*
* field_pb() -- field level edit for phonebook field
*
* ******************************************************************** */
int field_pb(struct phone_entry *pb, // phonebook entry pointer
int f, // field number
Window *w) // current window
{
switch (f) // based on field number
{
case 0: // name field
case 1: // modem telephone number
case 2: // fax telephone number
case 3: // modem setup string
return(field_edit(w, // edit the string field
14, f + 1, // ..using a col and row
&pb->strings[f], PB_LEN)); // ..initial data and length
case 4: // baud rate
case 5: // parity
case 6: // data bits
case 7: // stop bits
pb->lp[f - 4] = // use next entry
&line_parms[pb->lp[f - 4]->next];// ..in the parms list
return(0); // ..then return to caller
default:
return(0); // default case return
}
}
/* ******************************************************************** *
*
* edit_pb() -- edit the phonebook entry
*
* ******************************************************************** */
int edit_pb(int c, int r, // column and row for window
struct phone_entry *pb) // phonebook entry pointer
{
int i, // loop counter
k, // keyboard input
idx; // line index
char b[60], // work buffer
*p; // string pointer
Window edit_win(c, r, c + 48, r + 9, // define temporary window
menu_cn, menu_cr); // ..for editing pb entry
edit_win.Open(double_line); // open window with a border
idx = 0; // set up for first entry
while(1) // loop till user exits
{
for (i = 0; i < 8; i++) // walk thru phonebook entry
{ // ..and build display window
if (i < 4) // q. doing strings fields?
{
p = pb->strings[i]; // a. yes .. get pointer
p = p ? p : ""; // ..and handle null pointer
}
else
p = pb->lp[i - 4]->parm; // else .. get line parm ptr
sprintf(b, "%-12.12s%-32.32s", // format a line with fld name
fld_name[i], p); // ..and corresponding data
edit_win.GotoXY(2, i + 1); // position to start of line
if (i == idx) // q. selected line?
edit_win.DisplayReverse(b); // a. yes .. highlight line
else
edit_win.Display(b); // else .. just display it
}
while (NOT (k = get_key(NO_ALT))) // wait for a key
; // ..before continuing
if ((k == CR) || k == SPACE) // q. edit requested?
{
phone_changed = 1; // a. yes .. set changed flag
k = field_pb(pb, idx, // call field edit routine
&edit_win);
}
switch (k) // based on keyboard input
{ // ..or edit return code
case 0: // no key available
break; // ..just wait for next key
case UP: // move up list
if (--idx < 0) // q. already at top of list?
idx = 7; // a. yes .. goto bottom
break; // wait for next key
case DOWN: // move down list
if (++idx == 8) // q. already at bottom?
idx = 0; // a. yes .. goto top of list
break; // wait for next key
case ESC: // escape from this menu
k = 0; // set key value to zero
// ..and fall into next case
case LEFT: // move left
case RIGHT: // ..or move right
return(k); // just rtn with the keystroke
default: // error case
printf(BELL); // ..just ring the bell
}
}
}
/* ******************************************************************** *
*
* wait_for() -- wait for response strings
*
* returns: -1 = abort by user
* 0 = timeout
* 1 = response 1 found
* 2 = response 2 found
*
* ******************************************************************** */
int wait_for(char *s1, // response string #1
char *s2, // ..and response string #2
long t) // seconds to wait
{
char c, // work character
m, l; // modem and line status
int len, // string length
rc = 0; // return code
char *b = 0; // work buffer pointer
t = SECS(t); // convert seconds to ticks
len = strlen(s1); // get first string's length
if (len < strlen(s2)) // q. second string longer?
len = strlen(s2); // a. yes .. save other's len
b = (char *) malloc_chk(len + 1); // get a work buffer
memset(b, ' ', len); // ..clear to blanks
b[len] = 0; // ..and make into a string
while (1)
{
if (time_out(&t) || (rc != 0)) // q. timed out waiting?
{
free(b); // a. yes .. free buffer
return(rc); // ..and return to caller
}
if (get_key(NO_ALT) == ESC) // q. get an ESC key?
rc = -1; // a. yes .. quit waiting
if (comm->Read(&c, &m, &l) != 0) // q. character available?
continue; // a. no .. just loop around
memmove(b, &b[1], len - 1); // shift buffer up by one
b[len - 1] = c; // put in new character
if (strstr(b, s1)) // q. find response string #1?
rc = 1; // a. yes .. quit and return
if (strstr(b, s2)) // q. find response string #2?
rc = 2; // a. yes .. quit and return
}
}
/* ******************************************************************** *
*
* send_expanded() -- expand and send the modem setup strings
*
* returns: 0 = sucessful response
* 1 = modem timeout or error response
*
* ******************************************************************** */
int send_expanded(char *s, // setup string
Window *win) // display window
{
int i, // loop control variable
rc = 0; // return code
char *w, // work pointer
*t; // text to output
if (NOT s || NOT first_nonblank(s)) // q. blank setup string?
return(0); // a. yes .. just return
win->Display(dial_msg[6]); // tell user about modem setup
s = w = strdup(s); // get a copy of the string
for (i = 0; NOT rc; i++) // loop thru tokens
{
s = strtok(i == 0 ? s : 0, delimit_4); // get a token from the string
if (NOT s) // q. out of tokens?
break; // a. yes .. exit loop
if (*s == '"' && LAST(s) == '"') // q. string constant?
{
LAST(s) = 0; // a. yes .. remove quote
t = ascii_encode(&s[1]); // ..and set up string
}
else
{
t = user_commands.Find(s); // lookup as user command
if (NOT t) // q. find user command?
{
win->Display(dial_msg[13]); // a. no .. give part of msg
win->Display(s); // ..then token name
rc = 14; // ..set up return code
break; // ..and exit loop
}
}
comm->Write(t); // send string to comm port
comm->Write(CMD_EXECUTE); // ..and modem execute string
switch (wait_for(CMD_OK, CMD_ERROR, 5)) // handle modem response
{
case -1: // user terminated wait
rc = 2; // set up msg/return code
break; // ..and exit loop
case 0: // timeout
rc = 3; // set up msg/return code
break; // ..and exit loop
case 1: // valid response from modem
break; // ..then just continue on
case 2: // invalid response from modem
rc = 8; // set up msg/return code
break; // ..and exit loop
}
}
win->Display(dial_msg[rc ? rc : 7]); // inform user of status
if (rc) // q. error return?
wait_ms(2000L); // a. yes .. wait a bit
free(w); // release work string
return(rc ? 1 : 0); // ..and return to caller
}
/* ******************************************************************** *
*
* dial_pb() -- dial the phonebook entry
*
* ******************************************************************** */
void dial_pb(struct phone_entry *pb, // phonebook entry pointer
int c, int r) // column and row for window
{
Window dial_win(c, r, c + 50, r + 9, // define temporary window
menu_cn, menu_cr); // ..for editing pb entry
dial_win.Open(single_line); // open progress window
if (first_nonblank(pb->PB_PHONE) == 0) // q. any phone number?
{
dial_win.Display(dial_msg[12]); // a. no .. give bad news
wait_ms(1500L); // ..wait a bit
return; // ..then return
}
dial_win.Display(dial_msg[0]); // give starting message
comm->SetSpeed(pb->PB_BAUD->value); // set baud rate
comm->SetLine(pb->PB_PAR->value | // ..and line control register
pb->PB_DATA->value | // ..with parity, data bits
pb->PB_STOP->value); // ..and stop bits
line[SPEED].lp = pb->PB_BAUD; // set global structure
line[PARITY].lp = pb->PB_PAR; // ..for baud, parity
line[DATA].lp = pb->PB_DATA; // ..data bits
line[STOP].lp = pb->PB_STOP; // ..and stop bits
status_line(); // ..then update status line
comm->IClear(); // ..and clear input buffer
if (*CMD_RESET) // q. reset command avail?
{ // a. yes .. send reset
dial_win.Display(dial_msg[1]); // keep user updated
comm->Write(CMD_RESET); // send reset command out
comm->Write(CMD_EXECUTE); // .. and execute the reset
switch (wait_for(CMD_OK, CMD_ERROR, 5)) // handle modem response
{
case -1: // user terminated wait
dial_win.Display(dial_msg[2]); // give confirmation message
wait_ms(1000L); // ..wait a second
return; // ..and return to caller
case 0: // timeout
dial_win.Display(dial_msg[3]); // inform user
break; // ..and continue on
case 1: // valid response from modem
dial_win.Display(dial_msg[4]); // inform user
wait_ms(500L); // wait .5 seconds
break; // ..and continue on
case 2: // invalid response from modem
dial_win.Display(dial_msg[5]); // inform user
wait_ms(2000L); // ..wait a second
return; // ..and return to caller
}
}
if (send_expanded(pb->PB_MODEM, &dial_win)) // q. error or user abort?
return; // a. yes .. return to caller
dial_win.Display(dial_msg[9]); // give user update
comm->Write(CMD_DIAL); // send out dial prefix,
comm->Write(pb->PB_PHONE); // ..the phone number,
comm->Write(CMD_EXECUTE); // ..and modem execute string
switch (wait_for(CMD_CONNECT, // handle modem response
CMD_NO_CONN, 45))
{
case -1: // user terminated wait
dial_win.Display(dial_msg[2]); // give confirmation message
wait_ms(1000L); // ..wait a second
return; // ..and return to caller
case 0: // timeout
dial_win.Display(dial_msg[3]); // inform user
break; // ..and continue
case 1: // connection established
dial_win.Display(dial_msg[10]); // inform user
wait_for(endings[0], endings[1], 2);// ..eat rest of the line
break; // ..and exit the loop
case 2: // dial failed
dial_win.Display(dial_msg[11]); // inform user
break; // ..and continue
}
wait_ms(2000L); // wait a second, then return
}
/* ******************************************************************** *
*
* save_pb() -- save phonebook to disk
*
* ******************************************************************** */
void save_pb(void)
{
int i; // loop counter
char **s; // work string pointer
struct line_parameters **p; // work line parms pointer
FILE *phone; // phonebook file handle
if (NOT phone_changed) // q. phonebook changed?
return; // a. no .. just return
phone_changed = 0; // clear changed flag
if (NOT (phone = fopen(pb_path, "w"))) // q. file open ok?
quit_with(open_error, pb_path); // a. no .. quit w/error msg
for (i = 0; i < COUNT(phonebook); i++) // for each phonebook entry
{
s = &phonebook[i].strings[0]; // set up strings array ptr
p = &phonebook[i].lp[0]; // ..and parms array pointer
fprintf(phone, pb_format, // write one group of lines
s[0] ? s[0] : "", // ..with entry name
s[1] ? s[1] : "", // ..modem phone number
s[2] ? s[2] : "", // ..fax phone number
s[3] ? s[3] : "", // ..modem setup string
p[0]->parm, p[1]->parm, // ..baud rate and parity
p[2]->parm, p[3]->parm); // ..data and stop bits
}
fclose(phone); // close file
}
/* ******************************************************************** *
*
* phone_list() -- select, display, and edit phone book
*
* ******************************************************************** */
int phone_list(int c, int r) // column and row for window
{
int i, // loop counter
k, // keyboard input
idx; // line index
char b[40], // work buffer
*p; // work pointer
Window phone_win(c, r, c + 39, // define temporary window
r + COUNT(phonebook) + 1, // ..to hold phone list
menu_cn, menu_cr); // ..using system colors
phone_win.Open(double_line); // open window with a border
idx = 0; // set up for first entry
while(1) // loop till user exits
{
for (i = 0; i < COUNT(phonebook); i++) // walk thru phonebook
{
if ((p = phonebook[i].PB_NAME) == 0)// q. name available?
p = ""; // a. no .. point at null str
sprintf(b, "%2d. %-32.32s", // format a buffer with name
i + 1, p); // ..and line number
phone_win.GotoXY(2, i + 1); // position to start of line
if (i == idx) // q. selected line?
phone_win.DisplayReverse(b); // a. yes .. highlight line
else
phone_win.Display(b); // else .. just display it
}
while (NOT (k = get_key(NO_ALT))) // wait for a key
; // ..before continuing
switch (k) // based on keyboard input
{
case SPACE: // edit selected entry
k = edit_pb(c + 2, r + idx + 2, // edit phonebook entry
&phonebook[idx]); // ..giving coords for window
save_pb(); // ..then save phonebook
if (k != 0) // q. allowed to continue?
return(k); // a. no .. rtn with new key
break; // else .. wait for next key
case CR: // dial selected number
dial_pb(&phonebook[idx], // call dial routine
c + 2, r + idx + 2); // ..giving window coordinates
return(ESC); // ..and exit to terminal mode
case UP: // move up list
if (--idx < 0) // q. already at top of list?
idx = COUNT(phonebook) - 1; // a. yes .. goto bottom
break; // wait for next key
case DOWN: // move down list
if (++idx == COUNT(phonebook)) // q. already at bottom?
idx = 0; // a. yes .. goto top of list
break; // wait for next key
case ESC: // escape from this menu
k = 0; // set key value to zero
// ..and fall into next case
case LEFT: // move left
case RIGHT: // ..or move right
return(k); // just rtn with the keystroke
default: // error case
printf(BELL); // ..just ring the bell
}
}
}
/* ******************************************************************** *
*
* load_pb() -- load phonebook from disk
*
* ******************************************************************** */
void load_pb(void)
{
int i, j, k; // loop counters
char *p, // string pointers
buf[80]; // input line buffer
FILE *phone; // phonebook file handle
for (i = 0; i < COUNT(phonebook); i++) // for each phonebook entry
for (j = 0; j < 4; j++) // ..and each line parm field
phonebook[i].lp[j] = line[j].lp; // ..set up their defaults
_searchenv(pb_file, "PATH", pb_path); // find the phonebook file
if (*pb_path) // q. find a phonebook?
{ // a. yes .. process file
if (NOT (phone = fopen(pb_path, "r"))) // q. file open ok?
quit_with(open_error, pb_path); // a. no .. quit w/error msg
printf(loading_pb, pb_path); // else .. inform user
}
else
{
strcpy(pb_path, pb_file); // else .. set up filename
return; // ..and then return
}
for (i = 0; i < COUNT(phonebook) // for each phonebook entry
&& NOT feof(phone); i++) // ..while there is data
for (j = 0; j < 8; j++) // ..and for each field
{
if (NOT fgets(buf, sizeof(buf), // q. read fail
phone)) // ..or are we at EOF?
break; // a. yes .. exit loop
if ((p = strrchr(buf, '\n')) != 0) // q. CR at end of line?
*p = 0; // a. yes .. trim line
if ((p = first_nonblank(buf)) == 0) // q. completely blank line?
continue; // a. yes .. check next line
switch (j) // handle line within entry
{
case 0: // name field
case 1: // modem phone number
case 2: // fax phone number
case 3: // modem set up string
phonebook[i].strings[j] = // save the address
strdup(p); // ..of a copy of the string
break; // ..then continue w/next line
case 4: // baud rate setting
case 5: // parity setting
case 6: // data bits
case 7: // stop bit
for (k = 0; k < // validate file's entry by
COUNT(line_parms) // ..looking through line
&& (stricmp(p, // ..parameters array to
line_parms[k].parm) // ..find a match,
|| ((j - 4) != // ..but only in the
line_parms[k].idx));// ..proper category
k++)
;
if (k == COUNT (line_parms))// q. find parameter?
quit_with(pb_setting, // a. no .. quit w/error msg
phonebook[i].strings[0], // ..with name
fld_name[j], p); // ..entry and data
phonebook[i].lp[j - 4] = // save line parameters addr
&line_parms[k]; // ..in phonebook entry
break; // ..and continue w/next line
}
}
fclose(phone); // close file when done
}