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