1/*
2 * Copyright (c) 1988, 1990, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#if 0
31#ifndef lint
32static const char sccsid[] = "@(#)terminal.c	8.2 (Berkeley) 2/16/95";
33#endif
34#endif
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD: stable/11/contrib/telnet/telnet/terminal.c 351432 2019-08-23 17:40:47Z emaste $");
37
38#include <arpa/telnet.h>
39#include <sys/types.h>
40
41#include <stdlib.h>
42
43#include "ring.h"
44
45#include "externs.h"
46#include "types.h"
47
48#ifdef	ENCRYPTION
49#include <libtelnet/encrypt.h>
50#endif
51
52Ring		ttyoring, ttyiring;
53unsigned char	ttyobuf[2*BUFSIZ], ttyibuf[BUFSIZ];
54
55int termdata;			/* Debugging flag */
56
57#ifdef	USE_TERMIO
58# ifndef VDISCARD
59cc_t termFlushChar;
60# endif
61# ifndef VLNEXT
62cc_t termLiteralNextChar;
63# endif
64# ifndef VSUSP
65cc_t termSuspChar;
66# endif
67# ifndef VWERASE
68cc_t termWerasChar;
69# endif
70# ifndef VREPRINT
71cc_t termRprntChar;
72# endif
73# ifndef VSTART
74cc_t termStartChar;
75# endif
76# ifndef VSTOP
77cc_t termStopChar;
78# endif
79# ifndef VEOL
80cc_t termForw1Char;
81# endif
82# ifndef VEOL2
83cc_t termForw2Char;
84# endif
85# ifndef VSTATUS
86cc_t termAytChar;
87# endif
88#else
89cc_t termForw2Char;
90cc_t termAytChar;
91#endif
92
93/*
94 * initialize the terminal data structures.
95 */
96
97void
98init_terminal(void)
99{
100    if (ring_init(&ttyoring, ttyobuf, sizeof ttyobuf) != 1) {
101	exit(1);
102    }
103    if (ring_init(&ttyiring, ttyibuf, sizeof ttyibuf) != 1) {
104	exit(1);
105    }
106    autoflush = TerminalAutoFlush();
107}
108
109/*
110 *		Send as much data as possible to the terminal, else exits if
111 *		it encounters a permanent failure when writing to the tty.
112 *
113 *		Return value:
114 *			-1: No useful work done, data waiting to go out.
115 *			 0: No data was waiting, so nothing was done.
116 *			 1: All waiting data was written out.
117 *			 n: All data - n was written out.
118 */
119
120int
121ttyflush(int drop)
122{
123    int n, n0, n1;
124
125    n0 = ring_full_count(&ttyoring);
126    if ((n1 = n = ring_full_consecutive(&ttyoring)) > 0) {
127	if (drop) {
128	    TerminalFlushOutput();
129	    /* we leave 'n' alone! */
130	} else {
131	    n = TerminalWrite(ttyoring.consume, n);
132	}
133    }
134    if (n > 0) {
135	if (termdata && n) {
136	    Dump('>', ttyoring.consume, n);
137	}
138	/*
139	 * If we wrote everything, and the full count is
140	 * larger than what we wrote, then write the
141	 * rest of the buffer.
142	 */
143	if (n1 == n && n0 > n) {
144		n1 = n0 - n;
145		if (!drop)
146			n1 = TerminalWrite(ttyoring.bottom, n1);
147		if (n1 > 0)
148			n += n1;
149	}
150	ring_consumed(&ttyoring, n);
151    }
152    if (n < 0) {
153	if (errno == EAGAIN || errno == EINTR) {
154	    return -1;
155	} else {
156	    ring_consumed(&ttyoring, ring_full_count(&ttyoring));
157	    setconnmode(0);
158	    setcommandmode();
159	    NetClose(net);
160	    fprintf(stderr, "Write error on local output.\n");
161	    exit(1);
162	}
163	return -1;
164    }
165    if (n == n0) {
166	if (n0)
167	    return -1;
168	return 0;
169    }
170    return n0 - n + 1;
171}
172
173
174/*
175 * These routines decides on what the mode should be (based on the values
176 * of various global variables).
177 */
178
179
180int
181getconnmode(void)
182{
183    extern int linemode;
184    int mode = 0;
185#ifdef	KLUDGELINEMODE
186    extern int kludgelinemode;
187#endif
188
189    if (my_want_state_is_dont(TELOPT_ECHO))
190	mode |= MODE_ECHO;
191
192    if (localflow)
193	mode |= MODE_FLOW;
194
195    if (my_want_state_is_will(TELOPT_BINARY))
196	mode |= MODE_INBIN;
197
198    if (his_want_state_is_will(TELOPT_BINARY))
199	mode |= MODE_OUTBIN;
200
201#ifdef	KLUDGELINEMODE
202    if (kludgelinemode) {
203	if (my_want_state_is_dont(TELOPT_SGA)) {
204	    mode |= (MODE_TRAPSIG|MODE_EDIT);
205	    if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) {
206		mode &= ~MODE_ECHO;
207	    }
208	}
209	return(mode);
210    }
211#endif
212    if (my_want_state_is_will(TELOPT_LINEMODE))
213	mode |= linemode;
214    return(mode);
215}
216
217void
218setconnmode(int force)
219{
220#ifdef	ENCRYPTION
221    static int enc_passwd = 0;
222#endif	/* ENCRYPTION */
223    int newmode;
224
225    newmode = getconnmode()|(force?MODE_FORCE:0);
226
227    TerminalNewMode(newmode);
228
229#ifdef  ENCRYPTION
230    if ((newmode & (MODE_ECHO|MODE_EDIT)) == MODE_EDIT) {
231	if (my_want_state_is_will(TELOPT_ENCRYPT)
232				&& (enc_passwd == 0) && !encrypt_output) {
233	    encrypt_request_start(0, 0);
234	    enc_passwd = 1;
235	}
236    } else {
237	if (enc_passwd) {
238	    encrypt_request_end();
239	    enc_passwd = 0;
240	}
241    }
242#endif	/* ENCRYPTION */
243
244}
245
246void
247setcommandmode(void)
248{
249    TerminalNewMode(-1);
250}
251