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