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