1: char *dialv = "Dial Command, V2.0(008) 26 Jul 85"; 2: 3: /* C K U D I A -- Dialing program for connection to remote system */ 4: 5: /* 6: Author: Herm Fischer (HFISCHER@USC-ECLB) 7: Contributed to Columbia University for inclusion in C-Kermit. 8: Copyright (C) 1985, Herman Fischer, 16400 Ventura Blvd, Encino CA 91436 9: Permission is granted to any individual or institution to use, copy, or 10: redistribute this software so long as it is not sold for profit, provided this 11: copyright notice is retained. 12: 13: ------ 14: 15: This module should work under all versions of Unix. It calls externally 16: defined system-depended functions for i/o, but depends upon the existence 17: of various modem control functions. 18: 19: This module, and the supporting routines in the ckutio.c module, assume 20: that the computer and modem properly utilize the following data communi- 21: cations signals (that means one should prepare the modem to use, not 22: circumvent, these signals): 23: 24: Data Terminal Ready: This signal is asserted by the computer 25: when Kermit is about to ask the modem to dial a call, and is 26: removed when Kermit wishes to have the modem hang up a call. 27: The signal is asserted both while Kermit is asking the modem 28: to dial a specific number, and after connection, while Kermit 29: is in a data exchange mode. 30: 31: Carrier detect: This signal must be asserted by the modem when 32: a carrier is detected from a remote modem on a communications 33: circuit. It must be removed by the modem when the circuit 34: disconnects or is hung up. (Carrier detect is ignored while 35: Kermit is asking the modem to dial the call, because there is 36: no consistant usage of this signal during the dialing phase 37: among different modem manufacturers.) 38: 39: */ 40: 41: /* 42: * Modifications: 43: * 44: * 21-Jul-85 Fixed failure returns hanging on no carrier signal 45: * Requires tthang change too (ckutio.c revision) 46: * -- Herm Fischer 47: * 48: * 28-Jun-85 Fixed bug with defaulting the modem-failure message 49: * in lbuf. 50: * -- Dan Schullman 51: * 52: * 27-Jun-85 Merged in code from Joe Orost at Berkeley for 53: * supporting the US Robotics modem, which included 54: * changing the single characters in MDMINF into 55: * multi-character strings and modifying waitFor. 56: * -- Dan Schullman 57: * 58: * 26-Jun-85 Allow interrupts to be used to abort dialing, 59: * and ring the bell when a connection is made. 60: * Reorganized some of the failure paths to use the 61: * same code, and now close the line on failures. 62: * Allow use of stored numbers with the DF100 and 63: * DF200 modems. Handlers now declared after the 64: * call to setjmp. 65: * -- Dan Schullman 66: * 67: * 24-May-85 DF03, DF100-series, DF200-series, and "unknown" modem 68: * support added. Also restructured the various data 69: * tables, fixed some bugs related to missing data and 70: * missing case labels, and modified the failure message 71: * to display the "reason" given by the modem. 72: * -- Dan Schullman 73: */ 74: 75: /* 76: * To add support for another modem, do the following: 77: * 78: * Define a modem number symbol (n_XXX) for it, keeping the list 79: * in alphabetical and numerical order, and renumbering the values 80: * as necessary. 81: * 82: * Create a MDMINF structure for it, again keeping the list alphabetical 83: * for sanity's sake. 84: * 85: * Add the address of the MDMINF structure to the ptrtab array, again 86: * in alphabetical and numerical order. 87: * 88: * Add the "user visible" modem name and corresponding modem number to 89: * the mdmtab array, again in alphabetical order. 90: * 91: * Read through the code and add modem-specific sections as necessary. 92: */ 93: 94: /* 95: * The intent of the "unknown" modem is hopefully to allow KERMIT to support 96: * unknown modems by having the user type the entire autodial sequence 97: * (possibly including control characters, etc.) as the "phone number". 98: * The only reason that the CONNECT command cannot be used to do this is 99: * that a remote line cannot normally be opened unless carrier is present. 100: * 101: * The protocol and other characteristics of this modem are unknown, with 102: * some "reasonable" values being chosen for some of them. The only way to 103: * detect if a connection is made is to look for carrier present. 104: * 105: * SUPPORT IS CURRENTLY ONLY PARTIALLY SKETCHED OUT FOR THIS. ALSO, IT 106: * SHOULD PERHAPS BE HANDLED MUCH EARLIER, SIMPLY READING USER INPUT AND 107: * SENDING IT TO THE MODEM AND ECHOING MODEM RESPONSES BACK TO THE USER, 108: * ALL THE TIME LOOKING FOR CARRIER. OF COURSE, THE PROBLEM THEN BECOMES 109: * ONE OF ALLOWING THE USER TO ABORT THE DIALING. WE COULD CHOOSE SOME 110: * PHRASE THAT WOULD PRESUMABLY NEVER BE A PART OF A VALID AUTODIAL SEQUENCE 111: * (E.G., "QUIT" and "quit"). -- DS 112: */ 113: #include "ckcdeb.h" 114: #include <stdio.h> 115: #include <ctype.h> 116: #include <signal.h> 117: #include <setjmp.h> 118: #include "ckcker.h" 119: #include "ckucmd.h" 120: 121: extern int flow, local, mdmtyp, quiet, speed; 122: extern char ttname[], sesfil[]; 123: 124: #define MDMINF struct mdminf 125: 126: MDMINF /* structure for modem-specific information */ 127: { 128: int dial_time; /* time modem allows for dialing (secs) */ 129: char *pause_chars; /* character(s) to tell modem to pause */ 130: int pause_time; /* time associated with pause chars (secs) */ 131: char *wake_str; /* string to wakeup modem & put in cmd mode */ 132: int wake_rate; /* delay between wake_str characters (msecs) */ 133: char *wake_prompt; /* string prompt after wake_str */ 134: char *dmode_str; /* string to put modem in dialing mode */ 135: char *dmode_prompt; /* string prompt for dialing mode */ 136: char *dial_str; /* dialing string, with "%s" for number */ 137: int dial_rate; /* delay between dialing characters (msecs) */ 138: }; 139: 140: /* 141: * Define symbolic modem numbers. 142: * 143: * The numbers MUST correspond to the ordering of entries 144: * within the ptrtab array, and start at one (1). 145: * 146: * It is assumed that there are relatively few of these 147: * values, and that the high(er) bytes of the value may 148: * be used for modem-specific mode information. 149: * 150: * REMEMBER that only the first eight characters of these 151: * names are guaranteed to be unique. 152: */ 153: 154: #define n_CERMETEK 1 155: #define n_DF03 2 156: #define n_DF100 3 157: #define n_DF200 4 158: #define n_GDC 5 159: #define n_HAYES 6 160: #define n_PENRIL 7 161: #define n_RACAL 8 162: #define n_UNKNOWN 9 163: #define n_USROBOT 10 164: #define n_VENTEL 11 165: 166: /* 167: * Declare modem "variant" numbers for any of the above for which it is 168: * necessary to note various operational modes, using the second byte 169: * of a modem number. 170: * 171: * It is assumed that such modem modes share the same modem-specific 172: * information (see MDMINF structure) but may differ in some of the actions 173: * that are performed. 174: */ 175: #define n_HAYESNV ( n_HAYES + ( 1<<8 ) ) 176: 177: /* 178: * Declare structures containing modem-specific information. 179: * 180: * REMEMBER that only the first SEVEN characters of these 181: * names are guaranteed to be unique. 182: */ 183: 184: static 185: MDMINF CERMETEK = /* information for "Cermetek Info-Mate 212 A" modem */ 186: { 187: 20, /* dial_time */ 188: "BbPpTt", /* pause_chars */ 189: 0, /* pause_time */ /** unknown -- DS **/ 190: " XY\016R\r", /* wake_str */ 191: 200, /* wake_rate */ 192: "", /* wake_prompt */ 193: "", /* dmode_str */ 194: "", /* dmode_prompt */ 195: "\016D '%s'\r", /* dial_str */ 196: 200 /* dial_rate */ 197: }; 198: 199: static 200: MDMINF DF03 = /* information for "DEC DF03-AC" modem */ 201: { 202: 27, /* dial_time */ 203: "=", /* pause_chars */ /* wait for second dial tone */ 204: 15, /* pause_time */ 205: "\001\002", /* wake_str */ 206: 0, /* wake_rate */ 207: "", /* wake_prompt */ 208: "", /* dmode_str */ 209: "", /* dmode_prompt */ 210: "%s", /* dial_str */ 211: 0 /* dial_rate */ 212: }; 213: 214: static 215: MDMINF DF100 = /* information for "DEC DF100-series" modem */ 216: /* 217: * The telephone "number" can include "P"s and/or "T"s 218: * within it to indicate that subsequent digits are 219: * to be dialed using pulse or tone dialing. The 220: * modem defaults to pulse dialing. You may modify 221: * the dial string below to explicitly default all 222: * dialing to pulse or tone, but doing so prevents 223: * the use of phone numbers that you may have stored 224: * in the modem's memory. 225: */ 226: { 227: 30, /* dial_time */ 228: "=", /* pause_chars */ /* wait for second dial tone */ 229: 15, /* pause_time */ 230: "\001", /* wake_str */ 231: 0, /* wake_rate */ 232: "", /* wake_prompt */ 233: "", /* dmode_str */ 234: "", /* dmode_prompt */ 235: "%s#", /* dial_str */ 236: 0 /* dial_rate */ 237: }; 238: 239: static 240: MDMINF DF200 = /* information for "DEC DF200-series" modem */ 241: /* 242: * The telephone "number" can include "P"s and/or "T"s 243: * within it to indicate that subsequent digits are 244: * to be dialed using pulse or tone dialing. The 245: * modem defaults to pulse dialing. You may modify 246: * the dial string below to explicitly default all 247: * dialing to pulse or tone, but doing so prevents 248: * the use of phone numbers that you may have stored 249: * in the modem's memory. 250: */ 251: { 252: 30, /* dial_time */ 253: "=W", /* pause_chars */ /* =: second tone; W: 5 secs */ 254: 15, /* pause_time */ /* worst case */ 255: "\002", /* wake_str */ /* allow stored number usage */ 256: 0, /* wake_rate */ 257: "", /* wake_prompt */ 258: "", /* dmode_str */ 259: "", /* dmode_prompt */ 260: "%s!", /* dial_str */ 261: 0 /* dial_rate */ 262: }; 263: 264: static 265: MDMINF GDC = /* information for "GeneralDataComm 212A/ED" modem */ 266: { 267: 32, /* dial_time */ 268: "%", /* pause_chars */ 269: 3, /* pause_time */ 270: "\r\r", /* wake_str */ 271: 500, /* wake_rate */ 272: "$", /* wake_prompt */ 273: "D\r", /* dmode_str */ 274: ":", /* dmode_prompt */ 275: "T%s\r", /* dial_str */ 276: 0 /* dial_rate */ 277: }; 278: 279: static 280: MDMINF HAYES = /* information for "Hayes" modem */ 281: { 282: 35, /* dial_time */ 283: ",", /* pause_chars */ 284: 2, /* pause_time */ 285: "AT\r", /* wake_str */ 286: 0, /* wake_rate */ 287: "", /* wake_prompt */ 288: "", /* dmode_str */ 289: "", /* dmode_prompt */ 290: "AT DT %s\r", /* dial_str */ 291: 0 /* dial_rate */ 292: }; 293: 294: static 295: MDMINF PENRIL = /* information for "Penril" modem */ 296: { 297: 50, /* dial_time */ 298: "", /* pause_chars */ /** unknown -- HF **/ 299: 0, /* pause_time */ 300: "\r\r", /* wake_str */ 301: 300, /* wake_rate */ 302: ">", /* wake_prompt */ 303: "k\r", /* dmode_str */ 304: ":", /* dmode_prompt */ 305: "%s\r", /* dial_str */ 306: 0 /* dial_rate */ 307: }; 308: 309: static 310: MDMINF RACAL = /* information for "Racal Vadic" modem */ 311: { 312: 35, /* dial_time */ 313: "Kk", /* pause_chars */ 314: 5, /* pause_time */ 315: "\005\r", /* wake_str */ 316: 50, /* wake_rate */ 317: "*", /* wake_prompt */ 318: "D\r", /* dmode_str */ 319: "?", /* dmode_prompt */ 320: "%s\r", /* dial_str */ 321: 0 /* dial_rate */ 322: }; 323: 324: static 325: MDMINF UNKNOWN = /* information for "Unknown" modem */ 326: { 327: 30, /* dial_time */ 328: "", /* pause_chars */ 329: 0, /* pause_time */ 330: "", /* wake_str */ 331: 0, /* wake_rate */ 332: "", /* wake_prompt */ 333: "", /* dmode_str */ 334: "", /* dmode_prompt */ 335: "%s\r", /* dial_str */ 336: 0 /* dial_rate */ 337: }; 338: 339: static 340: MDMINF USROBOT = /* information for "US Robotics 212A" modem */ 341: { 342: 30, /* dial_time */ 343: ",", /* pause_chars */ 344: 2, /* pause_time */ 345: "ATS2=01\r", /* wake_str */ 346: 0, /* wake_rate */ 347: "OK\r", /* wake_prompt */ 348: "", /* dmode_str */ 349: "", /* dmode_prompt */ 350: "ATTD%s\r", /* dial_str */ 351: 0 /* dial_rate */ 352: }; 353: 354: static 355: MDMINF VENTEL = /* information for "Ventel" modem */ 356: { 357: 20, /* dial_time */ 358: "%", /* pause_chars */ 359: 5, /* pause_time */ 360: "\r\r\r", /* wake_str */ 361: 300, /* wake_rate */ 362: "$", /* wake_prompt */ 363: "", /* dmode_str */ 364: "", /* dmode_prompt */ 365: "<K%s'r>", /* dial_str */ 366: 0 /* dial_rate */ 367: }; 368: 369: /* 370: * Declare table for converting modem numbers to information pointers. 371: * 372: * The entries MUST be in ascending order by modem number, without any 373: * "gaps" in the numbers, and starting from one (1). 374: * 375: * This table should NOT include entries for the "variant" modem numbers, 376: * since it is assumed that they share the same information as the normal 377: * value. 378: */ 379: static 380: MDMINF *ptrtab[] = 381: { 382: &CERMETEK, 383: &DF03, 384: &DF100, 385: &DF200, 386: &GDC, 387: &HAYES, 388: &PENRIL, 389: &RACAL, 390: &UNKNOWN, 391: &USROBOT, 392: &VENTEL 393: }; 394: 395: /* 396: * Declare modem names and associated numbers for command parsing, 397: * and also for doing number-to-name translation. 398: * 399: * The entries MUST be in alphabetical order by modem name. 400: */ 401: struct keytab mdmtab[] = 402: { 403: "cermetek", n_CERMETEK, 0, 404: "df03-ac", n_DF03, 0, 405: "df100-series", n_DF100, 0, 406: "df200-series", n_DF200, 0, 407: "direct", 0, 0, 408: "gendatacomm", n_GDC, 0, 409: "hayes", n_HAYES, 0, 410: "penril", n_PENRIL, 0, 411: "racalvadic", n_RACAL, 0, 412: "unknown", n_UNKNOWN, 0, 413: "usrobotics-212a", n_USROBOT, 0, 414: "ventel", n_VENTEL, 0 415: }; 416: 417: int nmdm = (sizeof(mdmtab) / sizeof(struct keytab)); /* number of modems */ 418: 419: #define DIALING 4 /* for ttpkt parameter */ 420: #define CONNECT 5 421: 422: #define CONNECTED 1 /* for completion status */ 423: #define FAILED 2 424: 425: /* 426: * Failure reasons for use with the 'longjmp' exit. 427: */ 428: #define F_time 1 /* timeout */ 429: #define F_int 2 /* interrupt */ 430: #define F_modem 3 /* modem-detected failure */ 431: #define F_minit 4 /* cannot initialize modem */ 432: 433: static 434: char *F_reason[5] = { /* failure reasons for message */ 435: "Unknown", "Timeout", "Interrupt", "Modem", "Initialize" }; 436: 437: static int tries = 0; 438: 439: #define LBUFL 100 440: static char lbuf[LBUFL]; 441: 442: static jmp_buf sjbuf; 443: 444: static int (*savAlrm)(); /* for saving alarm handler */ 445: static int (*savInt)(); /* for saving interrupt handler */ 446: 447: dialtime() { /* timer interrupt handler */ 448: longjmp( sjbuf, F_time ); 449: } 450: 451: dialint() /* user-interrupt handler */ 452: { 453: longjmp( sjbuf, F_int ); 454: } 455: 456: static 457: ttolSlow(s,millisec) char *s; int millisec; { /* output s-l-o-w-l-y */ 458: for (; *s; s++) { 459: ttoc(*s); 460: msleep(millisec); 461: } 462: } 463: 464: /* 465: * Wait for a string of characters. 466: * 467: * The characters are waited for individually, and other characters may 468: * be received "in between". This merely guarantees that the characters 469: * ARE received, and in the order specified. 470: */ 471: static 472: waitFor(s) char *s; 473: { 474: CHAR c; 475: while ( c = *s++ ) /* while more characters remain... */ 476: while ( ( ttinc(0) & 0177 ) != c ) ; /* wait for the character */ 477: } 478: 479: static 480: didWeGet(s,r) char *s, *r; { /* Looks in string s for response r */ 481: int lr = strlen(r); /* 0 means not found, 1 means found it */ 482: int i; 483: for (i = strlen(s)-lr; i >= 0; i--) 484: if ( s[i] == r[0] ) if ( !strncmp(s+i,r,lr) ) return( 1 ); 485: return( 0 ); 486: } 487: 488: 489: /* R E S E T -- Reset alarms, etc. on exit. */ 490: 491: static 492: reset () 493: { 494: alarm(0); 495: signal(SIGALRM,savAlrm); /* restore alarm handler */ 496: signal(SIGINT,savInt); /* restore interrupt handler */ 497: } 498: 499: 500: 501: /* D I A L -- Dial up the remote system */ 502: 503: dial(telnbr) char *telnbr; { 504: 505: char c; 506: char *i, *j; 507: int waitct, status; 508: char errmsg[50], *erp; 509: MDMINF *pmdminf; /* pointer to modem-specific info */ 510: int augmdmtyp; /* "augmented" modem type, to handle modem modes */ 511: int mdmEcho = 0; /* assume modem does not echo */ 512: int n, n1; 513: char *pc; /* pointer to a character */ 514: 515: if (!mdmtyp) { 516: printf("Sorry, you must 'set modem' first\n"); 517: return(-2); 518: } 519: if (!local) { 520: printf("Sorry, you must 'set line' first\n"); 521: return(-2); 522: } 523: if (speed < 0) { 524: printf("Sorry, you must 'set speed' first\n"); 525: return(-2); 526: } 527: if (ttopen(ttname,&local,mdmtyp) < 0) {/* Open, no wait for carrier */ 528: erp = errmsg; 529: sprintf(erp,"Sorry, can't open %s",ttname); 530: perror(errmsg); 531: return(-2); 532: } 533: pmdminf = ptrtab[mdmtyp-1]; /* set pointer to modem info */ 534: augmdmtyp = mdmtyp; /* initialize "augmented" modem type */ 535: /* cont'd... */ 536: 537: 538: /* interdigit waits for tone dial */ 539: /* ...dial, cont'd */ 540: 541: 542: waitct = 1*strlen(telnbr) ; /* compute time to dial worst case */ 543: waitct += pmdminf->dial_time; /* dialtone + completion wait times */ 544: for (i=telnbr; *i; i++) /* add in pause characters time */ 545: for (j=pmdminf->pause_chars; *j; j++) 546: if (*i == *j) { 547: waitct += pmdminf->pause_time; 548: break; 549: } 550: 551: printf("Dialing thru %s, speed %d, number %s.\r\n",ttname,speed,telnbr); 552: printf("The timeout for completing the call is %d seconds.\r\n",waitct); 553: printf("Type the interrupt character to cancel the dialing.\r\n"); 554: 555: /* Hang up the modem (in case it wasn't "on hook") */ 556: 557: if ( tthang() < 0 ) { 558: printf("Sorry, Can't hang up tty line\n"); 559: return(-2); 560: } 561: 562: /* Condition console terminal and communication line */ 563: /* place line into "clocal" dialing state */ 564: if ( ttpkt(speed,DIALING) < 0 ) { 565: printf("Sorry, Can't condition communication line\n"); 566: return(-2); 567: } 568: 569: /* 570: * Establish jump vector, or handle "failure" jumps. 571: */ 572: 573: if ( n = setjmp(sjbuf) ) /* if a "failure jump" was taken... */ 574: { 575: alarm ( 0 ); /* disable timeouts */ 576: if ( n1 = setjmp(sjbuf) ) /* failure while handling failure */ 577: { 578: printf ( "%s failure while handling failure.\r\n", F_reason[n1] ); 579: } 580: else /* first (i.e., non-nested) failure */ 581: { 582: signal ( SIGALRM, dialtime ); /* be sure to catch signals */ 583: if ( signal ( SIGINT, SIG_IGN ) != SIG_IGN ) 584: signal ( SIGINT, dialint ); 585: alarm ( 5 ); /* be sure to get out of this section */ 586: ttclos (); /* hangup and close the line */ 587: } 588: switch ( n ) /* type of failure */ 589: { 590: case F_time: /* timed out */ 591: { 592: printf ( "No connection made within the allotted time.\r\n" ); 593: break; 594: } 595: case F_int: /* dialing interrupted */ 596: { 597: printf ( "Dialing interrupted.\r\n" ); 598: break; 599: } 600: case F_modem: /* modem detected a failure */ 601: { 602: printf ( "Failed (\"" ); 603: for ( pc=lbuf; *pc; pc++ ) 604: if ( isprint(*pc) ) 605: putchar(*pc); /* display printable reason */ 606: printf ( "\").\r\n" ); 607: break; 608: } 609: case F_minit: /* cannot initialize modem */ 610: { 611: printf ( "Cannot initialize modem.\r\n" ); 612: break; 613: } 614: } 615: reset (); /* reset alarms, etc. */ 616: return ( -2 ); /* exit with failure code */ 617: } 618: 619: /* 620: * Set timer and interrupt handlers. 621: */ 622: 623: savAlrm = signal(SIGALRM,dialtime); /* set alarm handler */ 624: if ( ( savInt = signal ( SIGINT, SIG_IGN ) ) != SIG_IGN ) 625: signal ( SIGINT, dialint ); /* set int handler if not ignored */ 626: alarm(10); /* give modem 10 seconds to wake up */ 627: 628: ttflui(); /* flush input buffer if any */ 629: 630: /* 631: * Put modem in command mode. 632: */ 633: 634: #define OKAY 1 /* modem attention attempt status */ 635: #define IGNORE 2 636: #define GOT_O -2 637: #define GOT_A -3 638: 639: switch (augmdmtyp) { 640: case n_HAYES: 641: case n_HAYESNV: 642: while(tries++ < 4) { 643: ttol( HAYES.wake_str, strlen(HAYES.wake_str) ); /* wakeup */ 644: status = 0; 645: while ( status <= 0 ) { 646: switch (ttinc(0) & 0177) { 647: case 'A': /* echoing, ignore */ 648: status = GOT_A; 649: break; 650: case 'T': 651: if (status == GOT_A) { 652: mdmEcho = 1; /* expect echoing later */ 653: status = 0; 654: break; 655: } 656: status = IGNORE; 657: break; 658: case '\n': 659: case '\r': 660: status = 0; 661: break; 662: case '0': /* numeric result code */ 663: augmdmtyp = n_HAYESNV; /* nonverbal result codes */ 664: status = OKAY; 665: break; 666: case 'O': /* maybe English result code*/ 667: status = GOT_O; 668: break; 669: case 'K': 670: if (status == GOT_O) { 671: augmdmtyp = n_HAYES; 672: status = OKAY; 673: break; 674: } /* else its default anyway */ 675: default: 676: status = IGNORE; 677: break; 678: } 679: } 680: if (status == OKAY) break; 681: if (status == IGNORE) ttflui(); 682: sleep(1); /* wait before retrying */ 683: } 684: if (status != 0) break; 685: longjmp( sjbuf, F_minit ); /* modem-initialization failure */ 686: 687: /* cont'd... */ 688: 689: /* interdigit waits for tone dial */ 690: /* ...dial, cont'd */ 691: 692: default: /* place modem into command mode */ 693: ttolSlow(pmdminf->wake_str, pmdminf->wake_rate); 694: waitFor(pmdminf->wake_prompt); 695: break; 696: } 697: alarm(0); /* turn off alarm */ 698: msleep(500); /* give things settling time */ 699: alarm(10); /* alarm on dialing prompts */ 700: 701: 702: /* Dial the number */ 703: 704: /* put modem into dialing mode */ 705: ttolSlow(pmdminf->dmode_str, pmdminf->dial_rate); 706: if (pmdminf->dmode_prompt) { /* wait for prompt, if any expected */ 707: waitFor(pmdminf->dmode_prompt); 708: msleep(300); 709: } 710: 711: alarm(0); /* turn off alarm on dialing prompts */ 712: alarm(waitct); /* time to allow for connecting */ 713: ttflui(); /* clear out stuff from waking modem up */ 714: sprintf(lbuf, pmdminf->dial_str, telnbr); /* form dialing string */ 715: ttolSlow(lbuf,pmdminf->dial_rate); /* send dialing string */ 716: 717: if (augmdmtyp == n_RACAL) { /* acknowledge printout of dialing string */ 718: sleep(3); 719: ttflui(); 720: ttoc('\r'); 721: } 722: 723: /* cont'd... */ 724: 725: 726: /* interdigit waits for tone dial */ 727: /* ...dial, cont'd */ 728: 729: 730: /* Check for connection */ 731: 732: /* 733: * I believe we also need to look for carrier in order to determine if a 734: * connection has been made. In fact, for many we may only want to look for 735: * the "failure" responses in order to short-circuit the timeout, and let 736: * carrier be the determination of whether a connection has been made. -- DS 737: */ 738: 739: status = 0; 740: strcpy(lbuf,"No Connection"); /* default failure reason */ 741: while (status == 0) { 742: switch (augmdmtyp) { 743: default: 744: for (n=0; n < LBUFL; n++) { /* accumulate response */ 745: lbuf[n] = (ttinc(0) & 0177); 746: if ( lbuf[n] == '\r' || lbuf[n] == '\n' ) break; 747: } 748: lbuf[n] = '\0'; /* terminate response from modem */ 749: if (n) { /* if one or more characters present */ 750: switch (augmdmtyp) { 751: case n_CERMETEK: 752: if (didWeGet(lbuf,"\016A")) { 753: status = CONNECTED; 754: ttolSlow("\016U 1\r",200); /* make transparent*/ 755: } 756: break; 757: case n_DF100: /* DF100 won't generate some of these */ 758: case n_DF200: 759: if (didWeGet(lbuf,"Attached")) status = CONNECTED; 760: /* 761: * The DF100 will respond with "Attached" even if DTR 762: * and/or carrier are not present. Another reason to 763: * (also) wait for carrier? 764: */ 765: if (didWeGet(lbuf,"Busy")) status = FAILED; 766: if (didWeGet(lbuf,"Disconnected")) status = FAILED; 767: if (didWeGet(lbuf,"Error")) status = FAILED; 768: if (didWeGet(lbuf,"No answer")) status = FAILED; 769: if (didWeGet(lbuf,"No dial tone")) status = FAILED; 770: if (didWeGet(lbuf,"Speed:")) status = FAILED; 771: /* 772: * It appears that the "Speed:..." response comes after an 773: * "Attached" response, so this is never seen. HOWEVER, 774: * it would be very handy to detect this and temporarily 775: * reset the speed, since it's a nuiscance otherwise. 776: * If we wait for some more input from the modem, how do 777: * we know if it's from the remote host or the modem? 778: * Carrier reportedly doesn't get set until after the 779: * "Speed:..." response (if any) is sent. Another reason 780: * to (also) wait for carrier. 781: */ 782: break; 783: case n_GDC: 784: if (didWeGet(lbuf,"ON LINE")) status = CONNECTED; 785: if (didWeGet(lbuf,"NO CONNECT")) status = FAILED; 786: break; 787: case n_HAYES: 788: case n_USROBOT: 789: if (didWeGet(lbuf,"CONNECT")) status = CONNECTED; 790: if (didWeGet(lbuf,"NO CARRIER")) status = FAILED; 791: break; 792: case n_PENRIL: 793: if (didWeGet(lbuf,"OK")) status = CONNECTED; 794: if (didWeGet(lbuf,"BUSY")) status = FAILED; 795: if (didWeGet(lbuf,"NO RING")) status = FAILED; 796: break; 797: case n_RACAL: 798: if (didWeGet(lbuf,"ON LINE")) status = CONNECTED; 799: if (didWeGet(lbuf,"FAILED CALL")) status = FAILED; 800: break; 801: case n_VENTEL: 802: if (didWeGet(lbuf,"ONLINE!")) status = CONNECTED; 803: if (didWeGet(lbuf,"BUSY")) status = FAILED; 804: if (didWeGet(lbuf,"DEAD PHONE")) status = FAILED; 805: break; 806: } 807: } 808: break; 809: 810: case n_DF03: /* because response lacks CR or NL */ 811: c = ttinc(0) & 0177; 812: if ( c == 'A' ) status = CONNECTED; 813: if ( c == 'B' ) status = FAILED; 814: break; 815: 816: case n_HAYESNV: 817: c = ttinc(0) & 0177; 818: if (mdmEcho) { /* sponge up dialing string */ 819: mdmEcho = c!='\r'; /* until return is echoed */ 820: break; 821: } 822: if (c == '1') status = CONNECTED; 823: if (c == '3') status = FAILED; 824: if (c == '5') status = CONNECTED; 825: break; 826: 827: case n_UNKNOWN: 828: /** SHOULD WAIT FOR CARRIER OR TIMEOUT -- DS **/ 829: break; 830: } /* switch (augmdmtyp) */ 831: } /* while status == 0 */ 832: 833: 834: alarm(0); /* turn off alarm on connecting */ 835: if ( status != CONNECTED ) /* modem-detected failure */ 836: longjmp( sjbuf, F_modem ); /* exit (with reason in lbuf) */ 837: alarm(3); /* precaution in case of trouble */ 838: ttpkt(speed,CONNECT); /* cancel dialing state ioctl */ 839: reset (); /* reset alarms, etc. */ 840: if ( ! quiet ) 841: printf ( "Call completed.\07\r\n" ); 842: return ( 0 ); /* return, and presumably connect */ 843: }