1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23/*	  All Rights Reserved	*/
24
25/*
26 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
27 * Use is subject to license terms.
28 */
29
30#include "mt.h"
31#include "uucp.h"
32static char _ProtoSys[40];	/* protocol string from Systems file entry */
33static char _ProtoDev[40];	/* protocol string from Devices file entry */
34static char _ProtoCfg[];	/* protocol string from Config  file entry */
35
36static jmp_buf Sjbuf;
37static unsigned expecttime;
38
39static int	Modemctrl;
40
41static void alarmtr(int);
42static void getProto(char *, char *);
43static int finds(char *, char *[], int);
44static int getto(char *[]);	/* make this static when ct uses altconn() */
45static int chat(int, char *[], int, char *, char *);
46static int rddev(char *, char *[], char *, int);
47static int expect(char *, int);
48static int wrstr(int, char *, int, int);
49static int wrchr(int, char *, int);
50static int processdev(char *[], char *[]);
51static int getdevline(char *, int);
52static int getsysline(char *, int);
53static int sysaccess(int);
54static int clear_hup(int);
55#ifndef SMALL
56static char *currsys(void);
57static char *currdev(void);
58#endif
59static int wait_for_hangup(int);
60static int expect_str(char *, int);
61
62static void sendthem(char *, int, char *, char *);
63static void nap(unsigned int);
64static int notin(char *, char *);
65static int ifdate(char *);
66static int classmatch(char *[], char *[]);
67
68static char *Myline = CNULL;	/* to force which line will be used */
69static char *Mytype = CNULL;	/* to force selection of specific device type */
70
71/*
72 * conn - place a telephone call to system and login, etc.
73 *
74 * return codes:
75 *	FAIL - connection failed
76 *	>0  - file no.  -  connect ok
77 * When a failure occurs, Uerror is set.
78 */
79
80static void sysreset(void);
81static int
82conn(char *system)
83{
84	int nf, fn = FAIL;
85	char *flds[F_MAX+1];
86
87	CDEBUG(4, "conn(%s)\n", system);
88	Uerror = 0;
89	while ((nf = finds(system, flds, F_MAX)) > 0) {
90		fn = getto(flds);
91		CDEBUG(4, "getto ret %d\n", fn);
92		if (fn < 0)
93			continue;
94		if (EQUALS(Progname, "uucico")) {
95			if (chat(nf - F_LOGIN, flds + F_LOGIN, fn, "", "") ==
96			    SUCCESS) {
97				sysreset();
98				return (fn); /* successful return */
99			}
100
101			/* login failed */
102			DEBUG(6, "close caller (%d)\n", fn);
103			fd_rmlock(fn);
104			(void) close(fn);
105			if (Dc[0] != NULLCHAR) {
106				/*EMPTY*/
107				DEBUG(6, "delock line (%s)\n", Dc);
108			}
109		} else {
110			sysreset();
111			return (fn);
112		}
113	}
114
115	/* finds or getto failed */
116	sysreset();
117	CDEBUG(1, "Call Failed: %s\n", UERRORTEXT);
118	return (FAIL);
119}
120
121static void devreset(void);
122
123/*
124 * getto - connect to remote machine
125 *
126 * return codes:
127 *	>0  -  file number - ok
128 *	FAIL  -  failed
129 */
130
131static int
132getto(char *flds[])
133{
134	char *dev[D_MAX+2], devbuf[BUFSIZ];
135	int status;
136	int dcf = -1;
137	int reread = 0;
138	int tries = 0;	/* count of call attempts - for limit purposes */
139
140	CDEBUG(1, "Device Type %s wanted\n", flds[F_TYPE]);
141	Uerror = 0;
142	while (tries < TRYCALLS) {
143		if ((status = rddev(flds[F_TYPE], dev, devbuf, D_MAX)) ==
144		    FAIL) {
145			if (tries == 0 || ++reread >= TRYCALLS)
146				break;
147			devreset();
148			continue;
149		}
150		/* check class, check (and possibly set) speed */
151		if (classmatch(flds, dev) != SUCCESS) {
152			DEBUG(7, "Skipping entry in '%s'", currdev());
153			DEBUG(7, " - class (%s) not wanted.\n", dev[D_CLASS]);
154			continue;
155		}
156		DEBUG(5, "Trying device entry from '%s'.\n", currdev());
157		if ((dcf = processdev(flds, dev)) >= 0)
158			break;
159
160		switch (Uerror) {
161		case SS_CANT_ACCESS_DEVICE:
162		case SS_DEVICE_FAILED:
163		case SS_LOCKED_DEVICE:
164			break;
165		default:
166			tries++;
167			break;
168		}
169	}
170	devreset();	/* reset devices file(s) */
171	if (status == FAIL && !Uerror) {
172		CDEBUG(1, "Requested Device Type Not Found\n%s", "");
173		Uerror = SS_NO_DEVICE;
174	}
175	return (dcf);
176}
177
178/*
179 * classmatch - process 'Any' in Devices and Systems and
180 *	determine the correct speed, or match for ==
181 */
182
183static int
184classmatch(char *flds[], char *dev[])
185{
186	/* check class, check (and possibly set) speed */
187	if (EQUALS(flds[F_CLASS], "Any") && EQUALS(dev[D_CLASS], "Any")) {
188		dev[D_CLASS] = DEFAULT_BAUDRATE;
189		return (SUCCESS);
190	} else if (EQUALS(dev[D_CLASS], "Any")) {
191		dev[D_CLASS] = flds[F_CLASS];
192		return (SUCCESS);
193	} else if (EQUALS(flds[F_CLASS], "Any") ||
194	    EQUALS(flds[F_CLASS], dev[D_CLASS]))
195		return (SUCCESS);
196	else
197		return (FAIL);
198}
199
200
201/*
202 *	rddev - find and unpack a line from device file for this caller type
203 *	lines starting with whitespace of '#' are comments
204 *
205 *	return codes:
206 *		>0  -  number of arguments in vector - succeeded
207 *		FAIL - EOF
208 */
209
210static int
211rddev(char *type, char *dev[], char *buf, int devcount)
212{
213	char *commap, d_type[BUFSIZ];
214	int na;
215
216	while (getdevline(buf, BUFSIZ)) {
217		if (buf[0] == ' ' || buf[0] == '\t' || buf[0] == '\n' ||
218		    buf[0] == '\0' || buf[0] == '#')
219			continue;
220		na = getargs(buf, dev, devcount);
221		ASSERT(na >= D_CALLER, "BAD LINE", buf, na);
222
223		if (strncmp(dev[D_LINE], "/dev/", 5) == 0) {
224			/* since cu (altconn()) strips off leading */
225			/* "/dev/",  do the same here.  */
226			(void) strcpy(dev[D_LINE], &(dev[D_LINE][5]));
227		}
228
229		/* may have ",M" subfield in D_LINE */
230		Modemctrl = FALSE;
231		if ((commap = strchr(dev[D_LINE], ',')) != NULL) {
232			if (strcmp(commap, ",M") == SAME)
233				Modemctrl = TRUE;
234			*commap = '\0';
235		}
236
237		/*
238		 * D_TYPE field may have protocol subfield, which
239		 * must be pulled off before comparing to desired type.
240		 */
241		(void) strcpy(d_type, dev[D_TYPE]);
242		if ((commap = strchr(d_type, ',')) != NULL)
243			*commap = '\0';
244
245		/* to force the requested device type to be used. */
246		if ((Mytype != NULL) && (!EQUALS(Mytype, d_type)))
247			continue;
248		/* to force the requested line to be used */
249		if ((Myline != NULL) && (!EQUALS(Myline, dev[D_LINE])))
250			continue;
251
252		bsfix(dev);	/* replace \X fields */
253
254		if (EQUALS(d_type, type)) {
255			getProto(_ProtoDev, dev[D_TYPE]);
256			return (na);
257		}
258	}
259	return (FAIL);
260}
261
262
263/*
264 * finds	- set system attribute vector
265 *
266 * input:
267 *	fsys - open Systems file descriptor
268 *	sysnam - system name to find
269 * output:
270 *	flds - attibute vector from Systems file
271 *	fldcount - number of fields in flds
272 * return codes:
273 *	>0  -  number of arguments in vector - succeeded
274 *	FAIL - failed
275 * Uerror set:
276 *	0 - found a line in Systems file
277 *	SS_BADSYSTEM - no line found in Systems file
278 *	SS_TIME_WRONG - wrong time to call
279 */
280
281static int
282finds(char *sysnam, char *flds[], int fldcount)
283{
284	static char *info;	/* dynamically allocated BUFSIZ */
285	int na;
286
287	/*
288	 * format of fields
289	 *	0 name;
290	 *	1 time
291	 *	2 acu/hardwired
292	 *	3 speed
293	 *	etc
294	 */
295
296	if (sysnam == 0 || *sysnam == 0) {
297		Uerror = SS_BADSYSTEM;
298		return (FAIL);
299	}
300
301	if (info == NULL) {
302		info = malloc(BUFSIZ);
303		if (info == NULL) {
304			DEBUG(1, "malloc failed for info in finds\n", 0);
305			return (0);
306		}
307	}
308	while (getsysline(info, BUFSIZ)) {
309		na = getargs(info, flds, fldcount);
310		bsfix(flds);	/* replace \X fields */
311		if (!EQUALSN(sysnam, flds[F_NAME], MAXBASENAME))
312			continue;
313		/* check if requested Mytype device type */
314		if ((Mytype != CNULL) &&
315		    (!EQUALSN(flds[F_TYPE], Mytype, strlen(Mytype)))) {
316			DEBUG(7, "Skipping entry in '%s'", currsys());
317			DEBUG(7, " - type (%s) not wanted.\n", flds[F_TYPE]);
318			continue;
319		} else {
320			/*EMPTY*/
321			DEBUG(5, "Trying entry from '%s'", currsys());
322			DEBUG(5, " - device type %s.\n", flds[F_TYPE]);
323		}
324		/* OK if not uucico (ie. ct or cu) or the time is right */
325		if (!EQUALS(Progname, "uucico") || ifdate(flds[F_TIME])) {
326			/*  found a good entry  */
327			getProto(_ProtoSys, flds[F_TYPE]);
328			Uerror = 0;
329			return (na);	/* FOUND OK LINE */
330		}
331		CDEBUG(1, "Wrong Time To Call: %s\n", flds[F_TIME]);
332		Uerror = SS_TIME_WRONG;
333	}
334	if (!Uerror)
335		Uerror = SS_BADSYSTEM;
336	return (FAIL);
337}
338
339/*
340 * getProto - get the protocol letters from the input string.
341 * input:
342 *	str - string from Systems/Devices/Config file,
343 *		a ',' delimits the protocol string
344 *		e.g. ACU,g or DK,d
345 * output:
346 *	str - the , (if present) will be replaced with NULLCHAR
347 *
348 * return:  none
349 */
350
351static void
352getProto(char *save, char *str)
353{
354	char *p;
355
356	*save = NULLCHAR;
357	if ((p = strchr(str, ',')) != NULL) {
358		*p = NULLCHAR;
359		(void) strcpy(save, p+1);
360		DEBUG(7, "Protocol = %s\n", save);
361	}
362}
363
364/*
365 * chat -	do conversation
366 * input:
367 *	nf - number of fields in flds array
368 *	flds - fields from Systems file
369 *	fn - write file number
370 *	phstr1 - phone number to replace \D
371 *	phstr2 - phone number to replace \T
372 *
373 *	return codes:  0  |  FAIL
374 */
375
376static int
377chat(int nf, char *flds[], int fn, char *phstr1, char *phstr2)
378{
379	char *want, *altern;
380	int k, ok;
381
382	for (k = 0; k < nf; k += 2) {
383		want = flds[k];
384		ok = FAIL;
385		while (ok != 0) {
386			altern = index(want, '-');
387			if (altern != NULL)
388				*altern++ = NULLCHAR;
389			ok = expect(want, fn);
390			if (ok == 0)
391				break;
392			if (altern == NULL) {
393				Uerror = SS_LOGIN_FAILED;
394				logent(UERRORTEXT, "FAILED");
395				return (FAIL);
396			}
397			want = index(altern, '-');
398			if (want != NULL)
399				*want++ = NULLCHAR;
400			sendthem(altern, fn, phstr1, phstr2);
401		}
402		(void) sleep(2);
403		if (flds[k+1])
404			sendthem(flds[k+1], fn, phstr1, phstr2);
405	}
406	return (0);
407}
408
409#define	MR 1000
410
411/*
412 *	expect(str, fn)	look for expected string w/ possible special chars
413 *	char *str;
414 *
415 *	return codes:
416 *		0  -  found
417 *		FAIL  -  lost line or too many characters read
418 *		some character  -  timed out
419 */
420
421static int
422expect(char *str, int fn)
423{
424	char *bptr, *sptr;
425	char    buf[BUFSIZ];
426
427	bptr = buf;
428
429	for (sptr = str; *sptr; sptr++) {
430		if (*sptr == '\\') {
431			switch (*++sptr) {
432			case 'H':
433				*bptr++ = '\0';
434				if (expect_str(buf, fn) == FAIL) {
435					return (FAIL);
436				}
437				if (wait_for_hangup(fn) == FAIL) {
438					return (FAIL);
439				}
440				bptr = buf;
441				continue;
442			case '\\':
443				*bptr++ = '\\';
444				continue;
445			default:
446				*bptr++ = '\\';
447				*bptr++ = *sptr;
448				continue;
449			}
450		} else
451			*bptr++ = *sptr;
452	}
453	*bptr = '\0';
454	if (expect_str(buf, fn) == FAIL) {
455		return (FAIL);
456	}
457	return (0);
458}
459
460/*
461 *	expect_str(str, fn)	look for expected string, w/ no special chars
462 *
463 *	return codes:
464 *		0  -  found
465 *		FAIL  -  too many characters read
466 *		some character  -  timed out
467 */
468
469static int
470expect_str(char *str, int fn)
471{
472	static char rdvec[MR];
473	char *rp = rdvec;
474	int kr, c;
475	char nextch;
476
477	*rp = 0;
478
479	CDEBUG(4, "expect: (%s", "");
480	for (c = 0; (kr = str[c]) != 0; c++)
481		if (kr < 040) {
482			/*EMPTY*/
483			CDEBUG(4, "^%c", kr | 0100);
484		} else {
485			/*EMPTY*/
486			CDEBUG(4, "%c", kr);
487		}
488	CDEBUG(4, ")\n%s", "");
489
490	if (EQUALS(str, "\"\"")) {
491		CDEBUG(4, "got it\n%s", "");
492		return (0);
493	}
494	if (*str == '\0')
495		return (0);
496	if (setjmp(Sjbuf))
497		return (FAIL);
498	(void) signal(SIGALRM, alarmtr);
499	(void) alarm(expecttime);
500	while (notin(str, rdvec)) {
501		errno = 0;
502		kr = (*Read)(fn, &nextch, 1);
503		if (kr <= 0) {
504			(void) alarm(0);
505			CDEBUG(4, "lost line errno - %d\n", errno);
506			logent("LOGIN", "LOST LINE");
507			return (FAIL);
508		}
509		c = nextch & 0177;
510		CDEBUG(4, "%s", c < 040 ? "^" : "");
511		CDEBUG(4, "%c", c < 040 ? c | 0100 : c);
512		if ((*rp = nextch & 0177) != NULLCHAR)
513			rp++;
514		if (rp >= rdvec + MR) {
515			CDEBUG(4, "enough already\n%s", "");
516			(void) alarm(0);
517			return (FAIL);
518		}
519		*rp = NULLCHAR;
520	}
521	(void) alarm(0);
522	CDEBUG(4, "got it\n%s", "");
523	return (0);
524}
525
526
527/*
528 *	alarmtr()  -  catch alarm routine for "expect".
529 */
530/*ARGSUSED*/
531static void
532alarmtr(int sig)
533{
534	CDEBUG(6, "timed out\n%s", "");
535	longjmp(Sjbuf, 1);
536}
537
538/*
539 *	wait_for_hangup() - wait for a hangup to occur on the given device
540 */
541int
542wait_for_hangup(int dcf)
543{
544	int rval;
545	char buff[BUFSIZ];
546
547	CDEBUG(4, "Waiting for hangup\n%s", "");
548	while ((rval = read(dcf, buff, BUFSIZ)) > 0)
549		;
550
551	if (rval < 0)
552		return (FAIL);
553	CDEBUG(4, "Received hangup\n%s", "");
554
555	if (clear_hup(dcf) != SUCCESS) {
556		CDEBUG(4, "Unable to clear hup on device\n%s", "");
557		return (FAIL);
558	}
559	return (SUCCESS);
560}
561
562/*
563 *	sendthem(str, fn, phstr1, phstr2)	send line of chat sequence
564 *	char *str, *phstr;
565 *
566 *	return codes:  none
567 */
568
569#define	FLUSH() { \
570	if ((bptr - buf) > 0) \
571		if (wrstr(fn, buf, bptr - buf, echocheck) != SUCCESS) \
572			goto err; \
573	bptr = buf; \
574}
575
576static void
577sendthem(char *str, int fn, char *phstr1, char *phstr2)
578{
579	int sendcr = 1, echocheck = 0;
580	char	*sptr, *bptr;
581	char	buf[BUFSIZ];
582	struct termio	ttybuf;
583
584	/* should be EQUALS, but previous versions had BREAK n for integer n */
585
586	if (PREFIX("BREAK", str)) {
587		/* send break */
588		CDEBUG(5, "BREAK\n%s", "");
589		(*genbrk)(fn);
590		return;
591	}
592
593	if (EQUALS(str, "EOT")) {
594		CDEBUG(5, "EOT\n%s", "");
595		(void) (*Write)(fn, EOTMSG, strlen(EOTMSG));
596		return;
597	}
598
599	if (EQUALS(str, "\"\"")) {
600		CDEBUG(5, "\"\"\n%s", "");
601		str += 2;
602	}
603
604	bptr = buf;
605	CDEBUG(5, "sendthem (%s", "");
606	for (sptr = str; *sptr; sptr++) {
607		if (*sptr == '\\') {
608			switch (*++sptr) {
609
610			/* adjust switches */
611			case 'c':	/* no CR after string */
612				FLUSH();
613				if (sptr[1] == NULLCHAR) {
614					CDEBUG(5, "<NO CR>%s", "");
615					sendcr = 0;
616				} else {
617					/*EMPTY*/
618					CDEBUG(5, "<NO CR IGNORED>\n%s", "");
619				}
620				continue;
621			}
622
623			/* stash in buf and continue */
624			switch (*sptr) {
625			case 'D':	/* raw phnum */
626				(void) strcpy(bptr, phstr1);
627				bptr += strlen(bptr);
628				continue;
629			case 'T':	/* translated phnum */
630				(void) strcpy(bptr, phstr2);
631				bptr += strlen(bptr);
632				continue;
633			case 'N':	/* null */
634				*bptr++ = 0;
635				continue;
636			case 's':	/* space */
637				*bptr++ = ' ';
638				continue;
639			case '\\':	/* backslash escapes itself */
640				*bptr++ = *sptr;
641				continue;
642			default:	/* send the backslash */
643				*bptr++ = '\\';
644				*bptr++ = *sptr;
645				continue;
646
647			/* flush buf, perform action, and continue */
648			case 'E':	/* echo check on */
649				FLUSH();
650				CDEBUG(5, "ECHO CHECK ON\n%s", "");
651				echocheck = 1;
652				continue;
653			case 'e':	/* echo check off */
654				FLUSH();
655				CDEBUG(5, "ECHO CHECK OFF\n%s", "");
656				echocheck = 0;
657				continue;
658			case 'd':	/* sleep briefly */
659				FLUSH();
660				CDEBUG(5, "DELAY\n%s", "");
661				(void) sleep(2);
662				continue;
663			case 'p':	/* pause momentarily */
664				FLUSH();
665				CDEBUG(5, "PAUSE\n%s", "");
666				nap(HZ/4);	/* approximately 1/4 second */
667				continue;
668			case 'K':	/* inline break */
669				FLUSH();
670				CDEBUG(5, "BREAK\n%s", "");
671				(*genbrk)(fn);
672				continue;
673			case 'M':	/* modem control - set CLOCAL */
674			case 'm':	/* no modem control - clear CLOCAL */
675				FLUSH();
676				CDEBUG(5, ")\n%s CLOCAL ",
677				    (*sptr == 'M' ? "set" : "clear"));
678				if ((*Ioctl)(fn, TCGETA, &ttybuf) != 0) {
679					/*EMPTY*/
680					CDEBUG(5,
681					    "ignored. TCGETA failed, errno %d",
682					    errno);
683				} else {
684					if (*sptr == 'M')
685					ttybuf.c_cflag |= CLOCAL;
686					else
687					ttybuf.c_cflag &= ~CLOCAL;
688					if ((*Ioctl)(fn, TCSETAW, &ttybuf) != 0)
689						/*EMPTY*/
690					CDEBUG(5,
691					    "failed. TCSETAW failed, errno %d",
692					    errno);
693				}
694				CDEBUG(5, "\n%s", "");
695				continue;
696			}
697		} else
698			*bptr++ = *sptr;
699	}
700	if (sendcr)
701		*bptr++ = '\r';
702	if ((bptr - buf) > 0)
703		(void) wrstr(fn, buf, bptr - buf, echocheck);
704
705err:
706	CDEBUG(5, ")\n%s", "");
707}
708
709#undef FLUSH
710
711static int
712wrstr(int fn, char *buf, int len, int echocheck)
713{
714	int	i;
715	char dbuf[BUFSIZ], *dbptr = dbuf;
716
717	buf[len] = 0;
718
719	if (echocheck)
720		return (wrchr(fn, buf, len));
721
722	if (Debug >= 5) {
723		if (sysaccess(ACCESS_SYSTEMS) == 0) {
724			/* Systems file access ok */
725			for (i = 0; i < len; i++) {
726				*dbptr = buf[i];
727				if (*dbptr < 040) {
728					*dbptr++ = '^';
729					*dbptr = buf[i] | 0100;
730				}
731				dbptr++;
732			}
733			*dbptr = 0;
734		} else
735			(void) strcpy(dbuf, "????????");
736		CDEBUG(5, "%s", dbuf);
737	}
738	if ((*Write)(fn, buf, len) != len)
739		return (FAIL);
740	return (SUCCESS);
741}
742
743static int
744wrchr(int fn, char *buf, int len)
745{
746	int	i, saccess;
747	char	cin, cout;
748
749	saccess = (sysaccess(ACCESS_SYSTEMS) == 0); /* protect Systems file */
750	if (setjmp(Sjbuf))
751		return (FAIL);
752	(void) signal(SIGALRM, alarmtr);
753
754	for (i = 0; i < len; i++) {
755		cout = buf[i];
756		if (saccess) {
757			/*EMPTY*/
758			CDEBUG(5, "%s", cout < 040 ? "^" : "");
759			CDEBUG(5, "%c", cout < 040 ? cout | 0100 : cout);
760		} else {
761			/*EMPTY*/
762			CDEBUG(5, "?%s", "");
763		}
764		if (((*Write)(fn, &cout, 1)) != 1)
765			return (FAIL);
766		do {
767			(void) alarm(expecttime);
768			if ((*Read)(fn, &cin, 1) != 1)
769				return (FAIL);
770			(void) alarm(0);
771			cin &= 0177;
772			if (saccess) {
773				/*EMPTY*/
774				CDEBUG(5, "%s", cin < 040 ? "^" : "");
775				CDEBUG(5, "%c", cin < 040 ? cin | 0100 : cin);
776			} else {
777				/*EMPTY*/
778				CDEBUG(5, "?%s", "");
779			}
780		} while (cout != (cin & 0177));
781	}
782	return (SUCCESS);
783}
784
785
786/*
787 *	notin(sh, lg)	check for occurrence of substring "sh"
788 *	char *sh, *lg;
789 *
790 *	return codes:
791 *		0  -  found the string
792 *		1  -  not in the string
793 */
794
795static int
796notin(char *sh, char *lg)
797{
798	while (*lg != NULLCHAR) {
799		if (PREFIX(sh, lg))
800			return (0);
801		else
802			lg++;
803	}
804	return (1);
805}
806
807
808/*
809 *	ifdate(s)
810 *	char *s;
811 *
812 *	ifdate  -  this routine will check a string (s)
813 *	like "MoTu0800-1730" to see if the present
814 *	time is within the given limits.
815 *	SIDE EFFECT - Retrytime is set to number following ";"
816 *
817 *	String alternatives:
818 *		Wk - Mo thru Fr
819 *		zero or one time means all day
820 *		Any - any day
821 *
822 *	return codes:
823 *		0  -  not within limits
824 *		1  -  within limits
825 */
826
827static int
828ifdate(char *s)
829{
830	static char *days[] = {
831		"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0
832	};
833	time_t	clock;
834	int	t__now;
835	char	*p;
836	struct tm	*tp;
837
838	(void) time(&clock);
839	tp = localtime(&clock);
840	t__now = tp->tm_hour * 100 + tp->tm_min;	/* "navy" time */
841
842	/*
843	 *	pick up retry time for failures
844	 *	global variable Retrytime is set here
845	 */
846	if ((p = rindex(s, ';')) != NULL)
847		if (isdigit(p[1])) {
848		if (sscanf(p+1, "%ld", &Retrytime) < 1)
849			Retrytime = 5;	/* 5 minutes is error default */
850		Retrytime  *= 60;
851		*p = NULLCHAR;
852		}
853
854	while (*s) {
855		int	i, dayok;
856
857		for (dayok = 0; (!dayok) && isalpha(*s); s++) {
858			if (PREFIX("Any", s))
859				dayok = 1;
860			else if (PREFIX("Wk", s)) {
861				if (tp->tm_wday >= 1 && tp->tm_wday <= 5)
862					dayok = 1;
863			} else
864				for (i = 0; days[i]; i++)
865					if (PREFIX(days[i], s))
866						if (tp->tm_wday == i)
867							dayok = 1;
868		}
869
870		if (dayok) {
871			int	t__low, t__high;
872
873			while (isalpha(*s))	/* flush remaining day stuff */
874				s++;
875
876			if ((sscanf(s, "%d-%d", &t__low, &t__high) < 2) ||
877			    (t__low == t__high))
878				return (1);
879
880			/* 0000 crossover? */
881			if (t__low < t__high) {
882				if (t__low <= t__now && t__now <= t__high)
883					return (1);
884			} else if (t__low <= t__now || t__now <= t__high)
885				return (1);
886
887			/* aim at next time slot */
888			if ((s = index(s, ',')) == NULL)
889				break;
890		}
891		if (*s)
892			s++;
893	}
894	return (0);
895}
896
897/*
898 *	char *
899 *	fdig(cp)	find first digit in string
900 *
901 *	return - pointer to first digit in string or end of string
902 */
903
904static char *
905fdig(char *cp)
906{
907	char *c;
908
909	for (c = cp; *c; c++)
910		if (*c >= '0' && *c <= '9')
911			break;
912	return (c);
913}
914
915	/* nap(n) -- sleep for 'n' ticks of 1/60th sec each. */
916	/* This version uses the select system call */
917
918
919static void
920nap(unsigned int n)
921{
922	struct timeval tv;
923
924	if (n == 0)
925		return;
926	tv.tv_sec = n/60;
927	tv.tv_usec = ((n%60)*1000000L)/60;
928	(void) select(32, 0, 0, 0, &tv);
929}
930