home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / uucp-1.04 / contrib / xchat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-06  |  32.8 KB  |  1,445 lines

  1. /*
  2.  *  ***********
  3.  *  * XCHAT.C *
  4.  *  ***********
  5.  *
  6.  * Extended chat processor for Taylor UUCP. See accompanying documentation.
  7.  *
  8.  * Written by:
  9.  *   Bob Denny (denny@alisa.com)
  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.  
  1445.