home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 4 / DATAFILE_PDCD4.iso / utilities / utilsf / gsm / GSM / chat_c < prev    next >
Encoding:
Text File  |  1995-05-31  |  14.2 KB  |  840 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.  *        Karl Fox <karl@MorningStar.Com>
  10.  *        Morning Star Technologies, Inc.
  11.  *        1760 Zollinger Road
  12.  *        Columbus, OH  43221
  13.  *        (614)451-1883
  14.  */
  15.  
  16. #if defined(TOOL_SCCS) && ! defined(lint)
  17. static char sccs_id[] = "@(#)chat.c    1.7";
  18. #endif
  19. #if defined(TOOL_RCS) && ! defined(lint)
  20. static char *RcsId = "$Header$";
  21. #endif
  22.  
  23. # include    <stdio.h>
  24. # ifdef __arm
  25. #  include    <termios.h>
  26. # else
  27. #  include    <termio.h>
  28. # endif
  29. # include    <fcntl.h>
  30. # include    <signal.h>
  31. # include    <errno.h>
  32. # include    <sys/types.h>
  33. # include    <sys/stat.h>
  34.  
  35. # ifdef sun
  36. # include    <pixrect/pr_impl_util.h>
  37. # if defined(SUNOS) && SUNOS >= 41
  38. # ifndef HDB
  39. # define    HDB
  40. # endif
  41. # endif
  42. # endif
  43.  
  44. # define    STR_LEN        1024
  45.  
  46. #if defined(sun) | defined(SYSV) | defined(POSIX_SOURCE)
  47. #define SIGTYPE void
  48. #else 
  49. #define SIGTYPE int
  50. #endif
  51.  
  52. /*************** Micro getopt() *********************************************/
  53. # define    OPTION(c,v)    (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \
  54.                 (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\
  55.                 &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0))
  56. # define    OPTARG(c,v)    (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \
  57.                 (_O=4,(char*)0):(char*)0)
  58. # define    OPTONLYARG(c,v)    (_O&2&&**v?(_O=1,--c,*v++):(char*)0)
  59. # define    ARG(c,v)    (c?(--c,*v++):(char*)0)
  60.  
  61. static int _O = 0;        /* Internal state */
  62. /*************** Micro getopt() *********************************************/
  63.  
  64. char *program_name;
  65.  
  66. extern char *strcpy(), *strcat(), *malloc();
  67. extern int strlen();
  68. # define    copyof(s)    ((s) ? strcpy(malloc(strlen(s) + 1), s) : (s))
  69.  
  70. # ifndef LOCK_DIR
  71. #  ifdef HDB
  72. #   define    LOCK_DIR    "/usr/spool/locks"
  73. #  else /* HDB */
  74. #   ifdef __arm
  75. #     define    LOCK_DIR    "/var/spool/uucp"
  76. #   else
  77. #     define    LOCK_DIR    "/usr/spool/uucp"
  78. #   endif
  79. #  endif /* HDB */
  80. # endif /* LOCK_DIR */
  81.  
  82. # define    MAX_ABORTS    50
  83. # define    DEFAULT_CHAT_TIMEOUT    30
  84.  
  85. int verbose = 0;
  86. int quiet = 0;
  87. char *lock_file = (char *)0;
  88. int timeout = DEFAULT_CHAT_TIMEOUT;
  89.  
  90. int have_tty_parameters = 0;
  91. #ifdef __arm
  92. struct termios saved_tty_parameters;
  93. #else
  94. struct termio saved_tty_parameters;
  95. #endif
  96.  
  97. char *abort_string[MAX_ABORTS], *fail_reason = (char *)0,
  98.     fail_buffer[50];
  99. int n_aborts = 0, abort_next = 0, timeout_next = 0;
  100.  
  101. /*
  102.  *    chat [ -v ] [ -t timeout ] [ -l lock-file ] \
  103.  *        [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]]
  104.  *
  105.  *    Perform a UUCP-dialer-like chat script on stdin and stdout.
  106.  */
  107. main(argc, argv)
  108. int argc;
  109. char **argv;
  110.     {
  111.     int option;
  112.     char *arg;
  113.  
  114.     program_name = *argv;
  115.  
  116.     while (option = OPTION(argc, argv))
  117.     switch (option)
  118.         {
  119.         case 'v':
  120.         ++verbose;
  121.         break;
  122.  
  123.         case 'l':
  124.         if (arg = OPTARG(argc, argv))
  125.             lock_file = copyof(arg);
  126.         else
  127.             usage();
  128.  
  129.         break;
  130.  
  131.         case 't':
  132.         if (arg = OPTARG(argc, argv))
  133.             timeout = atoi(arg);
  134.         else
  135.             usage();
  136.  
  137.         break;
  138.  
  139.         default:
  140.         usage();
  141.         }
  142.  
  143.     init();
  144.     
  145.     while (arg = ARG(argc, argv))
  146.     {
  147.     expect(arg);
  148.  
  149.     if (arg = ARG(argc, argv))
  150.         send(arg);
  151.     }
  152.  
  153.     terminate(0);
  154.     }
  155.  
  156. /*
  157.  *    We got an error parsing the command line.
  158.  */
  159. usage()
  160.     {
  161.     fprintf(stderr,
  162.         "Usage: %s [ -v ] [ -l lock-file ] [ -t timeout ] chat-script\n",
  163.         program_name);
  164.     exit(1);
  165.     }
  166.  
  167. /*
  168.  *    Print a warning message.
  169.  */
  170. /*VARARGS1*/
  171. warn(format, arg1, arg2, arg3, arg4)
  172. char *format;
  173. int arg1, arg2, arg3, arg4;
  174.     {
  175.     fprintf(stderr, "%s: Warning: ", program_name);
  176.     fprintf(stderr, format, arg1, arg2, arg3, arg4);
  177.     fprintf(stderr, "\n");
  178.     }
  179.  
  180. /*
  181.  *    Print an error message and terminate.
  182.  */
  183. /*VARARGS1*/
  184. fatal(format, arg1, arg2, arg3, arg4)
  185. char *format;
  186. int arg1, arg2, arg3, arg4;
  187.     {
  188.     fprintf(stderr, "%s: ", program_name);
  189.     fprintf(stderr, format, arg1, arg2, arg3, arg4);
  190.     fprintf(stderr, "\n");
  191.     unlock();
  192.     terminate(1);
  193.     }
  194.  
  195. /*
  196.  *    Print an error message along with the system error message and
  197.  *    terminate.
  198.  */
  199. /*VARARGS1*/
  200. sysfatal(format, arg1, arg2, arg3, arg4)
  201. char *format;
  202. int arg1, arg2, arg3, arg4;
  203.     {
  204.     char message[STR_LEN];
  205.  
  206.     sprintf(message, "%s: ", program_name);
  207.     sprintf(message + strlen(message), format, arg1, arg2, arg3, arg4);
  208.     perror(message);
  209.     unlock();
  210.     terminate(1);
  211.     }
  212.  
  213. int alarmed = 0;
  214.  
  215. SIGTYPE
  216.   sigalrm()
  217. {
  218.     int flags;
  219.  
  220.     alarm(1); alarmed = 1;        /* Reset alarm to avoid race window */
  221.     signal(SIGALRM, sigalrm);        /* that can cause hanging in read() */
  222.  
  223.     if ((flags = fcntl(0, F_GETFL, 0)) == -1)
  224.     sysfatal("Can't get file mode flags on stdin");
  225.     else
  226.     if (fcntl(0, F_SETFL, flags | FNDELAY) == -1)
  227.         sysfatal("Can't set file mode flags on stdin");
  228.  
  229.     if (verbose)
  230.     {
  231.     fprintf(stderr, "alarm\n");
  232.     fflush(stderr);
  233.     }
  234.     }
  235.  
  236. unalarm()
  237.     {
  238.     int flags;
  239.  
  240.     if ((flags = fcntl(0, F_GETFL, 0)) == -1)
  241.     sysfatal("Can't get file mode flags on stdin");
  242.     else
  243.     if (fcntl(0, F_SETFL, flags & ~FNDELAY) == -1)
  244.         sysfatal("Can't set file mode flags on stdin");
  245.     }
  246.  
  247. SIGTYPE
  248.   sigint()
  249. {
  250.   fatal("SIGINT");
  251. }
  252.  
  253. SIGTYPE
  254.   sigterm()
  255. {
  256.   fatal("SIGTERM");
  257. }
  258.  
  259. SIGTYPE
  260.   sighup()
  261. {
  262.   fatal("SIGHUP");
  263. }
  264.  
  265. init()
  266.     {
  267.     signal(SIGINT, sigint);
  268.     signal(SIGTERM, sigterm);
  269.     signal(SIGHUP, sighup);
  270.  
  271.     if (lock_file)
  272.     lock();
  273.  
  274.     set_tty_parameters();
  275.     signal(SIGALRM, sigalrm);
  276.     alarm(0); alarmed = 0;
  277.     }
  278.  
  279. set_tty_parameters()
  280.     {
  281. #ifdef __arm
  282.     struct termios t;
  283.  
  284.     if (tcgetattr(0, &t) < 0)
  285.     sysfatal("Can't get terminal parameters");
  286. #else
  287.     struct termio t;
  288.  
  289.     if (ioctl(0, TCGETA, &t) < 0)
  290.     sysfatal("Can't get terminal parameters");
  291. #endif
  292.  
  293.     saved_tty_parameters = t;
  294.     have_tty_parameters = 1;
  295.  
  296. #if 1
  297.     t.c_cflag = CREAD | CS8 | HUPCL | CLOCAL;
  298. #else
  299.     t.c_cflag = CREAD | CS8 | HUPCL | CLOCAL | CSTOPB;
  300. #endif
  301.     t.c_iflag = IGNBRK | IXOFF | IXON | ISTRIP | IGNPAR;
  302.     t.c_lflag = 0;
  303.     t.c_cc[VERASE] = t.c_cc[VKILL] = 0;
  304.     t.c_cc[VMIN] = 1;
  305.     t.c_cc[VTIME] = 0;
  306.  
  307. #ifdef __arm
  308.     if (tcsetattr(0, TCSADRAIN, &t) < 0)
  309.     sysfatal("Can't set terminal parameters");
  310. #else
  311.     if (ioctl(0, TCSETA, &t) < 0)
  312.     sysfatal("Can't set terminal parameters");
  313. #endif
  314.     }
  315.  
  316. terminate(status)
  317. {
  318. #ifdef __arm
  319.   if (have_tty_parameters &&
  320.       tcsetattr(0, TCSADRAIN, &saved_tty_parameters) < 0) {
  321.     perror("Can't restore terminal parameters");
  322.     unlock();
  323.     exit(1);
  324.   }
  325. #else
  326.   if (have_tty_parameters && ioctl(0, TCSETA, &saved_tty_parameters) < 0) {
  327.     perror("Can't restore terminal parameters");
  328.     unlock();
  329.     exit(1);
  330.   }
  331. #endif
  332.   exit(status);
  333. }
  334.  
  335. /*
  336.  *    Create a lock file for the named lock device
  337.  */
  338. lock()
  339.     {
  340.     int fd, pid;
  341.  
  342.     lock_file = strcat(strcat(strcpy(malloc(strlen(LOCK_DIR)
  343.                        + 1 + strlen(lock_file) + 1),
  344.                 LOCK_DIR), "/"), lock_file);
  345.  
  346.     if ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0)
  347.     {
  348.     char *s = lock_file;
  349.  
  350.     lock_file = (char *)0;    /* Don't remove someone else's lock file! */
  351.     sysfatal("Can't get lock file '%s'", s);
  352.     }
  353.  
  354. # ifdef HDB
  355.     sprintf(hdb_lock_buffer, "%10d\n", getpid());
  356.     write(fd, hdb_lock_buffer, 11);
  357. # else /* HDB */
  358.     pid = getpid();
  359.     write(fd, &pid, sizeof pid);
  360. # endif /* HDB */
  361.  
  362.     close(fd);
  363.     }
  364.  
  365. /*
  366.  *    Remove our lockfile
  367.  */
  368. unlock()
  369.     {
  370.     if (lock_file)
  371.     {
  372.     unlink(lock_file);
  373.     lock_file = (char *)0;
  374.     }
  375.     }
  376.  
  377. /*
  378.  *    'Clean up' this string.
  379.  */
  380. char *clean(s, sending)
  381. register char *s;
  382. int sending;
  383.     {
  384.     char temp[STR_LEN];
  385.     register char *s1;
  386.     int add_return = sending;
  387.  
  388.     for (s1 = temp; *s; ++s)
  389.      switch (*s)
  390.          {
  391.          case '\\':
  392.          switch (*++s)
  393.              {
  394.              case '\\':
  395.              case 'd':    if (sending)
  396.                     *s1++ = '\\';
  397.  
  398.                 *s1++ = *s;
  399.                 break;
  400.  
  401.              case 'q':    quiet = ! quiet; break;
  402.              case 'r':    *s1++ = '\r'; break;
  403.              case 'n':    *s1++ = '\n'; break;
  404.              case 's':    *s1++ = ' '; break;
  405.  
  406.              case 'c':    if (sending && s[1] == '\0')
  407.                     add_return = 0;
  408.                 else
  409.                     *s1++ = *s;
  410.  
  411.                 break;
  412.  
  413.              default:    *s1++ = *s;
  414.              }
  415.  
  416.          break;
  417.  
  418.          case '^':
  419.          *s1++ = (int)(*++s) & 0x1F;
  420.          break;
  421.  
  422.          default:
  423.          *s1++ = *s;
  424.          }
  425.     
  426.     if (add_return)
  427.     *s1++ = '\r';
  428.  
  429.     *s1 = '\0';
  430.     return (copyof(temp));
  431.     }
  432.  
  433. /*
  434.  *
  435.  */
  436. expect(s)
  437. register char *s;
  438.     {
  439.     if (strcmp(s, "ABORT") == 0)
  440.     {
  441.     ++abort_next;
  442.     return;
  443.     }
  444.  
  445.     if (strcmp(s, "TIMEOUT") == 0)
  446.     {
  447.     ++timeout_next;
  448.     return;
  449.     }
  450.  
  451.     while (*s)
  452.     {
  453.     register char *hyphen;
  454.  
  455.     for (hyphen = s; *hyphen; ++hyphen)
  456.         if (*hyphen == '-')
  457.         if (hyphen == s || hyphen[-1] != '\\')
  458.             break;
  459.     
  460.     if (*hyphen == '-')
  461.         {
  462.         *hyphen = '\0';
  463.  
  464.         if (get_string(s))
  465.         return;
  466.         else
  467.         {
  468.         s = hyphen + 1;
  469.  
  470.         for (hyphen = s; *hyphen; ++hyphen)
  471.             if (*hyphen == '-')
  472.             if (hyphen == s || hyphen[-1] != '\\')
  473.                 break;
  474.  
  475.         if (*hyphen == '-')
  476.             {
  477.             *hyphen = '\0';
  478.  
  479.             send(s);
  480.             s = hyphen + 1;
  481.             }
  482.         else
  483.             {
  484.             send(s);
  485.             return;
  486.             }
  487.         }
  488.         }
  489.     else
  490.         if (get_string(s))
  491.         return;
  492.         else
  493.         {
  494.         if (fail_reason)
  495.             fprintf(stderr, "Failed(%s)\n", fail_reason);
  496.         else
  497.             fprintf(stderr, "Failed\n");
  498.  
  499.         fflush(stderr);
  500.         unlock();
  501.         terminate(1);
  502.         }
  503.     }
  504.     }
  505.  
  506. char *character(c)
  507. char c;
  508.     {
  509.     static char string[10];
  510.     char *meta;
  511.  
  512.     meta = (c & 0x80) ? "M-" : "";
  513.     c &= 0x7F;
  514.  
  515.     if (c < 32)
  516.     sprintf(string, "%s^%c", meta, (int)c + '@');
  517.     else
  518.     if (c == 127)
  519.         sprintf(string, "%s^?", meta);
  520.     else
  521.         sprintf(string, "%s%c", meta, c);
  522.  
  523.     return (string);
  524.     }
  525.  
  526. /*
  527.  *
  528.  */
  529. send(s)
  530. register char *s;
  531.     {
  532.     if (abort_next)
  533.     {
  534.     char *s1;
  535.  
  536.     abort_next = 0;
  537.  
  538.     if (n_aborts >= MAX_ABORTS)
  539.         fatal("Too many ABORT strings");
  540.  
  541.     s1 = clean(s, 0);
  542.  
  543.     if (strlen(s1) > strlen(s))
  544.         fatal("Illegal ABORT string ('%s')\n", s);
  545.  
  546.     if (strlen(s1) > sizeof fail_buffer - 1)
  547.         fatal("Too long ABORT string ('%s')\n", s);
  548.  
  549.     strcpy(s, s1);
  550.     abort_string[n_aborts++] = s;
  551.  
  552.     if (verbose)
  553.         {
  554.         register char *s1 = s;
  555.  
  556.         fprintf(stderr, "abort on (");
  557.  
  558.         for (s1 = s; *s1; ++s1)
  559.         fprintf(stderr, "%s", character(*s1));
  560.  
  561.         fprintf(stderr, ")\n");
  562.         fflush(stderr);
  563.         }
  564.     }
  565.     else
  566.     if (timeout_next)
  567.         {
  568.         timeout_next = 0;
  569.         timeout = atoi(s);
  570.  
  571.         if (timeout <= 0)
  572.         timeout = DEFAULT_CHAT_TIMEOUT;
  573.  
  574.         if (verbose)
  575.         {
  576.         fprintf(stderr, "timeout set to %d seconds\n", timeout);
  577.         fflush(stderr);
  578.         }
  579.         }
  580.     else
  581.         if ( ! put_string(s))
  582.         {
  583.         fprintf(stderr, "Failed\n");
  584.         fflush(stderr);
  585.         unlock();
  586.         terminate(1);
  587.         }
  588.     }
  589.  
  590. int get_char()
  591.     {
  592.     int status;
  593.     char c;
  594.  
  595.     status = read(0, &c, 1);
  596.  
  597.     switch (status)
  598.     {
  599.     case 1:
  600.         return ((int)c & 0x7F);
  601.  
  602.     default:
  603.         warn("read() on stdin returned %d", status);
  604.  
  605.     case -1:
  606.         if ((status = fcntl(0, F_GETFL, 0)) == -1)
  607.         sysfatal("Can't get file mode flags on stdin");
  608.         else
  609.         if (fcntl(0, F_SETFL, status & ~FNDELAY) == -1)
  610.             sysfatal("Can't set file mode flags on stdin");
  611.  
  612.         return (-1);
  613.     }
  614.     }
  615.  
  616. int put_char(c)
  617. char c;
  618.     {
  619.     int status;
  620.  
  621.     delay();
  622.  
  623.     status = write(1, &c, 1);
  624.  
  625.     switch (status)
  626.     {
  627.     case 1:
  628.         return (0);
  629.  
  630.     default:
  631.         warn("write() on stdout returned %d", status);
  632.  
  633.     case -1:
  634.         if ((status = fcntl(0, F_GETFL, 0)) == -1)
  635.         sysfatal("Can't get file mode flags on stdin");
  636.         else
  637.         if (fcntl(0, F_SETFL, status & ~FNDELAY) == -1)
  638.             sysfatal("Can't set file mode flags on stdin");
  639.  
  640.         return (-1);
  641.     }
  642.     }
  643.  
  644. int put_string(s)
  645. register char *s;
  646.     {
  647.     s = clean(s, 1);
  648.  
  649.     if (verbose)
  650.     {
  651.     fprintf(stderr, "send (");
  652.  
  653.     if (quiet)
  654.         fprintf(stderr, "??????");
  655.     else
  656.         {
  657.         register char *s1 = s;
  658.  
  659.         for (s1 = s; *s1; ++s1)
  660.         fprintf(stderr, "%s", character(*s1));
  661.         }
  662.  
  663.     fprintf(stderr, ")\n");
  664.     fflush(stderr);
  665.     }
  666.  
  667.     alarm(timeout); alarmed = 0;
  668.  
  669.     for ( ; *s; ++s)
  670.     {
  671.     register char c = *s;
  672.  
  673.     if (c == '\\')
  674.     {
  675.         if ((c = *++s) == '\0')
  676.         break;
  677.         else
  678.         if (c == 'd')        /* \d -- Delay */
  679.             {
  680.             sleep(2);
  681.             continue;
  682.             }
  683.     }
  684.  
  685.     if (alarmed || put_char(*s) < 0)
  686.         {
  687.         extern int errno;
  688.  
  689.         alarm(0); alarmed = 0;
  690.  
  691.         if (verbose)
  692.         {
  693.         if (errno == EINTR || errno == EWOULDBLOCK)
  694.             fprintf(stderr, " -- write timed out\n");
  695.         else
  696.             perror(" -- write failed");
  697.  
  698.         fflush(stderr);
  699.         }
  700.  
  701.         return (0);
  702.         }
  703.     }
  704.  
  705.     alarm(0); alarmed = 0;
  706.     return (1);
  707.     }
  708.  
  709. /*
  710.  *    'Wait for' this string to appear on this file descriptor.
  711.  */
  712. int get_string(string)
  713. register char *string;
  714.     {
  715.     char temp[STR_LEN];
  716.     int c, printed = 0, len;
  717.     register char *s = temp, *end = s + STR_LEN;
  718.  
  719.     fail_reason = (char *)0;
  720.     string = clean(string, 0);
  721.     len = strlen(string);
  722.  
  723.     if (verbose)
  724.     {
  725.     register char *s1;
  726.  
  727.     fprintf(stderr, "expect (");
  728.  
  729.     for (s1 = string; *s1; ++s1)
  730.         fprintf(stderr, "%s", character(*s1));
  731.  
  732.     fprintf(stderr, ")\n");
  733.     fflush(stderr);
  734.     }
  735.  
  736.     if (len == 0)
  737.     {
  738.     if (verbose)
  739.         {
  740.         fprintf(stderr, "got it\n");
  741.         fflush(stderr);
  742.         }
  743.  
  744.     return (1);
  745.     }
  746.  
  747.     alarm(timeout); alarmed = 0;
  748.  
  749.     while ( ! alarmed && (c = get_char()) >= 0)
  750.     {
  751.     int n, abort_len;
  752.  
  753.     if (verbose)
  754.         {
  755.         if (c == '\n')
  756.         fprintf(stderr, "\n");
  757.         else
  758.         fprintf(stderr, "%s", character(c));
  759.  
  760.         fflush(stderr);
  761.         }
  762.  
  763.     *s++ = c;
  764.  
  765.     if (s >= end)
  766.         {
  767.         if (verbose)
  768.         {
  769.         fprintf(stderr, " -- too much data\n");
  770.         fflush(stderr);
  771.         }
  772.  
  773.         alarm(0); alarmed = 0;
  774.         return (0);
  775.         }
  776.  
  777.     if (s - temp >= len &&
  778.         c == string[len - 1] &&
  779.         strncmp(s - len, string, len) == 0)
  780.         {
  781.         if (verbose)
  782.         {
  783.         fprintf(stderr, "got it\n");
  784.         fflush(stderr);
  785.         }
  786.  
  787.         alarm(0); alarmed = 0;
  788.         return (1);
  789.         }
  790.  
  791.     for (n = 0; n < n_aborts; ++n)
  792.         if (s - temp >= (abort_len = strlen(abort_string[n])) &&
  793.         strncmp(s - abort_len, abort_string[n], abort_len) == 0)
  794.         {
  795.         if (verbose)
  796.             {
  797.             fprintf(stderr, " -- failed\n");
  798.             fflush(stderr);
  799.             }
  800.  
  801.         alarm(0); alarmed = 0;
  802.         strcpy(fail_reason = fail_buffer, abort_string[n]);
  803.         return (0);
  804.         }
  805.  
  806.     if (alarmed && verbose)
  807.         warn("Alarm synchronization problem");
  808.     }
  809.  
  810.     alarm(0);
  811.     
  812.     if (verbose && printed)
  813.     {
  814.     if (alarmed)
  815.         fprintf(stderr, " -- read timed out\n");
  816.     else
  817.         perror(" -- read failed");
  818.  
  819.     fflush(stderr);
  820.     }
  821.  
  822.     alarmed = 0;
  823.     return (0);
  824.     }
  825.  
  826. /*
  827.  *    Delay an amount appropriate for between typed characters.
  828.  */
  829. delay()
  830.     {
  831. # ifdef NO_USLEEP
  832.     register int i;
  833.  
  834.     for (i = 0; i < 30000; ++i)        /* ... did we just say appropriate? */
  835.     ;
  836. # else /* NO_USLEEP */
  837.     usleep(100);
  838. # endif /* NO_USLEEP */
  839.     }
  840.