xref: /titanic_44/usr/src/cmd/bnu/callers.c (revision 0cd13cbfb4270b840b4bd22ec5f673b2b6a2c02b)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27 /*	  All Rights Reserved  	*/
28 
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 
33 #include "uucp.h"
34 
35 #if defined(BSD4_2) || defined(ATTSVR4)
36 #include <netdb.h>
37 #include <netinet/in.h>
38 #include <sys/socket.h>
39 #endif
40 #ifdef UNET
41 #include  "UNET/unetio.h"
42 #include  "UNET/tcp.h"
43 #endif
44 
45 #include <libgen.h>
46 
47 EXTERN void alarmtr();
48 EXTERN jmp_buf Sjbuf;
49 EXTERN char *fdig();
50 EXTERN int interface();
51 EXTERN int fd_mklock(), fd_cklock(), chat(), getdialline();
52 EXTERN void fixline(), fd_rmlock();
53 static void translate();
54 static int gdial();
55 EXTERN int	Modemctrl;
56 EXTERN unsigned connecttime;
57 EXTERN int (*Setup)();
58 
59 /*
60  *	to add a new caller:
61  *	declare the function that knows how to call on the device,
62  *	add a line to the callers table giving the name of the device
63  *	(from Devices file) and the name of the function
64  *	add the function to the end of this file
65  */
66 
67 #ifdef DIAL801
68 EXTERN int	dial801();
69 EXTERN int	open801();
70 #endif
71 
72 #ifdef DATAKIT
73 EXTERN int	dkcall();
74 #endif /* DATAKIT */
75 
76 #ifdef V8
77 int	Dialout();
78 #endif
79 
80 #ifdef TCP
81 int	unetcall();
82 int	tcpcall();
83 #endif /* TCP */
84 
85 #ifdef SYTEK
86 int	sytcall();
87 #endif /* SYTEK */
88 
89 #ifdef TLI
90 EXTERN int	tlicall();
91 #endif /* TLI */
92 
93 static struct caller Caller[] = {
94 
95 #ifdef DIAL801
96 	{"801",		dial801},
97 	{"212",		dial801},
98 #endif /* DIAL801 */
99 
100 #ifdef V8
101 	{"Dialout",	Dialout},	/* ditto but using dialout(III) */
102 #endif
103 
104 #ifdef TCP
105 #if defined(BSD4_2) || defined(ATTSVR4)
106 	{"TCP",		tcpcall},	/* 4.2BSD sockets */
107 #else /* !BSD4_2 */
108 #ifdef UNET
109 	{"TCP",		unetcall},	/* 3com implementation of tcp */
110 	{"Unetserver",	unetcall},
111 #endif /* UNET */
112 #endif /* BSD4_2 || ATTSVR4 */
113 #endif /* TCP */
114 
115 #ifdef DATAKIT
116 	{"DK",		dkcall},	/* standard AT&T DATAKIT VCS caller */
117 #endif /* DATAKIT */
118 
119 #ifdef SYTEK
120 	{"Sytek",	sytcall},	/* untested but should work */
121 #endif /* SYTEK */
122 
123 #ifdef TLI
124 	{"TLI",		tlicall},	/* AT&T Transport Layer Interface */
125 #ifdef TLIS
126 	{"TLIS",	tlicall},	/* AT&T Transport Layer Interface */
127 #endif /*  TLIS  */
128 #endif /* TLI */
129 
130 	{NULL, 		NULL}		/* this line must be last */
131 };
132 
133 /*
134  *	exphone - expand phone number for given prefix and number
135  *
136  *	return code - none
137  */
138 
139 static void
140 exphone(in, out)
141 char *in, *out;
142 {
143 	FILE *fn;
144 	char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH];
145 	char buf[BUFSIZ];
146 	char *s1;
147 
148 	if (!isalpha(*in)) {
149 		(void) strcpy(out, in);
150 		return;
151 	}
152 
153 	s1=pre;
154 	while (isalpha(*in))
155 		*s1++ = *in++;
156 	*s1 = NULLCHAR;
157 	s1 = npart;
158 	while (*in != NULLCHAR)
159 		*s1++ = *in++;
160 	*s1 = NULLCHAR;
161 
162 	tpre[0] = NULLCHAR;
163 	fn = fopen(DIALCODES, "r");
164 	if (fn != NULL) {
165 		while (fgets(buf, BUFSIZ, fn)) {
166 			if ( sscanf(buf, "%s%s", p, tpre) < 1)
167 				continue;
168 			if (EQUALS(p, pre))
169 				break;
170 			tpre[0] = NULLCHAR;
171 		}
172 		fclose(fn);
173 	}
174 
175 	(void) strcpy(out, tpre);
176 	(void) strcat(out, npart);
177 	return;
178 }
179 
180 /*
181  * repphone - Replace \D and \T sequences in arg with phone
182  * expanding and translating as appropriate.
183  */
184 static char *
185 repphone(arg, phone, trstr)
186 char *arg, *phone, *trstr;
187 {
188 	static char pbuf[2*(MAXPH+2)];
189 	char *fp, *tp;
190 
191 	for (tp=pbuf; *arg; arg++) {
192 		if (*arg != '\\') {
193 			*tp++ = *arg;
194 			continue;
195 		} else {
196 			switch (*(arg+1)) {
197 			case 'T':
198 				exphone(phone, tp);
199 				translate(trstr, tp);
200 				for(; *tp; tp++)
201 				    ;
202 				arg++;
203 				break;
204 			case 'D':
205 				for(fp=phone; *tp = *fp++; tp++)
206 				    ;
207 				arg++;
208 				break;
209 			default:
210 				*tp++ = *arg;
211 				break;
212 			}
213 		}
214 	}
215 	*tp = '\0';
216 	return(pbuf);
217 }
218 
219 static u_int saved_mode;
220 static char saved_dcname[20];
221 
222 /*
223  * processdev - Process a line from the Devices file
224  *
225  * return codes:
226  *	file descriptor  -  succeeded
227  *	FAIL  -  failed
228  */
229 GLOBAL int
230 processdev(flds, dev)
231 char *flds[], *dev[];
232 {
233 	int dcf = -1;
234 	struct caller	*ca;
235 	char *args[D_MAX+1], dcname[20];
236 	char **sdev;
237 	EXTERN int pop_push();
238 	EXTERN void  setdevcfg();
239 	int nullfd;
240 	char *phonecl;			/* clear phone string */
241 	char phoneex[2*(MAXPH+2)];	/* expanded phone string */
242 	EXTERN void ttygenbrk();
243 	struct termio tty_orig;
244 	int ret_orig = -1;
245 
246 	sdev = dev;
247 	/*	set up default "break" routine	*/
248 	genbrk = ttygenbrk;
249 
250 	/*	initialize Devconfig info	*/
251 	DEBUG(5, "processdev: calling setdevcfg(%s, ", Progname);
252 	DEBUG(5, "%s)\n", flds[F_TYPE]);
253 	setdevcfg(Progname, flds[F_TYPE]);
254 
255 	for (ca = Caller; ca->CA_type != NULL; ca++) {
256 		/* This will find built-in caller functions */
257 		if (EQUALS(ca->CA_type, dev[D_CALLER])) {
258 			DEBUG(5, "Internal caller type %s\n", dev[D_CALLER]);
259 			if (dev[D_ARG] == NULL) {
260 				/* if NULL - assume translate */
261 				dev[D_ARG+1] = NULL;	/* needed for for loop later to mark the end */
262 				dev[D_ARG] = "\\T";
263 			}
264 			dev[D_ARG] = repphone(dev[D_ARG], flds[F_PHONE], "");
265 			if ((dcf = (*(ca->CA_caller))(flds, dev)) < 0)
266 				return(dcf) ;
267 			if ( interface( ca->CA_type ) ) {
268 				DEBUG(5, "interface(%s) failed", ca->CA_type);
269 				Uerror = SS_DEVICE_FAILED;
270 				/*	restore vanilla unix interface	*/
271 				(void)interface("UNIX");
272 				return(FAIL);
273 			}
274 			dev += 2; /* Skip to next CALLER and ARG */
275 			break;
276 		}
277 	}
278 	if (dcf == -1) {
279 		/* Here if not a built-in caller function */
280 
281 		/* We do locking (file and advisory) after open	*/
282 
283 		/*
284 		 * Open the line
285 		 */
286 		if ( *dev[D_LINE] != '/' ) {
287 			(void) sprintf(dcname, "/dev/%s", dev[D_LINE]);
288 		} else {
289 			(void) strcpy(dcname, dev[D_LINE] );
290 		}
291 		/* take care of the possible partial open fd */
292 		(void) close(nullfd = open("/", O_RDONLY));
293 		if (setjmp(Sjbuf)) {
294 			(void) close(nullfd);
295 			DEBUG(1, "generic open timeout\n%s", "");
296 			logent("generic open", "TIMEOUT");
297 			Uerror = SS_CANT_ACCESS_DEVICE;
298 			goto bad;
299 		}
300 		(void) signal(SIGALRM, alarmtr);
301 		(void) alarm(10);
302 		if ( Modemctrl ) {
303 			DEBUG(7, "opening with O_NDELAY set\n%s", "");
304 			dcf = open(dcname, (O_RDWR | O_NDELAY) );
305 			saved_mode = O_RDWR | O_NDELAY;
306 		} else {
307 			dcf = open(dcname, O_RDWR );
308 			saved_mode = O_RDWR;
309 		}
310 		strcpy(saved_dcname, dcname);
311 		(void) alarm(0);
312 		if (dcf < 0) {
313 			DEBUG(1, "generic open failed, errno = %d\n", errno);
314 			(void) close(nullfd);
315 			logent("generic open", "FAILED");
316 			Uerror = SS_CANT_ACCESS_DEVICE;
317 			goto bad;
318 		}
319 
320 		/* check locks BEFORE modifying the stream */
321 
322 		if ( fd_mklock(dcf) != SUCCESS ) {
323 			DEBUG(1, "failed to lock device %s\n", dcname);
324 			Uerror = SS_LOCKED_DEVICE;
325 			goto bad;
326 		}
327 
328 		if ( Modemctrl ) {
329 			DEBUG(7, "clear O_NDELAY\n%s", "");
330 			if ( fcntl(dcf, F_SETFL,
331 				(fcntl(dcf, F_GETFL, 0) & ~O_NDELAY)) < 0 ) {
332 				DEBUG( 7, "clear O_NDELAY failed, errno %d\n", errno);
333 				Uerror = SS_DEVICE_FAILED;
334 				goto bad;
335 			}
336 		}
337 	}
338 
339 	if ( (*Setup)( MASTER, &dcf, &dcf ) ) {
340 		/*	any device|system lock files we should remove?	*/
341 		DEBUG(5, "MASTER Setup failed%s", "");
342 		Uerror = SS_DEVICE_FAILED;
343 		goto bad;
344 	}
345 
346 	/* configure any requested streams modules */
347 	if ( !pop_push(dcf) ) {
348 		DEBUG(5, "STREAMS module configuration failed%s\n","");
349 		Uerror = SS_DEVICE_FAILED;
350 		goto bad;
351 	}
352 
353 	/* save initial state of line in case script fails */
354 	ret_orig = ioctl(dcf, TCGETA, &tty_orig);
355 
356 	/* use sdev[] since dev[] is incremented for internal callers */
357 	fixline(dcf, atoi(fdig(sdev[D_CLASS])), D_DIRECT);
358 
359 	/*
360 	 * Now loop through the remaining callers and chat
361 	 * according to scripts in dialers file.
362 	 */
363 	for (; dev[D_CALLER] != NULL; dev += 2) {
364 		int w;
365 		/*
366 		 * Scan Dialers file to find an entry
367 		 */
368 		if ((w = gdial(dev[D_CALLER], args, D_MAX)) < 1) {
369 			logent("generic call to gdial", "FAILED");
370 			Uerror = SS_CANT_ACCESS_DEVICE;
371 			goto bad;
372 		}
373 		if (w <= 2)	/* do nothing - no chat */
374 			break;
375 		/*
376 		 * Translate the phone number
377 		 */
378 		if (dev[D_ARG] == NULL) {
379 			/* if NULL - assume no translation */
380 			dev[D_ARG+1] = NULL; /* needed for for loop to mark the end */
381 			dev[D_ARG] = "\\D";
382 		}
383 
384 		phonecl = repphone(dev[D_ARG], flds[F_PHONE], args[1]);
385 		exphone(phonecl, phoneex);
386 		translate(args[1], phoneex);
387 		/*
388 		 * Chat
389 		 */
390 		if (chat(w-2, &args[2], dcf, phonecl, phoneex) != SUCCESS) {
391 			CDEBUG(5, "\nCHAT gdial(%s) FAILED\n", dev[D_CALLER]);
392 			Uerror = SS_CHAT_FAILED;
393 			goto bad;
394 		}
395 	}
396 	/*
397 	 * Success at last!
398 	 */
399 	strcpy(Dc, sdev[D_LINE]);
400 	return(dcf);
401 bad:
402 	if ( dcf >= 0 ) {
403 		/* reset line settings if we got them in the beginning */
404 		if ( ret_orig == 0 )
405 			(void) ioctl(dcf, TCSETAW, &tty_orig);
406 		fd_rmlock(dcf);
407 		(void)close(dcf);
408 	}
409 	/*	restore vanilla unix interface	*/
410 	(void)interface("UNIX");
411 	return(FAIL);
412 }
413 
414 /*
415  * clear_hup()	clear the hangup state of the given device
416  */
417 GLOBAL int
418 clear_hup(dcf)
419 int dcf;
420 {
421 	int ndcf;
422 	if ((ndcf = open(saved_dcname, saved_mode)) < 0) {
423 		return (FAIL);
424 	}
425 	if (ndcf != dcf) {
426 		close(ndcf);
427 	}
428 	return (SUCCESS);
429 }
430 
431 
432 /*
433  * translate the pairs of characters present in the first
434  * string whenever the first of the pair appears in the second
435  * string.
436  */
437 static void
438 translate(ttab, str)
439 char *ttab, *str;
440 {
441 	char *s;
442 
443 	for(;*ttab && *(ttab+1); ttab += 2)
444 		for(s=str;*s;s++)
445 			if(*ttab == *s)
446 				*s = *(ttab+1);
447 	return;
448 }
449 
450 #define MAXLINE	512
451 /*
452  * Get the information about the dialer.
453  * gdial(type, arps, narps)
454  *	type	-> type of dialer (e.g., penril)
455  *	arps	-> array of pointers returned by gdial
456  *	narps	-> number of elements in array returned by gdial
457  * Return value:
458  *	-1	-> Can't open DIALERFILE
459  *	0	-> requested type not found
460  *	>0	-> success - number of fields filled in
461  */
462 static int
463 gdial(type, arps, narps)
464 char *type, *arps[];
465 int narps;
466 {
467 	static char info[MAXLINE];
468 	int na;
469 	EXTERN void dialreset();
470 	EXTERN char * currdial();
471 
472 	DEBUG(2, "gdial(%s) called\n", type);
473 	while (getdialline(info, sizeof(info))) {
474 		if ((info[0] == '#') || (info[0] == ' ') ||
475 		    (info[0] == '\t') || (info[0] == '\n'))
476 			continue;
477 		if ((na = getargs(info, arps, narps)) == 0)
478 			continue;
479 		if (EQUALS(arps[0], type)) {
480 		    DEBUG(5, "Trying caller script '%s'", type);
481 		    DEBUG(5, " from '%s'.\n", currdial());
482 		    dialreset();
483 		    bsfix(arps);
484 		    return(na);
485 		}
486 	}
487 	DEBUG(1, "%s not found in Dialers file\n", type);
488 	dialreset();
489 	return(0);
490 }
491 
492 
493 #ifdef DATAKIT
494 
495 /*
496  *	dkcall(flds, dev)	make a DATAKIT VCS connection
497  *				  DATAKIT VCS is a trademark of AT&T
498  *
499  *	return codes:
500  *		>0 - file number - ok
501  *		FAIL - failed
502  */
503 
504 #include "dk.h"
505 EXTERN int dkdial();
506 
507 /*ARGSUSED*/
508 GLOBAL int
509 dkcall(flds, dev)
510 char *flds[], *dev[];
511 {
512 	int fd;
513 #ifdef V8
514 	extern int cdkp_ld;
515 #endif
516 
517 	char	dialstring[64];
518 	EXTERN	void dkbreak();
519 
520 	strcpy(dialstring, dev[D_ARG]);
521 	DEBUG(4, "dkcall(%s)\n", dialstring);
522 
523 
524 #ifdef V8
525 	if (setjmp(Sjbuf)) {
526 		Uerror = SS_DIAL_FAILED;
527 		return(FAIL);
528 	}
529 
530 	(void) signal(SIGALRM, alarmtr);
531 	(void) alarm(connecttime);
532 	DEBUG(4, "tdkdial(%s", flds[F_PHONE]);
533 	DEBUG(4, ", %d)\n", atoi(dev[D_CLASS]));
534     	if ((fd = tdkdial(flds[F_PHONE], atoi(dev[D_CLASS]))) >= 0)
535 	    if (dkproto(fd, cdkp_ld) < 0)
536 	       {
537 	    	close(fd);
538 	    	fd = -1;
539 	       }
540 	(void) alarm(0);
541 #else
542 	fd = dkdial(dialstring);
543 #endif
544 
545 	(void) strcpy(Dc, "DK");
546 	if (fd < 0) {
547 		Uerror = SS_DIAL_FAILED;
548 		return(FAIL);
549 	}
550 	else {
551 		genbrk = dkbreak;
552 		return(fd);
553 	}
554 }
555 
556 #endif /* DATAKIT */
557 
558 #ifdef TCP
559 
560 /*
561  *	tcpcall(flds, dev)	make ethernet/socket connection
562  *
563  *	return codes:
564  *		>0 - file number - ok
565  *		FAIL - failed
566  */
567 
568 #if !(defined(BSD4_2) || defined(ATTSVR4))
569 /*ARGSUSED*/
570 GLOBAL int
571 tcpcall(flds, dev)
572 char	*flds[], *dev[];
573 {
574 	Uerror = SS_NO_DEVICE;
575 	return(FAIL);
576 }
577 #else /* BSD4_2 */
578 /*ARGSUSED*/
579 GLOBAL int
580 tcpcall(flds, dev)
581 char *flds[], *dev[];
582 {
583 	int ret;
584 	short port;
585 	struct servent *sp;
586 	struct hostent *hp;
587 	struct sockaddr_in sin;
588 
589 	if (EQUALS(flds[F_CLASS], "-")) {
590 		/*
591 		 * Use standard UUCP port number.
592 		 */
593 		sp = getservbyname("uucp", "tcp");
594 		endservent();
595 		ASSERT(sp != NULL, "No uucp service number", 0, 0);
596 		port = sp->s_port;
597 	} else {
598 		/*
599 		 * Systems file specifies a port number.
600 		 */
601 		sp = getservbyname(flds[F_CLASS], "tcp");
602 		endservent();
603 		if (sp == NULL) {
604 			port = htons(atoi(flds[F_CLASS]));
605 			if (port == 0) {
606 				logent("tcpopen", "unknown port number");
607 				Uerror = SS_NO_DEVICE;
608 				return(FAIL);
609 			}
610 		} else
611 			port = sp->s_port;
612 	}
613 	if (EQUALS(flds[F_PHONE], "-")) {
614 		/*
615 		 * Use UUCP name as host name.
616 		 */
617 		hp = gethostbyname(flds[F_NAME]);
618 	} else {
619 		/*
620 		 * Systems file specifies a host name different from the UUCP
621 		 * host name.
622 		 */
623 		hp = gethostbyname(flds[F_PHONE]);
624 	}
625 	endhostent();
626 	if (hp == NULL) {
627 		logent("tcpopen", "no such host");
628 		Uerror = SS_NO_DEVICE;
629 		return(FAIL);
630 	}
631 	DEBUG(4, "tcpdial host %s, ", hp->h_name);
632 	DEBUG(4, "port %d\n", ntohs(port));
633 
634 	ret = socket(AF_INET, SOCK_STREAM, 0);
635 	if (ret < 0) {
636 		DEBUG(5, "no socket: %s\n", strerror(errno));
637 		logent("no socket", strerror(errno));
638 		Uerror = SS_NO_DEVICE;
639 		return(FAIL);
640 	}
641 	sin.sin_family = hp->h_addrtype;
642 #ifdef BSD4_2
643 	bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
644 #else
645 	memcpy((caddr_t)&sin.sin_addr, hp->h_addr, hp->h_length);
646 #endif
647 	sin.sin_port = port;
648 	if (setjmp(Sjbuf)) {
649 		DEBUG(4, "timeout tcpopen\n%s", "");
650 		logent("tcpopen", "TIMEOUT");
651 		Uerror = SS_NO_DEVICE;
652 		return(FAIL);
653 	}
654 	(void) signal(SIGALRM, alarmtr);
655 	(void) alarm(connecttime);
656 	DEBUG(7, "family: %d\n", sin.sin_family);
657 	DEBUG(7, "port: %d\n", sin.sin_port);
658 	DEBUG(7, "addr: %08x\n",*((int *) &sin.sin_addr));
659 	if (connect(ret, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
660 		(void) alarm(0);
661 		(void) close(ret);
662 		DEBUG(5, "connect failed: %s\n", strerror(errno));
663 		logent("connect failed", strerror(errno));
664 		Uerror = SS_NO_DEVICE;
665 		return(FAIL);
666 	}
667 	(void) signal(SIGPIPE, SIG_IGN);  /* watch out for broken ipc link...*/
668 	(void) alarm(0);
669 	(void) strcpy(Dc, "IPC");
670 	return(ret);
671 }
672 
673 #endif /* BSD4_2 */
674 
675 /*
676  *	unetcall(flds, dev)	make ethernet connection
677  *
678  *	return codes:
679  *		>0 - file number - ok
680  *		FAIL - failed
681  */
682 
683 #ifndef UNET
684 /*ARGSUSED*/
685 GLOBAL int
686 unetcall(flds, dev)
687 char	*flds[], *dev[];
688 {
689 	Uerror = SS_NO_DEVICE;
690 	return(FAIL);
691 }
692 #else /* UNET */
693 GLOBAL int
694 unetcall(flds, dev)
695 char *flds[], *dev[];
696 {
697 	int ret;
698 	int port;
699 
700 	port = atoi(dev[D_ARG]);
701 	DEBUG(4, "unetdial host %s, ", flds[F_PHONE]);
702 	DEBUG(4, "port %d\n", port);
703 	(void) alarm(connecttime);
704 	ret = tcpopen(flds[F_PHONE], port, 0, TO_ACTIVE, "rw");
705 	(void) alarm(0);
706 	endhnent();
707 	if (ret < 0) {
708 		DEBUG(5, "tcpopen failed: errno %d\n", errno);
709 		Uerror = SS_DIAL_FAILED;
710 		return(FAIL);
711 	}
712 	(void) strcpy(Dc, "UNET");
713 	return(ret);
714 }
715 #endif /* UNET */
716 
717 #endif /* TCP */
718 
719 #ifdef SYTEK
720 
721 /*
722  *	sytcall(flds, dev)	make a sytek connection
723  *
724  *	return codes:
725  *		>0 - file number - ok
726  *		FAIL - failed
727  */
728 
729 /*ARGSUSED*/
730 GLOBAL int
731 sytcall(flds, dev)
732 char *flds[], *dev[];
733 {
734 	int dcr, dcr2, nullfd, ret;
735 	char dcname[20], command[BUFSIZ];
736 
737 	(void) sprintf(dcname, "/dev/%s", dev[D_LINE]);
738 	DEBUG(4, "dc - %s, ", dcname);
739 	dcr = open(dcname, O_WRONLY|O_NDELAY);
740 	if (dcr < 0) {
741 		Uerror = SS_DIAL_FAILED;
742 		DEBUG(4, "OPEN FAILED %s\n", dcname);
743 		return(FAIL);
744 	}
745 	if ( fd_mklock(dcr) != SUCCESS ) {
746 		(void)close(dcr);
747 		DEBUG(1, "failed to lock device %s\n", dcname);
748 		Uerror = SS_LOCKED_DEVICE;
749 		return(FAIL);
750 	}
751 
752 	sytfixline(dcr, atoi(fdig(dev[D_CLASS])), D_DIRECT);
753 	(void) sleep(2);
754 	DEBUG(4, "Calling Sytek unit %s\n", dev[D_ARG]);
755 	(void) sprintf(command,"\r\rcall %s\r", dev[D_ARG]);
756 	ret = (*Write)(dcr, command, strlen(command));
757 	(void) sleep(1);
758 	DEBUG(4, "COM1 return = %d\n", ret);
759 	sytfix2line(dcr);
760 	(void) close(nullfd = open("/", O_RDONLY));
761 	(void) signal(SIGALRM, alarmtr);
762 	if (setjmp(Sjbuf)) {
763 		DEBUG(4, "timeout sytek open\n%s", "");
764 		(void) close(nullfd);
765 		(void) close(dcr2);
766 		fd_rmlock(dcr);
767 		(void) close(dcr);
768 		Uerror = SS_DIAL_FAILED;
769 		return(FAIL);
770 	}
771 	(void) alarm(10);
772 	dcr2 = open(dcname,O_RDWR);
773 	(void) alarm(0);
774 	fd_rmlock(dcr);
775 	(void) close(dcr);
776 	if (dcr2 < 0) {
777 		DEBUG(4, "OPEN 2 FAILED %s\n", dcname);
778 		Uerror = SS_DIAL_FAILED;
779 		(void) close(nullfd);	/* kernel might think dc2 is open */
780 		return(FAIL);
781 	}
782 	if ( fd_mklock(dcr2) != SUCCESS ) {
783 		(void)close(dcr2);
784 		DEBUG(1, "failed to lock device %s\n", dcname);
785 		Uerror = SS_LOCKED_DEVICE;
786 		return(FAIL);
787 	return(dcr2);
788 }
789 
790 #endif /* SYTEK */
791 
792 #ifdef DIAL801
793 
794 /*
795  *	dial801(flds, dev)	dial remote machine on 801/801
796  *	char *flds[], *dev[];
797  *
798  *	return codes:
799  *		file descriptor  -  succeeded
800  *		FAIL  -  failed
801  *
802  *	unfortunately, open801() is different for usg and non-usg
803  */
804 
805 /*ARGSUSED*/
806 GLOBAL int
807 dial801(flds, dev)
808 char *flds[], *dev[];
809 {
810 	char dcname[20], dnname[20], phone[MAXPH+2];
811 	int dcf = -1, speed;
812 
813 	(void) sprintf(dnname, "/dev/%s", dev[D_CALLDEV]);
814 	(void) sprintf(phone, "%s%s", dev[D_ARG]   , ACULAST);
815 	(void) sprintf(dcname, "/dev/%s", dev[D_LINE]);
816 	CDEBUG(1, "Use Port %s, ", dcname);
817 	DEBUG(4, "acu - %s, ", dnname);
818 	VERBOSE("Trying modem - %s, ", dcname);	/* for cu */
819 	VERBOSE("acu - %s, ", dnname);	/* for cu */
820 	if(getuid()==0 || GRPCHK(getgid())) {
821 		CDEBUG(1, "Phone Number  %s\n", phone);
822 		/* In cu, only give out the phone number to trusted people. */
823 		VERBOSE("calling  %s:  ", phone);	/* for cu */
824 	}
825 	speed = atoi(fdig(dev[D_CLASS]));
826 	dcf = open801(dcname, dnname, phone, speed);
827 	if (dcf >= 0) {
828 	        if ( fd_mklock(dcf) != SUCCESS ) {
829 			(void) close(dcf);
830 			DEBUG(5, "fd_mklock line %s failed\n", dev[D_LINE]);
831 			Uerror = SS_LOCKED_DEVICE;
832 			return(FAIL);
833 		}
834 		fixline(dcf, speed, D_ACU);
835 		(void) strcpy(Dc, dev[D_LINE]);	/* for later unlock() */
836 		VERBOSE("SUCCEEDED\n%s", "");
837 	} else {
838 		VERBOSE("FAILED\n%s", "");
839 	}
840 	return(dcf);
841 }
842 
843 
844 #ifndef ATTSV
845 /*ARGSUSED*/
846 GLOBAL int
847 open801(dcname, dnname, phone, speed)
848 char *dcname, *dnname, *phone;
849 {
850 	int nw, lt, dcf = -1, nullfd, dnf = -1;
851 	pid_t w_ret, pid = -1;
852 	unsigned timelim;
853 
854 	if ((dnf = open(dnname, O_WRONLY)) < 0) {
855 		DEBUG(5, "can't open %s\n", dnname);
856 		Uerror = SS_CANT_ACCESS_DEVICE;
857 		return(FAIL);
858 	}
859 	DEBUG(5, "%s is open\n", dnname);
860 
861 	(void) close(nullfd = open("/dev/null", O_RDONLY));/* partial open hack */
862 	if (setjmp(Sjbuf)) {
863 		DEBUG(4, "timeout modem open\n%s", "");
864 		(void) close(nullfd);
865 		(void) close(dcf);
866 		(void) close(dnf);
867 		logent("801 open", "TIMEOUT");
868 		if (pid > 0) {
869 			kill(pid, 9);
870 			wait((int *) 0);
871 		}
872 		Uerror = SS_DIAL_FAILED;
873 		return(FAIL);
874 	}
875 	(void) signal(SIGALRM, alarmtr);
876 	timelim = 5 * strlen(phone);
877 	(void) alarm(timelim < connecttime ? connecttime : timelim);
878 	if ((pid = fork()) == 0) {
879 		sleep(2);
880 		nw = (*Write)(dnf, phone, lt = strlen(phone));
881 		if (nw != lt) {
882 			DEBUG(4, "ACU write error %d\n", errno);
883 			logent("ACU write", "FAILED");
884 			exit(1);
885 		}
886 		DEBUG(4, "ACU write ok\n%s", "");
887 		exit(0);
888 	}
889 	/*  open line - will return on carrier */
890 	dcf = open(dcname, O_RDWR);
891 
892 	DEBUG(4, "dcf is %d\n", dcf);
893 	if (dcf < 0) {	/* handle like a timeout */
894 		(void) alarm(0);
895 		longjmp(Sjbuf, 1);
896 	}
897 
898 	/* modem is open */
899 	while ((w_ret = wait(&lt)) != pid)
900 		if (w_ret == -1 && errno != EINTR) {
901 			DEBUG(4, "Wait failed errno=%d\n", errno);
902 			(void) close(dcf);
903 			(void) close(dnf);
904 			Uerror = SS_DIAL_FAILED;
905 			return(FAIL);
906 		}
907 	(void) alarm(0);
908 
909 	(void) close(dnf);	/* no reason to keep the 801 open */
910 	if (lt != 0) {
911 		DEBUG(4, "Fork Stat %o\n", lt);
912 		(void) close(dcf);
913 		Uerror = SS_DIAL_FAILED;
914 		return(FAIL);
915 	}
916 	return(dcf);
917 }
918 
919 #else /* ATTSV */
920 
921 GLOBAL int
922 open801(dcname, dnname, phone, speed)
923 char *dcname, *dnname, *phone;
924 {
925 	int nw, lt, dcf = -1, nullfd, dnf = -1, ret;
926 	unsigned timelim;
927 
928 	(void) close(nullfd = open("/", O_RDONLY));	/* partial open hack */
929 	if (setjmp(Sjbuf)) {
930 		DEBUG(4, "DN write %s\n", "timeout");
931 		(void) close(dnf);
932 		(void) close(dcf);
933 		(void) close(nullfd);
934 		Uerror = SS_DIAL_FAILED;
935 		return(FAIL);
936 	}
937 	(void) signal(SIGALRM, alarmtr);
938 	timelim = 5 * strlen(phone);
939 	(void) alarm(timelim < connecttime ? connecttime : timelim);
940 
941 	if ((dnf = open(dnname, O_WRONLY)) < 0 ) {
942 		DEBUG(5, "can't open %s\n", dnname);
943 		Uerror = SS_CANT_ACCESS_DEVICE;
944 		return(FAIL);
945 	}
946 	DEBUG(5, "%s is open\n", dnname);
947 	if ( fd_mklock(dnf) != SUCCESS ) {
948 		(void)close(dnf);
949 		DEBUG(1, "failed to lock device %s\n", dnname);
950 		Uerror = SS_LOCKED_DEVICE;
951 	}
952 	if (  (dcf = open(dcname, O_RDWR | O_NDELAY)) < 0 ) {
953 		DEBUG(5, "can't open %s\n", dcname);
954 		Uerror = SS_CANT_ACCESS_DEVICE;
955 		return(FAIL);
956 	}
957 	if ( fd_mklock(dcf) != SUCCESS ) {
958 		(void)close(dcf);
959 		DEBUG(1, "failed to lock device %s\n", dcname);
960 		Uerror = SS_LOCKED_DEVICE;
961 		return(FAIL);
962 	}
963 
964 	DEBUG(4, "dcf is %d\n", dcf);
965 	fixline(dcf, speed, D_ACU);
966 	nw = (*Write)(dnf, phone, lt = strlen(phone));
967 	if (nw != lt) {
968 		(void) alarm(0);
969 		DEBUG(4, "ACU write error %d\n", errno);
970 		(void) close(dnf);
971 		(void) close(dcf);
972 		Uerror = SS_DIAL_FAILED;
973 		return(FAIL);
974 	} else
975 		DEBUG(4, "ACU write ok\n%s", "");
976 
977 	(void) close(dnf);
978 	(void) close(nullfd = open("/", O_RDONLY));	/* partial open hack */
979 	ret = open(dcname, O_RDWR);  /* wait for carrier  */
980 	(void) alarm(0);
981 	(void) close(ret);	/* close 2nd modem open() */
982 	if (ret < 0) {		/* open() interrupted by alarm */
983 		DEBUG(4, "Line open %s\n", "failed");
984 		Uerror = SS_DIAL_FAILED;
985 		(void) close(nullfd);		/* close partially opened modem */
986 		return(FAIL);
987 	}
988 	(void) fcntl(dcf,F_SETFL, fcntl(dcf, F_GETFL, 0) & ~O_NDELAY);
989 	return(dcf);
990 }
991 #endif /* ATTSV */
992 
993 #endif /* DIAL801 */
994 
995 #ifdef V8
996 GLOBAL int
997 Dialout(flds)
998 char *flds[];
999 {
1000     int fd;
1001     char phone[MAXPH+2];
1002 
1003     exphone(flds[F_PHONE], phone);
1004 
1005     DEBUG(4, "call dialout(%s", phone);
1006     DEBUG(4, ", %s)\n", dev[D_CLASS]);
1007     fd = dialout(phone, dev[D_CLASS]);
1008     if (fd == -1)
1009 	Uerror = SS_NO_DEVICE;
1010     if (fd == -3)
1011 	Uerror = SS_DIAL_FAILED;
1012     if (fd == -9)
1013 	Uerror = SS_DEVICE_FAILED;
1014 
1015     (void) strcpy(Dc, "Dialout");
1016 
1017     return(fd);
1018 }
1019 #endif /* V8 */
1020 
1021 #ifdef TLI
1022 /*
1023  *
1024  * AT&T Transport Layer Interface
1025  *
1026  * expected in Devices
1027  *	TLI line1 - - TLI
1028  * or
1029  *	TLIS line1 - - TLIS
1030  *
1031  */
1032 
1033 #include <sys/tiuser.h>
1034 
1035 EXTERN void tfaillog();
1036 
1037 char *t_alloc();
1038 int t_bind(), t_close(), t_connect(), t_free(), t_look(), t_open(), t_rcvdis();
1039 
1040 #define	CONNECT_ATTEMPTS	3
1041 #define	TFREE(p, type)	if ((p)) t_free((char *)(p), (type))
1042 
1043 /*
1044  * returns fd to remote uucp daemon
1045  */
1046 /*ARGSUSED*/
1047 GLOBAL int
1048 tlicall(flds, dev)
1049 char *flds[];
1050 char *dev[];
1051 {
1052 	char		addrbuf[ BUFSIZ ];
1053 	char		devname[MAXNAMESIZE];
1054 	int		fd;
1055 	int	i, j;
1056 	struct t_bind	*bind_ret = 0;
1057 	struct t_info	tinfo;
1058 	struct t_call	*sndcall = 0, *rcvcall = 0;
1059 	extern int	t_errno;
1060 
1061 	EXTERN struct netbuf	*stoa();
1062 
1063 	if ( dev[D_LINE][0] != '/' ) {
1064 		/*	dev holds device name relative to /dev	*/
1065 		sprintf(devname, "/dev/%s", dev[D_LINE]);
1066 	} else {
1067 		/*	dev holds full path name of device	*/
1068 		strcpy(devname, dev[D_LINE]);
1069 	}
1070 	/* gimme local transport endpoint */
1071 	errno = t_errno = 0;
1072 	if (setjmp(Sjbuf)) {
1073 		DEBUG(1, "t_open timeout\n%s", "");
1074 		logent("t_open", "TIMEOUT");
1075 		Uerror = SS_NO_DEVICE;
1076 		return(FAIL);
1077 	}
1078 	(void) signal(SIGALRM, alarmtr);
1079 	(void) alarm(5);
1080 	fd = t_open(devname, O_RDWR, &tinfo);
1081 	(void) alarm(0);
1082 	if (fd < 0) {
1083 		tfaillog(fd, "t_open" );
1084 		Uerror = SS_NO_DEVICE;
1085 		return(FAIL);
1086 	}
1087 	if ( fd_mklock(fd) != SUCCESS ) {
1088 		(void)t_close(fd);
1089 		DEBUG(1, "tlicall: failed to lock device %s\n", devname);
1090 		Uerror = SS_LOCKED_DEVICE;
1091 		return(FAIL);
1092 	}
1093 
1094 	/* allocate tli structures	*/
1095 	errno = t_errno = 0;
1096 	if ( (bind_ret = (struct t_bind *)t_alloc(fd, T_BIND, T_ALL)) ==
1097 	    (struct t_bind *)NULL
1098 	|| (sndcall = (struct t_call *)t_alloc(fd, T_CALL, T_ALL)) ==
1099 	    (struct t_call *)NULL
1100 	|| (rcvcall = (struct t_call *)t_alloc(fd, T_CALL, T_ALL)) ==
1101 	    (struct t_call *)NULL ) {
1102 		tfaillog(fd, "t_alloc" );
1103 		TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
1104 		TFREE(rcvcall, T_CALL);
1105 		Uerror = SS_NO_DEVICE;
1106 		return(FAIL);
1107 	}
1108 
1109 	/* bind */
1110 	errno = t_errno = 0;
1111 	if (t_bind(fd, (struct t_bind *) 0, bind_ret ) < 0) {
1112 		tfaillog(fd, "t_bind" );
1113 		TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
1114 		TFREE(rcvcall, T_CALL);
1115 		Uerror = SS_NO_DEVICE;
1116 		fd_rmlock(fd);
1117 		(void) t_close(fd);
1118 		return(FAIL);
1119 	}
1120 	DEBUG(5, "tlicall: bound to %s\n", bind_ret->addr.buf);
1121 
1122 	/*
1123 	 * Prepare to connect.
1124 	 *
1125 	 * If address begins with "\x", "\X", "\o", or "\O",
1126 	 * assume is hexadecimal or octal address and use stoa()
1127 	 * to convert it.
1128 	 *
1129 	 * Else is usual uucico address -- only \N's left to process.
1130 	 * Walk thru connection address, changing \N's to NULLCHARs.
1131 	 * Note:  If a NULLCHAR must be part of the connection address,
1132 	 * it must be overtly included in the address.  One recommended
1133 	 * way is to do it in the Devices file, thusly:
1134 	 *		Netname /dev/netport - - TLI \D\000
1135 	 * bsfix() turns \000 into \N and then the loop below makes it a
1136 	 * real, included-in-the-length null-byte.
1137 	 *
1138 	 * The DEBUG must print the strecpy'd address (so that
1139 	 * non-printables will have been replaced with C escapes).
1140 	 */
1141 
1142 	DEBUG(5, "t_connect to addr \"%s\"\n",
1143 		strecpy( addrbuf, dev[D_ARG], "\\" ) );
1144 
1145 	if ( dev[D_ARG][0] == '\\' &&
1146 	( dev[D_ARG][1] == 'x' || dev[D_ARG][1] == 'X'
1147 	|| dev[D_ARG][1] == 'o' || dev[D_ARG][1] == 'O' ) ) {
1148 		if ( stoa(dev[D_ARG], &(sndcall->addr)) == (struct netbuf *)NULL ) {
1149 			DEBUG(5, "tlicall: stoa failed\n%s", "");
1150 			logent("tlicall", "string-to-address failed");
1151 			TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
1152 			TFREE(rcvcall, T_CALL);
1153 			Uerror = SS_NO_DEVICE;
1154 			fd_rmlock(fd);
1155 			(void) t_close(fd);
1156 			return(FAIL);
1157 		}
1158 	} else {
1159 		for( i = j = 0; i < BUFSIZ && dev[D_ARG][i] != NULLCHAR;
1160 		++i, ++j ) {
1161 			if( dev[D_ARG][i] == '\\'  &&  dev[D_ARG][i+1] == 'N' ) {
1162 				addrbuf[j] = NULLCHAR;
1163 				++i;
1164 			}
1165 			else {
1166 				addrbuf[j] = dev[D_ARG][i];
1167 			}
1168 		}
1169 		sndcall->addr.buf = addrbuf;
1170 		sndcall->addr.len = j;
1171 	}
1172 
1173 	if (setjmp(Sjbuf)) {
1174 		DEBUG(4, "timeout tlicall\n%s", "");
1175 		logent("tlicall", "TIMEOUT");
1176 		TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
1177 		TFREE(rcvcall, T_CALL);
1178 		Uerror = SS_NO_DEVICE;
1179 		fd_rmlock(fd);
1180 		(void) t_close(fd);
1181 		return(FAIL);
1182 	}
1183 	(void) signal(SIGALRM, alarmtr);
1184 	(void) alarm(connecttime);
1185 
1186 	/* connect to the service -- some listeners can't handle */
1187 	/* multiple connect requests, so try it a few times */
1188 	errno = t_errno = 0;
1189 	for ( i = 0; i < CONNECT_ATTEMPTS; ++i ) {
1190 		if (t_connect(fd, sndcall, rcvcall) == 0)
1191 			break;
1192 		if ( (t_errno == TLOOK) && (t_look(fd) == T_DISCONNECT)) {
1193 			t_rcvdis(fd,NULL);
1194 			(void) alarm(0);
1195 		} else {
1196 			(void) alarm(0);
1197 			tfaillog(fd, "t_connect");
1198 			TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
1199 			TFREE(rcvcall, T_CALL);
1200 			Uerror = SS_DIAL_FAILED;
1201 			fd_rmlock(fd);
1202 			(void) t_close(fd);
1203 			return(FAIL);
1204 		}
1205 	}
1206 	(void) alarm(0);
1207 	TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
1208 	TFREE(rcvcall, T_CALL);
1209 	if ( i == CONNECT_ATTEMPTS ) {
1210 		tfaillog(fd, "t_connect");
1211 		Uerror = SS_DIAL_FAILED;
1212 		fd_rmlock(fd);
1213 		(void) t_close(fd);
1214 		return(FAIL);
1215 	}
1216 	errno = t_errno = 0;
1217 	(void) strcpy(Dc, dev[D_CALLER]);
1218 	return(fd);
1219 }
1220 #endif /* TLI */
1221