xref: /illumos-gate/usr/src/cmd/bnu/line.c (revision f998c95e3b7029fe5f7542e115f7474ddb8024d7)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1995 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 /* This is a new line.c, which consists of line.c and culine.c
34  * merged together.
35  */
36 
37 #include "uucp.h"
38 
39 static struct sg_spds {
40 	int	sp_val,
41 		sp_name;
42 } spds[] = {
43 	{  50,   B50},
44 	{  75,   B75},
45 	{ 110,  B110},
46 	{ 134,  B134},
47 	{ 150,  B150},
48 	{ 200,  B200},
49 	{ 300,  B300},
50 	{ 600,  B600},
51 	{1200, B1200},
52 	{1800, B1800},
53 	{2400, B2400},
54 	{4800, B4800},
55 	{9600, B9600},
56 #ifdef EXTA
57 	{19200,	EXTA},
58 #endif
59 #ifdef B19200
60 	{19200,	B19200},
61 #endif
62 #ifdef B38400
63 	{38400,	B38400},
64 #endif
65 	{57600, B57600},
66 	{76800, B76800},
67 	{115200, B115200},
68 	{153600, B153600},
69 	{230400, B230400},
70 	{307200, B307200},
71 	{460800, B460800},
72 	{0,    0}
73 };
74 
75 #define PACKSIZE	64
76 #define HEADERSIZE	6
77 
78 GLOBAL int
79      packsize = PACKSIZE,
80     xpacksize = PACKSIZE;
81 
82 #define SNDFILE	'S'
83 #define RCVFILE 'R'
84 #define RESET	'X'
85 
86 #ifdef PKSPEEDUP
87 GLOBAL int linebaudrate;	/* for speedup hook in pk1.c */
88 #endif /*  PKSPEEDUP  */
89 static int Saved_line;		/* was savline() successful?	*/
90 static int Saved_termios;	/* was termios saved?	*/
91 GLOBAL int
92 	Oddflag = 0,	/* Default is no parity */
93 	Evenflag = 0,	/* Default is no parity */
94 	Duplex = 1,	/* Default is full duplex */
95 	Terminal = 0,	/* Default is no terminal */
96 	term_8bit = -1,	/* Default to terminal setting or 8 bit */
97 	line_8bit = -1;	/* Default is same as terminal */
98 
99 static char *P_PARITY  = "Parity option error\r\n";
100 
101 #ifdef ATTSVTTY
102 
103 static struct termio Savettyb;
104 static struct termios Savettybs;
105 /*
106  * set speed/echo/mode...
107  *	tty 	-> terminal name
108  *	spwant 	-> speed
109  *	type	-> type
110  *
111  *	if spwant == 0, speed is untouched
112  *	type is unused, but needed for compatibility
113  *
114  * return:
115  *	none
116  */
117 /*ARGSUSED*/
118 GLOBAL void
119 fixline(tty, spwant, type)
120 int	tty, spwant, type;
121 {
122 	register struct sg_spds	*ps;
123 	struct termio		ttbuf;
124 	struct termios		ttbufs;
125 	int			speed = -1;
126 	int			i, istermios, ospeed;
127 
128 	DEBUG(6, "fixline(%d, ", tty);
129 	DEBUG(6, "%d)\n", spwant);
130 	if ((istermios = (*Ioctl)(tty, TCGETS, &ttbufs)) < 0) {
131 		if ((*Ioctl)(tty, TCGETA, &ttbuf) != 0) {
132 			return;
133 		} else {
134 			ttbufs.c_lflag = ttbuf.c_lflag;
135 			ttbufs.c_oflag = ttbuf.c_oflag;
136 			ttbufs.c_iflag = ttbuf.c_iflag;
137 			ttbufs.c_cflag = ttbuf.c_cflag;
138 			for(i = 0; i < NCC; i++)
139 				ttbufs.c_cc[i] = ttbuf.c_cc[i];
140 	    	}
141 	}
142 	if (spwant > 0) {
143 		for (ps = spds; ps->sp_val; ps++)
144 			if (ps->sp_val == spwant) {
145 				speed = ps->sp_name;
146 				break;
147 			}
148 		if ( speed < 0 )
149 		    DEBUG(5, "speed (%d) not supported\n", spwant);
150 		ASSERT(speed >= 0, "BAD SPEED", "", spwant);
151 		ttbufs.c_cflag &= 0xffff0000;
152 		cfsetospeed(&ttbufs, speed);
153 	} else { /* determine the current speed setting */
154 		ospeed = cfgetospeed(&ttbufs);
155 		ttbufs.c_cflag &= 0xffff0000;
156 		cfsetospeed(&ttbufs, ospeed);
157 		for (ps = spds; ps->sp_val; ps++)
158 			if (ps->sp_name == ospeed) {
159 				spwant = ps->sp_val;
160 				break;
161 			}
162 	}
163 	/*
164 	 * In order to prevent attempts at split speed, all baud rate
165 	 * bitfields should be cleared. Thus cfsetispeed is used to
166 	 * set the speed to zero.
167 	 */
168 	(void) cfsetispeed(&ttbufs, 0);
169 	ttbufs.c_iflag &= 0xffff0000;
170 	ttbufs.c_oflag &= 0xffff0000;
171 	ttbufs.c_lflag &= 0xffff0000;
172 #ifdef PKSPEEDUP
173 	linebaudrate = spwant;
174 #endif /*  PKSPEEDUP  */
175 
176 #ifdef NO_MODEM_CTRL
177 	/*   CLOCAL may cause problems on pdp11s with DHs */
178 	if (type == D_DIRECT) {
179 		DEBUG(4, "fixline - direct\n%s", "");
180 		ttbufs.c_cflag |= CLOCAL;
181 	} else
182 #endif /* NO_MODEM_CTRL */
183 		ttbufs.c_cflag &= ~CLOCAL;
184 
185 	if ( !EQUALS(Progname, "uucico") ) {
186 
187 		/* set attributes associated with -h, -t, -e, and -o options */
188 
189 		ttbufs.c_iflag = (IGNPAR | IGNBRK | IXON | IXOFF);
190 		ttbufs.c_cc[VEOF] = '\1';
191 		ttbufs.c_cflag |= ( CREAD | (speed ? HUPCL : 0));
192 
193 		if ( line_8bit ) {
194 		    ttbufs.c_cflag |= CS8;
195 		    ttbufs.c_iflag &= ~ISTRIP;
196 		} else {
197 		    if (Evenflag) {			/*even parity -e */
198 			ttbufs.c_cflag &= ~PARODD;
199 		    } else if(Oddflag) {		/*odd parity -o */
200 			ttbufs.c_cflag |= PARODD;
201 		    }
202 		    ttbufs.c_cflag |= CS7|PARENB;
203 		    ttbufs.c_iflag |= ISTRIP;
204 		}
205 
206 		if(!Duplex)				/*half duplex -h */
207 		    ttbufs.c_iflag &= ~(IXON | IXOFF);
208 		if(Terminal)				/* -t */
209 		    ttbufs.c_oflag |= (OPOST | ONLCR);
210 
211 	} else { /* non-uucico */
212 		ttbufs.c_cflag |= (CS8 | CREAD | (speed ? HUPCL : 0));
213 		ttbufs.c_cc[VMIN] = HEADERSIZE;
214 		ttbufs.c_cc[VTIME] = 1;
215 	}
216 
217 	if (istermios < 0) {
218 		ttbuf.c_lflag = ttbufs.c_lflag;
219 		ttbuf.c_oflag = ttbufs.c_oflag;
220 		ttbuf.c_iflag = ttbufs.c_iflag;
221 		ttbuf.c_cflag = ttbufs.c_cflag;
222 		for(i = 0; i < NCC; i++)
223 			ttbuf.c_cc[i] = ttbufs.c_cc[i];
224 		ASSERT((*Ioctl)(tty, TCSETAW, &ttbuf) >= 0,
225 	    	    "RETURN FROM fixline ioctl", "", errno);
226 	} else {
227 		ASSERT((*Ioctl)(tty, TCSETSW, &ttbufs) >= 0,
228 	    	    "RETURN FROM fixline ioctl", "", errno);
229 	}
230 
231 	return;
232 }
233 
234 GLOBAL void
235 sethup(dcf)
236 int	dcf;
237 {
238 	struct termio ttbuf;
239 
240 	if ((*Ioctl)(dcf, TCGETA, &ttbuf) != 0)
241 		return;
242 	if (!(ttbuf.c_cflag & HUPCL)) {
243 		ttbuf.c_cflag |= HUPCL;
244 		(void) (*Ioctl)(dcf, TCSETAW, &ttbuf);
245 	}
246 	return;
247 }
248 
249 GLOBAL void
250 ttygenbrk(fn)
251 register int	fn;
252 {
253 	if (isatty(fn))
254 		(void) (*Ioctl)(fn, TCSBRK, 0);
255 	return;
256 }
257 
258 
259 /*
260  * optimize line setting for sending or receiving files
261  * return:
262  *	none
263  */
264 GLOBAL void
265 setline(type)
266 register char	type;
267 {
268 	static struct termio tbuf;
269 	static struct termios tbufs;
270 	int i, vtime, istermios, ospeed;
271 
272 	DEBUG(2, "setline - %c\n", type);
273 
274 	if ((istermios = (*Ioctl)(Ifn, TCGETS, &tbufs)) < 0) {
275 		if ((*Ioctl)(Ifn, TCGETA, &tbuf) != 0) {
276 			return;
277 		} else {
278 			tbufs.c_lflag = tbuf.c_lflag;
279 			tbufs.c_oflag = tbuf.c_oflag;
280 			tbufs.c_iflag = tbuf.c_iflag;
281 			tbufs.c_cflag = tbuf.c_cflag;
282 			for(i = 0; i < NCC; i++)
283 				tbufs.c_cc[i] = tbuf.c_cc[i];
284 		}
285 	}
286 	switch (type) {
287 	case RCVFILE:
288 		ospeed = cfgetospeed(&tbufs);
289 		switch (ospeed) {
290 #ifdef B19200
291 		case B19200:
292 #else
293 #ifdef EXTA
294 		case EXTA:
295 #endif
296 #endif
297 #ifdef B38400
298 		case B38400:
299 #endif
300 		case B57600:
301 		case B76800:
302 		case B115200:
303 		case B153600:
304 		case B230400:
305 		case B307200:
306 		case B460800:
307 		case B9600:
308 			vtime = 1;
309 			break;
310 		case B4800:
311 			vtime = 4;
312 			break;
313 		default:
314 			vtime = 8;
315 			break;
316 		}
317 		if (tbufs.c_cc[VMIN] != packsize ||
318 		    tbufs.c_cc[VTIME] != vtime) {
319 		    tbufs.c_cc[VMIN] = packsize;
320 		    tbufs.c_cc[VTIME] = vtime;
321 		    if (istermios < 0) {
322 			tbuf.c_lflag = tbufs.c_lflag;
323 			tbuf.c_oflag = tbufs.c_oflag;
324 			tbuf.c_iflag = tbufs.c_iflag;
325 			tbuf.c_cflag = tbufs.c_cflag;
326 			for(i = 0; i < NCC; i++)
327 				tbuf.c_cc[i] = tbufs.c_cc[i];
328 		        if ( (*Ioctl)(Ifn, TCSETAW, &tbuf) != 0 )
329 			    DEBUG(4, "setline Ioctl failed errno=%d\n", errno);
330 		    } else {
331 		        if ( (*Ioctl)(Ifn, TCSETSW, &tbufs) != 0 )
332 			    DEBUG(4, "setline Ioctl failed errno=%d\n", errno);
333 		    }
334 		}
335 		break;
336 
337 	case SNDFILE:
338 	case RESET:
339 		if (tbufs.c_cc[VMIN] != HEADERSIZE) {
340 		    tbufs.c_cc[VMIN] = HEADERSIZE;
341 		    if (istermios < 0) {
342 			tbuf.c_lflag = tbufs.c_lflag;
343 			tbuf.c_oflag = tbufs.c_oflag;
344 			tbuf.c_iflag = tbufs.c_iflag;
345 			tbuf.c_cflag = tbufs.c_cflag;
346 			for(i = 0; i < NCC; i++)
347 				tbuf.c_cc[i] = tbufs.c_cc[i];
348 		    	if ( (*Ioctl)(Ifn, TCSETAW, &tbuf) != 0 )
349 			    DEBUG(4, "setline Ioctl failed errno=%d\n", errno);
350 		    } else {
351 		        if ( (*Ioctl)(Ifn, TCSETSW, &tbufs) != 0 )
352 			    DEBUG(4, "setline Ioctl failed errno=%d\n", errno);
353 		    }
354 		}
355 		break;
356 	}
357 	return;
358 }
359 
360 GLOBAL int
361 savline()
362 {
363 	if ((Saved_termios = (*Ioctl)(0, TCGETS, &Savettybs)) < 0) {
364 	    if ( (*Ioctl)(0, TCGETA, &Savettyb) != 0 ) {
365 		Saved_line = FALSE;
366 	    } else {
367 		Saved_line = TRUE;
368 		Savettyb.c_cflag = (Savettyb.c_cflag & ~CS8) | CS7 | PARENB;
369 		Savettyb.c_oflag |= OPOST;
370 		Savettyb.c_lflag |= (ISIG|ICANON|ECHO);
371 	    }
372 	} else {
373 		Saved_line = TRUE;
374 		Savettybs.c_cflag = (Savettybs.c_cflag & ~CS8) | CS7 | PARENB;
375 		Savettybs.c_oflag |= OPOST;
376 		Savettybs.c_lflag |= (ISIG|ICANON|ECHO);
377 	}
378 	return(0);
379 }
380 
381 #ifdef SYTEK
382 
383 /*
384  *	sytfixline(tty, spwant)	set speed/echo/mode...
385  *	int tty, spwant;
386  *
387  *	return codes:  none
388  */
389 
390 GLOBAL void
391 sytfixline(tty, spwant)
392 int tty, spwant;
393 {
394 	struct termio ttbuf;
395 	struct termios ttbufs;
396 	struct sg_spds *ps;
397 	int speed = -1;
398 	int i, ret, istermios;
399 
400 	if ((istermios = (*Ioctl)(tty, TCGETS, &ttbufs)) < 0) {
401 		if ( (*Ioctl)(tty, TCGETA, &ttbuf) != 0 ) {
402 			return;
403 		} else {
404 			ttbufs.c_lflag = ttbuf.c_lflag;
405 			ttbufs.c_oflag = ttbuf.c_oflag;
406 			ttbufs.c_iflag = ttbuf.c_iflag;
407 			ttbufs.c_cflag = ttbuf.c_cflag;
408 			for(i = 0; i < NCC; i++)
409 				ttbufs.c_cc[i] = ttbuf.c_cc[i];
410 		}
411 	}
412 	for (ps = spds; ps->sp_val >= 0; ps++)
413 		if (ps->sp_val == spwant)
414 			speed = ps->sp_name;
415 	DEBUG(4, "sytfixline - speed= %d\n", speed);
416 	ASSERT(speed >= 0, "BAD SPEED", "", spwant);
417 	ttbufs.c_iflag &= 0xffff0000;
418 	ttbufs.c_oflag &= 0xffff0000;
419 	ttbufs.c_lflag &= 0xffff0000;
420 	ttbufs.c_cflag &= 0xffff0000;
421 	cfsetospeed(&ttbufs, speed);
422 	ttbufs.c_cflag |= (CS8|CLOCAL);
423 	ttbufs.c_cc[VMIN] = 6;
424 	ttbufs.c_cc[VTIME] = 1;
425 	if (istermios < 0) {
426 		ttbuf.c_lflag = ttbufs.c_lflag;
427 		ttbuf.c_oflag = ttbufs.c_oflag;
428 		ttbuf.c_iflag = ttbufs.c_iflag;
429 		ttbuf.c_cflag = ttbufs.c_cflag;
430 		for(i = 0; i < NCC; i++)
431 			ttbuf.c_cc[i] = ttbufs.c_cc[i];
432 		ret = (*Ioctl)(tty, TCSETAW, &ttbuf);
433 	} else
434 		ret = (*Ioctl)(tty, TCSETAWS &ttbufs);
435 	ASSERT(ret >= 0, "RETURN FROM sytfixline", "", ret);
436 	return;
437 }
438 
439 GLOBAL void
440 sytfix2line(tty)
441 int tty;
442 {
443 	struct termio ttbuf;
444 	int ret;
445 
446 	if ( (*Ioctl)(tty, TCGETA, &ttbuf) != 0 )
447 		return;
448 	ttbuf.c_cflag &= ~CLOCAL;
449 	ttbuf.c_cflag |= CREAD|HUPCL;
450 	ret = (*Ioctl)(tty, TCSETAW, &ttbuf);
451 	ASSERT(ret >= 0, "RETURN FROM sytfix2line", "", ret);
452 	return;
453 }
454 
455 #endif /* SYTEK */
456 
457 GLOBAL int
458 restline()
459 {
460 	if ( Saved_line == TRUE ) {
461 		if (Saved_termios < 0)
462 			return((*Ioctl)(0, TCSETAW, &Savettyb));
463 		else
464 			return((*Ioctl)(0, TCSETSW, &Savettybs));
465 	}
466 	return(0);
467 }
468 
469 #else /* !ATTSVTTY */
470 
471 static struct sgttyb Savettyb;
472 
473 /*
474  *	fixline(tty, spwant, type)	set speed/echo/mode...
475  *	int tty, spwant;
476  *
477  *	if spwant == 0, speed is untouched
478  *	type is unused, but needed for compatibility
479  *
480  *	return codes:  none
481  */
482 
483 /*ARGSUSED*/
484 GLOBAL void
485 fixline(tty, spwant, type)
486 int tty, spwant, type;
487 {
488 	struct sgttyb	ttbuf;
489 	struct sg_spds	*ps;
490 	int		 speed = -1;
491 
492 	DEBUG(6, "fixline(%d, ", tty);
493 	DEBUG(6, "%d)\n", spwant);
494 
495 	if ((*Ioctl)(tty, TIOCGETP, &ttbuf) != 0)
496 		return;
497 	if (spwant > 0) {
498 		for (ps = spds; ps->sp_val; ps++)
499 			if (ps->sp_val == spwant) {
500 				speed = ps->sp_name;
501 				break;
502 			}
503 		ASSERT(speed >= 0, "BAD SPEED", "", spwant);
504 		ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed;
505 	} else {
506 		for (ps = spds; ps->sp_val; ps++)
507 			if (ps->sp_name == ttbuf.sg_ispeed) {
508 				spwant = ps->sp_val;
509 				break;
510 			}
511 		ASSERT(spwant >= 0, "BAD SPEED", "", ttbuf.sg_ispeed);
512 	}
513 	ttbuf.sg_flags = (ANYP | RAW);
514 #ifdef PKSPEEDUP
515 	linebaudrate = spwant;
516 #endif /*  PKSPEEDUP  */
517 	(void) (*Ioctl)(tty, TIOCSETP, &ttbuf);
518 	(void) (*Ioctl)(tty, TIOCHPCL, STBNULL);
519 	(void) (*Ioctl)(tty, TIOCEXCL, STBNULL);
520 	return;
521 }
522 
523 GLOBAL void
524 sethup(dcf)
525 int	dcf;
526 {
527 	if (isatty(dcf))
528 		(void) (*Ioctl)(dcf, TIOCHPCL, STBNULL);
529 	return;
530 }
531 
532 /*
533  *	genbrk		send a break
534  *
535  *	return codes;  none
536  */
537 
538 GLOBAL void
539 ttygenbrk(fn)
540 {
541 	if (isatty(fn)) {
542 		(void) (*Ioctl)(fn, TIOCSBRK, 0);
543 #ifndef V8
544 		nap(HZ/10);				/* 0.1 second break */
545 		(void) (*Ioctl)(fn, TIOCCBRK, 0);
546 #endif
547 	}
548 	return;
549 }
550 
551 /*
552  * V7 and RT aren't smart enough for this -- linebaudrate is the best
553  * they can do.
554  */
555 /*ARGSUSED*/
556 GLOBAL void
557 setline(dummy) { }
558 
559 GLOBAL int
560 savline()
561 {
562 	if (  (*Ioctl)(0, TIOCGETP, &Savettyb) != 0 )
563 		Saved_line = FALSE;
564 	else {
565 		Saved_line = TRUE;
566 		Savettyb.sg_flags |= ECHO;
567 		Savettyb.sg_flags &= ~RAW;
568 	}
569 	return(0);
570 }
571 
572 GLOBAL int
573 restline()
574 {
575 	if ( Saved_line == TRUE )
576 		return((*Ioctl)(0, TIOCSETP, &Savettyb));
577 	return(0);
578 }
579 #endif
580