|
|
1.1 ! root 1: /* ! 2: * *********** ! 3: * * XCHAT.C * ! 4: * *********** ! 5: * ! 6: * Extended chat processor for Taylor UUCP. See accompanying documentation. ! 7: * ! 8: * Written by: ! 9: * Bob Denny ([email protected]) ! 10: * Based on code in DECUS UUCP (for VAX/VMS) ! 11: * ! 12: * History: ! 13: * Version 1.0 shipped with Taylor 1.03. No configuration info inside. ! 14: * ! 15: * Bob Denny - Sun Aug 30 18:41:30 1992 ! 16: * V1.1 - long overdue changes for other systems. Rip out interval ! 17: * timer code, use timer code from Taylor UUCP, use select() ! 18: * for timed reads. Use Taylor UUCP "conf.h" file to set ! 19: * configuration for this program. Add defaulting of script ! 20: * and log file paths. ! 21: * ! 22: * Bugs: ! 23: * Does not support BSD terminal I/O. Anyone care to add it? ! 24: */ ! 25: ! 26: #include <sys/types.h> ! 27: #include <stdio.h> ! 28: #include <string.h> ! 29: #include <ctype.h> ! 30: #include <signal.h> ! 31: #include <time.h> ! 32: #include <sys/ioctl.h> ! 33: #include <sys/termio.h> ! 34: ! 35: #include "xc-conf.h" ! 36: ! 37: /* ! 38: * Pick a timing routine to use, as done in Taylor UUCP. ! 39: */ ! 40: #if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS || HAVE_POLL ! 41: #define USE_SELECT_TIMER 0 ! 42: #else ! 43: #define USE_SELECT_TIMER HAVE_SELECT ! 44: #if USE_SELECT_TIMER ! 45: #include <sys/time.h> ! 46: #endif ! 47: #endif ! 48: ! 49: #if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS ! 50: #undef HAVE_POLL ! 51: #define HAVE_POLL 0 ! 52: #endif ! 53: ! 54: #if HAVE_USLEEP || HAVE_NAP ! 55: #undef HAVE_NAPMS ! 56: #define HAVE_NAPMS 0 ! 57: #endif ! 58: ! 59: #if HAVE_USLEEP ! 60: #undef HAVE_NAP ! 61: #define HAVE_NAP 0 ! 62: #endif ! 63: ! 64: static int ttblind(); ! 65: static int ttcd(); ! 66: ! 67: /* script entry -- "compiled" form of dial, hangup, or login script */ ! 68: ! 69: struct script { ! 70: struct script *next; /* pointer to next entry, or null */ ! 71: int opcode; /* numeric opcode */ ! 72: char *strprm; /* pointer to string param */ ! 73: long intprm; /* integer parameter */ ! 74: char *newstate; /* new state name */ ! 75: }; ! 76: ! 77: /* opcode definition array element -- one for each possible opcode */ ! 78: ! 79: struct script_opdef { ! 80: char *opname; ! 81: int opcode; /* numeric opcode -- same as array index */ ! 82: int prmtype; /* one of SC_NONE, SC_STR, SC_XSTR, SC_INT */ ! 83: int newstate; /* one of SC_NONE, SC_NWST */ ! 84: }; ! 85: ! 86: /* values for opcode */ ! 87: ! 88: #define SC_LABEL 0 /* "label" (state name) */ ! 89: #define SC_CDLY 1 /* set char output delay in msec */ ! 90: #define SC_PCHR 2 /* pause char for dial string (from P in input) */ ! 91: #define SC_PTIM 3 /* seconds to allow for pause char */ ! 92: #define SC_WCHR 4 /* wait char for dial string (from W in input) */ ! 93: #define SC_WTIM 5 /* seconds to allow for wait char */ ! 94: #define SC_ZERO 6 /* zero counter */ ! 95: #define SC_INCR 7 /* increment counter */ ! 96: #define SC_IFGT 8 /* change state if counter > int param */ ! 97: #define SC_WAIT 9 /* wait for int param seconds */ ! 98: #define SC_GOTO 10 /* unconditional change to new state */ ! 99: #define SC_SEND 11 /* send strparam (after sprintf substitutions) */ ! 100: #define SC_BRK 12 /* send a break */ ! 101: #define SC_HANG 13 /* drop DTR */ ! 102: #define SC_DIAL 14 /* send telno string (after subst PCHR & WCHR) */ ! 103: #define SC_DTIM 15 /* time in msec per digit (for timeout calculations) */ ! 104: /* default = 100 (one tenth second) */ ! 105: #define SC_CTIM 16 /* additional time (in seconds) to wait for carrier */ ! 106: /* default = 45 seconds */ ! 107: #define SC_EXIT 17 /* script done, success */ ! 108: #define SC_FAIL 18 /* script done, failure */ ! 109: #define SC_LOG 19 /* write strparam to uucp.log */ ! 110: #define SC_LOGE 20 /* write strparam to uucp.log w/error ind */ ! 111: #define SC_DBG 21 /* write strparam to debug log if debug lvl = LGI */ ! 112: #define SC_DBGE 22 /* write strparam to debug log if debug lvl = LGIE */ ! 113: #define SC_DBST 23 /* 'or' intparam into debug mask */ ! 114: #define SC_DBCL 24 /* 'bicl' intparam into debug mask */ ! 115: #define SC_TIMO 25 /* newstate if no match in intparam secs */ ! 116: /* (uses calculated dial time if intparam is 0) */ ! 117: #define SC_XPCT 26 /* wait for strparam, goto _newstate if found */ ! 118: #define SC_CARR 27 /* goto _newstate if carrier detected */ ! 119: #define SC_FLSH 28 /* flush typeahead buffer */ ! 120: #define SC_IFBL 29 /* change state if controller is blind w/o CD */ ! 121: #define SC_IFBG 30 /* chg state if ctlr is blind and counter > intprm */ ! 122: #define SC_SNDP 31 /* send parameter n */ ! 123: #define SC_IF1P 32 /* if parameter n present */ ! 124: #define SC_IF0P 33 /* if parameter n absent */ ! 125: #define SC_DBOF 34 /* open debugging file */ ! 126: #define SC_TELN 35 /* Set telno from parameter n */ ! 127: #define SC_7BIT 36 /* Set port to 7-bit stripping */ ! 128: #define SC_8BIT 37 /* Set port for 8-bit characters */ ! 129: #define SC_PNON 38 /* Set port for 8-bit, no parity */ ! 130: #define SC_PEVN 39 /* Set port for 7-bit, even parity */ ! 131: #define SC_PODD 40 /* Set port for 7-bit, odd parity */ ! 132: #define SC_HUPS 41 /* Change state on HUP signal */ ! 133: #define SC_END 42 /* end of array */ ! 134: ! 135: /* values for prmtype, prm2type */ ! 136: ! 137: #define SC_NONE 0 /* no parameter */ ! 138: #define SC_STR 1 /* simple string */ ! 139: #define SC_INT 2 /* integer */ ! 140: #define SC_NWST 3 /* new state name */ ! 141: #define SC_XSTR 4 /* translated string */ ! 142: ! 143: /* opcode definition table for dial/login/hangup scripts */ ! 144: ! 145: static struct script_opdef sc_opdef[] = ! 146: { ! 147: {"label", SC_LABEL, SC_NONE, SC_NONE}, ! 148: {"chrdly", SC_CDLY, SC_INT, SC_NONE}, ! 149: {"pchar", SC_PCHR, SC_STR, SC_NONE}, ! 150: {"ptime", SC_PTIM, SC_INT, SC_NONE}, ! 151: {"wchar", SC_WCHR, SC_STR, SC_NONE}, ! 152: {"wtime", SC_WTIM, SC_INT, SC_NONE}, ! 153: {"zero", SC_ZERO, SC_NONE, SC_NONE}, ! 154: {"count", SC_INCR, SC_NONE, SC_NONE}, ! 155: {"ifgtr", SC_IFGT, SC_INT, SC_NWST}, ! 156: {"sleep", SC_WAIT, SC_INT, SC_NONE}, ! 157: {"goto", SC_GOTO, SC_NONE, SC_NWST}, ! 158: {"send", SC_SEND, SC_XSTR, SC_NONE}, ! 159: {"break", SC_BRK, SC_NONE, SC_NONE}, ! 160: {"hangup", SC_HANG, SC_NONE, SC_NONE}, ! 161: {"7bit", SC_7BIT, SC_NONE, SC_NONE}, ! 162: {"8bit", SC_8BIT, SC_NONE, SC_NONE}, ! 163: {"nopar", SC_PNON, SC_NONE, SC_NONE}, ! 164: {"evenpar", SC_PEVN, SC_NONE, SC_NONE}, ! 165: {"oddpar", SC_PODD, SC_NONE, SC_NONE}, ! 166: {"telno", SC_TELN, SC_INT, SC_NONE}, ! 167: {"dial", SC_DIAL, SC_NONE, SC_NONE}, ! 168: {"dgttime", SC_DTIM, SC_INT, SC_NONE}, ! 169: {"ctime", SC_CTIM, SC_INT, SC_NONE}, ! 170: {"success", SC_EXIT, SC_NONE, SC_NONE}, ! 171: {"failed", SC_FAIL, SC_NONE, SC_NONE}, ! 172: {"log", SC_LOG, SC_XSTR, SC_NONE}, ! 173: {"logerr", SC_LOGE, SC_XSTR, SC_NONE}, ! 174: {"debug", SC_DBG, SC_XSTR, SC_NONE}, ! 175: {"debuge", SC_DBGE, SC_XSTR, SC_NONE}, ! 176: {"dbgset", SC_DBST, SC_INT, SC_NONE}, ! 177: {"dbgclr", SC_DBCL, SC_INT, SC_NONE}, ! 178: {"dbgfile", SC_DBOF, SC_XSTR, SC_NONE}, ! 179: {"timeout", SC_TIMO, SC_INT, SC_NWST}, ! 180: {"expect", SC_XPCT, SC_XSTR, SC_NWST}, ! 181: {"ifcarr", SC_CARR, SC_NONE, SC_NWST}, ! 182: {"ifhang", SC_HUPS, SC_NONE, SC_NWST}, ! 183: {"flush", SC_FLSH, SC_NONE, SC_NONE}, ! 184: {"ifblind", SC_IFBL, SC_NONE, SC_NWST}, ! 185: {"ifblgtr", SC_IFBG, SC_INT, SC_NWST}, ! 186: {"sendstr", SC_SNDP, SC_INT, SC_NONE}, ! 187: {"ifstr", SC_IF1P, SC_INT, SC_NWST}, ! 188: {"ifnstr", SC_IF0P, SC_INT, SC_NWST}, ! 189: {"table end", SC_END, SC_NONE, SC_NONE} ! 190: }; ! 191: ! 192: #define SUCCESS 0 ! 193: #define FAIL 1 ! 194: #define ERROR -1 ! 195: #define MAX_SCLINE 255 /* max length of a line in a script file */ ! 196: #define MAX_EXPCT 127 /* max length of an expect string */ ! 197: #define CTL_DELIM " \t\n\r" /* Delimiters for tokens */ ! 198: #define SAME 0 /* if (strcmp(a,b) == SAME) ... */ ! 199: #define SLOP 10 /* Slop space on arrays */ ! 200: #define MAX_STRING 200 /* Max length string to send/expect */ ! 201: ! 202: #define DEBUG_LEVEL(level) \ ! 203: (Debug & (1 << level)) ! 204: ! 205: #define DB_LOG 0 /* error messages and a copy of the LOGFILE output */ ! 206: #define DB_LGIE 1 /* dial,login,init trace -- errors only */ ! 207: #define DB_LGI 2 /* dial,login,init trace -- nonerrors (incl chr I/O) */ ! 208: #define DB_LGII 3 /* script processing internals */ ! 209: ! 210: #define TRUE 1 ! 211: #define FALSE 0 ! 212: ! 213: #define NONE 0 ! 214: #define EVEN 1 ! 215: #define ODD 2 ! 216: ! 217: #define logit(m, p1) fprintf(stderr, "%s %s\n", m, p1) ! 218: ! 219: static char **paramv; /* Parameter vector */ ! 220: static int paramc; /* Parameter count */ ! 221: static char telno[64]; /* Telephone number w/meta-chars */ ! 222: static int Debug; ! 223: static int fShangup = FALSE; /* TRUE if HUP signal received */ ! 224: static FILE *dbf = NULL; ! 225: static struct termio old, new; ! 226: ! 227: extern int usignal(); ! 228: extern int uhup(); ! 229: ! 230: static struct siglist ! 231: { ! 232: int signal; ! 233: int (*o_catcher) (); ! 234: int (*n_catcher) (); ! 235: } sigtbl[] = { ! 236: { SIGHUP, NULL, uhup }, ! 237: { SIGINT, NULL, usignal }, ! 238: { SIGIOT, NULL, usignal }, ! 239: { SIGQUIT, NULL, usignal }, ! 240: { SIGTERM, NULL, usignal }, ! 241: { SIGALRM, NULL, usignal }, ! 242: { 0, NULL, NULL } /* Table end */ ! 243: }; ! 244: ! 245: extern struct script *read_script(); ! 246: extern void msleep(); ! 247: extern char xgetc(); ! 248: extern void charlog(); ! 249: extern void setup_tty(); ! 250: extern void restore_tty(); ! 251: extern void ttoslow(); ! 252: extern void ttflui(); ! 253: extern void tthang(); ! 254: extern void ttbreak(); ! 255: extern void tt7bit(); ! 256: extern void ttpar(); ! 257: extern void DEBUG(); ! 258: ! 259: extern void *malloc(); ! 260: ! 261: ! 262: /* ! 263: * ********************************** ! 264: * * BEGIN EXECUTION - MAIN PROGRAM * ! 265: * ********************************** ! 266: * ! 267: * This program is called by Taylor UUCP with a list of ! 268: * arguments in argc/argv, and stdin/stdout mapped to the ! 269: * tty device, and stderr mapped to the Taylor logfile, where ! 270: * anything written to stdout will be logged as an error. ! 271: * ! 272: */ ! 273: int main(argc, argv) ! 274: int argc; ! 275: char *argv[]; ! 276: { ! 277: int i, stat; ! 278: FILE *sf; ! 279: char sfname[256]; ! 280: struct script *script; ! 281: struct siglist *sigs; ! 282: ! 283: /* ! 284: * The following is needed because my cpp does not have the ! 285: * #error directive... ! 286: */ ! 287: #if ! HAVE_SELECT ! 288: no_select_sorry(); /* Sad way to fail make */ ! 289: #endif ! 290: ! 291: paramv = &argv[2]; /* Parameters start at 2nd arg */ ! 292: paramc = argc - 2; /* Number of live parameters */ ! 293: ! 294: telno[0] = '\0'; ! 295: ! 296: if (argc < 2) ! 297: { ! 298: fprintf(stderr, "%s: no script file supplied\n", argv[0]); ! 299: exit(FAIL); ! 300: } ! 301: ! 302: /* ! 303: * If the script file argument begins with '/', then we assume ! 304: * it is an absolute pathname, otherwise, we prepend the ! 305: * SCRIPT_DIR path. ! 306: */ ! 307: *sfname = '\0'; /* Empty name string */ ! 308: if(argv[1][0] != '/') /* If relative path */ ! 309: strcat(sfname, SCRIPT_DIR); /* Prepend the default dir. */ ! 310: strcat(sfname, argv[1]); /* Add the script file name */ ! 311: ! 312: /* ! 313: * Now open the script file. ! 314: */ ! 315: if ((sf = fopen(sfname, "r")) == NULL) ! 316: { ! 317: fprintf(stderr, "%s: Failed to open script %s\n", argv[0], sfname); ! 318: perror(" "); ! 319: exit(FAIL); ! 320: } ! 321: ! 322: /* ! 323: * COMPILE SCRIPT ! 324: */ ! 325: if ((script = read_script(sf)) == NULL) ! 326: { ! 327: fprintf(stderr, "%s: script error in \"%s\"\n", argv[0], argv[1]); ! 328: exit(FAIL); ! 329: } ! 330: ! 331: /* ! 332: * Set up a signal catcher so the line can be returned to ! 333: * it's current state if something nasty happens. ! 334: */ ! 335: sigs = &sigtbl[0]; ! 336: while(sigs->signal) ! 337: { ! 338: sigs->o_catcher = (int (*) ())signal(sigs->signal, sigs->n_catcher); ! 339: sigs += 1; ! 340: } ! 341: ! 342: /* ! 343: * Save current tty settings, then set up raw, single ! 344: * character input processing, with 7-bit stripping. ! 345: */ ! 346: setup_tty(); ! 347: ! 348: /* ! 349: * EXECUTE SCRIPT ! 350: */ ! 351: if ((stat = do_script(script)) != SUCCESS) ! 352: fprintf(stderr, "%s: script %s failed.\n", argv[0], argv[1]); ! 353: ! 354: /* ! 355: * Clean up and exit. ! 356: */ ! 357: restore_tty(); ! 358: #ifdef FIXSIGS ! 359: sigs = &sigtbl[0]; ! 360: while(sigs->signal) ! 361: if(sigs->o_catcher != -1) ! 362: signal(sigs->signal, sigs->o_catcher); ! 363: #endif ! 364: exit(stat); ! 365: } ! 366: ! 367: /* ! 368: * deal_script - deallocate a script and all strings it points to ! 369: */ ! 370: int deal_script(loc) ! 371: struct script *loc; ! 372: { ! 373: /* ! 374: * If pointer is null, just exit ! 375: */ ! 376: if (loc == (struct script *)NULL) ! 377: return SUCCESS; ! 378: ! 379: /* ! 380: * Deallocate the rest of the script ! 381: */ ! 382: deal_script(loc->next); ! 383: ! 384: /* ! 385: * Deallocate the string parameter, if any ! 386: */ ! 387: if (loc->strprm != (char *)NULL) ! 388: free(loc->strprm); ! 389: ! 390: /* ! 391: * Deallocate the new state name parameter, if any ! 392: */ ! 393: if (loc->newstate != (char *)NULL) ! 394: free(loc->newstate); ! 395: ! 396: /* ! 397: * Deallocate this entry ! 398: */ ! 399: free(loc); ! 400: ! 401: return SUCCESS; ! 402: } ! 403: ! 404: ! 405: /* ! 406: * read_script ! 407: * ! 408: * Read & compile a script, return pointer to first entry, or null if bad ! 409: */ ! 410: struct script *read_script(fd) ! 411: FILE *fd; ! 412: { ! 413: struct script *this = NULL; ! 414: struct script *prev = NULL; ! 415: struct script *first = NULL; ! 416: long len, i; ! 417: char inpline[MAX_SCLINE]; ! 418: char inpcopy[MAX_SCLINE]; ! 419: char *c, *cln, *opc, *cp; ! 420: ! 421: /* ! 422: * MAIN COMPILATION LOOP ! 423: */ ! 424: while ((c = fgets(inpline, (sizeof inpline - 1), fd)) != (char *)NULL) ! 425: { ! 426: /* ! 427: * Skip comments and blank lines ! 428: */ ! 429: if (*c == '#' || *c == '\n') ! 430: continue; ! 431: ! 432: /* ! 433: * Get rid of the trailing newline, and copy the string ! 434: */ ! 435: inpline[strlen(inpline)-1] = '\0'; ! 436: strcpy(inpcopy, inpline); ! 437: ! 438: /* ! 439: * Look for text starting in the first col (a label) ! 440: */ ! 441: if ((!isspace(inpline[0])) && ! 442: (cln = strchr (inpline, ':')) != (char *)NULL) { ! 443: this = (struct script *)malloc (sizeof (struct script)); ! 444: if (prev != (struct script *)NULL) ! 445: prev->next = this; ! 446: prev = this; ! 447: if (first == (struct script *)NULL) ! 448: first = this; ! 449: this->next = (struct script *)NULL; ! 450: this->opcode = SC_LABEL; ! 451: len = cln - c; ! 452: this->strprm = (char *)malloc(len+1); ! 453: strncpy(this->strprm, c, len); ! 454: (this->strprm)[len] = '\0'; ! 455: this->intprm = 0; ! 456: this->newstate = (char *)NULL; ! 457: c = cln + 1; ! 458: } ! 459: ! 460: /* ! 461: * Now handle the opcode. Fold it to lower case. ! 462: */ ! 463: opc = strtok(c, CTL_DELIM); ! 464: if (opc == (char *)NULL) /* If no opcode... */ ! 465: continue; /* ...read the next line */ ! 466: cp = opc; ! 467: while(*cp) ! 468: tolower(*cp++); ! 469: ! 470: /* ! 471: * If we have an opcode but we haven't seen anything ! 472: * else (like a label) yet, i.e., this is the first ! 473: * entry, and there was no label. We need to ! 474: * cobble up a label so that read_script is happy ! 475: */ ! 476: if (first == (struct script *)NULL) ! 477: { ! 478: this = (struct script *)malloc (sizeof (struct script)); ! 479: prev = this; ! 480: first = this; ! 481: this->next = (struct script *)NULL; ! 482: this->opcode = SC_LABEL; ! 483: this->strprm = (char *)malloc(2); ! 484: strcpy(this->strprm, ":"); ! 485: this->intprm = 0; ! 486: this->newstate = (char *)NULL; ! 487: } ! 488: ! 489: /* ! 490: * Find opcode - ndex through the opcode definition table ! 491: */ ! 492: for (i=1; sc_opdef[i].opcode != SC_END; i++) ! 493: if (strcmp(opc, sc_opdef[i].opname) == SAME) ! 494: break; ! 495: if ((sc_opdef[i].opcode) == SC_END) ! 496: { ! 497: logit ("Bad opcode in script", opc); ! 498: deal_script(first); ! 499: return (struct script *)NULL; ! 500: } ! 501: ! 502: /* ! 503: * Found opcode. Allocate a new command node and initialize ! 504: */ ! 505: this = (struct script *)malloc(sizeof (struct script)); ! 506: prev->next = this; ! 507: prev = this; ! 508: this->next = (struct script *)NULL; ! 509: this->opcode = sc_opdef[i].opcode; ! 510: this->strprm = (char *)NULL; ! 511: this->intprm = 0; ! 512: this->newstate = (char *)NULL; ! 513: ! 514: /* ! 515: * Pick up new state parameter, if any ! 516: */ ! 517: if (sc_opdef[i].newstate == SC_NWST) ! 518: { ! 519: c = strtok((char *)NULL, CTL_DELIM); ! 520: if (c == (char *)NULL) ! 521: { ! 522: logit("Missing new state", opc); ! 523: deal_script(first); ! 524: return (struct script *)NULL; ! 525: } ! 526: else ! 527: { ! 528: this->newstate = (char *)malloc(strlen(c)+1); ! 529: strcpy(this->newstate, c); ! 530: } ! 531: } ! 532: ! 533: /* ! 534: * Pick up the string or integer parameter. Handle missing ! 535: * parameter gracefully. ! 536: */ ! 537: switch (sc_opdef[i].prmtype) ! 538: { ! 539: /* ! 540: * INT parameter - convert and store in node ! 541: */ ! 542: case SC_INT: ! 543: c = strtok((char *)NULL, CTL_DELIM); ! 544: if (c == (char *)NULL) ! 545: { ! 546: logit("Missing script param", opc); ! 547: deal_script(first); ! 548: return (struct script *)NULL; ! 549: } ! 550: /* ! 551: * If this is the parameter to DBST or DBCL, force ! 552: * base-10 conversion, else convert per parameter. ! 553: */ ! 554: if (sc_opdef[i].opcode == SC_DBST || ! 555: sc_opdef[i].opcode == SC_DBCL) ! 556: this->intprm = strtol(c, (char **)NULL, 0); ! 557: else ! 558: this->intprm = strtol(c, (char **)NULL, 10); ! 559: break; ! 560: ! 561: /* ! 562: * STR/XSTR strings. ! 563: */ ! 564: case SC_STR: ! 565: case SC_XSTR: ! 566: c = strtok((char *)NULL, CTL_DELIM); ! 567: if (c == (char *)NULL) ! 568: { ! 569: logit("Missing script param", opc); ! 570: deal_script(first); ! 571: return (struct script *)NULL; ! 572: } ! 573: /* ! 574: * For XSTR opcode, use c to find out where ! 575: * the string param begins in the copy of the ! 576: * input line, and pick up all that's left of ! 577: * the line (to allow imbedded blanks, etc.). ! 578: */ ! 579: if (sc_opdef[i].prmtype == SC_XSTR) ! 580: c = &inpcopy[0] + (c - &inpline[0]); ! 581: ! 582: /* ! 583: * Allocate a buffer for the string parameter ! 584: */ ! 585: this->strprm = (char *)malloc(strlen(c)+1); ! 586: ! 587: /* ! 588: * For XSTR, Translate the string and store its ! 589: * length. Note that, after escape sequences are ! 590: * compressed, the resulting string may well be a ! 591: * few bytes shorter than the input string (whose ! 592: * length was the basis for the malloc above), ! 593: * but it will never be longer. ! 594: */ ! 595: if (sc_opdef[i].prmtype == SC_XSTR) ! 596: { ! 597: this->intprm = xlat_str(this->strprm, c); ! 598: this->strprm[this->intprm] = '\0'; ! 599: } ! 600: else ! 601: strcpy(this->strprm, c); ! 602: break; ! 603: ! 604: } ! 605: } ! 606: ! 607: /* ! 608: * EOF ! 609: */ ! 610: return first; ! 611: } ! 612: ! 613: ! 614: /* ! 615: * xlat_str ! 616: * ! 617: * Translate embedded escape characters in a "send" or "expect" string. ! 618: * ! 619: * Called by read_script(), above. ! 620: * ! 621: * Returns the actual length of the resulting string. Note that imbedded ! 622: * nulls (specified by \000 in the input) ARE allowed in the result. ! 623: */ ! 624: xlat_str(out, in) ! 625: char *out, *in; ! 626: { ! 627: register int i = 0, j = 0; ! 628: int byte, k; ! 629: ! 630: while (in[i]) ! 631: { ! 632: if (in[i] != '\\') ! 633: { ! 634: out[j++] = in[i++]; ! 635: } ! 636: else ! 637: { ! 638: switch (in[++i]) ! 639: { ! 640: case 'd': /* EOT */ ! 641: out[j++] = 0x04; ! 642: break; ! 643: case 'N': /* null */ ! 644: out[j++] = 0x00; ! 645: break; ! 646: case 'n': /* line feed */ ! 647: out[j++] = 0x0a; ! 648: break; ! 649: case 'r': /* carriage return */ ! 650: out[j++] = 0x0d; ! 651: break; ! 652: case 's': /* space */ ! 653: out[j++] = ' '; ! 654: break; ! 655: case 't': /* tab */ ! 656: out[j++] = '\t'; ! 657: break; ! 658: case '-': /* hyphen */ ! 659: out[j++] = '-'; ! 660: break; ! 661: case '\\': /* back slash */ ! 662: out[j++] = '\\'; ! 663: break; ! 664: case '0': /* '\nnn' format */ ! 665: case '1': ! 666: case '2': ! 667: case '3': ! 668: case '4': ! 669: case '5': ! 670: case '6': ! 671: case '7': ! 672: byte = in[i] - '0'; ! 673: k = 0; ! 674: ! 675: while (3 > ++k) ! 676: if ((in[i+1] < '0') || (in[i+1] > '7')) ! 677: break; ! 678: else ! 679: { ! 680: byte = (byte<<3) + in[i+1] - '0'; ! 681: ++i; ! 682: } ! 683: out[j++] = byte; ! 684: break; ! 685: default: /* don't know so skip it */ ! 686: break; ! 687: } ! 688: ++i; ! 689: } ! 690: } ! 691: return j; ! 692: } ! 693: ! 694: ! 695: /* find a state within a script */ ! 696: ! 697: struct script * ! 698: find_state(begin, newstate) ! 699: struct script *begin; ! 700: char *newstate; ! 701: { ! 702: struct script *here; ! 703: ! 704: for (here=begin; here != (struct script *)NULL; here=here->next) { ! 705: if (here->opcode == SC_LABEL && ! 706: strcmp(here->strprm, newstate) == SAME) ! 707: return here; ! 708: } ! 709: return (struct script *)NULL; ! 710: } ! 711: ! 712: ! 713: /* ! 714: * do_script() - execute a script ! 715: */ ! 716: int do_script(begin) ! 717: struct script *begin; ! 718: { ! 719: struct script *curstate, *newstate, *curscr; ! 720: int dbgsave; ! 721: char tempstr[MAX_SCLINE]; ! 722: char dfname[256]; ! 723: char *c, chr; ! 724: int prmlen; ! 725: int dbfd; ! 726: ! 727: time_t sc_carrtime = 45000; /* time to wf carr after dial */ ! 728: time_t sc_chrdly = 100; /* delay time for ttoslow */ ! 729: time_t sc_ptime = 2000; /* time to allow for pause char */ ! 730: time_t sc_wtime = 10000; /* time to allow for wait char */ ! 731: time_t sc_dtime = 100; /* time to allow for each digit */ ! 732: time_t sc_dtmo; /* total time to dial number */ ! 733: int sc_counter; /* random counter */ ! 734: char sc_pchar = ','; /* modem pause character */ ! 735: char sc_wchar = 'W'; /* modem wait-for-dialtone character */ ! 736: time_t sc_begwait; /* time at beg of wait */ ! 737: time_t sc_secs; /* timeout period */ ! 738: ! 739: int expcnt; ! 740: int expin; ! 741: static char expbuf[MAX_EXPCT]; ! 742: ! 743: dbgsave = Debug; ! 744: curstate = begin; ! 745: ! 746: if (curstate == (struct script *)NULL) ! 747: return SUCCESS; ! 748: ! 749: _newstate: ! 750: /* ! 751: * do all of curstate's actions. Enter with curstate pointing ! 752: * to a label entry ! 753: */ ! 754: expin = 0; ! 755: ! 756: for (curscr = curstate->next; /* point to 1st scr after label */ ! 757: (curscr != (struct script *)NULL) && /* do until end of scr */ ! 758: (curscr->opcode != SC_LABEL); /* or next label */ ! 759: curscr = curscr->next) ! 760: { ! 761: expcnt = 0; ! 762: switch (curscr->opcode) ! 763: { ! 764: case SC_LABEL: ! 765: logit("Script proc err", curstate->strprm); ! 766: return FAIL; ! 767: ! 768: case SC_FLSH: ! 769: DEBUG(DB_LGII, "Flushing typeahead buffer\n", 0); ! 770: ttflui(); ! 771: break; ! 772: ! 773: case SC_CDLY: ! 774: sc_chrdly = curscr->intprm; ! 775: DEBUG(DB_LGII, "Set chrdly to %d\n", sc_chrdly); ! 776: break; ! 777: ! 778: case SC_PCHR: ! 779: sc_pchar = *(curscr->strprm); ! 780: DEBUG(DB_LGII, "Set pause char to %c\n", sc_pchar); ! 781: break; ! 782: ! 783: case SC_PTIM: ! 784: sc_ptime = curscr->intprm; ! 785: DEBUG(DB_LGII, "Set pause time to %d\n", sc_ptime); ! 786: break; ! 787: ! 788: case SC_WCHR: ! 789: sc_wchar = *(curscr->strprm); ! 790: DEBUG(DB_LGII, "Set wait char to %c\n", sc_wchar); ! 791: break; ! 792: ! 793: case SC_WTIM: ! 794: sc_wtime = curscr->intprm; ! 795: DEBUG(DB_LGII, "Set wait time to %d\n", sc_wtime); ! 796: break; ! 797: ! 798: case SC_ZERO: ! 799: sc_counter = 0; ! 800: DEBUG(DB_LGII, "Set counter to %d\n", sc_counter); ! 801: break; ! 802: ! 803: case SC_INCR: ! 804: sc_counter++; ! 805: DEBUG(DB_LGII, "Incr counter to %d\n", sc_counter); ! 806: break; ! 807: ! 808: case SC_WAIT: ! 809: DEBUG(DB_LGII, "Sleeping %d tenth-secs\n", curscr->intprm); ! 810: msleep(curscr->intprm); ! 811: break; ! 812: ! 813: case SC_DTIM: ! 814: sc_dtime = curscr->intprm; ! 815: DEBUG(DB_LGII, "Digit time is %d\n", sc_dtime); ! 816: break; ! 817: ! 818: case SC_CTIM: ! 819: sc_carrtime = curscr->intprm; ! 820: DEBUG(DB_LGII, "Carrier time is %d\n", sc_carrtime); ! 821: break; ! 822: ! 823: case SC_EXIT: ! 824: Debug = dbgsave; ! 825: DEBUG(DB_LGI, "Script ended successfully\n", 0); ! 826: return SUCCESS; ! 827: ! 828: case SC_FAIL: ! 829: Debug = dbgsave; ! 830: if (DEBUG_LEVEL(DB_LGI) && dbf != NULL) ! 831: fprintf(dbf, "Script failed\n"); ! 832: else if (expin) ! 833: charlog(expbuf, expin, DB_LOG, ! 834: "Script failed. Last received data"); ! 835: return FAIL; ! 836: ! 837: case SC_LOG: ! 838: logit(curscr->strprm, ""); ! 839: break; ! 840: ! 841: case SC_LOGE: ! 842: logit("ERROR: ", curscr->strprm); ! 843: break; ! 844: ! 845: case SC_DBOF: ! 846: /* ! 847: * If the debug file name does not begin with "/", then ! 848: * we prepend the LOG_DIR to the string. Then CREATE the ! 849: * file. This WIPES OUT previous logs. ! 850: */ ! 851: *dfname = '\0'; /* Zero name string */ ! 852: if(curscr->strprm[0] != '/') ! 853: strcat(dfname, LOG_DIR); /* Prepend default directory */ ! 854: strcat(dfname, curscr->strprm); /* Add given string */ ! 855: DEBUG(DB_LGII, "Open debug file %s\n", dfname); ! 856: if ((dbfd = creat (dfname, 0600)) <= 0) ! 857: { ! 858: logit("Failed to create debug log %s", dfname); ! 859: perror(""); ! 860: return FAIL; ! 861: } ! 862: if ((dbf = fdopen(dbfd, "w")) == NULL) ! 863: { ! 864: logit("Failed to open debug log fildes.", ""); ! 865: perror(""); ! 866: return FAIL; ! 867: } ! 868: break; ! 869: ! 870: case SC_DBG: ! 871: DEBUG(DB_LGI, "<%s>\n", curscr->strprm); ! 872: break; ! 873: ! 874: case SC_DBGE: ! 875: DEBUG(DB_LGIE, "ERROR: <%s>\n", curscr->strprm); ! 876: break; ! 877: ! 878: case SC_DBST: ! 879: Debug |= curscr->intprm; ! 880: DEBUG(DB_LGII, "Debug mask set to %04o (octal)\n", Debug); ! 881: break; ! 882: ! 883: case SC_DBCL: ! 884: Debug &= ~(curscr->intprm); ! 885: DEBUG(DB_LGII, "Debug mask set to %04o (octal)\n", Debug); ! 886: break; ! 887: ! 888: case SC_BRK: ! 889: DEBUG(DB_LGI, "Sending break\n", 0); ! 890: ttbreak(); ! 891: break; ! 892: ! 893: case SC_HANG: ! 894: DEBUG(DB_LGI, "Dropping DTR\n", 0); ! 895: tthang(); ! 896: break; ! 897: ! 898: case SC_7BIT: ! 899: DEBUG(DB_LGI, "Enabling 7-bit stripping\n", 0); ! 900: tt7bit(TRUE); ! 901: break; ! 902: ! 903: case SC_8BIT: ! 904: DEBUG(DB_LGI, "Disabling 7-bit stripping\n", 0); ! 905: tt7bit(FALSE); ! 906: break; ! 907: ! 908: case SC_PNON: ! 909: DEBUG(DB_LGI, "Setting 8-bit, no parity\n", 0); ! 910: ttpar(NONE); ! 911: break; ! 912: ! 913: case SC_PEVN: ! 914: DEBUG(DB_LGI, "Setting 7-bit, even parity\n", 0); ! 915: ttpar(EVEN); ! 916: break; ! 917: ! 918: case SC_PODD: ! 919: DEBUG(DB_LGI, "Setting 7-bit, odd parity\n", 0); ! 920: ttpar(ODD); ! 921: break; ! 922: ! 923: case SC_IFBL: ! 924: if (ttblind()) ! 925: { ! 926: DEBUG(DB_LGI, "Blind mux,\n", 0); ! 927: goto _chgstate; ! 928: } ! 929: break; ! 930: ! 931: case SC_IFBG: ! 932: if (ttblind() && sc_counter > curscr->intprm) ! 933: { ! 934: DEBUG(DB_LGI, "Blind mux & ctr > %d\n", ! 935: curscr->intprm); ! 936: goto _chgstate; ! 937: } ! 938: break; ! 939: ! 940: case SC_IFGT: ! 941: if (sc_counter > curscr->intprm) ! 942: { ! 943: DEBUG(DB_LGI, "Counter > %d\n", curscr->intprm); ! 944: goto _chgstate; ! 945: } ! 946: break; ! 947: ! 948: case SC_GOTO: ! 949: _chgstate: ! 950: DEBUG(DB_LGI, "Changing to state %s\n", ! 951: curscr->newstate); ! 952: curstate = find_state(begin, curscr->newstate); ! 953: if (curstate == NULL) ! 954: { ! 955: logit("New state not found", ! 956: curscr->newstate); ! 957: return FAIL; ! 958: } ! 959: goto _newstate; ! 960: ! 961: case SC_SEND: ! 962: ttoslow(curscr->strprm, curscr->intprm, sc_chrdly); ! 963: break; ! 964: ! 965: case SC_TELN: ! 966: if (curscr->intprm > paramc - 1) ! 967: { ! 968: sprintf(tempstr, "telno - param #%d", curscr->intprm); ! 969: logit(tempstr, " not present"); ! 970: return FAIL; ! 971: } ! 972: strcpy(telno, paramv[curscr->intprm]); ! 973: DEBUG(DB_LGII, "telno set to %s\n", telno); ! 974: break; ! 975: ! 976: case SC_SNDP: ! 977: if (curscr->intprm > paramc - 1) ! 978: { ! 979: sprintf(tempstr, "sendstr - param #%d", curscr->intprm); ! 980: logit(tempstr, " not present"); ! 981: return FAIL; ! 982: } ! 983: prmlen = xlat_str(tempstr, paramv[curscr->intprm]); ! 984: ttoslow(tempstr, prmlen, sc_chrdly); ! 985: break; ! 986: ! 987: case SC_IF1P: ! 988: if (curscr->intprm < paramc) ! 989: goto _chgstate; ! 990: break; ! 991: ! 992: case SC_IF0P: ! 993: if (curscr->intprm >= paramc) ! 994: goto _chgstate; ! 995: break; ! 996: ! 997: case SC_DIAL: ! 998: if(telno[0] == '\0') ! 999: { ! 1000: logit("telno not set", ""); ! 1001: return(FAIL); ! 1002: } ! 1003: /* ! 1004: * Compute and set a default timeout for the 'timeout' ! 1005: * command. Some parameters in this computation may be ! 1006: * changed by the script. See the man page xchat(8) for ! 1007: * details. ! 1008: */ ! 1009: sc_dtmo = (sc_dtime+sc_chrdly)*strlen(telno) ! 1010: + sc_carrtime; ! 1011: c=strcpy(tempstr, telno); ! 1012: for (; *c!='\0'; c++) ! 1013: { ! 1014: if (*c == 'W') ! 1015: { ! 1016: *c = sc_wchar; ! 1017: sc_dtmo += sc_wtime; ! 1018: } ! 1019: else if (*c == 'P') ! 1020: { ! 1021: *c = sc_pchar; ! 1022: sc_dtmo += sc_ptime; ! 1023: } ! 1024: } ! 1025: DEBUG(DB_LGI, "Dialing, default timeout is %d millisecs\n", sc_dtmo); ! 1026: ttoslow(tempstr, 0, sc_chrdly); ! 1027: break; ! 1028: ! 1029: case SC_TIMO: /* these are "expects", don't bother */ ! 1030: case SC_XPCT: /* with them yet, other than noting that */ ! 1031: case SC_CARR: /* they exist */ ! 1032: expcnt++; ! 1033: break; ! 1034: } ! 1035: ! 1036: } ! 1037: ! 1038: /* we've done the current state's actions, now do its expects, if any */ ! 1039: ! 1040: if (expcnt == 0) ! 1041: { ! 1042: if (curscr != (struct script *)NULL && ! 1043: (curscr->opcode == SC_LABEL)) ! 1044: { ! 1045: curstate = curscr; ! 1046: DEBUG(DB_LGI, "Fell through to state %s\n", ! 1047: curstate->strprm); ! 1048: goto _newstate; ! 1049: } ! 1050: else ! 1051: { ! 1052: logit("No way out of state", curstate->strprm); ! 1053: return FAIL; ! 1054: } ! 1055: } ! 1056: ! 1057: time(&sc_begwait); /* log time at beg of expect */ ! 1058: DEBUG(DB_LGI, "Doing expects for state %s\n", curstate->strprm); ! 1059: charlog((char *)NULL, 0, DB_LGI, "Received"); ! 1060: ! 1061: while (1) ! 1062: { ! 1063: chr = xgetc(1); /* Returns upon char input or 1 sec. tmo */ ! 1064: ! 1065: charlog(&chr, 1, DB_LGI, (char *)NULL); ! 1066: ! 1067: if (chr != EOF) ! 1068: { ! 1069: if (expin < MAX_EXPCT) ! 1070: { ! 1071: expbuf[expin++] = chr & 0x7f; ! 1072: } ! 1073: else ! 1074: { ! 1075: strncpy(expbuf, &expbuf[1], MAX_EXPCT-1); ! 1076: expbuf[MAX_EXPCT-1] = chr & 0x7f; ! 1077: } ! 1078: } ! 1079: ! 1080: /* for each entry in the current state... */ ! 1081: ! 1082: for (curscr = curstate->next; ! 1083: (curscr != (struct script *)NULL) && ! 1084: (curscr->opcode != SC_LABEL); ! 1085: curscr = curscr->next) ! 1086: { ! 1087: ! 1088: switch (curscr->opcode) ! 1089: { ! 1090: case SC_TIMO: ! 1091: sc_secs = curscr->intprm; ! 1092: if (sc_secs == 0) ! 1093: sc_secs = sc_dtmo; ! 1094: sc_secs /= 1000; ! 1095: if (time(NULL)-sc_begwait > sc_secs) ! 1096: { ! 1097: DEBUG(DB_LGI, ! 1098: "\nTimed out (%d secs)\n", sc_secs); ! 1099: goto _chgstate; ! 1100: } ! 1101: break; ! 1102: ! 1103: case SC_CARR: ! 1104: if (ttcd()) ! 1105: { ! 1106: DEBUG(DB_LGI, "\nGot carrier\n", 0); ! 1107: goto _chgstate; ! 1108: } ! 1109: break; ! 1110: ! 1111: case SC_HUPS: ! 1112: if (fShangup) ! 1113: { ! 1114: DEBUG(DB_LGI, "\nGot data set hangup\n", 0); ! 1115: goto _chgstate; ! 1116: } ! 1117: break; ! 1118: ! 1119: case SC_XPCT: ! 1120: if ((expin >= curscr->intprm) && ! 1121: (strncmp(curscr->strprm, ! 1122: &expbuf[expin - curscr->intprm], ! 1123: curscr->intprm) == SAME)) ! 1124: { ! 1125: charlog(curscr->strprm, curscr->intprm, ! 1126: DB_LGI, "Matched"); ! 1127: goto _chgstate; ! 1128: } ! 1129: break; ! 1130: ! 1131: } ! 1132: } ! 1133: } ! 1134: } ! 1135: ! 1136: /* ! 1137: * SIGNAL HANDLERS ! 1138: */ ! 1139: ! 1140: /* ! 1141: * usignal - generic signal catcher ! 1142: */ ! 1143: static int usignal(isig) ! 1144: int isig; ! 1145: { ! 1146: DEBUG(DB_LOG, "Caught signal %d. Exiting...\n", isig); ! 1147: restore_tty(); ! 1148: exit(FAIL); ! 1149: } ! 1150: ! 1151: /* ! 1152: * uhup - HUP catcher ! 1153: */ ! 1154: static int uhup(isig) ! 1155: int isig; ! 1156: { ! 1157: DEBUG(DB_LOG, "Data set hangup.\n"); ! 1158: fShangup = TRUE; ! 1159: } ! 1160: ! 1161: /* ! 1162: * TERMINAL I/O ROUTINES ! 1163: */ ! 1164: ! 1165: /* ! 1166: * xgetc - get a character with timeout ! 1167: * ! 1168: * Assumes that stdin is opened on a terminal or TCP socket ! 1169: * with O_NONBLOCK. ! 1170: */ ! 1171: static char xgetc(tmo) ! 1172: int tmo; /* Timeout, seconds */ ! 1173: { ! 1174: char c; ! 1175: struct timeval s; ! 1176: int f = 1; /* Select on stdin */ ! 1177: int result; ! 1178: ! 1179: if(read(0, &c, 1) <= 0) /* If no data available */ ! 1180: { ! 1181: s.tv_sec = (long)tmo; ! 1182: s.tv_usec = 0L; ! 1183: if(select (1, &f, (int *) NULL, &f, &s) == 1) ! 1184: read(0, &c, 1); ! 1185: else ! 1186: c = '\377'; ! 1187: } ! 1188: ! 1189: return(c); ! 1190: } ! 1191: ! 1192: /* ! 1193: * Pause for an interval in milliseconds ! 1194: */ ! 1195: void msleep(msec) ! 1196: long msec; ! 1197: { ! 1198: ! 1199: #if HAVE_USLEEP ! 1200: if(msec == 0) /* Skip all of this if delay = 0 */ ! 1201: return; ! 1202: usleep (msec * (long)1000); ! 1203: #endif /* HAVE_USLEEP */ ! 1204: ! 1205: #if HAVE_NAPMS ! 1206: if(msec == 0) /* Skip all of this if delay = 0 */ ! 1207: return; ! 1208: napms (msec); ! 1209: #endif /* HAVE_NAPMS */ ! 1210: ! 1211: #if HAVE_NAP ! 1212: if(msec == 0) /* Skip all of this if delay = 0 */ ! 1213: return; ! 1214: nap (msec); ! 1215: #endif /* HAVE_NAP */ ! 1216: ! 1217: #if HAVE_POLL ! 1218: struct pollfd sdummy; ! 1219: ! 1220: if(msec == 0) ! 1221: return; ! 1222: /* ! 1223: * We need to pass an unused pollfd structure because poll checks ! 1224: * the address before checking the number of elements. ! 1225: */ ! 1226: poll (&sdummy, 0, msec); ! 1227: #endif /* HAVE_POLL */ ! 1228: ! 1229: #if USE_SELECT_TIMER ! 1230: struct timeval s; ! 1231: ! 1232: if(msec == 0) ! 1233: return; ! 1234: s.tv_sec = msec / 1000L; ! 1235: s.tv_usec = (msec % 1000L) * 1000L; ! 1236: select (0, (int *) NULL, (int *) NULL, (int *) NULL, &s); ! 1237: #endif /* USE_SELECT_TIMER */ ! 1238: ! 1239: #if ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP && \ ! 1240: ! HAVE_POLL && ! USE_SELECT_TIMER ! 1241: if(msec == 0) ! 1242: return; ! 1243: sleep (1); /* Sleep for a whole second (UGH!) */ ! 1244: #endif /* HAVE_ and USE_ nothing */ ! 1245: } ! 1246: ! 1247: /* ! 1248: * Debugging output ! 1249: */ ! 1250: static void DEBUG(level, msg1, msg2) ! 1251: int level; ! 1252: char *msg1, *msg2; ! 1253: { ! 1254: if ((dbf != NULL) && DEBUG_LEVEL(level)) ! 1255: fprintf(dbf, msg1, msg2); ! 1256: } ! 1257: ! 1258: /* ! 1259: * charlog - log a string of characters ! 1260: * ! 1261: * SPECIAL CASE: msg=NULL, len=1 and msg[0]='\377' gets logged ! 1262: * when read does its 1 sec. timeout. Log "<1 sec.>" ! 1263: * so user can see elapsed time ! 1264: */ ! 1265: static void charlog(buf, len, mask, msg) ! 1266: char *buf; ! 1267: int len, mask; ! 1268: char *msg; ! 1269: { ! 1270: char tbuf[256]; ! 1271: ! 1272: if (DEBUG_LEVEL(mask) && dbf != NULL) ! 1273: { ! 1274: if(msg == (char *)NULL) ! 1275: msg = ""; ! 1276: strncpy(tbuf, buf, len); ! 1277: tbuf[len] = '\0'; ! 1278: if(len == 1 && tbuf[0] == '\377') ! 1279: strcpy(tbuf, "<1 sec.>"); ! 1280: fprintf(dbf, "%s %s\n", msg, tbuf); ! 1281: } ! 1282: } ! 1283: ! 1284: /* ! 1285: * setup_tty() ! 1286: * ! 1287: * Save current tty settings, then set up raw, single ! 1288: * character input processing, with 7-bit stripping. ! 1289: */ ! 1290: static void setup_tty() ! 1291: { ! 1292: register int i; ! 1293: ! 1294: ioctl(0, TCGETA, &old); ! 1295: ! 1296: new = old; ! 1297: ! 1298: for(i = 0; i < 7; i++) ! 1299: new.c_cc[i] = '\0'; ! 1300: new.c_cc[VMIN] = 0; /* MIN = 0, use requested count */ ! 1301: new.c_cc[VTIME] = 10; /* TIME = 1 sec. */ ! 1302: new.c_iflag = ISTRIP; /* Raw mode, 7-bit stripping */ ! 1303: new.c_lflag = 0; /* No special line discipline */ ! 1304: ! 1305: ioctl(0, TCSETA, &new); ! 1306: } ! 1307: ! 1308: /* ! 1309: * restore_tty() - restore signal handlers and tty modes on exit. ! 1310: */ ! 1311: static void restore_tty(sig) ! 1312: int sig; ! 1313: { ! 1314: ioctl(0, TCSETA, &old); ! 1315: return; ! 1316: } ! 1317: ! 1318: /* ! 1319: * ttoslow() - Send characters with pacing delays ! 1320: */ ! 1321: static void ttoslow(s, len, delay) ! 1322: char *s; ! 1323: int len; ! 1324: time_t delay; ! 1325: { ! 1326: int i; ! 1327: ! 1328: if (len == 0) ! 1329: len = strlen(s); ! 1330: ! 1331: charlog (s, len, DB_LGI, "Sending slowly"); ! 1332: ! 1333: for (i = 0; i < len; i++, s++) ! 1334: { ! 1335: write(1, s, 1); ! 1336: msleep(delay); ! 1337: } ! 1338: } ! 1339: ! 1340: /* ! 1341: * ttflui - flush input buffer ! 1342: */ ! 1343: static void ttflui() ! 1344: { ! 1345: if(isatty(0)) ! 1346: (void) ioctl ( 0, TCFLSH, 0); ! 1347: } ! 1348: ! 1349: /* ! 1350: * ttcd - Test if carrier is present ! 1351: * ! 1352: * NOT IMPLEMENTED. I don't know how!!! ! 1353: */ ! 1354: static int ttcd() ! 1355: { ! 1356: return TRUE; ! 1357: } ! 1358: ! 1359: /* ! 1360: * tthang - Force DTR low for 1-2 sec. ! 1361: */ ! 1362: static void tthang() ! 1363: { ! 1364: if(!isatty()) ! 1365: return; ! 1366: ! 1367: #ifdef TCCLRDTR ! 1368: (void) ioctl (1, TCCLRDTR, 0); ! 1369: sleep (2); ! 1370: (void) ioctl (1, TCSETDTR, 0); ! 1371: #endif ! 1372: ! 1373: return; ! 1374: } ! 1375: ! 1376: /* ! 1377: * ttbreak - Send a "break" on the line ! 1378: */ ! 1379: static void ttbreak() ! 1380: { ! 1381: (void) ioctl (1, TCSBRK, 0); ! 1382: } ! 1383: ! 1384: /* ! 1385: * ttblind - return TRUE if tty is "blind" ! 1386: * ! 1387: * NOT IMPLEMENTED - Don't know how!!! ! 1388: */ ! 1389: static int ttblind() ! 1390: { ! 1391: return FALSE; ! 1392: } ! 1393: ! 1394: /* ! 1395: * tt7bit - enable/disable 7-bit stripping on line ! 1396: */ ! 1397: static void tt7bit(enable) ! 1398: int enable; ! 1399: { ! 1400: if(enable) ! 1401: new.c_iflag |= ISTRIP; ! 1402: else ! 1403: new.c_iflag &= ~ISTRIP; ! 1404: ! 1405: ioctl(0, TCSETA, &new); ! 1406: } ! 1407: ! 1408: /* ! 1409: * ttpar - Set parity mode on line. Ignore parity errors on input. ! 1410: */ ! 1411: static void ttpar(mode) ! 1412: int mode; ! 1413: { ! 1414: switch(mode) ! 1415: { ! 1416: case NONE: ! 1417: new.c_iflag &= ~(INPCK | IGNPAR); ! 1418: new.c_cflag &= ~(CSIZE | PARENB | PARODD); ! 1419: new.c_cflag |= CS8; ! 1420: break; ! 1421: ! 1422: case EVEN: ! 1423: new.c_iflag |= (INPCK | IGNPAR); ! 1424: new.c_cflag &= ~(CSIZE | PARODD); ! 1425: new.c_cflag |= (CS7 | PARENB); ! 1426: ! 1427: break; ! 1428: ! 1429: case ODD: ! 1430: new.c_iflag |= (INPCK | IGNPAR); ! 1431: new.c_cflag &= ~(CSIZE); ! 1432: new.c_cflag |= (CS7 | PARENB | PARODD); ! 1433: break; ! 1434: } ! 1435: ! 1436: ioctl(0, TCSETA, &new); ! 1437: } ! 1438: ! 1439: ! 1440: ! 1441: ! 1442: ! 1443: ! 1444:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.