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 which 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 
        } 
    } 
 
return(0);                                  // MSC C/C++ needs this 
 
} 
 
 
 
/* ******************************************************************** * 
 * 
 *  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 set up 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 progresss 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 system wide 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 
            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 or 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 
        } 
    } 
 
return(0);                                  // MSC needs this to be happy 
 
} 
 
 
 
/* ******************************************************************** * 
 * 
 *  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 
 
}