Annotation of coherent/g/usr/lib/uucp/tay104/contrib/xchat.c, revision 1.1.1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.