home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / Connectivity / GateKeeper-2.1 / chat / chat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-03-04  |  18.0 KB  |  1,109 lines

  1. /*
  2.  *    Chat -- a program for automatic session establishment (i.e. dial
  3.  *        the phone and log in).
  4.  *
  5.  *    This software is in the public domain.
  6.  *
  7.  *    Please send all bug reports, requests for information, etc. to:
  8.  *
  9.  *        Al Longyear (longyear@netcom.com)
  10.  *        (I was the last person to change this code.)
  11.  *
  12.  *        Added ability to handle Bourne shell style comments (i.e. # comment)
  13.  *            Felipe A. Rodriguez <far@ix.netcom.com>  3/4/97
  14.  *
  15.  *    The original author is:
  16.  *
  17.  *        Karl Fox <karl@MorningStar.Com>
  18.  *        Morning Star Technologies, Inc.
  19.  *        1760 Zollinger Road
  20.  *        Columbus, OH  43221
  21.  *        (614)451-1883
  22.  */
  23.  
  24. static char rcsid[] = "$Id: chat.c.3.2,v 5.1 1996/02/23 21:07:14 perkins Exp $";
  25.  
  26. #include <stdio.h>
  27. #include <fcntl.h>
  28. #include <signal.h>
  29. #include <errno.h>
  30. #include <string.h>
  31. #include <stdlib.h>
  32. #include <sys/types.h>
  33. #include <sys/stat.h>
  34. #include <syslog.h>
  35.  
  36. #ifndef TERMIO
  37. #undef    TERMIOS
  38. #define TERMIOS
  39. #endif
  40.  
  41. #ifdef TERMIO
  42. #include <termio.h>
  43. #endif
  44. #ifdef TERMIOS
  45. #include <termios.h>
  46. #endif
  47.  
  48. #define    STR_LEN    1024
  49.  
  50. #ifndef SIGTYPE
  51. #define SIGTYPE void
  52. #endif
  53.  
  54. #ifdef __STDC__
  55. #undef __P
  56. #define __P(x)    x
  57. #else
  58. #define __P(x)    ()
  59. #define const
  60. #endif
  61.  
  62. /*************** Micro getopt() *********************************************/
  63. #define    OPTION(c,v)    (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \
  64.                 (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\
  65.                 &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0))
  66. #define    OPTARG(c,v)    (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \
  67.                 (_O=4,(char*)0):(char*)0)
  68. #define    OPTONLYARG(c,v)    (_O&2&&**v?(_O=1,--c,*v++):(char*)0)
  69. #define    ARG(c,v)    (c?(--c,*v++):(char*)0)
  70.  
  71. static int _O = 0;        /* Internal state */
  72. /*************** Micro getopt() *********************************************/
  73.  
  74. char *program_name;
  75.  
  76. #define    MAX_ABORTS        50
  77. #define    DEFAULT_CHAT_TIMEOUT    45
  78.  
  79. int verbose = 0;
  80. int quiet = 0;
  81. char *lock_file = (char *)0;
  82. char *chat_file = (char *)0;
  83. int timeout = DEFAULT_CHAT_TIMEOUT;
  84.  
  85. int have_tty_parameters = 0;
  86. #ifdef TERMIO
  87. struct termio saved_tty_parameters;
  88. #endif
  89. #ifdef TERMIOS
  90. struct termios saved_tty_parameters;
  91. #endif
  92.  
  93. char *abort_string[MAX_ABORTS], *fail_reason = (char *)0,
  94.     fail_buffer[50];
  95. int n_aborts = 0, abort_next = 0, timeout_next = 0;
  96.  
  97. void *dup_mem __P((void *b, size_t c));
  98. void *copy_of __P((char *s));
  99. void usage __P((void));
  100. void logf __P((const char *str));
  101. void logflush __P((void));
  102. void fatal __P((const char *msg));
  103. void sysfatal __P((const char *msg));
  104. SIGTYPE sigalrm __P((int signo));
  105. SIGTYPE sigint __P((int signo));
  106. SIGTYPE sigterm __P((int signo));
  107. SIGTYPE sighup __P((int signo));
  108. void unalarm __P((void));
  109. void init __P((void));
  110. void set_tty_parameters __P((void));
  111. void break_sequence __P((void));
  112. void terminate __P((int status));
  113. void do_file __P((char *chat_file));
  114. void delay __P((void));
  115. int  get_string __P((register char *string));
  116. int  put_string __P((register char *s));
  117. int  write_char __P((int c));
  118. int  put_char __P((int c));
  119. int  get_char __P((void));
  120. void chat_send __P((register char *s));
  121. char *character __P((int c));
  122. void chat_expect __P((register char *s));
  123. char *clean __P((register char *s, int sending));
  124. void break_sequence __P((void));
  125. void terminate __P((int status));
  126. void die __P((void));
  127.  
  128. void *dup_mem(b, c)
  129. void *b;
  130. size_t c;
  131.     {
  132.     void *ans = malloc (c);
  133.     if (!ans)
  134.     fatal ("memory error!\n");
  135.     memcpy (ans, b, c);
  136.     return ans;
  137.     }
  138.  
  139. void *copy_of (s)
  140. char *s;
  141.     {
  142.     return dup_mem (s, strlen (s) + 1);
  143.     }
  144.  
  145. /*
  146.  *    chat [ -v ] [ -t timeout ] [ -f chat-file ] \
  147.  *        [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]]
  148.  *
  149.  *    Perform a UUCP-dialer-like chat script on stdin and stdout.
  150.  */
  151. int
  152. main(argc, argv)
  153. int argc;
  154. char **argv;
  155.     {
  156.     int option;
  157.     char *arg;
  158.  
  159.     program_name = *argv;
  160.  
  161.     while (option = OPTION(argc, argv))
  162.     switch (option)
  163.         {
  164.         case 'v':
  165.         ++verbose;
  166.         break;
  167.  
  168.         case 'f':
  169.         if (arg = OPTARG(argc, argv))
  170.             chat_file = copy_of(arg);
  171.         else
  172.             usage();
  173.  
  174.         break;
  175.  
  176.         case 'l':
  177.         if (arg = OPTARG(argc, argv))
  178.             lock_file = copy_of(arg);
  179.         else
  180.             usage();
  181.  
  182.         break;
  183.  
  184.         case 't':
  185.         if (arg = OPTARG(argc, argv))
  186.             timeout = atoi(arg);
  187.         else
  188.             usage();
  189.  
  190.         break;
  191.  
  192.         default:
  193.         usage();
  194.         }
  195.  
  196. #ifdef ultrix
  197.     openlog("chat", LOG_PID);
  198. #else
  199.     openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2);
  200.  
  201.     if (verbose) {
  202.     setlogmask(LOG_UPTO(LOG_INFO));
  203.     } else {
  204.     setlogmask(LOG_UPTO(LOG_WARNING));
  205.     }
  206. #endif
  207.  
  208.     init();
  209.     
  210.     if (chat_file != NULL)
  211.     {
  212.     arg = ARG(argc, argv);
  213.     if (arg != NULL)
  214.         usage();
  215.     else
  216.         do_file (chat_file);
  217.     }
  218.     else
  219.     {
  220.     while (arg = ARG(argc, argv))
  221.         {
  222.         chat_expect(arg);
  223.  
  224.         if (arg = ARG(argc, argv))
  225.         chat_send(arg);
  226.         }
  227.     }
  228.  
  229.     terminate(0);
  230.     }
  231.  
  232. /*
  233.  *  Process a chat script when read from a file.
  234.  */
  235.  
  236. void do_file (chat_file)
  237. char *chat_file;
  238.     {
  239.     int linect, len, sendflg;
  240.     char *sp, *arg, quote;
  241.     char buf [STR_LEN];
  242.     FILE *cfp;
  243.  
  244.     if ((cfp = fopen (chat_file, "r")) == NULL)
  245.     {
  246.     syslog (LOG_ERR, "%s -- open failed: %m", chat_file);
  247.     terminate (1);
  248.     }
  249.  
  250.     linect = 0;
  251.     sendflg = 0;
  252.  
  253.     while (fgets(buf, STR_LEN, cfp) != NULL)        // read lines until EOF
  254.     {
  255.     sp = strchr (buf, '\n');                        
  256.     if (sp)
  257.         *sp = '\0';                                    
  258.  
  259.     linect++;
  260.     sp = buf;
  261.     while (*sp != '\0')                                // parse a line
  262.         {
  263.         if (*sp == '#')                                // comments
  264.             {
  265.             logf(sp);                                // log comments thru syslog            
  266.             logf("\n");
  267.             while(*sp != '\0')
  268.                 sp++;
  269.             sp++;
  270.             }
  271.         else                                    // else parse for send/expect
  272.             {
  273.             if (*sp == ' ' || *sp == '\t')
  274.             {
  275.             ++sp;
  276.             continue;
  277.             }
  278.     
  279.             if (*sp == '"' || *sp == '\'')
  280.             {
  281.             quote = *sp++;
  282.             arg = sp;
  283.             while (*sp != quote)
  284.                 {
  285.                 if (*sp == '\0')
  286.                 {
  287.                 syslog (LOG_ERR, "unterminated quote (line %d)",
  288.                     linect);
  289.                 terminate (1);
  290.                 }
  291.                     
  292.                 if (*sp++ == '\\')
  293.                     {
  294.                     if (*sp != '\0')
  295.                         {
  296.                         ++sp;
  297.                         }
  298.                     }
  299.                 }
  300.             }
  301.             else
  302.             {
  303.             arg = sp;
  304.             while (*sp != '\0' && *sp != ' ' && *sp != '\t')
  305.                 {
  306.                 ++sp;
  307.                 }
  308.             }
  309.     
  310.             if (*sp != '\0')
  311.             *sp++ = '\0';
  312.     
  313.             if (sendflg)
  314.             {
  315.             chat_send (arg);
  316.             }
  317.             else
  318.             {
  319.             chat_expect (arg);
  320.             }
  321.             sendflg = !sendflg;
  322.             }
  323.             }
  324.     }
  325.     fclose (cfp);
  326.     }
  327.  
  328. /*
  329.  *    We got an error parsing the command line.
  330.  */
  331. void usage()
  332.     {
  333.     fprintf(stderr, "\
  334. Usage: %s [-v] [-t timeout] {-f chat-file || chat-script}\n",
  335.         program_name);
  336.     exit(1);
  337.     }
  338.  
  339. char line[256];
  340. char *p;
  341.  
  342. void logf (str)
  343. const char *str;
  344.     {
  345.     p = line + strlen(line);
  346.     strcat (p, str);
  347.  
  348.     if (str[strlen(str)-1] == '\n')
  349.     {
  350.     syslog (LOG_INFO, "%s", line);
  351.     line[0] = 0;
  352.     }
  353.     }
  354.  
  355. void logflush()
  356.     {
  357.     if (line[0] != 0)
  358.     {
  359.     syslog(LOG_INFO, "%s", line);
  360.     line[0] = 0;
  361.         }
  362.     }
  363.  
  364. /*
  365.  *    Terminate with an error.
  366.  */
  367. void die()
  368.     {
  369.     terminate(1);
  370.     }
  371.  
  372. /*
  373.  *    Print an error message and terminate.
  374.  */
  375.  
  376. void fatal (msg)
  377. const char *msg;
  378.     {
  379.     syslog(LOG_ERR, "%s", msg);
  380.     terminate(1);
  381.     }
  382.  
  383. /*
  384.  *    Print an error message along with the system error message and
  385.  *    terminate.
  386.  */
  387.  
  388. void sysfatal (msg)
  389. const char *msg;
  390.     {
  391.     syslog(LOG_ERR, "%s: %m", msg);
  392.     terminate(1);
  393.     }
  394.  
  395. int alarmed = 0;
  396.  
  397. SIGTYPE sigalrm(signo)
  398. int signo;
  399.     {
  400.     int flags;
  401.  
  402.     alarm(1);
  403.     alarmed = 1;        /* Reset alarm to avoid race window */
  404.     signal(SIGALRM, sigalrm);    /* that can cause hanging in read() */
  405.  
  406.     logflush();
  407.     if ((flags = fcntl(0, F_GETFL, 0)) == -1)
  408.     sysfatal("Can't get file mode flags on stdin");
  409.     else
  410.     if (fcntl(0, F_SETFL, flags | FNDELAY) == -1)
  411.         sysfatal("Can't set file mode flags on stdin");
  412.  
  413.     if (verbose)
  414.     {
  415.     syslog(LOG_INFO, "alarm");
  416.     }
  417.     }
  418.  
  419. void unalarm()
  420.     {
  421.     int flags;
  422.  
  423.     if ((flags = fcntl(0, F_GETFL, 0)) == -1)
  424.     sysfatal("Can't get file mode flags on stdin");
  425.     else
  426.     if (fcntl(0, F_SETFL, flags & ~FNDELAY) == -1)
  427.         sysfatal("Can't set file mode flags on stdin");
  428.     }
  429.  
  430. SIGTYPE sigint(signo)
  431. int signo;
  432.     {
  433.     fatal("SIGINT");
  434.     }
  435.  
  436. SIGTYPE sigterm(signo)
  437. int signo;
  438.     {
  439.     fatal("SIGTERM");
  440.     }
  441.  
  442. SIGTYPE sighup(signo)
  443. int signo;
  444.     {
  445.     fatal("SIGHUP");
  446.     }
  447.  
  448. void init()
  449.     {
  450.     signal(SIGINT, sigint);
  451.     signal(SIGTERM, sigterm);
  452.     signal(SIGHUP, sighup);
  453.  
  454.     set_tty_parameters();
  455.     signal(SIGALRM, sigalrm);
  456.     alarm(0);
  457.     alarmed = 0;
  458.     }
  459.  
  460. void set_tty_parameters()
  461.     {
  462. #ifdef TERMIO
  463.     struct termio t;
  464.  
  465.     if (ioctl(0, TCGETA, &t) < 0)
  466.     sysfatal("Can't get terminal parameters");
  467. #endif
  468. #ifdef TERMIOS
  469.     struct termios t;
  470.  
  471.     if (tcgetattr(0, &t) < 0)
  472.     sysfatal("Can't get terminal parameters");
  473. #endif
  474.  
  475.     saved_tty_parameters = t;
  476.     have_tty_parameters = 1;
  477.  
  478.     t.c_iflag |= IGNBRK | ISTRIP | IGNPAR;
  479.     t.c_oflag  = 0;
  480.     t.c_lflag  = 0;
  481.     t.c_cc[VERASE] = t.c_cc[VKILL] = 0;
  482.     t.c_cc[VMIN] = 1;
  483.     t.c_cc[VTIME] = 0;
  484.  
  485. #ifdef TERMIO
  486.     if (ioctl(0, TCSETA, &t) < 0)
  487.     sysfatal("Can't set terminal parameters");
  488. #endif
  489. #ifdef TERMIOS
  490.     if (tcsetattr(0, TCSANOW, &t) < 0)
  491.     sysfatal("Can't set terminal parameters");
  492. #endif
  493.     }
  494.  
  495. void break_sequence()
  496.     {
  497. #ifdef TERMIOS
  498.     tcsendbreak (0, 0);
  499. #endif
  500.     }
  501.  
  502. void terminate(status)
  503. int status;
  504.     {
  505.     if (have_tty_parameters &&
  506. #ifdef TERMIO
  507.         ioctl(0, TCSETA, &saved_tty_parameters) < 0
  508. #endif
  509. #ifdef TERMIOS
  510.     tcsetattr(0, TCSANOW, &saved_tty_parameters) < 0
  511. #endif
  512.     ) {
  513.     syslog(LOG_ERR, "Can't restore terminal parameters: %m");
  514.     exit(1);
  515.         }
  516.     exit(status);
  517.     }
  518.  
  519. /*
  520.  *    'Clean up' this string.
  521.  */
  522. char *clean(s, sending)
  523. register char *s;
  524. int sending;
  525.     {
  526.     char temp[STR_LEN], cur_chr;
  527.     register char *s1;
  528.     int add_return = sending;
  529. #define isoctal(chr) (((chr) >= '0') && ((chr) <= '7'))
  530.  
  531.     s1 = temp;
  532.     while (*s)
  533.     {
  534.     cur_chr = *s++;
  535.     if (cur_chr == '^')
  536.         {
  537.         cur_chr = *s++;
  538.         if (cur_chr == '\0')
  539.         {
  540.         *s1++ = '^';
  541.         break;
  542.         }
  543.         cur_chr &= 0x1F;
  544.         if (cur_chr != 0)
  545.         *s1++ = cur_chr;
  546.         continue;
  547.         }
  548.  
  549.     if (cur_chr != '\\')
  550.         {
  551.         *s1++ = cur_chr;
  552.         continue;
  553.         }
  554.  
  555.     cur_chr = *s++;
  556.     if (cur_chr == '\0')
  557.         {
  558.         if (sending)
  559.         {
  560.         *s1++ = '\\';
  561.         *s1++ = '\\';
  562.         }
  563.         break;
  564.         }
  565.  
  566.     switch (cur_chr)
  567.         {
  568.     case 'b':
  569.         *s1++ = '\b';
  570.         break;
  571.  
  572.     case 'c':
  573.         if (sending && *s == '\0')
  574.         add_return = 0;
  575.         else
  576.         *s1++ = cur_chr;
  577.         break;
  578.  
  579.     case '\\':
  580.     case 'K':
  581.     case 'p':
  582.     case 'd':
  583.         if (sending)
  584.         *s1++ = '\\';
  585.  
  586.         *s1++ = cur_chr;
  587.         break;
  588.  
  589.     case 'q':
  590.         quiet = ! quiet;
  591.         break;
  592.  
  593.     case 'r':
  594.         *s1++ = '\r';
  595.         break;
  596.  
  597.     case 'n':
  598.         *s1++ = '\n';
  599.         break;
  600.  
  601.     case 's':
  602.         *s1++ = ' ';
  603.         break;
  604.  
  605.     case 't':
  606.         *s1++ = '\t';
  607.         break;
  608.  
  609.     case 'N':
  610.         if (sending)
  611.         {
  612.         *s1++ = '\\';
  613.         *s1++ = '\0';
  614.         }
  615.         else
  616.         *s1++ = 'N';
  617.         break;
  618.         
  619.     default:
  620.         if (isoctal (cur_chr))
  621.         {
  622.         cur_chr &= 0x07;
  623.         if (isoctal (*s))
  624.             {
  625.             cur_chr <<= 3;
  626.             cur_chr |= *s++ - '0';
  627.             if (isoctal (*s))
  628.             {
  629.             cur_chr <<= 3;
  630.             cur_chr |= *s++ - '0';
  631.             }
  632.             }
  633.  
  634.         if (cur_chr != 0 || sending)
  635.             {
  636.             if (sending && (cur_chr == '\\' || cur_chr == 0))
  637.             *s1++ = '\\';
  638.             *s1++ = cur_chr;
  639.             }
  640.         break;
  641.         }
  642.  
  643.         if (sending)
  644.         *s1++ = '\\';
  645.         *s1++ = cur_chr;
  646.         break;
  647.         }
  648.     }
  649.  
  650.     if (add_return)
  651.     *s1++ = '\r';
  652.  
  653.     *s1++ = '\0'; /* guarantee closure */
  654.     *s1++ = '\0'; /* terminate the string */
  655.     return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */
  656.     }
  657.  
  658. /*
  659.  * Process the expect string
  660.  */
  661. void chat_expect(s)
  662. register char *s;
  663.     {
  664.     if (strcmp(s, "ABORT") == 0)
  665.     {
  666.     ++abort_next;
  667.     return;
  668.     }
  669.  
  670.     if (strcmp(s, "TIMEOUT") == 0)
  671.     {
  672.     ++timeout_next;
  673.     return;
  674.     }
  675.  
  676.     while (*s)
  677.     {
  678.     register char *hyphen;
  679.  
  680.     for (hyphen = s; *hyphen; ++hyphen)
  681.         if (*hyphen == '-')
  682.         if (hyphen == s || hyphen[-1] != '\\')
  683.             break;
  684.     
  685.     if (*hyphen == '-')
  686.         {
  687.         *hyphen = '\0';
  688.  
  689.         if (get_string(s))
  690.         return;
  691.         else
  692.         {
  693.         s = hyphen + 1;
  694.  
  695.         for (hyphen = s; *hyphen; ++hyphen)
  696.             if (*hyphen == '-')
  697.             if (hyphen == s || hyphen[-1] != '\\')
  698.                 break;
  699.  
  700.         if (*hyphen == '-')
  701.             {
  702.             *hyphen = '\0';
  703.  
  704.             chat_send(s);
  705.             s = hyphen + 1;
  706.             }
  707.         else
  708.             {
  709.             chat_send(s);
  710.             return;
  711.             }
  712.         }
  713.         }
  714.     else
  715.         if (get_string(s))
  716.         return;
  717.         else
  718.         {
  719.         if (fail_reason)
  720.             syslog(LOG_INFO, "Failed (%s)", fail_reason);
  721.         else
  722.             syslog(LOG_INFO, "Failed");
  723.  
  724.         terminate(1);
  725.         }
  726.     }
  727.     }
  728.  
  729. char *character(c)
  730. int c;
  731.     {
  732.     static char string[10];
  733.     char *meta;
  734.  
  735.     meta = (c & 0x80) ? "M-" : "";
  736.     c &= 0x7F;
  737.  
  738.     if (c < 32)
  739.     sprintf(string, "%s^%c", meta, (int)c + '@');
  740.     else
  741.     if (c == 127)
  742.         sprintf(string, "%s^?", meta);
  743.     else
  744.         sprintf(string, "%s%c", meta, c);
  745.  
  746.     return (string);
  747.     }
  748.  
  749. /*
  750.  *  process the reply string
  751.  */
  752. void chat_send (s)
  753. register char *s;
  754.     {
  755.     if (abort_next)
  756.     {
  757.     char *s1;
  758.  
  759.     abort_next = 0;
  760.  
  761.     if (n_aborts >= MAX_ABORTS)
  762.         fatal("Too many ABORT strings");
  763.  
  764.     s1 = clean(s, 0);
  765.  
  766.     if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1)
  767.         {
  768.         syslog(LOG_WARNING, "Illegal or too-long ABORT string ('%s')", s);
  769.         die();
  770.         }
  771.  
  772.     abort_string[n_aborts++] = s1;
  773.  
  774.     if (verbose)
  775.         {
  776.         logf("abort on (");
  777.  
  778.         for (s1 = s; *s1; ++s1)
  779.         logf(character(*s1));
  780.  
  781.         logf(")\n");
  782.         }
  783.     }
  784.     else
  785.     if (timeout_next)
  786.         {
  787.         timeout_next = 0;
  788.         timeout = atoi(s);
  789.  
  790.         if (timeout <= 0)
  791.         timeout = DEFAULT_CHAT_TIMEOUT;
  792.  
  793.         if (verbose)
  794.         {
  795.         syslog(LOG_INFO, "timeout set to %d seconds", timeout);
  796.         }
  797.         }
  798.     else
  799.         {
  800.         if (strcmp(s, "EOT") == 0)
  801.         s = "^D\\c";
  802.         else
  803.         if (strcmp(s, "BREAK") == 0)
  804.             s = "\\K\\c";
  805.         if ( ! put_string(s))
  806.         {
  807.         syslog(LOG_INFO, "Failed");
  808.         terminate(1);
  809.         }
  810.         }
  811.     }
  812.  
  813. int get_char()
  814.     {
  815.     int status;
  816.     char c;
  817.  
  818.     status = read(0, &c, 1);
  819.  
  820.     switch (status)
  821.     {
  822.     case 1:
  823.         return ((int)c & 0x7F);
  824.  
  825.     default:
  826.         syslog(LOG_WARNING, "warning: read() on stdin returned %d",
  827.            status);
  828.  
  829.     case -1:
  830.         if ((status = fcntl(0, F_GETFL, 0)) == -1)
  831.         sysfatal("Can't get file mode flags on stdin");
  832.         else
  833.         if (fcntl(0, F_SETFL, status & ~FNDELAY) == -1)
  834.             sysfatal("Can't set file mode flags on stdin");
  835.  
  836.         return (-1);
  837.     }
  838.     }
  839.  
  840. int put_char(c)
  841. int c;
  842.     {
  843.     int status;
  844.     char ch = c;
  845.  
  846.     delay();
  847.  
  848.     status = write(1, &ch, 1);
  849.  
  850.     switch (status)
  851.     {
  852.     case 1:
  853.         return (0);
  854.  
  855.     default:
  856.         syslog(LOG_WARNING, "warning: write() on stdout returned %d",
  857.            status);
  858.  
  859.     case -1:
  860.         if ((status = fcntl(0, F_GETFL, 0)) == -1)
  861.         sysfatal("Can't get file mode flags on stdin");
  862.         else
  863.         if (fcntl(0, F_SETFL, status & ~FNDELAY) == -1)
  864.             sysfatal("Can't set file mode flags on stdin");
  865.  
  866.         return (-1);
  867.     }
  868.     }
  869.  
  870. int write_char (c)
  871. int c;
  872.     {
  873.     if (alarmed || put_char(c) < 0)
  874.     {
  875.     extern int errno;
  876.  
  877.     alarm(0); alarmed = 0;
  878.  
  879.     if (verbose)
  880.         {
  881.         if (errno == EINTR || errno == EWOULDBLOCK)
  882.         syslog(LOG_INFO, " -- write timed out");
  883.         else
  884.         syslog(LOG_INFO, " -- write failed: %m");
  885.         }
  886.     return (0);
  887.     }
  888.     return (1);
  889.     }
  890.  
  891. int put_string (s)
  892. register char *s;
  893.     {
  894.     s = clean(s, 1);
  895.  
  896.     if (verbose)
  897.     {
  898.     logf("send (");
  899.  
  900.     if (quiet)
  901.         logf("??????");
  902.     else
  903.         {
  904.         register char *s1 = s;
  905.  
  906.         for (s1 = s; *s1; ++s1)
  907.         logf(character(*s1));
  908.         }
  909.  
  910.     logf(")\n");
  911.     }
  912.  
  913.     alarm(timeout); alarmed = 0;
  914.  
  915.     while (*s)
  916.     {
  917.     register char c = *s++;
  918.  
  919.     if (c != '\\')
  920.         {
  921.         if (!write_char (c))
  922.         return 0;
  923.         continue;
  924.         }
  925.  
  926.     c = *s++;
  927.     switch (c)
  928.         {
  929.     case 'd':
  930.         sleep(1);
  931.         break;
  932.  
  933.     case 'K':
  934.         break_sequence();
  935.         break;
  936.  
  937.     case 'p':
  938.         usleep(10000); /* 1/100th of a second. */
  939.         break;
  940.  
  941.     default:
  942.         if (!write_char (c))
  943.         return 0;
  944.         break;
  945.         }
  946.     }
  947.  
  948.     alarm(0);
  949.     alarmed = 0;
  950.     return (1);
  951.     }
  952.  
  953. /*
  954.  *    'Wait for' this string to appear on this file descriptor.
  955.  */
  956. int get_string(string)
  957. register char *string;
  958.     {
  959.     char temp[STR_LEN];
  960.     int c, printed = 0, len, minlen;
  961.     register char *s = temp, *end = s + STR_LEN;
  962.  
  963.     fail_reason = (char *)0;
  964.     string = clean(string, 0);
  965.     len = strlen(string);
  966.     minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1;
  967.  
  968.     if (verbose)
  969.     {
  970.     register char *s1;
  971.  
  972.     logf("expect (");
  973.  
  974.     for (s1 = string; *s1; ++s1)
  975.         logf(character(*s1));
  976.  
  977.     logf(")\n");
  978.     }
  979.  
  980.     if (len > STR_LEN)
  981.     {
  982.     syslog(LOG_INFO, "expect string is too long");
  983.     return 0;
  984.     }
  985.  
  986.     if (len == 0)
  987.     {
  988.     if (verbose)
  989.         {
  990.         syslog(LOG_INFO, "got it");
  991.         }
  992.  
  993.     return (1);
  994.     }
  995.  
  996.     alarm(timeout); alarmed = 0;
  997.  
  998.     while ( ! alarmed && (c = get_char()) >= 0)
  999.     {
  1000.     int n, abort_len;
  1001.  
  1002.     if (verbose)
  1003.         {
  1004.         if (c == '\n')
  1005.         logf("\n");
  1006.         else
  1007.         logf(character(c));
  1008.         }
  1009.  
  1010.     *s++ = c;
  1011.  
  1012.     if (s - temp >= len &&
  1013.         c == string[len - 1] &&
  1014.         strncmp(s - len, string, len) == 0)
  1015.         {
  1016.         if (verbose)
  1017.         {
  1018.         logf(" -- got it\n");
  1019.         }
  1020.  
  1021.         alarm(0); alarmed = 0;
  1022.         return (1);
  1023.         }
  1024.  
  1025.     for (n = 0; n < n_aborts; ++n)
  1026.         if (s - temp >= (abort_len = strlen(abort_string[n])) &&
  1027.         strncmp(s - abort_len, abort_string[n], abort_len) == 0)
  1028.         {
  1029.         if (verbose)
  1030.             {
  1031.             logf(" -- failed\n");
  1032.             }
  1033.  
  1034.         alarm(0); alarmed = 0;
  1035.         strcpy(fail_reason = fail_buffer, abort_string[n]);
  1036.         return (0);
  1037.         }
  1038.  
  1039.     if (s >= end)
  1040.         {
  1041.         strncpy(temp, s - minlen, minlen);
  1042.         s = temp + minlen;
  1043.         }
  1044.  
  1045.     if (alarmed && verbose)
  1046.         syslog(LOG_WARNING, "warning: alarm synchronization problem");
  1047.     }
  1048.  
  1049.     alarm(0);
  1050.     
  1051.     if (verbose && printed)
  1052.     {
  1053.     if (alarmed)
  1054.         logf(" -- read timed out\n");
  1055.     else
  1056.         {
  1057.         logflush();
  1058.         syslog(LOG_INFO, " -- read failed: %m");
  1059.         }
  1060.     }
  1061.  
  1062.     alarmed = 0;
  1063.     return (0);
  1064.     }
  1065.  
  1066. #ifdef ultrix
  1067. #undef NO_USLEEP
  1068. #include <sys/types.h>
  1069. #include <sys/time.h>
  1070.  
  1071. /*
  1072.   usleep -- support routine for 4.2BSD system call emulations
  1073.   last edit:  29-Oct-1984     D A Gwyn
  1074.   */
  1075.  
  1076. extern int      select();
  1077.  
  1078. int
  1079. usleep( usec )                  /* returns 0 if ok, else -1 */
  1080.     long        usec;        /* delay in microseconds */
  1081. {
  1082.     static struct            /* `timeval' */
  1083.     {
  1084.         long    tv_sec;        /* seconds */
  1085.         long    tv_usec;    /* microsecs */
  1086.     }   delay;        /* _select() timeout */
  1087.  
  1088.     delay.tv_sec = usec / 1000000L;
  1089.     delay.tv_usec = usec % 1000000L;
  1090.  
  1091.     return select( 0, (long *)0, (long *)0, (long *)0, &delay );
  1092. }
  1093. #endif
  1094.  
  1095. /*
  1096.  *    Delay an amount appropriate for between typed characters.
  1097.  */
  1098. void delay()
  1099.     {
  1100. # ifdef NO_USLEEP
  1101.     register int i;
  1102.  
  1103.     for (i = 0; i < 30000; ++i)        /* ... did we just say appropriate? */
  1104.     ;
  1105. # else /* NO_USLEEP */
  1106.     usleep(100);
  1107. # endif /* NO_USLEEP */
  1108.     }
  1109.