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