1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3*7c478bd9Sstevel@tonic-gate * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate */
5*7c478bd9Sstevel@tonic-gate
6*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
7*7c478bd9Sstevel@tonic-gate
8*7c478bd9Sstevel@tonic-gate /*
9*7c478bd9Sstevel@tonic-gate * Copyright (c) 1988, 1990, 1993
10*7c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved.
11*7c478bd9Sstevel@tonic-gate *
12*7c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without
13*7c478bd9Sstevel@tonic-gate * modification, are permitted provided that the following conditions
14*7c478bd9Sstevel@tonic-gate * are met:
15*7c478bd9Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright
16*7c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer.
17*7c478bd9Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright
18*7c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the
19*7c478bd9Sstevel@tonic-gate * documentation and/or other materials provided with the distribution.
20*7c478bd9Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software
21*7c478bd9Sstevel@tonic-gate * must display the following acknowledgement:
22*7c478bd9Sstevel@tonic-gate * This product includes software developed by the University of
23*7c478bd9Sstevel@tonic-gate * California, Berkeley and its contributors.
24*7c478bd9Sstevel@tonic-gate * 4. Neither the name of the University nor the names of its contributors
25*7c478bd9Sstevel@tonic-gate * may be used to endorse or promote products derived from this software
26*7c478bd9Sstevel@tonic-gate * without specific prior written permission.
27*7c478bd9Sstevel@tonic-gate *
28*7c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29*7c478bd9Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30*7c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31*7c478bd9Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32*7c478bd9Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33*7c478bd9Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34*7c478bd9Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35*7c478bd9Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36*7c478bd9Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37*7c478bd9Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38*7c478bd9Sstevel@tonic-gate * SUCH DAMAGE.
39*7c478bd9Sstevel@tonic-gate */
40*7c478bd9Sstevel@tonic-gate
41*7c478bd9Sstevel@tonic-gate #ifndef lint
42*7c478bd9Sstevel@tonic-gate static char sccsid[] = "@(#)telnet.c 8.1 (Berkeley) 6/6/93";
43*7c478bd9Sstevel@tonic-gate #endif /* not lint */
44*7c478bd9Sstevel@tonic-gate
45*7c478bd9Sstevel@tonic-gate #include <netdb.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
47*7c478bd9Sstevel@tonic-gate
48*7c478bd9Sstevel@tonic-gate #include <curses.h>
49*7c478bd9Sstevel@tonic-gate #include <signal.h>
50*7c478bd9Sstevel@tonic-gate /*
51*7c478bd9Sstevel@tonic-gate * By the way, we need to include curses.h before telnet.h since,
52*7c478bd9Sstevel@tonic-gate * among other things, telnet.h #defines 'DO', which is a variable
53*7c478bd9Sstevel@tonic-gate * declared in curses.h.
54*7c478bd9Sstevel@tonic-gate */
55*7c478bd9Sstevel@tonic-gate
56*7c478bd9Sstevel@tonic-gate #include <arpa/telnet.h>
57*7c478bd9Sstevel@tonic-gate
58*7c478bd9Sstevel@tonic-gate #include <ctype.h>
59*7c478bd9Sstevel@tonic-gate
60*7c478bd9Sstevel@tonic-gate #include "ring.h"
61*7c478bd9Sstevel@tonic-gate
62*7c478bd9Sstevel@tonic-gate #include "defines.h"
63*7c478bd9Sstevel@tonic-gate #include "externs.h"
64*7c478bd9Sstevel@tonic-gate #include "types.h"
65*7c478bd9Sstevel@tonic-gate #include "general.h"
66*7c478bd9Sstevel@tonic-gate
67*7c478bd9Sstevel@tonic-gate #include "auth.h"
68*7c478bd9Sstevel@tonic-gate #include "encrypt.h"
69*7c478bd9Sstevel@tonic-gate
70*7c478bd9Sstevel@tonic-gate #define strip(x) ((x)&0x7f)
71*7c478bd9Sstevel@tonic-gate
72*7c478bd9Sstevel@tonic-gate /* Buffer for sub-options */
73*7c478bd9Sstevel@tonic-gate static unsigned char subbuffer[SUBBUFSIZE];
74*7c478bd9Sstevel@tonic-gate static unsigned char *subpointer;
75*7c478bd9Sstevel@tonic-gate static unsigned char *subend;
76*7c478bd9Sstevel@tonic-gate
77*7c478bd9Sstevel@tonic-gate #define SB_CLEAR() subpointer = subbuffer;
78*7c478bd9Sstevel@tonic-gate #define SB_TERM() { subend = subpointer; SB_CLEAR(); }
79*7c478bd9Sstevel@tonic-gate #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof (subbuffer))) { \
80*7c478bd9Sstevel@tonic-gate *subpointer++ = (c); \
81*7c478bd9Sstevel@tonic-gate }
82*7c478bd9Sstevel@tonic-gate
83*7c478bd9Sstevel@tonic-gate #define SB_GET() ((*subpointer++)&0xff)
84*7c478bd9Sstevel@tonic-gate #define SB_PEEK() ((*subpointer)&0xff)
85*7c478bd9Sstevel@tonic-gate #define SB_EOF() (subpointer >= subend)
86*7c478bd9Sstevel@tonic-gate #define SB_LEN() (subend - subpointer)
87*7c478bd9Sstevel@tonic-gate
88*7c478bd9Sstevel@tonic-gate char options[SUBBUFSIZE]; /* The combined options */
89*7c478bd9Sstevel@tonic-gate char do_dont_resp[SUBBUFSIZE];
90*7c478bd9Sstevel@tonic-gate char will_wont_resp[SUBBUFSIZE];
91*7c478bd9Sstevel@tonic-gate
92*7c478bd9Sstevel@tonic-gate int eight = 0;
93*7c478bd9Sstevel@tonic-gate int autologin = 0; /* Autologin anyone? */
94*7c478bd9Sstevel@tonic-gate int skiprc = 0;
95*7c478bd9Sstevel@tonic-gate int connected;
96*7c478bd9Sstevel@tonic-gate int showoptions;
97*7c478bd9Sstevel@tonic-gate static int ISend; /* trying to send network data in */
98*7c478bd9Sstevel@tonic-gate int debug = 0;
99*7c478bd9Sstevel@tonic-gate int crmod;
100*7c478bd9Sstevel@tonic-gate int netdata; /* Print out network data flow */
101*7c478bd9Sstevel@tonic-gate int crlf; /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
102*7c478bd9Sstevel@tonic-gate int telnetport;
103*7c478bd9Sstevel@tonic-gate int SYNCHing; /* we are in TELNET SYNCH mode */
104*7c478bd9Sstevel@tonic-gate int flushout; /* flush output */
105*7c478bd9Sstevel@tonic-gate int autoflush = 0; /* flush output when interrupting? */
106*7c478bd9Sstevel@tonic-gate int autosynch; /* send interrupt characters with SYNCH? */
107*7c478bd9Sstevel@tonic-gate int localflow; /* we handle flow control locally */
108*7c478bd9Sstevel@tonic-gate int restartany; /* if flow control enabled, restart on any character */
109*7c478bd9Sstevel@tonic-gate int localchars; /* we recognize interrupt/quit */
110*7c478bd9Sstevel@tonic-gate int donelclchars; /* the user has set "localchars" */
111*7c478bd9Sstevel@tonic-gate int donebinarytoggle; /* the user has put us in binary */
112*7c478bd9Sstevel@tonic-gate int dontlecho; /* do we suppress local echoing right now? */
113*7c478bd9Sstevel@tonic-gate int eof_pending = 0; /* we received a genuine EOF on input, send IAC-EOF */
114*7c478bd9Sstevel@tonic-gate int globalmode;
115*7c478bd9Sstevel@tonic-gate
116*7c478bd9Sstevel@tonic-gate /* spin while waiting for authentication */
117*7c478bd9Sstevel@tonic-gate boolean_t scheduler_lockout_tty = B_FALSE;
118*7c478bd9Sstevel@tonic-gate int encrypt_flag = 0;
119*7c478bd9Sstevel@tonic-gate int forwardable_flag = 0;
120*7c478bd9Sstevel@tonic-gate int forward_flag = 0;
121*7c478bd9Sstevel@tonic-gate boolean_t wantencryption = B_FALSE;
122*7c478bd9Sstevel@tonic-gate
123*7c478bd9Sstevel@tonic-gate char *prompt = 0;
124*7c478bd9Sstevel@tonic-gate
125*7c478bd9Sstevel@tonic-gate cc_t escape;
126*7c478bd9Sstevel@tonic-gate cc_t rlogin;
127*7c478bd9Sstevel@tonic-gate boolean_t escape_valid = B_TRUE;
128*7c478bd9Sstevel@tonic-gate #ifdef KLUDGELINEMODE
129*7c478bd9Sstevel@tonic-gate cc_t echoc;
130*7c478bd9Sstevel@tonic-gate #endif
131*7c478bd9Sstevel@tonic-gate
132*7c478bd9Sstevel@tonic-gate /*
133*7c478bd9Sstevel@tonic-gate * Telnet receiver states for fsm
134*7c478bd9Sstevel@tonic-gate */
135*7c478bd9Sstevel@tonic-gate #define TS_DATA 0
136*7c478bd9Sstevel@tonic-gate #define TS_IAC 1
137*7c478bd9Sstevel@tonic-gate #define TS_WILL 2
138*7c478bd9Sstevel@tonic-gate #define TS_WONT 3
139*7c478bd9Sstevel@tonic-gate #define TS_DO 4
140*7c478bd9Sstevel@tonic-gate #define TS_DONT 5
141*7c478bd9Sstevel@tonic-gate #define TS_CR 6
142*7c478bd9Sstevel@tonic-gate #define TS_SB 7 /* sub-option collection */
143*7c478bd9Sstevel@tonic-gate #define TS_SE 8 /* looking for sub-option end */
144*7c478bd9Sstevel@tonic-gate
145*7c478bd9Sstevel@tonic-gate static int telrcv_state;
146*7c478bd9Sstevel@tonic-gate #ifdef OLD_ENVIRON
147*7c478bd9Sstevel@tonic-gate static unsigned char telopt_environ = TELOPT_NEW_ENVIRON;
148*7c478bd9Sstevel@tonic-gate #else
149*7c478bd9Sstevel@tonic-gate #define telopt_environ TELOPT_NEW_ENVIRON
150*7c478bd9Sstevel@tonic-gate #endif
151*7c478bd9Sstevel@tonic-gate
152*7c478bd9Sstevel@tonic-gate jmp_buf toplevel = { 0 };
153*7c478bd9Sstevel@tonic-gate jmp_buf peerdied;
154*7c478bd9Sstevel@tonic-gate
155*7c478bd9Sstevel@tonic-gate static int flushline;
156*7c478bd9Sstevel@tonic-gate int linemode;
157*7c478bd9Sstevel@tonic-gate
158*7c478bd9Sstevel@tonic-gate int reqd_linemode = 0; /* Set if either new or old line mode in */
159*7c478bd9Sstevel@tonic-gate /* effect since before initial negotiations */
160*7c478bd9Sstevel@tonic-gate
161*7c478bd9Sstevel@tonic-gate #ifdef KLUDGELINEMODE
162*7c478bd9Sstevel@tonic-gate int kludgelinemode = 1;
163*7c478bd9Sstevel@tonic-gate #endif
164*7c478bd9Sstevel@tonic-gate
165*7c478bd9Sstevel@tonic-gate /*
166*7c478bd9Sstevel@tonic-gate * The following are some clocks used to decide how to interpret
167*7c478bd9Sstevel@tonic-gate * the relationship between various variables.
168*7c478bd9Sstevel@tonic-gate */
169*7c478bd9Sstevel@tonic-gate
170*7c478bd9Sstevel@tonic-gate Clocks clocks;
171*7c478bd9Sstevel@tonic-gate
172*7c478bd9Sstevel@tonic-gate #ifdef notdef
173*7c478bd9Sstevel@tonic-gate Modelist modelist[] = {
174*7c478bd9Sstevel@tonic-gate { "telnet command mode", COMMAND_LINE },
175*7c478bd9Sstevel@tonic-gate { "character-at-a-time mode", 0 },
176*7c478bd9Sstevel@tonic-gate { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
177*7c478bd9Sstevel@tonic-gate { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
178*7c478bd9Sstevel@tonic-gate { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
179*7c478bd9Sstevel@tonic-gate { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
180*7c478bd9Sstevel@tonic-gate { "3270 mode", 0 },
181*7c478bd9Sstevel@tonic-gate };
182*7c478bd9Sstevel@tonic-gate #endif
183*7c478bd9Sstevel@tonic-gate
184*7c478bd9Sstevel@tonic-gate static void willoption(int);
185*7c478bd9Sstevel@tonic-gate static void wontoption(int);
186*7c478bd9Sstevel@tonic-gate static void lm_will(unsigned char *, int);
187*7c478bd9Sstevel@tonic-gate static void lm_wont(unsigned char *, int);
188*7c478bd9Sstevel@tonic-gate static void lm_do(unsigned char *, int);
189*7c478bd9Sstevel@tonic-gate static void lm_dont(unsigned char *, int);
190*7c478bd9Sstevel@tonic-gate static void slc_init(void);
191*7c478bd9Sstevel@tonic-gate static void slc_import(int);
192*7c478bd9Sstevel@tonic-gate static void slc_export(void);
193*7c478bd9Sstevel@tonic-gate static void slc_start_reply(size_t);
194*7c478bd9Sstevel@tonic-gate static void slc_add_reply(unsigned char, unsigned char, cc_t);
195*7c478bd9Sstevel@tonic-gate static void slc_end_reply(void);
196*7c478bd9Sstevel@tonic-gate static void slc(unsigned char *, int);
197*7c478bd9Sstevel@tonic-gate static int slc_update(void);
198*7c478bd9Sstevel@tonic-gate static void env_opt(unsigned char *, int);
199*7c478bd9Sstevel@tonic-gate static void env_opt_start(void);
200*7c478bd9Sstevel@tonic-gate static void sendeof(void);
201*7c478bd9Sstevel@tonic-gate static int is_unique(register char *, register char **, register char **);
202*7c478bd9Sstevel@tonic-gate
203*7c478bd9Sstevel@tonic-gate /*
204*7c478bd9Sstevel@tonic-gate * Initialize telnet environment.
205*7c478bd9Sstevel@tonic-gate */
206*7c478bd9Sstevel@tonic-gate
207*7c478bd9Sstevel@tonic-gate int
init_telnet()208*7c478bd9Sstevel@tonic-gate init_telnet()
209*7c478bd9Sstevel@tonic-gate {
210*7c478bd9Sstevel@tonic-gate if (env_init() == 0)
211*7c478bd9Sstevel@tonic-gate return (0);
212*7c478bd9Sstevel@tonic-gate
213*7c478bd9Sstevel@tonic-gate SB_CLEAR();
214*7c478bd9Sstevel@tonic-gate ClearArray(options);
215*7c478bd9Sstevel@tonic-gate
216*7c478bd9Sstevel@tonic-gate connected = ISend = localflow = donebinarytoggle = 0;
217*7c478bd9Sstevel@tonic-gate restartany = -1;
218*7c478bd9Sstevel@tonic-gate
219*7c478bd9Sstevel@tonic-gate SYNCHing = 0;
220*7c478bd9Sstevel@tonic-gate
221*7c478bd9Sstevel@tonic-gate /* Don't change NetTrace */
222*7c478bd9Sstevel@tonic-gate
223*7c478bd9Sstevel@tonic-gate escape = CONTROL(']');
224*7c478bd9Sstevel@tonic-gate rlogin = _POSIX_VDISABLE;
225*7c478bd9Sstevel@tonic-gate #ifdef KLUDGELINEMODE
226*7c478bd9Sstevel@tonic-gate echoc = CONTROL('E');
227*7c478bd9Sstevel@tonic-gate #endif
228*7c478bd9Sstevel@tonic-gate
229*7c478bd9Sstevel@tonic-gate flushline = 1;
230*7c478bd9Sstevel@tonic-gate telrcv_state = TS_DATA;
231*7c478bd9Sstevel@tonic-gate
232*7c478bd9Sstevel@tonic-gate return (1);
233*7c478bd9Sstevel@tonic-gate }
234*7c478bd9Sstevel@tonic-gate
235*7c478bd9Sstevel@tonic-gate
236*7c478bd9Sstevel@tonic-gate #ifdef notdef
237*7c478bd9Sstevel@tonic-gate #include <varargs.h>
238*7c478bd9Sstevel@tonic-gate
239*7c478bd9Sstevel@tonic-gate /*VARARGS*/
240*7c478bd9Sstevel@tonic-gate static void
printring(va_alist)241*7c478bd9Sstevel@tonic-gate printring(va_alist)
242*7c478bd9Sstevel@tonic-gate va_dcl
243*7c478bd9Sstevel@tonic-gate {
244*7c478bd9Sstevel@tonic-gate va_list ap;
245*7c478bd9Sstevel@tonic-gate char buffer[100]; /* where things go */
246*7c478bd9Sstevel@tonic-gate char *ptr;
247*7c478bd9Sstevel@tonic-gate char *format;
248*7c478bd9Sstevel@tonic-gate char *string;
249*7c478bd9Sstevel@tonic-gate Ring *ring;
250*7c478bd9Sstevel@tonic-gate int i;
251*7c478bd9Sstevel@tonic-gate
252*7c478bd9Sstevel@tonic-gate va_start(ap);
253*7c478bd9Sstevel@tonic-gate
254*7c478bd9Sstevel@tonic-gate ring = va_arg(ap, Ring *);
255*7c478bd9Sstevel@tonic-gate format = va_arg(ap, char *);
256*7c478bd9Sstevel@tonic-gate ptr = buffer;
257*7c478bd9Sstevel@tonic-gate
258*7c478bd9Sstevel@tonic-gate while ((i = *format++) != 0) {
259*7c478bd9Sstevel@tonic-gate if (i == '%') {
260*7c478bd9Sstevel@tonic-gate i = *format++;
261*7c478bd9Sstevel@tonic-gate switch (i) {
262*7c478bd9Sstevel@tonic-gate case 'c':
263*7c478bd9Sstevel@tonic-gate *ptr++ = va_arg(ap, int);
264*7c478bd9Sstevel@tonic-gate break;
265*7c478bd9Sstevel@tonic-gate case 's':
266*7c478bd9Sstevel@tonic-gate string = va_arg(ap, char *);
267*7c478bd9Sstevel@tonic-gate ring_supply_data(ring, buffer, ptr-buffer);
268*7c478bd9Sstevel@tonic-gate ring_supply_data(ring, string, strlen(string));
269*7c478bd9Sstevel@tonic-gate ptr = buffer;
270*7c478bd9Sstevel@tonic-gate break;
271*7c478bd9Sstevel@tonic-gate case 0:
272*7c478bd9Sstevel@tonic-gate ExitString("printring: trailing %%.\n",
273*7c478bd9Sstevel@tonic-gate EXIT_FAILURE);
274*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/
275*7c478bd9Sstevel@tonic-gate default:
276*7c478bd9Sstevel@tonic-gate ExitString("printring: unknown format "
277*7c478bd9Sstevel@tonic-gate "character.\n", EXIT_FAILURE);
278*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/
279*7c478bd9Sstevel@tonic-gate }
280*7c478bd9Sstevel@tonic-gate } else {
281*7c478bd9Sstevel@tonic-gate *ptr++ = i;
282*7c478bd9Sstevel@tonic-gate }
283*7c478bd9Sstevel@tonic-gate }
284*7c478bd9Sstevel@tonic-gate ring_supply_data(ring, buffer, ptr-buffer);
285*7c478bd9Sstevel@tonic-gate }
286*7c478bd9Sstevel@tonic-gate #endif
287*7c478bd9Sstevel@tonic-gate
288*7c478bd9Sstevel@tonic-gate /*
289*7c478bd9Sstevel@tonic-gate * These routines are in charge of sending option negotiations
290*7c478bd9Sstevel@tonic-gate * to the other side.
291*7c478bd9Sstevel@tonic-gate *
292*7c478bd9Sstevel@tonic-gate * The basic idea is that we send the negotiation if either side
293*7c478bd9Sstevel@tonic-gate * is in disagreement as to what the current state should be.
294*7c478bd9Sstevel@tonic-gate */
295*7c478bd9Sstevel@tonic-gate
296*7c478bd9Sstevel@tonic-gate void
send_do(c,init)297*7c478bd9Sstevel@tonic-gate send_do(c, init)
298*7c478bd9Sstevel@tonic-gate register int c, init;
299*7c478bd9Sstevel@tonic-gate {
300*7c478bd9Sstevel@tonic-gate if (init) {
301*7c478bd9Sstevel@tonic-gate if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
302*7c478bd9Sstevel@tonic-gate my_want_state_is_do(c))
303*7c478bd9Sstevel@tonic-gate return;
304*7c478bd9Sstevel@tonic-gate set_my_want_state_do(c);
305*7c478bd9Sstevel@tonic-gate do_dont_resp[c]++;
306*7c478bd9Sstevel@tonic-gate }
307*7c478bd9Sstevel@tonic-gate NET2ADD(IAC, DO);
308*7c478bd9Sstevel@tonic-gate NETADD(c);
309*7c478bd9Sstevel@tonic-gate printoption("SENT", DO, c);
310*7c478bd9Sstevel@tonic-gate }
311*7c478bd9Sstevel@tonic-gate
312*7c478bd9Sstevel@tonic-gate void
send_dont(c,init)313*7c478bd9Sstevel@tonic-gate send_dont(c, init)
314*7c478bd9Sstevel@tonic-gate register int c, init;
315*7c478bd9Sstevel@tonic-gate {
316*7c478bd9Sstevel@tonic-gate if (init) {
317*7c478bd9Sstevel@tonic-gate if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
318*7c478bd9Sstevel@tonic-gate my_want_state_is_dont(c))
319*7c478bd9Sstevel@tonic-gate return;
320*7c478bd9Sstevel@tonic-gate set_my_want_state_dont(c);
321*7c478bd9Sstevel@tonic-gate do_dont_resp[c]++;
322*7c478bd9Sstevel@tonic-gate }
323*7c478bd9Sstevel@tonic-gate NET2ADD(IAC, DONT);
324*7c478bd9Sstevel@tonic-gate NETADD(c);
325*7c478bd9Sstevel@tonic-gate printoption("SENT", DONT, c);
326*7c478bd9Sstevel@tonic-gate }
327*7c478bd9Sstevel@tonic-gate
328*7c478bd9Sstevel@tonic-gate void
send_will(c,init)329*7c478bd9Sstevel@tonic-gate send_will(c, init)
330*7c478bd9Sstevel@tonic-gate register int c, init;
331*7c478bd9Sstevel@tonic-gate {
332*7c478bd9Sstevel@tonic-gate if (init) {
333*7c478bd9Sstevel@tonic-gate if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
334*7c478bd9Sstevel@tonic-gate my_want_state_is_will(c))
335*7c478bd9Sstevel@tonic-gate return;
336*7c478bd9Sstevel@tonic-gate set_my_want_state_will(c);
337*7c478bd9Sstevel@tonic-gate will_wont_resp[c]++;
338*7c478bd9Sstevel@tonic-gate }
339*7c478bd9Sstevel@tonic-gate NET2ADD(IAC, WILL);
340*7c478bd9Sstevel@tonic-gate NETADD(c);
341*7c478bd9Sstevel@tonic-gate printoption("SENT", WILL, c);
342*7c478bd9Sstevel@tonic-gate }
343*7c478bd9Sstevel@tonic-gate
344*7c478bd9Sstevel@tonic-gate void
send_wont(c,init)345*7c478bd9Sstevel@tonic-gate send_wont(c, init)
346*7c478bd9Sstevel@tonic-gate register int c, init;
347*7c478bd9Sstevel@tonic-gate {
348*7c478bd9Sstevel@tonic-gate if (init) {
349*7c478bd9Sstevel@tonic-gate if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
350*7c478bd9Sstevel@tonic-gate my_want_state_is_wont(c))
351*7c478bd9Sstevel@tonic-gate return;
352*7c478bd9Sstevel@tonic-gate set_my_want_state_wont(c);
353*7c478bd9Sstevel@tonic-gate will_wont_resp[c]++;
354*7c478bd9Sstevel@tonic-gate }
355*7c478bd9Sstevel@tonic-gate NET2ADD(IAC, WONT);
356*7c478bd9Sstevel@tonic-gate NETADD(c);
357*7c478bd9Sstevel@tonic-gate printoption("SENT", WONT, c);
358*7c478bd9Sstevel@tonic-gate }
359*7c478bd9Sstevel@tonic-gate
360*7c478bd9Sstevel@tonic-gate
361*7c478bd9Sstevel@tonic-gate static void
willoption(option)362*7c478bd9Sstevel@tonic-gate willoption(option)
363*7c478bd9Sstevel@tonic-gate int option;
364*7c478bd9Sstevel@tonic-gate {
365*7c478bd9Sstevel@tonic-gate int new_state_ok = 0;
366*7c478bd9Sstevel@tonic-gate
367*7c478bd9Sstevel@tonic-gate if (do_dont_resp[option]) {
368*7c478bd9Sstevel@tonic-gate --do_dont_resp[option];
369*7c478bd9Sstevel@tonic-gate if (do_dont_resp[option] && my_state_is_do(option))
370*7c478bd9Sstevel@tonic-gate --do_dont_resp[option];
371*7c478bd9Sstevel@tonic-gate }
372*7c478bd9Sstevel@tonic-gate
373*7c478bd9Sstevel@tonic-gate if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
374*7c478bd9Sstevel@tonic-gate
375*7c478bd9Sstevel@tonic-gate switch (option) {
376*7c478bd9Sstevel@tonic-gate
377*7c478bd9Sstevel@tonic-gate case TELOPT_ECHO:
378*7c478bd9Sstevel@tonic-gate case TELOPT_SGA:
379*7c478bd9Sstevel@tonic-gate if (reqd_linemode && my_state_is_dont(option)) {
380*7c478bd9Sstevel@tonic-gate break;
381*7c478bd9Sstevel@tonic-gate }
382*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
383*7c478bd9Sstevel@tonic-gate case TELOPT_BINARY:
384*7c478bd9Sstevel@tonic-gate settimer(modenegotiated);
385*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
386*7c478bd9Sstevel@tonic-gate case TELOPT_STATUS:
387*7c478bd9Sstevel@tonic-gate case TELOPT_AUTHENTICATION:
388*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
389*7c478bd9Sstevel@tonic-gate case TELOPT_ENCRYPT:
390*7c478bd9Sstevel@tonic-gate new_state_ok = 1;
391*7c478bd9Sstevel@tonic-gate break;
392*7c478bd9Sstevel@tonic-gate
393*7c478bd9Sstevel@tonic-gate case TELOPT_TM:
394*7c478bd9Sstevel@tonic-gate if (flushout)
395*7c478bd9Sstevel@tonic-gate flushout = 0;
396*7c478bd9Sstevel@tonic-gate /*
397*7c478bd9Sstevel@tonic-gate * Special case for TM. If we get back a WILL,
398*7c478bd9Sstevel@tonic-gate * pretend we got back a WONT.
399*7c478bd9Sstevel@tonic-gate */
400*7c478bd9Sstevel@tonic-gate set_my_want_state_dont(option);
401*7c478bd9Sstevel@tonic-gate set_my_state_dont(option);
402*7c478bd9Sstevel@tonic-gate return; /* Never reply to TM will's/wont's */
403*7c478bd9Sstevel@tonic-gate
404*7c478bd9Sstevel@tonic-gate case TELOPT_LINEMODE:
405*7c478bd9Sstevel@tonic-gate default:
406*7c478bd9Sstevel@tonic-gate break;
407*7c478bd9Sstevel@tonic-gate }
408*7c478bd9Sstevel@tonic-gate
409*7c478bd9Sstevel@tonic-gate if (new_state_ok) {
410*7c478bd9Sstevel@tonic-gate set_my_want_state_do(option);
411*7c478bd9Sstevel@tonic-gate send_do(option, 0);
412*7c478bd9Sstevel@tonic-gate setconnmode(0); /* possibly set new tty mode */
413*7c478bd9Sstevel@tonic-gate } else {
414*7c478bd9Sstevel@tonic-gate do_dont_resp[option]++;
415*7c478bd9Sstevel@tonic-gate send_dont(option, 0);
416*7c478bd9Sstevel@tonic-gate }
417*7c478bd9Sstevel@tonic-gate }
418*7c478bd9Sstevel@tonic-gate set_my_state_do(option);
419*7c478bd9Sstevel@tonic-gate if (option == TELOPT_ENCRYPT)
420*7c478bd9Sstevel@tonic-gate encrypt_send_support();
421*7c478bd9Sstevel@tonic-gate }
422*7c478bd9Sstevel@tonic-gate
423*7c478bd9Sstevel@tonic-gate static void
wontoption(option)424*7c478bd9Sstevel@tonic-gate wontoption(option)
425*7c478bd9Sstevel@tonic-gate int option;
426*7c478bd9Sstevel@tonic-gate {
427*7c478bd9Sstevel@tonic-gate if (do_dont_resp[option]) {
428*7c478bd9Sstevel@tonic-gate --do_dont_resp[option];
429*7c478bd9Sstevel@tonic-gate if (do_dont_resp[option] && my_state_is_dont(option))
430*7c478bd9Sstevel@tonic-gate --do_dont_resp[option];
431*7c478bd9Sstevel@tonic-gate }
432*7c478bd9Sstevel@tonic-gate
433*7c478bd9Sstevel@tonic-gate if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
434*7c478bd9Sstevel@tonic-gate
435*7c478bd9Sstevel@tonic-gate switch (option) {
436*7c478bd9Sstevel@tonic-gate
437*7c478bd9Sstevel@tonic-gate #ifdef KLUDGELINEMODE
438*7c478bd9Sstevel@tonic-gate case TELOPT_SGA:
439*7c478bd9Sstevel@tonic-gate if (!kludgelinemode)
440*7c478bd9Sstevel@tonic-gate break;
441*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
442*7c478bd9Sstevel@tonic-gate #endif
443*7c478bd9Sstevel@tonic-gate case TELOPT_ECHO:
444*7c478bd9Sstevel@tonic-gate settimer(modenegotiated);
445*7c478bd9Sstevel@tonic-gate break;
446*7c478bd9Sstevel@tonic-gate
447*7c478bd9Sstevel@tonic-gate case TELOPT_TM:
448*7c478bd9Sstevel@tonic-gate if (flushout)
449*7c478bd9Sstevel@tonic-gate flushout = 0;
450*7c478bd9Sstevel@tonic-gate set_my_want_state_dont(option);
451*7c478bd9Sstevel@tonic-gate set_my_state_dont(option);
452*7c478bd9Sstevel@tonic-gate return; /* Never reply to TM will's/wont's */
453*7c478bd9Sstevel@tonic-gate
454*7c478bd9Sstevel@tonic-gate default:
455*7c478bd9Sstevel@tonic-gate break;
456*7c478bd9Sstevel@tonic-gate }
457*7c478bd9Sstevel@tonic-gate set_my_want_state_dont(option);
458*7c478bd9Sstevel@tonic-gate if (my_state_is_do(option))
459*7c478bd9Sstevel@tonic-gate send_dont(option, 0);
460*7c478bd9Sstevel@tonic-gate setconnmode(0); /* Set new tty mode */
461*7c478bd9Sstevel@tonic-gate } else if (option == TELOPT_TM) {
462*7c478bd9Sstevel@tonic-gate /*
463*7c478bd9Sstevel@tonic-gate * Special case for TM.
464*7c478bd9Sstevel@tonic-gate */
465*7c478bd9Sstevel@tonic-gate if (flushout)
466*7c478bd9Sstevel@tonic-gate flushout = 0;
467*7c478bd9Sstevel@tonic-gate set_my_want_state_dont(option);
468*7c478bd9Sstevel@tonic-gate }
469*7c478bd9Sstevel@tonic-gate set_my_state_dont(option);
470*7c478bd9Sstevel@tonic-gate }
471*7c478bd9Sstevel@tonic-gate
472*7c478bd9Sstevel@tonic-gate static void
dooption(option)473*7c478bd9Sstevel@tonic-gate dooption(option)
474*7c478bd9Sstevel@tonic-gate int option;
475*7c478bd9Sstevel@tonic-gate {
476*7c478bd9Sstevel@tonic-gate int new_state_ok = 0;
477*7c478bd9Sstevel@tonic-gate
478*7c478bd9Sstevel@tonic-gate if (will_wont_resp[option]) {
479*7c478bd9Sstevel@tonic-gate --will_wont_resp[option];
480*7c478bd9Sstevel@tonic-gate if (will_wont_resp[option] && my_state_is_will(option))
481*7c478bd9Sstevel@tonic-gate --will_wont_resp[option];
482*7c478bd9Sstevel@tonic-gate }
483*7c478bd9Sstevel@tonic-gate
484*7c478bd9Sstevel@tonic-gate if (will_wont_resp[option] == 0) {
485*7c478bd9Sstevel@tonic-gate if (my_want_state_is_wont(option)) {
486*7c478bd9Sstevel@tonic-gate
487*7c478bd9Sstevel@tonic-gate switch (option) {
488*7c478bd9Sstevel@tonic-gate
489*7c478bd9Sstevel@tonic-gate case TELOPT_TM:
490*7c478bd9Sstevel@tonic-gate /*
491*7c478bd9Sstevel@tonic-gate * Special case for TM. We send a WILL,
492*7c478bd9Sstevel@tonic-gate * but pretend we sent WONT.
493*7c478bd9Sstevel@tonic-gate */
494*7c478bd9Sstevel@tonic-gate send_will(option, 0);
495*7c478bd9Sstevel@tonic-gate set_my_want_state_wont(TELOPT_TM);
496*7c478bd9Sstevel@tonic-gate set_my_state_wont(TELOPT_TM);
497*7c478bd9Sstevel@tonic-gate return;
498*7c478bd9Sstevel@tonic-gate
499*7c478bd9Sstevel@tonic-gate case TELOPT_BINARY: /* binary mode */
500*7c478bd9Sstevel@tonic-gate case TELOPT_NAWS: /* window size */
501*7c478bd9Sstevel@tonic-gate case TELOPT_TSPEED: /* terminal speed */
502*7c478bd9Sstevel@tonic-gate case TELOPT_LFLOW: /* local flow control */
503*7c478bd9Sstevel@tonic-gate case TELOPT_TTYPE: /* terminal type option */
504*7c478bd9Sstevel@tonic-gate case TELOPT_SGA: /* no big deal */
505*7c478bd9Sstevel@tonic-gate case TELOPT_ENCRYPT: /* encryption variable option */
506*7c478bd9Sstevel@tonic-gate new_state_ok = 1;
507*7c478bd9Sstevel@tonic-gate break;
508*7c478bd9Sstevel@tonic-gate
509*7c478bd9Sstevel@tonic-gate case TELOPT_NEW_ENVIRON:
510*7c478bd9Sstevel@tonic-gate /* New environment variable option */
511*7c478bd9Sstevel@tonic-gate #ifdef OLD_ENVIRON
512*7c478bd9Sstevel@tonic-gate if (my_state_is_will(TELOPT_OLD_ENVIRON))
513*7c478bd9Sstevel@tonic-gate /* turn off the old */
514*7c478bd9Sstevel@tonic-gate send_wont(TELOPT_OLD_ENVIRON, 1);
515*7c478bd9Sstevel@tonic-gate goto env_common;
516*7c478bd9Sstevel@tonic-gate case TELOPT_OLD_ENVIRON:
517*7c478bd9Sstevel@tonic-gate /* Old environment variable option */
518*7c478bd9Sstevel@tonic-gate if (my_state_is_will(TELOPT_NEW_ENVIRON))
519*7c478bd9Sstevel@tonic-gate /* Don't enable if new one is in use! */
520*7c478bd9Sstevel@tonic-gate break;
521*7c478bd9Sstevel@tonic-gate env_common:
522*7c478bd9Sstevel@tonic-gate telopt_environ = option;
523*7c478bd9Sstevel@tonic-gate #endif
524*7c478bd9Sstevel@tonic-gate new_state_ok = 1;
525*7c478bd9Sstevel@tonic-gate break;
526*7c478bd9Sstevel@tonic-gate
527*7c478bd9Sstevel@tonic-gate case TELOPT_AUTHENTICATION:
528*7c478bd9Sstevel@tonic-gate if (autologin)
529*7c478bd9Sstevel@tonic-gate new_state_ok = 1;
530*7c478bd9Sstevel@tonic-gate break;
531*7c478bd9Sstevel@tonic-gate
532*7c478bd9Sstevel@tonic-gate case TELOPT_XDISPLOC: /* X Display location */
533*7c478bd9Sstevel@tonic-gate if (env_getvalue((unsigned char *)"DISPLAY"))
534*7c478bd9Sstevel@tonic-gate new_state_ok = 1;
535*7c478bd9Sstevel@tonic-gate break;
536*7c478bd9Sstevel@tonic-gate
537*7c478bd9Sstevel@tonic-gate case TELOPT_LINEMODE:
538*7c478bd9Sstevel@tonic-gate #ifdef KLUDGELINEMODE
539*7c478bd9Sstevel@tonic-gate kludgelinemode = 0;
540*7c478bd9Sstevel@tonic-gate send_do(TELOPT_SGA, 1);
541*7c478bd9Sstevel@tonic-gate #endif
542*7c478bd9Sstevel@tonic-gate set_my_want_state_will(TELOPT_LINEMODE);
543*7c478bd9Sstevel@tonic-gate send_will(option, 0);
544*7c478bd9Sstevel@tonic-gate set_my_state_will(TELOPT_LINEMODE);
545*7c478bd9Sstevel@tonic-gate slc_init();
546*7c478bd9Sstevel@tonic-gate return;
547*7c478bd9Sstevel@tonic-gate
548*7c478bd9Sstevel@tonic-gate case TELOPT_ECHO: /* We're never going to echo... */
549*7c478bd9Sstevel@tonic-gate default:
550*7c478bd9Sstevel@tonic-gate break;
551*7c478bd9Sstevel@tonic-gate }
552*7c478bd9Sstevel@tonic-gate
553*7c478bd9Sstevel@tonic-gate if (new_state_ok) {
554*7c478bd9Sstevel@tonic-gate set_my_want_state_will(option);
555*7c478bd9Sstevel@tonic-gate send_will(option, 0);
556*7c478bd9Sstevel@tonic-gate setconnmode(0); /* Set new tty mode */
557*7c478bd9Sstevel@tonic-gate } else {
558*7c478bd9Sstevel@tonic-gate will_wont_resp[option]++;
559*7c478bd9Sstevel@tonic-gate send_wont(option, 0);
560*7c478bd9Sstevel@tonic-gate }
561*7c478bd9Sstevel@tonic-gate } else {
562*7c478bd9Sstevel@tonic-gate /*
563*7c478bd9Sstevel@tonic-gate * Handle options that need more things done after the
564*7c478bd9Sstevel@tonic-gate * other side has acknowledged the option.
565*7c478bd9Sstevel@tonic-gate */
566*7c478bd9Sstevel@tonic-gate switch (option) {
567*7c478bd9Sstevel@tonic-gate case TELOPT_LINEMODE:
568*7c478bd9Sstevel@tonic-gate #ifdef KLUDGELINEMODE
569*7c478bd9Sstevel@tonic-gate kludgelinemode = 0;
570*7c478bd9Sstevel@tonic-gate send_do(TELOPT_SGA, 1);
571*7c478bd9Sstevel@tonic-gate #endif
572*7c478bd9Sstevel@tonic-gate set_my_state_will(option);
573*7c478bd9Sstevel@tonic-gate slc_init();
574*7c478bd9Sstevel@tonic-gate send_do(TELOPT_SGA, 0);
575*7c478bd9Sstevel@tonic-gate return;
576*7c478bd9Sstevel@tonic-gate }
577*7c478bd9Sstevel@tonic-gate }
578*7c478bd9Sstevel@tonic-gate }
579*7c478bd9Sstevel@tonic-gate set_my_state_will(option);
580*7c478bd9Sstevel@tonic-gate }
581*7c478bd9Sstevel@tonic-gate
582*7c478bd9Sstevel@tonic-gate static void
dontoption(option)583*7c478bd9Sstevel@tonic-gate dontoption(option)
584*7c478bd9Sstevel@tonic-gate int option;
585*7c478bd9Sstevel@tonic-gate {
586*7c478bd9Sstevel@tonic-gate
587*7c478bd9Sstevel@tonic-gate if (will_wont_resp[option]) {
588*7c478bd9Sstevel@tonic-gate --will_wont_resp[option];
589*7c478bd9Sstevel@tonic-gate if (will_wont_resp[option] && my_state_is_wont(option))
590*7c478bd9Sstevel@tonic-gate --will_wont_resp[option];
591*7c478bd9Sstevel@tonic-gate }
592*7c478bd9Sstevel@tonic-gate
593*7c478bd9Sstevel@tonic-gate if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
594*7c478bd9Sstevel@tonic-gate switch (option) {
595*7c478bd9Sstevel@tonic-gate case TELOPT_LINEMODE:
596*7c478bd9Sstevel@tonic-gate linemode = 0; /* put us back to the default state */
597*7c478bd9Sstevel@tonic-gate break;
598*7c478bd9Sstevel@tonic-gate #ifdef OLD_ENVIRON
599*7c478bd9Sstevel@tonic-gate case TELOPT_NEW_ENVIRON:
600*7c478bd9Sstevel@tonic-gate /*
601*7c478bd9Sstevel@tonic-gate * The new environ option wasn't recognized, try
602*7c478bd9Sstevel@tonic-gate * the old one.
603*7c478bd9Sstevel@tonic-gate */
604*7c478bd9Sstevel@tonic-gate send_will(TELOPT_OLD_ENVIRON, 1);
605*7c478bd9Sstevel@tonic-gate telopt_environ = TELOPT_OLD_ENVIRON;
606*7c478bd9Sstevel@tonic-gate break;
607*7c478bd9Sstevel@tonic-gate #endif
608*7c478bd9Sstevel@tonic-gate }
609*7c478bd9Sstevel@tonic-gate /* we always accept a DONT */
610*7c478bd9Sstevel@tonic-gate set_my_want_state_wont(option);
611*7c478bd9Sstevel@tonic-gate if (my_state_is_will(option))
612*7c478bd9Sstevel@tonic-gate send_wont(option, 0);
613*7c478bd9Sstevel@tonic-gate setconnmode(0); /* Set new tty mode */
614*7c478bd9Sstevel@tonic-gate }
615*7c478bd9Sstevel@tonic-gate set_my_state_wont(option);
616*7c478bd9Sstevel@tonic-gate }
617*7c478bd9Sstevel@tonic-gate
618*7c478bd9Sstevel@tonic-gate /*
619*7c478bd9Sstevel@tonic-gate * Given a buffer returned by tgetent(), this routine will turn
620*7c478bd9Sstevel@tonic-gate * the pipe seperated list of names in the buffer into an array
621*7c478bd9Sstevel@tonic-gate * of pointers to null terminated names. We toss out any bad,
622*7c478bd9Sstevel@tonic-gate * duplicate, or verbose names (names with spaces).
623*7c478bd9Sstevel@tonic-gate */
624*7c478bd9Sstevel@tonic-gate
625*7c478bd9Sstevel@tonic-gate static char *name_unknown = "UNKNOWN";
626*7c478bd9Sstevel@tonic-gate static char *unknown[] = { 0, 0 };
627*7c478bd9Sstevel@tonic-gate
628*7c478bd9Sstevel@tonic-gate static char **
mklist(buf,name)629*7c478bd9Sstevel@tonic-gate mklist(buf, name)
630*7c478bd9Sstevel@tonic-gate char *buf, *name;
631*7c478bd9Sstevel@tonic-gate {
632*7c478bd9Sstevel@tonic-gate register int n;
633*7c478bd9Sstevel@tonic-gate register char c, *cp, **argvp, *cp2, **argv, **avt;
634*7c478bd9Sstevel@tonic-gate
635*7c478bd9Sstevel@tonic-gate if (name) {
636*7c478bd9Sstevel@tonic-gate if (strlen(name) > 40u) {
637*7c478bd9Sstevel@tonic-gate name = 0;
638*7c478bd9Sstevel@tonic-gate unknown[0] = name_unknown;
639*7c478bd9Sstevel@tonic-gate } else {
640*7c478bd9Sstevel@tonic-gate unknown[0] = name;
641*7c478bd9Sstevel@tonic-gate upcase(name);
642*7c478bd9Sstevel@tonic-gate }
643*7c478bd9Sstevel@tonic-gate } else
644*7c478bd9Sstevel@tonic-gate unknown[0] = name_unknown;
645*7c478bd9Sstevel@tonic-gate /*
646*7c478bd9Sstevel@tonic-gate * Count up the number of names.
647*7c478bd9Sstevel@tonic-gate */
648*7c478bd9Sstevel@tonic-gate for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
649*7c478bd9Sstevel@tonic-gate if (*cp == '|')
650*7c478bd9Sstevel@tonic-gate n++;
651*7c478bd9Sstevel@tonic-gate }
652*7c478bd9Sstevel@tonic-gate /*
653*7c478bd9Sstevel@tonic-gate * Allocate an array to put the name pointers into
654*7c478bd9Sstevel@tonic-gate */
655*7c478bd9Sstevel@tonic-gate argv = malloc((n+3)*sizeof (char *));
656*7c478bd9Sstevel@tonic-gate if (argv == 0)
657*7c478bd9Sstevel@tonic-gate return (unknown);
658*7c478bd9Sstevel@tonic-gate
659*7c478bd9Sstevel@tonic-gate /*
660*7c478bd9Sstevel@tonic-gate * Fill up the array of pointers to names.
661*7c478bd9Sstevel@tonic-gate */
662*7c478bd9Sstevel@tonic-gate *argv = 0;
663*7c478bd9Sstevel@tonic-gate argvp = argv+1;
664*7c478bd9Sstevel@tonic-gate n = 0;
665*7c478bd9Sstevel@tonic-gate for (cp = cp2 = buf; (c = *cp) != NULL; cp++) {
666*7c478bd9Sstevel@tonic-gate if (c == '|' || c == ':') {
667*7c478bd9Sstevel@tonic-gate *cp++ = '\0';
668*7c478bd9Sstevel@tonic-gate /*
669*7c478bd9Sstevel@tonic-gate * Skip entries that have spaces or are over 40
670*7c478bd9Sstevel@tonic-gate * characters long. If this is our environment
671*7c478bd9Sstevel@tonic-gate * name, then put it up front. Otherwise, as
672*7c478bd9Sstevel@tonic-gate * long as this is not a duplicate name (case
673*7c478bd9Sstevel@tonic-gate * insensitive) add it to the list.
674*7c478bd9Sstevel@tonic-gate */
675*7c478bd9Sstevel@tonic-gate if (n || (cp - cp2 > 41))
676*7c478bd9Sstevel@tonic-gate /* EMPTY */;
677*7c478bd9Sstevel@tonic-gate else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
678*7c478bd9Sstevel@tonic-gate *argv = cp2;
679*7c478bd9Sstevel@tonic-gate else if (is_unique(cp2, argv+1, argvp))
680*7c478bd9Sstevel@tonic-gate *argvp++ = cp2;
681*7c478bd9Sstevel@tonic-gate if (c == ':')
682*7c478bd9Sstevel@tonic-gate break;
683*7c478bd9Sstevel@tonic-gate /*
684*7c478bd9Sstevel@tonic-gate * Skip multiple delimiters. Reset cp2 to
685*7c478bd9Sstevel@tonic-gate * the beginning of the next name. Reset n,
686*7c478bd9Sstevel@tonic-gate * the flag for names with spaces.
687*7c478bd9Sstevel@tonic-gate */
688*7c478bd9Sstevel@tonic-gate while ((c = *cp) == '|')
689*7c478bd9Sstevel@tonic-gate cp++;
690*7c478bd9Sstevel@tonic-gate cp2 = cp;
691*7c478bd9Sstevel@tonic-gate n = 0;
692*7c478bd9Sstevel@tonic-gate }
693*7c478bd9Sstevel@tonic-gate /*
694*7c478bd9Sstevel@tonic-gate * Skip entries with spaces or non-ascii values.
695*7c478bd9Sstevel@tonic-gate * Convert lower case letters to upper case.
696*7c478bd9Sstevel@tonic-gate */
697*7c478bd9Sstevel@tonic-gate if ((c == ' ') || !isascii(c))
698*7c478bd9Sstevel@tonic-gate n = 1;
699*7c478bd9Sstevel@tonic-gate else if (islower(c))
700*7c478bd9Sstevel@tonic-gate *cp = toupper(c);
701*7c478bd9Sstevel@tonic-gate }
702*7c478bd9Sstevel@tonic-gate
703*7c478bd9Sstevel@tonic-gate /*
704*7c478bd9Sstevel@tonic-gate * Check for an old V6 2 character name. If the second
705*7c478bd9Sstevel@tonic-gate * name points to the beginning of the buffer, and is
706*7c478bd9Sstevel@tonic-gate * only 2 characters long, move it to the end of the array.
707*7c478bd9Sstevel@tonic-gate */
708*7c478bd9Sstevel@tonic-gate if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
709*7c478bd9Sstevel@tonic-gate --argvp;
710*7c478bd9Sstevel@tonic-gate for (avt = &argv[1]; avt < argvp; avt++)
711*7c478bd9Sstevel@tonic-gate *avt = *(avt+1);
712*7c478bd9Sstevel@tonic-gate *argvp++ = buf;
713*7c478bd9Sstevel@tonic-gate }
714*7c478bd9Sstevel@tonic-gate
715*7c478bd9Sstevel@tonic-gate /*
716*7c478bd9Sstevel@tonic-gate * Duplicate last name, for TTYPE option, and null
717*7c478bd9Sstevel@tonic-gate * terminate the array. If we didn't find a match on
718*7c478bd9Sstevel@tonic-gate * our terminal name, put that name at the beginning.
719*7c478bd9Sstevel@tonic-gate */
720*7c478bd9Sstevel@tonic-gate cp = *(argvp-1);
721*7c478bd9Sstevel@tonic-gate *argvp++ = cp;
722*7c478bd9Sstevel@tonic-gate *argvp = 0;
723*7c478bd9Sstevel@tonic-gate
724*7c478bd9Sstevel@tonic-gate if (*argv == 0) {
725*7c478bd9Sstevel@tonic-gate if (name)
726*7c478bd9Sstevel@tonic-gate *argv = name;
727*7c478bd9Sstevel@tonic-gate else {
728*7c478bd9Sstevel@tonic-gate --argvp;
729*7c478bd9Sstevel@tonic-gate for (avt = argv; avt < argvp; avt++)
730*7c478bd9Sstevel@tonic-gate *avt = *(avt+1);
731*7c478bd9Sstevel@tonic-gate }
732*7c478bd9Sstevel@tonic-gate }
733*7c478bd9Sstevel@tonic-gate if (*argv)
734*7c478bd9Sstevel@tonic-gate return (argv);
735*7c478bd9Sstevel@tonic-gate else
736*7c478bd9Sstevel@tonic-gate return (unknown);
737*7c478bd9Sstevel@tonic-gate }
738*7c478bd9Sstevel@tonic-gate
739*7c478bd9Sstevel@tonic-gate static int
is_unique(name,as,ae)740*7c478bd9Sstevel@tonic-gate is_unique(name, as, ae)
741*7c478bd9Sstevel@tonic-gate register char *name, **as, **ae;
742*7c478bd9Sstevel@tonic-gate {
743*7c478bd9Sstevel@tonic-gate register char **ap;
744*7c478bd9Sstevel@tonic-gate register int n;
745*7c478bd9Sstevel@tonic-gate
746*7c478bd9Sstevel@tonic-gate n = strlen(name) + 1;
747*7c478bd9Sstevel@tonic-gate for (ap = as; ap < ae; ap++)
748*7c478bd9Sstevel@tonic-gate if (strncasecmp(*ap, name, n) == 0)
749*7c478bd9Sstevel@tonic-gate return (0);
750*7c478bd9Sstevel@tonic-gate return (1);
751*7c478bd9Sstevel@tonic-gate }
752*7c478bd9Sstevel@tonic-gate
753*7c478bd9Sstevel@tonic-gate #define termbuf ttytype
754*7c478bd9Sstevel@tonic-gate extern char ttytype[];
755*7c478bd9Sstevel@tonic-gate
756*7c478bd9Sstevel@tonic-gate int resettermname = 1;
757*7c478bd9Sstevel@tonic-gate
758*7c478bd9Sstevel@tonic-gate static char *
gettermname(void)759*7c478bd9Sstevel@tonic-gate gettermname(void)
760*7c478bd9Sstevel@tonic-gate {
761*7c478bd9Sstevel@tonic-gate char *tname;
762*7c478bd9Sstevel@tonic-gate static char **tnamep = 0;
763*7c478bd9Sstevel@tonic-gate static char **next;
764*7c478bd9Sstevel@tonic-gate int err;
765*7c478bd9Sstevel@tonic-gate
766*7c478bd9Sstevel@tonic-gate if (resettermname) {
767*7c478bd9Sstevel@tonic-gate resettermname = 0;
768*7c478bd9Sstevel@tonic-gate if (tnamep && tnamep != unknown)
769*7c478bd9Sstevel@tonic-gate free(tnamep);
770*7c478bd9Sstevel@tonic-gate tname = (char *)env_getvalue((unsigned char *)"TERM");
771*7c478bd9Sstevel@tonic-gate if ((tname != NULL) && (setupterm(tname, 1, &err) == 0)) {
772*7c478bd9Sstevel@tonic-gate tnamep = mklist(termbuf, tname);
773*7c478bd9Sstevel@tonic-gate } else {
774*7c478bd9Sstevel@tonic-gate if (tname && (strlen(tname) <= 40u)) {
775*7c478bd9Sstevel@tonic-gate unknown[0] = tname;
776*7c478bd9Sstevel@tonic-gate upcase(tname);
777*7c478bd9Sstevel@tonic-gate } else
778*7c478bd9Sstevel@tonic-gate unknown[0] = name_unknown;
779*7c478bd9Sstevel@tonic-gate tnamep = unknown;
780*7c478bd9Sstevel@tonic-gate }
781*7c478bd9Sstevel@tonic-gate next = tnamep;
782*7c478bd9Sstevel@tonic-gate }
783*7c478bd9Sstevel@tonic-gate if (*next == 0)
784*7c478bd9Sstevel@tonic-gate next = tnamep;
785*7c478bd9Sstevel@tonic-gate return (*next++);
786*7c478bd9Sstevel@tonic-gate }
787*7c478bd9Sstevel@tonic-gate /*
788*7c478bd9Sstevel@tonic-gate * suboption()
789*7c478bd9Sstevel@tonic-gate *
790*7c478bd9Sstevel@tonic-gate * Look at the sub-option buffer, and try to be helpful to the other
791*7c478bd9Sstevel@tonic-gate * side.
792*7c478bd9Sstevel@tonic-gate *
793*7c478bd9Sstevel@tonic-gate * Currently we recognize:
794*7c478bd9Sstevel@tonic-gate *
795*7c478bd9Sstevel@tonic-gate * Terminal type, send request.
796*7c478bd9Sstevel@tonic-gate * Terminal speed (send request).
797*7c478bd9Sstevel@tonic-gate * Local flow control (is request).
798*7c478bd9Sstevel@tonic-gate * Linemode
799*7c478bd9Sstevel@tonic-gate */
800*7c478bd9Sstevel@tonic-gate
801*7c478bd9Sstevel@tonic-gate static void
suboption()802*7c478bd9Sstevel@tonic-gate suboption()
803*7c478bd9Sstevel@tonic-gate {
804*7c478bd9Sstevel@tonic-gate unsigned char subchar;
805*7c478bd9Sstevel@tonic-gate
806*7c478bd9Sstevel@tonic-gate printsub('<', subbuffer, SB_LEN()+2);
807*7c478bd9Sstevel@tonic-gate switch (subchar = SB_GET()) {
808*7c478bd9Sstevel@tonic-gate case TELOPT_TTYPE:
809*7c478bd9Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_TTYPE))
810*7c478bd9Sstevel@tonic-gate return;
811*7c478bd9Sstevel@tonic-gate if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
812*7c478bd9Sstevel@tonic-gate return;
813*7c478bd9Sstevel@tonic-gate } else {
814*7c478bd9Sstevel@tonic-gate char *name;
815*7c478bd9Sstevel@tonic-gate unsigned char temp[50];
816*7c478bd9Sstevel@tonic-gate int len, bytes;
817*7c478bd9Sstevel@tonic-gate
818*7c478bd9Sstevel@tonic-gate name = gettermname();
819*7c478bd9Sstevel@tonic-gate len = strlen(name) + 4 + 2;
820*7c478bd9Sstevel@tonic-gate bytes = snprintf((char *)temp, sizeof (temp),
821*7c478bd9Sstevel@tonic-gate "%c%c%c%c%s%c%c", IAC, SB,
822*7c478bd9Sstevel@tonic-gate TELOPT_TTYPE, TELQUAL_IS, name, IAC, SE);
823*7c478bd9Sstevel@tonic-gate if ((len < NETROOM()) && (bytes < sizeof (temp))) {
824*7c478bd9Sstevel@tonic-gate ring_supply_data(&netoring, temp, len);
825*7c478bd9Sstevel@tonic-gate printsub('>', &temp[2], len-2);
826*7c478bd9Sstevel@tonic-gate } else {
827*7c478bd9Sstevel@tonic-gate ExitString("No room in buffer for "
828*7c478bd9Sstevel@tonic-gate "terminal type.\n", EXIT_FAILURE);
829*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/
830*7c478bd9Sstevel@tonic-gate }
831*7c478bd9Sstevel@tonic-gate }
832*7c478bd9Sstevel@tonic-gate break;
833*7c478bd9Sstevel@tonic-gate case TELOPT_TSPEED:
834*7c478bd9Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_TSPEED))
835*7c478bd9Sstevel@tonic-gate return;
836*7c478bd9Sstevel@tonic-gate if (SB_EOF())
837*7c478bd9Sstevel@tonic-gate return;
838*7c478bd9Sstevel@tonic-gate if (SB_GET() == TELQUAL_SEND) {
839*7c478bd9Sstevel@tonic-gate int ospeed, ispeed;
840*7c478bd9Sstevel@tonic-gate unsigned char temp[50];
841*7c478bd9Sstevel@tonic-gate int len, bytes;
842*7c478bd9Sstevel@tonic-gate
843*7c478bd9Sstevel@tonic-gate TerminalSpeeds(&ispeed, &ospeed);
844*7c478bd9Sstevel@tonic-gate
845*7c478bd9Sstevel@tonic-gate bytes = snprintf((char *)temp, sizeof (temp),
846*7c478bd9Sstevel@tonic-gate "%c%c%c%c%d,%d%c%c", IAC, SB,
847*7c478bd9Sstevel@tonic-gate TELOPT_TSPEED, TELQUAL_IS, ospeed, ispeed, IAC, SE);
848*7c478bd9Sstevel@tonic-gate len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
849*7c478bd9Sstevel@tonic-gate
850*7c478bd9Sstevel@tonic-gate if ((len < NETROOM()) && (bytes < sizeof (temp))) {
851*7c478bd9Sstevel@tonic-gate ring_supply_data(&netoring, temp, len);
852*7c478bd9Sstevel@tonic-gate printsub('>', temp+2, len - 2);
853*7c478bd9Sstevel@tonic-gate }
854*7c478bd9Sstevel@tonic-gate else
855*7c478bd9Sstevel@tonic-gate (void) printf(
856*7c478bd9Sstevel@tonic-gate "telnet: not enough room in buffer "
857*7c478bd9Sstevel@tonic-gate "for terminal speed option reply\n");
858*7c478bd9Sstevel@tonic-gate }
859*7c478bd9Sstevel@tonic-gate break;
860*7c478bd9Sstevel@tonic-gate case TELOPT_LFLOW:
861*7c478bd9Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_LFLOW))
862*7c478bd9Sstevel@tonic-gate return;
863*7c478bd9Sstevel@tonic-gate if (SB_EOF())
864*7c478bd9Sstevel@tonic-gate return;
865*7c478bd9Sstevel@tonic-gate switch (SB_GET()) {
866*7c478bd9Sstevel@tonic-gate case LFLOW_RESTART_ANY:
867*7c478bd9Sstevel@tonic-gate restartany = 1;
868*7c478bd9Sstevel@tonic-gate break;
869*7c478bd9Sstevel@tonic-gate case LFLOW_RESTART_XON:
870*7c478bd9Sstevel@tonic-gate restartany = 0;
871*7c478bd9Sstevel@tonic-gate break;
872*7c478bd9Sstevel@tonic-gate case LFLOW_ON:
873*7c478bd9Sstevel@tonic-gate localflow = 1;
874*7c478bd9Sstevel@tonic-gate break;
875*7c478bd9Sstevel@tonic-gate case LFLOW_OFF:
876*7c478bd9Sstevel@tonic-gate localflow = 0;
877*7c478bd9Sstevel@tonic-gate break;
878*7c478bd9Sstevel@tonic-gate default:
879*7c478bd9Sstevel@tonic-gate return;
880*7c478bd9Sstevel@tonic-gate }
881*7c478bd9Sstevel@tonic-gate setcommandmode();
882*7c478bd9Sstevel@tonic-gate setconnmode(0);
883*7c478bd9Sstevel@tonic-gate break;
884*7c478bd9Sstevel@tonic-gate
885*7c478bd9Sstevel@tonic-gate case TELOPT_LINEMODE:
886*7c478bd9Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_LINEMODE))
887*7c478bd9Sstevel@tonic-gate return;
888*7c478bd9Sstevel@tonic-gate if (SB_EOF())
889*7c478bd9Sstevel@tonic-gate return;
890*7c478bd9Sstevel@tonic-gate switch (SB_GET()) {
891*7c478bd9Sstevel@tonic-gate case WILL:
892*7c478bd9Sstevel@tonic-gate lm_will(subpointer, SB_LEN());
893*7c478bd9Sstevel@tonic-gate break;
894*7c478bd9Sstevel@tonic-gate case WONT:
895*7c478bd9Sstevel@tonic-gate lm_wont(subpointer, SB_LEN());
896*7c478bd9Sstevel@tonic-gate break;
897*7c478bd9Sstevel@tonic-gate case DO:
898*7c478bd9Sstevel@tonic-gate lm_do(subpointer, SB_LEN());
899*7c478bd9Sstevel@tonic-gate break;
900*7c478bd9Sstevel@tonic-gate case DONT:
901*7c478bd9Sstevel@tonic-gate lm_dont(subpointer, SB_LEN());
902*7c478bd9Sstevel@tonic-gate break;
903*7c478bd9Sstevel@tonic-gate case LM_SLC:
904*7c478bd9Sstevel@tonic-gate slc(subpointer, SB_LEN());
905*7c478bd9Sstevel@tonic-gate break;
906*7c478bd9Sstevel@tonic-gate case LM_MODE:
907*7c478bd9Sstevel@tonic-gate lm_mode(subpointer, SB_LEN(), 0);
908*7c478bd9Sstevel@tonic-gate break;
909*7c478bd9Sstevel@tonic-gate default:
910*7c478bd9Sstevel@tonic-gate break;
911*7c478bd9Sstevel@tonic-gate }
912*7c478bd9Sstevel@tonic-gate break;
913*7c478bd9Sstevel@tonic-gate
914*7c478bd9Sstevel@tonic-gate #ifdef OLD_ENVIRON
915*7c478bd9Sstevel@tonic-gate case TELOPT_OLD_ENVIRON:
916*7c478bd9Sstevel@tonic-gate #endif
917*7c478bd9Sstevel@tonic-gate case TELOPT_NEW_ENVIRON:
918*7c478bd9Sstevel@tonic-gate if (SB_EOF())
919*7c478bd9Sstevel@tonic-gate return;
920*7c478bd9Sstevel@tonic-gate switch (SB_PEEK()) {
921*7c478bd9Sstevel@tonic-gate case TELQUAL_IS:
922*7c478bd9Sstevel@tonic-gate case TELQUAL_INFO:
923*7c478bd9Sstevel@tonic-gate if (my_want_state_is_dont(subchar))
924*7c478bd9Sstevel@tonic-gate return;
925*7c478bd9Sstevel@tonic-gate break;
926*7c478bd9Sstevel@tonic-gate case TELQUAL_SEND:
927*7c478bd9Sstevel@tonic-gate if (my_want_state_is_wont(subchar)) {
928*7c478bd9Sstevel@tonic-gate return;
929*7c478bd9Sstevel@tonic-gate }
930*7c478bd9Sstevel@tonic-gate break;
931*7c478bd9Sstevel@tonic-gate default:
932*7c478bd9Sstevel@tonic-gate return;
933*7c478bd9Sstevel@tonic-gate }
934*7c478bd9Sstevel@tonic-gate env_opt(subpointer, SB_LEN());
935*7c478bd9Sstevel@tonic-gate break;
936*7c478bd9Sstevel@tonic-gate
937*7c478bd9Sstevel@tonic-gate case TELOPT_XDISPLOC:
938*7c478bd9Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_XDISPLOC))
939*7c478bd9Sstevel@tonic-gate return;
940*7c478bd9Sstevel@tonic-gate if (SB_EOF())
941*7c478bd9Sstevel@tonic-gate return;
942*7c478bd9Sstevel@tonic-gate if (SB_GET() == TELQUAL_SEND) {
943*7c478bd9Sstevel@tonic-gate unsigned char temp[50], *dp;
944*7c478bd9Sstevel@tonic-gate int len, bytes;
945*7c478bd9Sstevel@tonic-gate
946*7c478bd9Sstevel@tonic-gate if ((dp = env_getvalue((unsigned char *)"DISPLAY")) ==
947*7c478bd9Sstevel@tonic-gate NULL) {
948*7c478bd9Sstevel@tonic-gate /*
949*7c478bd9Sstevel@tonic-gate * Something happened, we no longer have a
950*7c478bd9Sstevel@tonic-gate * DISPLAY variable. So, turn off the option.
951*7c478bd9Sstevel@tonic-gate */
952*7c478bd9Sstevel@tonic-gate send_wont(TELOPT_XDISPLOC, 1);
953*7c478bd9Sstevel@tonic-gate break;
954*7c478bd9Sstevel@tonic-gate }
955*7c478bd9Sstevel@tonic-gate bytes = snprintf((char *)temp, sizeof (temp),
956*7c478bd9Sstevel@tonic-gate "%c%c%c%c%s%c%c", IAC, SB,
957*7c478bd9Sstevel@tonic-gate TELOPT_XDISPLOC, TELQUAL_IS, dp, IAC, SE);
958*7c478bd9Sstevel@tonic-gate len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
959*7c478bd9Sstevel@tonic-gate
960*7c478bd9Sstevel@tonic-gate if ((len < NETROOM()) && (bytes < sizeof (temp))) {
961*7c478bd9Sstevel@tonic-gate ring_supply_data(&netoring, temp, len);
962*7c478bd9Sstevel@tonic-gate printsub('>', temp+2, len - 2);
963*7c478bd9Sstevel@tonic-gate }
964*7c478bd9Sstevel@tonic-gate else
965*7c478bd9Sstevel@tonic-gate (void) printf(
966*7c478bd9Sstevel@tonic-gate "telnet: not enough room in buffer"
967*7c478bd9Sstevel@tonic-gate " for display location option reply\n");
968*7c478bd9Sstevel@tonic-gate }
969*7c478bd9Sstevel@tonic-gate break;
970*7c478bd9Sstevel@tonic-gate
971*7c478bd9Sstevel@tonic-gate case TELOPT_AUTHENTICATION: {
972*7c478bd9Sstevel@tonic-gate if (!autologin)
973*7c478bd9Sstevel@tonic-gate break;
974*7c478bd9Sstevel@tonic-gate if (SB_EOF())
975*7c478bd9Sstevel@tonic-gate return;
976*7c478bd9Sstevel@tonic-gate switch (SB_GET()) {
977*7c478bd9Sstevel@tonic-gate case TELQUAL_SEND:
978*7c478bd9Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
979*7c478bd9Sstevel@tonic-gate return;
980*7c478bd9Sstevel@tonic-gate auth_send(subpointer, SB_LEN());
981*7c478bd9Sstevel@tonic-gate break;
982*7c478bd9Sstevel@tonic-gate case TELQUAL_REPLY:
983*7c478bd9Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
984*7c478bd9Sstevel@tonic-gate return;
985*7c478bd9Sstevel@tonic-gate auth_reply(subpointer, SB_LEN());
986*7c478bd9Sstevel@tonic-gate break;
987*7c478bd9Sstevel@tonic-gate }
988*7c478bd9Sstevel@tonic-gate }
989*7c478bd9Sstevel@tonic-gate break;
990*7c478bd9Sstevel@tonic-gate
991*7c478bd9Sstevel@tonic-gate case TELOPT_ENCRYPT:
992*7c478bd9Sstevel@tonic-gate if (SB_EOF())
993*7c478bd9Sstevel@tonic-gate return;
994*7c478bd9Sstevel@tonic-gate switch (SB_GET()) {
995*7c478bd9Sstevel@tonic-gate case ENCRYPT_START:
996*7c478bd9Sstevel@tonic-gate if (my_want_state_is_dont(TELOPT_ENCRYPT))
997*7c478bd9Sstevel@tonic-gate return;
998*7c478bd9Sstevel@tonic-gate encrypt_start(subpointer, SB_LEN());
999*7c478bd9Sstevel@tonic-gate break;
1000*7c478bd9Sstevel@tonic-gate case ENCRYPT_END:
1001*7c478bd9Sstevel@tonic-gate if (my_want_state_is_dont(TELOPT_ENCRYPT))
1002*7c478bd9Sstevel@tonic-gate return;
1003*7c478bd9Sstevel@tonic-gate encrypt_end();
1004*7c478bd9Sstevel@tonic-gate break;
1005*7c478bd9Sstevel@tonic-gate case ENCRYPT_SUPPORT:
1006*7c478bd9Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_ENCRYPT))
1007*7c478bd9Sstevel@tonic-gate return;
1008*7c478bd9Sstevel@tonic-gate encrypt_support(subpointer, SB_LEN());
1009*7c478bd9Sstevel@tonic-gate break;
1010*7c478bd9Sstevel@tonic-gate case ENCRYPT_REQSTART:
1011*7c478bd9Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_ENCRYPT))
1012*7c478bd9Sstevel@tonic-gate return;
1013*7c478bd9Sstevel@tonic-gate encrypt_request_start(subpointer, SB_LEN());
1014*7c478bd9Sstevel@tonic-gate break;
1015*7c478bd9Sstevel@tonic-gate case ENCRYPT_REQEND:
1016*7c478bd9Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_ENCRYPT))
1017*7c478bd9Sstevel@tonic-gate return;
1018*7c478bd9Sstevel@tonic-gate /*
1019*7c478bd9Sstevel@tonic-gate * We can always send an REQEND so that we cannot
1020*7c478bd9Sstevel@tonic-gate * get stuck encrypting. We should only get this
1021*7c478bd9Sstevel@tonic-gate * if we have been able to get in the correct mode
1022*7c478bd9Sstevel@tonic-gate * anyhow.
1023*7c478bd9Sstevel@tonic-gate */
1024*7c478bd9Sstevel@tonic-gate encrypt_request_end();
1025*7c478bd9Sstevel@tonic-gate break;
1026*7c478bd9Sstevel@tonic-gate case ENCRYPT_IS:
1027*7c478bd9Sstevel@tonic-gate if (my_want_state_is_dont(TELOPT_ENCRYPT))
1028*7c478bd9Sstevel@tonic-gate return;
1029*7c478bd9Sstevel@tonic-gate encrypt_is(subpointer, SB_LEN());
1030*7c478bd9Sstevel@tonic-gate break;
1031*7c478bd9Sstevel@tonic-gate case ENCRYPT_REPLY:
1032*7c478bd9Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_ENCRYPT))
1033*7c478bd9Sstevel@tonic-gate return;
1034*7c478bd9Sstevel@tonic-gate encrypt_reply(subpointer, SB_LEN());
1035*7c478bd9Sstevel@tonic-gate break;
1036*7c478bd9Sstevel@tonic-gate case ENCRYPT_ENC_KEYID:
1037*7c478bd9Sstevel@tonic-gate if (my_want_state_is_dont(TELOPT_ENCRYPT))
1038*7c478bd9Sstevel@tonic-gate return;
1039*7c478bd9Sstevel@tonic-gate encrypt_enc_keyid(subpointer, SB_LEN());
1040*7c478bd9Sstevel@tonic-gate break;
1041*7c478bd9Sstevel@tonic-gate case ENCRYPT_DEC_KEYID:
1042*7c478bd9Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_ENCRYPT))
1043*7c478bd9Sstevel@tonic-gate return;
1044*7c478bd9Sstevel@tonic-gate encrypt_dec_keyid(subpointer, SB_LEN());
1045*7c478bd9Sstevel@tonic-gate break;
1046*7c478bd9Sstevel@tonic-gate default:
1047*7c478bd9Sstevel@tonic-gate break;
1048*7c478bd9Sstevel@tonic-gate }
1049*7c478bd9Sstevel@tonic-gate break;
1050*7c478bd9Sstevel@tonic-gate default:
1051*7c478bd9Sstevel@tonic-gate break;
1052*7c478bd9Sstevel@tonic-gate }
1053*7c478bd9Sstevel@tonic-gate }
1054*7c478bd9Sstevel@tonic-gate
1055*7c478bd9Sstevel@tonic-gate static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
1056*7c478bd9Sstevel@tonic-gate
1057*7c478bd9Sstevel@tonic-gate static void
lm_will(cmd,len)1058*7c478bd9Sstevel@tonic-gate lm_will(cmd, len)
1059*7c478bd9Sstevel@tonic-gate unsigned char *cmd;
1060*7c478bd9Sstevel@tonic-gate int len;
1061*7c478bd9Sstevel@tonic-gate {
1062*7c478bd9Sstevel@tonic-gate if (len < 1) {
1063*7c478bd9Sstevel@tonic-gate /* Should not happen... */
1064*7c478bd9Sstevel@tonic-gate (void) printf(
1065*7c478bd9Sstevel@tonic-gate "telnet: command missing from linemode WILL request\n");
1066*7c478bd9Sstevel@tonic-gate return;
1067*7c478bd9Sstevel@tonic-gate }
1068*7c478bd9Sstevel@tonic-gate switch (cmd[0]) {
1069*7c478bd9Sstevel@tonic-gate case LM_FORWARDMASK: /* We shouldn't ever get this... */
1070*7c478bd9Sstevel@tonic-gate default:
1071*7c478bd9Sstevel@tonic-gate str_lm[3] = DONT;
1072*7c478bd9Sstevel@tonic-gate str_lm[4] = cmd[0];
1073*7c478bd9Sstevel@tonic-gate if (NETROOM() > sizeof (str_lm)) {
1074*7c478bd9Sstevel@tonic-gate ring_supply_data(&netoring, str_lm, sizeof (str_lm));
1075*7c478bd9Sstevel@tonic-gate printsub('>', &str_lm[2], sizeof (str_lm)-2);
1076*7c478bd9Sstevel@tonic-gate }
1077*7c478bd9Sstevel@tonic-gate else
1078*7c478bd9Sstevel@tonic-gate (void) printf("telnet: not enough room in buffer for"
1079*7c478bd9Sstevel@tonic-gate "reply to linemode WILL request\n");
1080*7c478bd9Sstevel@tonic-gate break;
1081*7c478bd9Sstevel@tonic-gate }
1082*7c478bd9Sstevel@tonic-gate }
1083*7c478bd9Sstevel@tonic-gate
1084*7c478bd9Sstevel@tonic-gate static void
lm_wont(cmd,len)1085*7c478bd9Sstevel@tonic-gate lm_wont(cmd, len)
1086*7c478bd9Sstevel@tonic-gate unsigned char *cmd;
1087*7c478bd9Sstevel@tonic-gate int len;
1088*7c478bd9Sstevel@tonic-gate {
1089*7c478bd9Sstevel@tonic-gate if (len < 1) {
1090*7c478bd9Sstevel@tonic-gate /* Should not happen... */
1091*7c478bd9Sstevel@tonic-gate (void) printf(
1092*7c478bd9Sstevel@tonic-gate "telnet: command missing from linemode WONT request\n");
1093*7c478bd9Sstevel@tonic-gate return;
1094*7c478bd9Sstevel@tonic-gate }
1095*7c478bd9Sstevel@tonic-gate switch (cmd[0]) {
1096*7c478bd9Sstevel@tonic-gate case LM_FORWARDMASK: /* We shouldn't ever get this... */
1097*7c478bd9Sstevel@tonic-gate default:
1098*7c478bd9Sstevel@tonic-gate /* We are always DONT, so don't respond */
1099*7c478bd9Sstevel@tonic-gate return;
1100*7c478bd9Sstevel@tonic-gate }
1101*7c478bd9Sstevel@tonic-gate }
1102*7c478bd9Sstevel@tonic-gate
1103*7c478bd9Sstevel@tonic-gate static void
lm_do(cmd,len)1104*7c478bd9Sstevel@tonic-gate lm_do(cmd, len)
1105*7c478bd9Sstevel@tonic-gate unsigned char *cmd;
1106*7c478bd9Sstevel@tonic-gate int len;
1107*7c478bd9Sstevel@tonic-gate {
1108*7c478bd9Sstevel@tonic-gate if (len < 1) {
1109*7c478bd9Sstevel@tonic-gate /* Should not happen... */
1110*7c478bd9Sstevel@tonic-gate (void) printf(
1111*7c478bd9Sstevel@tonic-gate "telnet: command missing from linemode DO request\n");
1112*7c478bd9Sstevel@tonic-gate return;
1113*7c478bd9Sstevel@tonic-gate }
1114*7c478bd9Sstevel@tonic-gate switch (cmd[0]) {
1115*7c478bd9Sstevel@tonic-gate case LM_FORWARDMASK:
1116*7c478bd9Sstevel@tonic-gate default:
1117*7c478bd9Sstevel@tonic-gate str_lm[3] = WONT;
1118*7c478bd9Sstevel@tonic-gate str_lm[4] = cmd[0];
1119*7c478bd9Sstevel@tonic-gate if (NETROOM() > sizeof (str_lm)) {
1120*7c478bd9Sstevel@tonic-gate ring_supply_data(&netoring, str_lm, sizeof (str_lm));
1121*7c478bd9Sstevel@tonic-gate printsub('>', &str_lm[2], sizeof (str_lm)-2);
1122*7c478bd9Sstevel@tonic-gate }
1123*7c478bd9Sstevel@tonic-gate else
1124*7c478bd9Sstevel@tonic-gate (void) printf("telnet: not enough room in buffer for"
1125*7c478bd9Sstevel@tonic-gate "reply to linemode DO request\n");
1126*7c478bd9Sstevel@tonic-gate break;
1127*7c478bd9Sstevel@tonic-gate }
1128*7c478bd9Sstevel@tonic-gate }
1129*7c478bd9Sstevel@tonic-gate
1130*7c478bd9Sstevel@tonic-gate static void
lm_dont(cmd,len)1131*7c478bd9Sstevel@tonic-gate lm_dont(cmd, len)
1132*7c478bd9Sstevel@tonic-gate unsigned char *cmd;
1133*7c478bd9Sstevel@tonic-gate int len;
1134*7c478bd9Sstevel@tonic-gate {
1135*7c478bd9Sstevel@tonic-gate if (len < 1) {
1136*7c478bd9Sstevel@tonic-gate /* Should not happen... */
1137*7c478bd9Sstevel@tonic-gate (void) printf(
1138*7c478bd9Sstevel@tonic-gate "telnet: command missing from linemode DONT request\n");
1139*7c478bd9Sstevel@tonic-gate return;
1140*7c478bd9Sstevel@tonic-gate }
1141*7c478bd9Sstevel@tonic-gate switch (cmd[0]) {
1142*7c478bd9Sstevel@tonic-gate case LM_FORWARDMASK:
1143*7c478bd9Sstevel@tonic-gate default:
1144*7c478bd9Sstevel@tonic-gate /* we are always WONT, so don't respond */
1145*7c478bd9Sstevel@tonic-gate break;
1146*7c478bd9Sstevel@tonic-gate }
1147*7c478bd9Sstevel@tonic-gate }
1148*7c478bd9Sstevel@tonic-gate
1149*7c478bd9Sstevel@tonic-gate static unsigned char str_lm_mode[] = {
1150*7c478bd9Sstevel@tonic-gate IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
1151*7c478bd9Sstevel@tonic-gate };
1152*7c478bd9Sstevel@tonic-gate
1153*7c478bd9Sstevel@tonic-gate void
lm_mode(cmd,len,init)1154*7c478bd9Sstevel@tonic-gate lm_mode(cmd, len, init)
1155*7c478bd9Sstevel@tonic-gate unsigned char *cmd;
1156*7c478bd9Sstevel@tonic-gate int len, init;
1157*7c478bd9Sstevel@tonic-gate {
1158*7c478bd9Sstevel@tonic-gate if (len != 1)
1159*7c478bd9Sstevel@tonic-gate return;
1160*7c478bd9Sstevel@tonic-gate if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
1161*7c478bd9Sstevel@tonic-gate return;
1162*7c478bd9Sstevel@tonic-gate linemode = *cmd&(MODE_MASK&~MODE_ACK);
1163*7c478bd9Sstevel@tonic-gate str_lm_mode[4] = linemode;
1164*7c478bd9Sstevel@tonic-gate if (!init)
1165*7c478bd9Sstevel@tonic-gate str_lm_mode[4] |= MODE_ACK;
1166*7c478bd9Sstevel@tonic-gate if (NETROOM() > sizeof (str_lm_mode)) {
1167*7c478bd9Sstevel@tonic-gate ring_supply_data(&netoring, str_lm_mode, sizeof (str_lm_mode));
1168*7c478bd9Sstevel@tonic-gate printsub('>', &str_lm_mode[2], sizeof (str_lm_mode)-2);
1169*7c478bd9Sstevel@tonic-gate }
1170*7c478bd9Sstevel@tonic-gate else
1171*7c478bd9Sstevel@tonic-gate (void) printf("telnet: not enough room in buffer for"
1172*7c478bd9Sstevel@tonic-gate "reply to linemode request\n");
1173*7c478bd9Sstevel@tonic-gate setconnmode(0); /* set changed mode */
1174*7c478bd9Sstevel@tonic-gate }
1175*7c478bd9Sstevel@tonic-gate
1176*7c478bd9Sstevel@tonic-gate
1177*7c478bd9Sstevel@tonic-gate
1178*7c478bd9Sstevel@tonic-gate /*
1179*7c478bd9Sstevel@tonic-gate * slc()
1180*7c478bd9Sstevel@tonic-gate * Handle special character suboption of LINEMODE.
1181*7c478bd9Sstevel@tonic-gate */
1182*7c478bd9Sstevel@tonic-gate
1183*7c478bd9Sstevel@tonic-gate static struct spc {
1184*7c478bd9Sstevel@tonic-gate cc_t val;
1185*7c478bd9Sstevel@tonic-gate cc_t *valp;
1186*7c478bd9Sstevel@tonic-gate char flags; /* Current flags & level */
1187*7c478bd9Sstevel@tonic-gate char mylevel; /* Maximum level & flags */
1188*7c478bd9Sstevel@tonic-gate } spc_data[NSLC+1];
1189*7c478bd9Sstevel@tonic-gate
1190*7c478bd9Sstevel@tonic-gate #define SLC_IMPORT 0
1191*7c478bd9Sstevel@tonic-gate #define SLC_EXPORT 1
1192*7c478bd9Sstevel@tonic-gate #define SLC_RVALUE 2
1193*7c478bd9Sstevel@tonic-gate static int slc_mode = SLC_EXPORT;
1194*7c478bd9Sstevel@tonic-gate
1195*7c478bd9Sstevel@tonic-gate static void
slc_init()1196*7c478bd9Sstevel@tonic-gate slc_init()
1197*7c478bd9Sstevel@tonic-gate {
1198*7c478bd9Sstevel@tonic-gate register struct spc *spcp;
1199*7c478bd9Sstevel@tonic-gate
1200*7c478bd9Sstevel@tonic-gate localchars = 1;
1201*7c478bd9Sstevel@tonic-gate for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
1202*7c478bd9Sstevel@tonic-gate spcp->val = 0;
1203*7c478bd9Sstevel@tonic-gate spcp->valp = 0;
1204*7c478bd9Sstevel@tonic-gate spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
1205*7c478bd9Sstevel@tonic-gate }
1206*7c478bd9Sstevel@tonic-gate
1207*7c478bd9Sstevel@tonic-gate #define initfunc(func, flags) { \
1208*7c478bd9Sstevel@tonic-gate spcp = &spc_data[func]; \
1209*7c478bd9Sstevel@tonic-gate if (spcp->valp = tcval(func)) { \
1210*7c478bd9Sstevel@tonic-gate spcp->val = *spcp->valp; \
1211*7c478bd9Sstevel@tonic-gate spcp->mylevel = SLC_VARIABLE|(flags);\
1212*7c478bd9Sstevel@tonic-gate } else { \
1213*7c478bd9Sstevel@tonic-gate spcp->val = 0; \
1214*7c478bd9Sstevel@tonic-gate spcp->mylevel = SLC_DEFAULT; \
1215*7c478bd9Sstevel@tonic-gate } \
1216*7c478bd9Sstevel@tonic-gate }
1217*7c478bd9Sstevel@tonic-gate
1218*7c478bd9Sstevel@tonic-gate initfunc(SLC_SYNCH, 0);
1219*7c478bd9Sstevel@tonic-gate /* No BRK */
1220*7c478bd9Sstevel@tonic-gate initfunc(SLC_AO, 0);
1221*7c478bd9Sstevel@tonic-gate initfunc(SLC_AYT, 0);
1222*7c478bd9Sstevel@tonic-gate /* No EOR */
1223*7c478bd9Sstevel@tonic-gate initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
1224*7c478bd9Sstevel@tonic-gate initfunc(SLC_EOF, 0);
1225*7c478bd9Sstevel@tonic-gate initfunc(SLC_SUSP, SLC_FLUSHIN);
1226*7c478bd9Sstevel@tonic-gate initfunc(SLC_EC, 0);
1227*7c478bd9Sstevel@tonic-gate initfunc(SLC_EL, 0);
1228*7c478bd9Sstevel@tonic-gate initfunc(SLC_EW, 0);
1229*7c478bd9Sstevel@tonic-gate initfunc(SLC_RP, 0);
1230*7c478bd9Sstevel@tonic-gate initfunc(SLC_LNEXT, 0);
1231*7c478bd9Sstevel@tonic-gate initfunc(SLC_XON, 0);
1232*7c478bd9Sstevel@tonic-gate initfunc(SLC_XOFF, 0);
1233*7c478bd9Sstevel@tonic-gate initfunc(SLC_FORW1, 0);
1234*7c478bd9Sstevel@tonic-gate #ifdef USE_TERMIO
1235*7c478bd9Sstevel@tonic-gate initfunc(SLC_FORW2, 0);
1236*7c478bd9Sstevel@tonic-gate /* No FORW2 */
1237*7c478bd9Sstevel@tonic-gate #endif
1238*7c478bd9Sstevel@tonic-gate
1239*7c478bd9Sstevel@tonic-gate initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
1240*7c478bd9Sstevel@tonic-gate #undef initfunc
1241*7c478bd9Sstevel@tonic-gate
1242*7c478bd9Sstevel@tonic-gate if (slc_mode == SLC_EXPORT)
1243*7c478bd9Sstevel@tonic-gate slc_export();
1244*7c478bd9Sstevel@tonic-gate else
1245*7c478bd9Sstevel@tonic-gate slc_import(1);
1246*7c478bd9Sstevel@tonic-gate
1247*7c478bd9Sstevel@tonic-gate }
1248*7c478bd9Sstevel@tonic-gate
1249*7c478bd9Sstevel@tonic-gate void
slcstate()1250*7c478bd9Sstevel@tonic-gate slcstate()
1251*7c478bd9Sstevel@tonic-gate {
1252*7c478bd9Sstevel@tonic-gate (void) printf("Special characters are %s values\n",
1253*7c478bd9Sstevel@tonic-gate slc_mode == SLC_IMPORT ? "remote default" :
1254*7c478bd9Sstevel@tonic-gate slc_mode == SLC_EXPORT ? "local" :
1255*7c478bd9Sstevel@tonic-gate "remote");
1256*7c478bd9Sstevel@tonic-gate }
1257*7c478bd9Sstevel@tonic-gate
1258*7c478bd9Sstevel@tonic-gate void
slc_mode_export()1259*7c478bd9Sstevel@tonic-gate slc_mode_export()
1260*7c478bd9Sstevel@tonic-gate {
1261*7c478bd9Sstevel@tonic-gate slc_mode = SLC_EXPORT;
1262*7c478bd9Sstevel@tonic-gate if (my_state_is_will(TELOPT_LINEMODE))
1263*7c478bd9Sstevel@tonic-gate slc_export();
1264*7c478bd9Sstevel@tonic-gate }
1265*7c478bd9Sstevel@tonic-gate
1266*7c478bd9Sstevel@tonic-gate void
slc_mode_import(def)1267*7c478bd9Sstevel@tonic-gate slc_mode_import(def)
1268*7c478bd9Sstevel@tonic-gate int def;
1269*7c478bd9Sstevel@tonic-gate {
1270*7c478bd9Sstevel@tonic-gate slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
1271*7c478bd9Sstevel@tonic-gate if (my_state_is_will(TELOPT_LINEMODE))
1272*7c478bd9Sstevel@tonic-gate slc_import(def);
1273*7c478bd9Sstevel@tonic-gate }
1274*7c478bd9Sstevel@tonic-gate
1275*7c478bd9Sstevel@tonic-gate static unsigned char slc_import_val[] = {
1276*7c478bd9Sstevel@tonic-gate IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
1277*7c478bd9Sstevel@tonic-gate };
1278*7c478bd9Sstevel@tonic-gate static unsigned char slc_import_def[] = {
1279*7c478bd9Sstevel@tonic-gate IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
1280*7c478bd9Sstevel@tonic-gate };
1281*7c478bd9Sstevel@tonic-gate
1282*7c478bd9Sstevel@tonic-gate static void
slc_import(def)1283*7c478bd9Sstevel@tonic-gate slc_import(def)
1284*7c478bd9Sstevel@tonic-gate int def;
1285*7c478bd9Sstevel@tonic-gate {
1286*7c478bd9Sstevel@tonic-gate if (NETROOM() > sizeof (slc_import_val)) {
1287*7c478bd9Sstevel@tonic-gate if (def) {
1288*7c478bd9Sstevel@tonic-gate ring_supply_data(&netoring, slc_import_def,
1289*7c478bd9Sstevel@tonic-gate sizeof (slc_import_def));
1290*7c478bd9Sstevel@tonic-gate printsub('>', &slc_import_def[2],
1291*7c478bd9Sstevel@tonic-gate sizeof (slc_import_def)-2);
1292*7c478bd9Sstevel@tonic-gate } else {
1293*7c478bd9Sstevel@tonic-gate ring_supply_data(&netoring, slc_import_val,
1294*7c478bd9Sstevel@tonic-gate sizeof (slc_import_val));
1295*7c478bd9Sstevel@tonic-gate printsub('>', &slc_import_val[2],
1296*7c478bd9Sstevel@tonic-gate sizeof (slc_import_val)-2);
1297*7c478bd9Sstevel@tonic-gate }
1298*7c478bd9Sstevel@tonic-gate }
1299*7c478bd9Sstevel@tonic-gate else
1300*7c478bd9Sstevel@tonic-gate (void) printf(
1301*7c478bd9Sstevel@tonic-gate "telnet: not enough room in buffer for slc import"
1302*7c478bd9Sstevel@tonic-gate " request\n");
1303*7c478bd9Sstevel@tonic-gate }
1304*7c478bd9Sstevel@tonic-gate
1305*7c478bd9Sstevel@tonic-gate static uchar_t *slc_reply = NULL;
1306*7c478bd9Sstevel@tonic-gate static uchar_t *slc_replyp = NULL;
1307*7c478bd9Sstevel@tonic-gate /*
1308*7c478bd9Sstevel@tonic-gate * The SLC reply consists of: IAC, SB, TELOPT_LINEMODE, LM_SLC,
1309*7c478bd9Sstevel@tonic-gate * SLC triplets[], IAC, SE. i.e. it has a 'wrapper' of 6 control characters.
1310*7c478bd9Sstevel@tonic-gate */
1311*7c478bd9Sstevel@tonic-gate #define SLC_WRAPPER_SIZE 6
1312*7c478bd9Sstevel@tonic-gate
1313*7c478bd9Sstevel@tonic-gate static void
slc_export()1314*7c478bd9Sstevel@tonic-gate slc_export()
1315*7c478bd9Sstevel@tonic-gate {
1316*7c478bd9Sstevel@tonic-gate register struct spc *spcp;
1317*7c478bd9Sstevel@tonic-gate
1318*7c478bd9Sstevel@tonic-gate TerminalDefaultChars();
1319*7c478bd9Sstevel@tonic-gate
1320*7c478bd9Sstevel@tonic-gate slc_start_reply(NSLC * 3); /* 3 bytes needed per triplet */
1321*7c478bd9Sstevel@tonic-gate for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1322*7c478bd9Sstevel@tonic-gate if (spcp->mylevel != SLC_NOSUPPORT) {
1323*7c478bd9Sstevel@tonic-gate if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1324*7c478bd9Sstevel@tonic-gate spcp->flags = SLC_NOSUPPORT;
1325*7c478bd9Sstevel@tonic-gate else
1326*7c478bd9Sstevel@tonic-gate spcp->flags = spcp->mylevel;
1327*7c478bd9Sstevel@tonic-gate if (spcp->valp)
1328*7c478bd9Sstevel@tonic-gate spcp->val = *spcp->valp;
1329*7c478bd9Sstevel@tonic-gate slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1330*7c478bd9Sstevel@tonic-gate }
1331*7c478bd9Sstevel@tonic-gate }
1332*7c478bd9Sstevel@tonic-gate slc_end_reply();
1333*7c478bd9Sstevel@tonic-gate (void) slc_update();
1334*7c478bd9Sstevel@tonic-gate setconnmode(1); /* Make sure the character values are set */
1335*7c478bd9Sstevel@tonic-gate }
1336*7c478bd9Sstevel@tonic-gate
1337*7c478bd9Sstevel@tonic-gate static void
slc(cp,len)1338*7c478bd9Sstevel@tonic-gate slc(cp, len)
1339*7c478bd9Sstevel@tonic-gate register unsigned char *cp;
1340*7c478bd9Sstevel@tonic-gate int len;
1341*7c478bd9Sstevel@tonic-gate {
1342*7c478bd9Sstevel@tonic-gate register struct spc *spcp;
1343*7c478bd9Sstevel@tonic-gate register int func, level;
1344*7c478bd9Sstevel@tonic-gate
1345*7c478bd9Sstevel@tonic-gate slc_start_reply(len);
1346*7c478bd9Sstevel@tonic-gate
1347*7c478bd9Sstevel@tonic-gate for (; len >= 3; len -= 3, cp += 3) {
1348*7c478bd9Sstevel@tonic-gate
1349*7c478bd9Sstevel@tonic-gate func = cp[SLC_FUNC];
1350*7c478bd9Sstevel@tonic-gate
1351*7c478bd9Sstevel@tonic-gate if (func == 0) {
1352*7c478bd9Sstevel@tonic-gate /*
1353*7c478bd9Sstevel@tonic-gate * Client side: always ignore 0 function.
1354*7c478bd9Sstevel@tonic-gate */
1355*7c478bd9Sstevel@tonic-gate continue;
1356*7c478bd9Sstevel@tonic-gate }
1357*7c478bd9Sstevel@tonic-gate if (func > NSLC) {
1358*7c478bd9Sstevel@tonic-gate if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
1359*7c478bd9Sstevel@tonic-gate slc_add_reply(func, SLC_NOSUPPORT, 0);
1360*7c478bd9Sstevel@tonic-gate continue;
1361*7c478bd9Sstevel@tonic-gate }
1362*7c478bd9Sstevel@tonic-gate
1363*7c478bd9Sstevel@tonic-gate spcp = &spc_data[func];
1364*7c478bd9Sstevel@tonic-gate
1365*7c478bd9Sstevel@tonic-gate level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
1366*7c478bd9Sstevel@tonic-gate
1367*7c478bd9Sstevel@tonic-gate if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
1368*7c478bd9Sstevel@tonic-gate ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
1369*7c478bd9Sstevel@tonic-gate continue;
1370*7c478bd9Sstevel@tonic-gate }
1371*7c478bd9Sstevel@tonic-gate
1372*7c478bd9Sstevel@tonic-gate if (level == (SLC_DEFAULT|SLC_ACK)) {
1373*7c478bd9Sstevel@tonic-gate /*
1374*7c478bd9Sstevel@tonic-gate * This is an error condition, the SLC_ACK
1375*7c478bd9Sstevel@tonic-gate * bit should never be set for the SLC_DEFAULT
1376*7c478bd9Sstevel@tonic-gate * level. Our best guess to recover is to
1377*7c478bd9Sstevel@tonic-gate * ignore the SLC_ACK bit.
1378*7c478bd9Sstevel@tonic-gate */
1379*7c478bd9Sstevel@tonic-gate cp[SLC_FLAGS] &= ~SLC_ACK;
1380*7c478bd9Sstevel@tonic-gate }
1381*7c478bd9Sstevel@tonic-gate
1382*7c478bd9Sstevel@tonic-gate if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
1383*7c478bd9Sstevel@tonic-gate spcp->val = (cc_t)cp[SLC_VALUE];
1384*7c478bd9Sstevel@tonic-gate spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */
1385*7c478bd9Sstevel@tonic-gate continue;
1386*7c478bd9Sstevel@tonic-gate }
1387*7c478bd9Sstevel@tonic-gate
1388*7c478bd9Sstevel@tonic-gate level &= ~SLC_ACK;
1389*7c478bd9Sstevel@tonic-gate
1390*7c478bd9Sstevel@tonic-gate if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
1391*7c478bd9Sstevel@tonic-gate spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
1392*7c478bd9Sstevel@tonic-gate spcp->val = (cc_t)cp[SLC_VALUE];
1393*7c478bd9Sstevel@tonic-gate }
1394*7c478bd9Sstevel@tonic-gate if (level == SLC_DEFAULT) {
1395*7c478bd9Sstevel@tonic-gate if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
1396*7c478bd9Sstevel@tonic-gate spcp->flags = spcp->mylevel;
1397*7c478bd9Sstevel@tonic-gate else
1398*7c478bd9Sstevel@tonic-gate spcp->flags = SLC_NOSUPPORT;
1399*7c478bd9Sstevel@tonic-gate }
1400*7c478bd9Sstevel@tonic-gate slc_add_reply(func, spcp->flags, spcp->val);
1401*7c478bd9Sstevel@tonic-gate }
1402*7c478bd9Sstevel@tonic-gate slc_end_reply();
1403*7c478bd9Sstevel@tonic-gate if (slc_update())
1404*7c478bd9Sstevel@tonic-gate setconnmode(1); /* set the new character values */
1405*7c478bd9Sstevel@tonic-gate }
1406*7c478bd9Sstevel@tonic-gate
1407*7c478bd9Sstevel@tonic-gate void
slc_check()1408*7c478bd9Sstevel@tonic-gate slc_check()
1409*7c478bd9Sstevel@tonic-gate {
1410*7c478bd9Sstevel@tonic-gate register struct spc *spcp;
1411*7c478bd9Sstevel@tonic-gate
1412*7c478bd9Sstevel@tonic-gate slc_start_reply(NSLC * 3); /* 3 bytes needed per triplet */
1413*7c478bd9Sstevel@tonic-gate for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1414*7c478bd9Sstevel@tonic-gate if (spcp->valp && spcp->val != *spcp->valp) {
1415*7c478bd9Sstevel@tonic-gate spcp->val = *spcp->valp;
1416*7c478bd9Sstevel@tonic-gate if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1417*7c478bd9Sstevel@tonic-gate spcp->flags = SLC_NOSUPPORT;
1418*7c478bd9Sstevel@tonic-gate else
1419*7c478bd9Sstevel@tonic-gate spcp->flags = spcp->mylevel;
1420*7c478bd9Sstevel@tonic-gate slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1421*7c478bd9Sstevel@tonic-gate }
1422*7c478bd9Sstevel@tonic-gate }
1423*7c478bd9Sstevel@tonic-gate slc_end_reply();
1424*7c478bd9Sstevel@tonic-gate setconnmode(1);
1425*7c478bd9Sstevel@tonic-gate }
1426*7c478bd9Sstevel@tonic-gate
1427*7c478bd9Sstevel@tonic-gate static void
slc_start_reply(size_t len)1428*7c478bd9Sstevel@tonic-gate slc_start_reply(size_t len)
1429*7c478bd9Sstevel@tonic-gate {
1430*7c478bd9Sstevel@tonic-gate /*
1431*7c478bd9Sstevel@tonic-gate * SLC triplets may contain escaped characters, allow for
1432*7c478bd9Sstevel@tonic-gate * worst case by allocating 2 bytes for every character.
1433*7c478bd9Sstevel@tonic-gate */
1434*7c478bd9Sstevel@tonic-gate slc_reply = realloc(slc_reply, (len * 2) + SLC_WRAPPER_SIZE);
1435*7c478bd9Sstevel@tonic-gate if (slc_reply == NULL) {
1436*7c478bd9Sstevel@tonic-gate fprintf(stderr, "telnet: error allocating SLC reply memory\n");
1437*7c478bd9Sstevel@tonic-gate return;
1438*7c478bd9Sstevel@tonic-gate }
1439*7c478bd9Sstevel@tonic-gate slc_replyp = slc_reply;
1440*7c478bd9Sstevel@tonic-gate *slc_replyp++ = IAC;
1441*7c478bd9Sstevel@tonic-gate *slc_replyp++ = SB;
1442*7c478bd9Sstevel@tonic-gate *slc_replyp++ = TELOPT_LINEMODE;
1443*7c478bd9Sstevel@tonic-gate *slc_replyp++ = LM_SLC;
1444*7c478bd9Sstevel@tonic-gate }
1445*7c478bd9Sstevel@tonic-gate
1446*7c478bd9Sstevel@tonic-gate static void
slc_add_reply(unsigned char func,unsigned char flags,cc_t value)1447*7c478bd9Sstevel@tonic-gate slc_add_reply(unsigned char func, unsigned char flags, cc_t value)
1448*7c478bd9Sstevel@tonic-gate {
1449*7c478bd9Sstevel@tonic-gate if ((*slc_replyp++ = func) == IAC)
1450*7c478bd9Sstevel@tonic-gate *slc_replyp++ = IAC;
1451*7c478bd9Sstevel@tonic-gate if ((*slc_replyp++ = flags) == IAC)
1452*7c478bd9Sstevel@tonic-gate *slc_replyp++ = IAC;
1453*7c478bd9Sstevel@tonic-gate if ((*slc_replyp++ = (unsigned char)value) == IAC)
1454*7c478bd9Sstevel@tonic-gate *slc_replyp++ = IAC;
1455*7c478bd9Sstevel@tonic-gate }
1456*7c478bd9Sstevel@tonic-gate
1457*7c478bd9Sstevel@tonic-gate static void
slc_end_reply()1458*7c478bd9Sstevel@tonic-gate slc_end_reply()
1459*7c478bd9Sstevel@tonic-gate {
1460*7c478bd9Sstevel@tonic-gate register int len;
1461*7c478bd9Sstevel@tonic-gate
1462*7c478bd9Sstevel@tonic-gate *slc_replyp++ = IAC;
1463*7c478bd9Sstevel@tonic-gate *slc_replyp++ = SE;
1464*7c478bd9Sstevel@tonic-gate len = slc_replyp - slc_reply;
1465*7c478bd9Sstevel@tonic-gate if (len <= SLC_WRAPPER_SIZE)
1466*7c478bd9Sstevel@tonic-gate return;
1467*7c478bd9Sstevel@tonic-gate if (NETROOM() > len) {
1468*7c478bd9Sstevel@tonic-gate ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
1469*7c478bd9Sstevel@tonic-gate printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
1470*7c478bd9Sstevel@tonic-gate }
1471*7c478bd9Sstevel@tonic-gate else
1472*7c478bd9Sstevel@tonic-gate (void) printf("telnet: not enough room in buffer for slc end "
1473*7c478bd9Sstevel@tonic-gate "reply\n");
1474*7c478bd9Sstevel@tonic-gate }
1475*7c478bd9Sstevel@tonic-gate
1476*7c478bd9Sstevel@tonic-gate static int
slc_update()1477*7c478bd9Sstevel@tonic-gate slc_update()
1478*7c478bd9Sstevel@tonic-gate {
1479*7c478bd9Sstevel@tonic-gate register struct spc *spcp;
1480*7c478bd9Sstevel@tonic-gate int need_update = 0;
1481*7c478bd9Sstevel@tonic-gate
1482*7c478bd9Sstevel@tonic-gate for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1483*7c478bd9Sstevel@tonic-gate if (!(spcp->flags&SLC_ACK))
1484*7c478bd9Sstevel@tonic-gate continue;
1485*7c478bd9Sstevel@tonic-gate spcp->flags &= ~SLC_ACK;
1486*7c478bd9Sstevel@tonic-gate if (spcp->valp && (*spcp->valp != spcp->val)) {
1487*7c478bd9Sstevel@tonic-gate *spcp->valp = spcp->val;
1488*7c478bd9Sstevel@tonic-gate need_update = 1;
1489*7c478bd9Sstevel@tonic-gate }
1490*7c478bd9Sstevel@tonic-gate }
1491*7c478bd9Sstevel@tonic-gate return (need_update);
1492*7c478bd9Sstevel@tonic-gate }
1493*7c478bd9Sstevel@tonic-gate
1494*7c478bd9Sstevel@tonic-gate #ifdef OLD_ENVIRON
1495*7c478bd9Sstevel@tonic-gate #ifdef ENV_HACK
1496*7c478bd9Sstevel@tonic-gate /*
1497*7c478bd9Sstevel@tonic-gate * Earlier version of telnet/telnetd from the BSD code had
1498*7c478bd9Sstevel@tonic-gate * the definitions of VALUE and VAR reversed. To ensure
1499*7c478bd9Sstevel@tonic-gate * maximum interoperability, we assume that the server is
1500*7c478bd9Sstevel@tonic-gate * an older BSD server, until proven otherwise. The newer
1501*7c478bd9Sstevel@tonic-gate * BSD servers should be able to handle either definition,
1502*7c478bd9Sstevel@tonic-gate * so it is better to use the wrong values if we don't
1503*7c478bd9Sstevel@tonic-gate * know what type of server it is.
1504*7c478bd9Sstevel@tonic-gate */
1505*7c478bd9Sstevel@tonic-gate int env_auto = 1;
1506*7c478bd9Sstevel@tonic-gate int old_env_var = OLD_ENV_VAR;
1507*7c478bd9Sstevel@tonic-gate int old_env_value = OLD_ENV_VALUE;
1508*7c478bd9Sstevel@tonic-gate #else
1509*7c478bd9Sstevel@tonic-gate #define old_env_var OLD_ENV_VAR
1510*7c478bd9Sstevel@tonic-gate #define old_env_value OLD_ENV_VALUE
1511*7c478bd9Sstevel@tonic-gate #endif
1512*7c478bd9Sstevel@tonic-gate #endif
1513*7c478bd9Sstevel@tonic-gate
1514*7c478bd9Sstevel@tonic-gate static void
env_opt(buf,len)1515*7c478bd9Sstevel@tonic-gate env_opt(buf, len)
1516*7c478bd9Sstevel@tonic-gate register unsigned char *buf;
1517*7c478bd9Sstevel@tonic-gate register int len;
1518*7c478bd9Sstevel@tonic-gate {
1519*7c478bd9Sstevel@tonic-gate register unsigned char *ep = 0, *epc = 0;
1520*7c478bd9Sstevel@tonic-gate register int i;
1521*7c478bd9Sstevel@tonic-gate
1522*7c478bd9Sstevel@tonic-gate switch (buf[0]&0xff) {
1523*7c478bd9Sstevel@tonic-gate case TELQUAL_SEND:
1524*7c478bd9Sstevel@tonic-gate env_opt_start();
1525*7c478bd9Sstevel@tonic-gate if (len == 1) {
1526*7c478bd9Sstevel@tonic-gate env_opt_add(NULL);
1527*7c478bd9Sstevel@tonic-gate } else for (i = 1; i < len; i++) {
1528*7c478bd9Sstevel@tonic-gate switch (buf[i]&0xff) {
1529*7c478bd9Sstevel@tonic-gate #ifdef OLD_ENVIRON
1530*7c478bd9Sstevel@tonic-gate case OLD_ENV_VAR:
1531*7c478bd9Sstevel@tonic-gate #ifdef ENV_HACK
1532*7c478bd9Sstevel@tonic-gate if (telopt_environ == TELOPT_OLD_ENVIRON &&
1533*7c478bd9Sstevel@tonic-gate env_auto) {
1534*7c478bd9Sstevel@tonic-gate /* Server has the same definitions */
1535*7c478bd9Sstevel@tonic-gate old_env_var = OLD_ENV_VAR;
1536*7c478bd9Sstevel@tonic-gate old_env_value = OLD_ENV_VALUE;
1537*7c478bd9Sstevel@tonic-gate }
1538*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
1539*7c478bd9Sstevel@tonic-gate #endif
1540*7c478bd9Sstevel@tonic-gate case OLD_ENV_VALUE:
1541*7c478bd9Sstevel@tonic-gate /*
1542*7c478bd9Sstevel@tonic-gate * Although OLD_ENV_VALUE is not legal, we will
1543*7c478bd9Sstevel@tonic-gate * still recognize it, just in case it is an
1544*7c478bd9Sstevel@tonic-gate * old server that has VAR & VALUE mixed up...
1545*7c478bd9Sstevel@tonic-gate */
1546*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
1547*7c478bd9Sstevel@tonic-gate #else
1548*7c478bd9Sstevel@tonic-gate case NEW_ENV_VAR:
1549*7c478bd9Sstevel@tonic-gate #endif
1550*7c478bd9Sstevel@tonic-gate case ENV_USERVAR:
1551*7c478bd9Sstevel@tonic-gate if (ep) {
1552*7c478bd9Sstevel@tonic-gate *epc = 0;
1553*7c478bd9Sstevel@tonic-gate env_opt_add(ep);
1554*7c478bd9Sstevel@tonic-gate }
1555*7c478bd9Sstevel@tonic-gate ep = epc = &buf[i+1];
1556*7c478bd9Sstevel@tonic-gate break;
1557*7c478bd9Sstevel@tonic-gate case ENV_ESC:
1558*7c478bd9Sstevel@tonic-gate i++;
1559*7c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/
1560*7c478bd9Sstevel@tonic-gate default:
1561*7c478bd9Sstevel@tonic-gate if (epc)
1562*7c478bd9Sstevel@tonic-gate *epc++ = buf[i];
1563*7c478bd9Sstevel@tonic-gate break;
1564*7c478bd9Sstevel@tonic-gate }
1565*7c478bd9Sstevel@tonic-gate }
1566*7c478bd9Sstevel@tonic-gate if (ep) {
1567*7c478bd9Sstevel@tonic-gate *epc = 0;
1568*7c478bd9Sstevel@tonic-gate env_opt_add(ep);
1569*7c478bd9Sstevel@tonic-gate }
1570*7c478bd9Sstevel@tonic-gate env_opt_end(1);
1571*7c478bd9Sstevel@tonic-gate break;
1572*7c478bd9Sstevel@tonic-gate
1573*7c478bd9Sstevel@tonic-gate case TELQUAL_IS:
1574*7c478bd9Sstevel@tonic-gate case TELQUAL_INFO:
1575*7c478bd9Sstevel@tonic-gate /* Ignore for now. We shouldn't get it anyway. */
1576*7c478bd9Sstevel@tonic-gate break;
1577*7c478bd9Sstevel@tonic-gate
1578*7c478bd9Sstevel@tonic-gate default:
1579*7c478bd9Sstevel@tonic-gate break;
1580*7c478bd9Sstevel@tonic-gate }
1581*7c478bd9Sstevel@tonic-gate }
1582*7c478bd9Sstevel@tonic-gate
1583*7c478bd9Sstevel@tonic-gate static unsigned char *opt_reply;
1584*7c478bd9Sstevel@tonic-gate static unsigned char *opt_replyp;
1585*7c478bd9Sstevel@tonic-gate static unsigned char *opt_replyend;
1586*7c478bd9Sstevel@tonic-gate #define OPT_REPLY_INITIAL_SIZE 256
1587*7c478bd9Sstevel@tonic-gate /*
1588*7c478bd9Sstevel@tonic-gate * The opt reply consists of: IAC, SB, telopt_environ, TELQUAL_IS,
1589*7c478bd9Sstevel@tonic-gate * value, IAC, SE. i.e. it has a 'wrapper' of 6 control characters.
1590*7c478bd9Sstevel@tonic-gate */
1591*7c478bd9Sstevel@tonic-gate #define OPT_WRAPPER_SIZE 6
1592*7c478bd9Sstevel@tonic-gate
1593*7c478bd9Sstevel@tonic-gate static void
env_opt_start()1594*7c478bd9Sstevel@tonic-gate env_opt_start()
1595*7c478bd9Sstevel@tonic-gate {
1596*7c478bd9Sstevel@tonic-gate opt_reply = realloc(opt_reply, OPT_REPLY_INITIAL_SIZE);
1597*7c478bd9Sstevel@tonic-gate if (opt_reply == NULL) {
1598*7c478bd9Sstevel@tonic-gate (void) printf(
1599*7c478bd9Sstevel@tonic-gate "telnet: error allocating environment option memory\n");
1600*7c478bd9Sstevel@tonic-gate opt_reply = opt_replyp = opt_replyend = NULL;
1601*7c478bd9Sstevel@tonic-gate return;
1602*7c478bd9Sstevel@tonic-gate }
1603*7c478bd9Sstevel@tonic-gate opt_replyp = opt_reply;
1604*7c478bd9Sstevel@tonic-gate opt_replyend = opt_reply + OPT_REPLY_INITIAL_SIZE;
1605*7c478bd9Sstevel@tonic-gate *opt_replyp++ = IAC;
1606*7c478bd9Sstevel@tonic-gate *opt_replyp++ = SB;
1607*7c478bd9Sstevel@tonic-gate *opt_replyp++ = telopt_environ;
1608*7c478bd9Sstevel@tonic-gate *opt_replyp++ = TELQUAL_IS;
1609*7c478bd9Sstevel@tonic-gate }
1610*7c478bd9Sstevel@tonic-gate
1611*7c478bd9Sstevel@tonic-gate void
env_opt_start_info()1612*7c478bd9Sstevel@tonic-gate env_opt_start_info()
1613*7c478bd9Sstevel@tonic-gate {
1614*7c478bd9Sstevel@tonic-gate env_opt_start();
1615*7c478bd9Sstevel@tonic-gate if (opt_replyp)
1616*7c478bd9Sstevel@tonic-gate opt_replyp[-1] = TELQUAL_INFO;
1617*7c478bd9Sstevel@tonic-gate }
1618*7c478bd9Sstevel@tonic-gate
1619*7c478bd9Sstevel@tonic-gate void
env_opt_add(ep)1620*7c478bd9Sstevel@tonic-gate env_opt_add(ep)
1621*7c478bd9Sstevel@tonic-gate register unsigned char *ep;
1622*7c478bd9Sstevel@tonic-gate {
1623*7c478bd9Sstevel@tonic-gate register unsigned char *vp, c;
1624*7c478bd9Sstevel@tonic-gate int opt_reply_size;
1625*7c478bd9Sstevel@tonic-gate int opt_reply_used;
1626*7c478bd9Sstevel@tonic-gate
1627*7c478bd9Sstevel@tonic-gate if (opt_reply == NULL) /* XXX */
1628*7c478bd9Sstevel@tonic-gate return; /* XXX */
1629*7c478bd9Sstevel@tonic-gate
1630*7c478bd9Sstevel@tonic-gate if (ep == NULL || *ep == '\0') {
1631*7c478bd9Sstevel@tonic-gate /* Send user defined variables first. */
1632*7c478bd9Sstevel@tonic-gate (void) env_default(1, 0);
1633*7c478bd9Sstevel@tonic-gate while (ep = env_default(0, 0))
1634*7c478bd9Sstevel@tonic-gate env_opt_add(ep);
1635*7c478bd9Sstevel@tonic-gate
1636*7c478bd9Sstevel@tonic-gate /* Now add the list of well know variables. */
1637*7c478bd9Sstevel@tonic-gate (void) env_default(1, 1);
1638*7c478bd9Sstevel@tonic-gate while (ep = env_default(0, 1))
1639*7c478bd9Sstevel@tonic-gate env_opt_add(ep);
1640*7c478bd9Sstevel@tonic-gate return;
1641*7c478bd9Sstevel@tonic-gate }
1642*7c478bd9Sstevel@tonic-gate vp = env_getvalue(ep);
1643*7c478bd9Sstevel@tonic-gate
1644*7c478bd9Sstevel@tonic-gate /*
1645*7c478bd9Sstevel@tonic-gate * Calculate space required for opt_reply and allocate more if required.
1646*7c478bd9Sstevel@tonic-gate * Assume worst case that every character is escaped, so needs 2 bytes.
1647*7c478bd9Sstevel@tonic-gate */
1648*7c478bd9Sstevel@tonic-gate opt_reply_used = opt_replyp - opt_reply; /* existing contents */
1649*7c478bd9Sstevel@tonic-gate opt_reply_size = opt_reply_used + OPT_WRAPPER_SIZE +
1650*7c478bd9Sstevel@tonic-gate (2 * (strlen((char *)ep))) +
1651*7c478bd9Sstevel@tonic-gate (vp == NULL ? 0 : (2 * strlen((char *)vp)));
1652*7c478bd9Sstevel@tonic-gate
1653*7c478bd9Sstevel@tonic-gate if (opt_reply_size > (opt_replyend - opt_reply)) {
1654*7c478bd9Sstevel@tonic-gate opt_reply = realloc(opt_reply, opt_reply_size);
1655*7c478bd9Sstevel@tonic-gate if (opt_reply == NULL) {
1656*7c478bd9Sstevel@tonic-gate (void) printf(
1657*7c478bd9Sstevel@tonic-gate "telnet: can't allocate environment option "
1658*7c478bd9Sstevel@tonic-gate "reply\n");
1659*7c478bd9Sstevel@tonic-gate opt_reply = opt_replyp = opt_replyend = NULL;
1660*7c478bd9Sstevel@tonic-gate return;
1661*7c478bd9Sstevel@tonic-gate }
1662*7c478bd9Sstevel@tonic-gate opt_replyp = opt_reply + opt_reply_used;
1663*7c478bd9Sstevel@tonic-gate opt_replyend = opt_reply + opt_reply_size;
1664*7c478bd9Sstevel@tonic-gate }
1665*7c478bd9Sstevel@tonic-gate
1666*7c478bd9Sstevel@tonic-gate if (opt_welldefined((char *)ep))
1667*7c478bd9Sstevel@tonic-gate #ifdef OLD_ENVIRON
1668*7c478bd9Sstevel@tonic-gate if (telopt_environ == TELOPT_OLD_ENVIRON)
1669*7c478bd9Sstevel@tonic-gate *opt_replyp++ = old_env_var;
1670*7c478bd9Sstevel@tonic-gate else
1671*7c478bd9Sstevel@tonic-gate #endif
1672*7c478bd9Sstevel@tonic-gate *opt_replyp++ = NEW_ENV_VAR;
1673*7c478bd9Sstevel@tonic-gate else
1674*7c478bd9Sstevel@tonic-gate *opt_replyp++ = ENV_USERVAR;
1675*7c478bd9Sstevel@tonic-gate for (;;) {
1676*7c478bd9Sstevel@tonic-gate while ((c = *ep++) != NULL) {
1677*7c478bd9Sstevel@tonic-gate switch (c&0xff) {
1678*7c478bd9Sstevel@tonic-gate case IAC:
1679*7c478bd9Sstevel@tonic-gate *opt_replyp++ = IAC;
1680*7c478bd9Sstevel@tonic-gate break;
1681*7c478bd9Sstevel@tonic-gate case NEW_ENV_VAR:
1682*7c478bd9Sstevel@tonic-gate case NEW_ENV_VALUE:
1683*7c478bd9Sstevel@tonic-gate case ENV_ESC:
1684*7c478bd9Sstevel@tonic-gate case ENV_USERVAR:
1685*7c478bd9Sstevel@tonic-gate *opt_replyp++ = ENV_ESC;
1686*7c478bd9Sstevel@tonic-gate break;
1687*7c478bd9Sstevel@tonic-gate }
1688*7c478bd9Sstevel@tonic-gate *opt_replyp++ = c;
1689*7c478bd9Sstevel@tonic-gate }
1690*7c478bd9Sstevel@tonic-gate if ((ep = vp) != NULL) {
1691*7c478bd9Sstevel@tonic-gate #ifdef OLD_ENVIRON
1692*7c478bd9Sstevel@tonic-gate if (telopt_environ == TELOPT_OLD_ENVIRON)
1693*7c478bd9Sstevel@tonic-gate *opt_replyp++ = old_env_value;
1694*7c478bd9Sstevel@tonic-gate else
1695*7c478bd9Sstevel@tonic-gate #endif
1696*7c478bd9Sstevel@tonic-gate *opt_replyp++ = NEW_ENV_VALUE;
1697*7c478bd9Sstevel@tonic-gate vp = NULL;
1698*7c478bd9Sstevel@tonic-gate } else
1699*7c478bd9Sstevel@tonic-gate break;
1700*7c478bd9Sstevel@tonic-gate }
1701*7c478bd9Sstevel@tonic-gate }
1702*7c478bd9Sstevel@tonic-gate
1703*7c478bd9Sstevel@tonic-gate int
opt_welldefined(ep)1704*7c478bd9Sstevel@tonic-gate opt_welldefined(ep)
1705*7c478bd9Sstevel@tonic-gate char *ep;
1706*7c478bd9Sstevel@tonic-gate {
1707*7c478bd9Sstevel@tonic-gate if ((strcmp(ep, "USER") == 0) ||
1708*7c478bd9Sstevel@tonic-gate (strcmp(ep, "DISPLAY") == 0) ||
1709*7c478bd9Sstevel@tonic-gate (strcmp(ep, "PRINTER") == 0) ||
1710*7c478bd9Sstevel@tonic-gate (strcmp(ep, "SYSTEMTYPE") == 0) ||
1711*7c478bd9Sstevel@tonic-gate (strcmp(ep, "JOB") == 0) ||
1712*7c478bd9Sstevel@tonic-gate (strcmp(ep, "ACCT") == 0))
1713*7c478bd9Sstevel@tonic-gate return (1);
1714*7c478bd9Sstevel@tonic-gate return (0);
1715*7c478bd9Sstevel@tonic-gate }
1716*7c478bd9Sstevel@tonic-gate void
env_opt_end(emptyok)1717*7c478bd9Sstevel@tonic-gate env_opt_end(emptyok)
1718*7c478bd9Sstevel@tonic-gate register int emptyok;
1719*7c478bd9Sstevel@tonic-gate {
1720*7c478bd9Sstevel@tonic-gate register int len;
1721*7c478bd9Sstevel@tonic-gate
1722*7c478bd9Sstevel@tonic-gate len = opt_replyp - opt_reply + 2;
1723*7c478bd9Sstevel@tonic-gate if (emptyok || len > OPT_WRAPPER_SIZE) {
1724*7c478bd9Sstevel@tonic-gate *opt_replyp++ = IAC;
1725*7c478bd9Sstevel@tonic-gate *opt_replyp++ = SE;
1726*7c478bd9Sstevel@tonic-gate if (NETROOM() > len) {
1727*7c478bd9Sstevel@tonic-gate ring_supply_data(&netoring, opt_reply, len);
1728*7c478bd9Sstevel@tonic-gate printsub('>', &opt_reply[2], len - 2);
1729*7c478bd9Sstevel@tonic-gate }
1730*7c478bd9Sstevel@tonic-gate else
1731*7c478bd9Sstevel@tonic-gate (void) printf("telnet: not enough room in buffer for "
1732*7c478bd9Sstevel@tonic-gate "environment option end reply\n");
1733*7c478bd9Sstevel@tonic-gate }
1734*7c478bd9Sstevel@tonic-gate if (opt_reply) {
1735*7c478bd9Sstevel@tonic-gate free(opt_reply);
1736*7c478bd9Sstevel@tonic-gate opt_reply = opt_replyp = opt_replyend = NULL;
1737*7c478bd9Sstevel@tonic-gate }
1738*7c478bd9Sstevel@tonic-gate }
1739*7c478bd9Sstevel@tonic-gate
1740*7c478bd9Sstevel@tonic-gate
1741*7c478bd9Sstevel@tonic-gate
1742*7c478bd9Sstevel@tonic-gate int
telrcv()1743*7c478bd9Sstevel@tonic-gate telrcv()
1744*7c478bd9Sstevel@tonic-gate {
1745*7c478bd9Sstevel@tonic-gate register int c;
1746*7c478bd9Sstevel@tonic-gate register int scc;
1747*7c478bd9Sstevel@tonic-gate register unsigned char *sbp;
1748*7c478bd9Sstevel@tonic-gate int count;
1749*7c478bd9Sstevel@tonic-gate int returnValue = 0;
1750*7c478bd9Sstevel@tonic-gate int min_room = 0;
1751*7c478bd9Sstevel@tonic-gate
1752*7c478bd9Sstevel@tonic-gate scc = 0;
1753*7c478bd9Sstevel@tonic-gate count = 0;
1754*7c478bd9Sstevel@tonic-gate while (--min_room > 2 || (min_room = TTYROOM()) > 2) {
1755*7c478bd9Sstevel@tonic-gate if (scc == 0) {
1756*7c478bd9Sstevel@tonic-gate if (count) {
1757*7c478bd9Sstevel@tonic-gate ring_consumed(&netiring, count);
1758*7c478bd9Sstevel@tonic-gate returnValue = 1;
1759*7c478bd9Sstevel@tonic-gate count = 0;
1760*7c478bd9Sstevel@tonic-gate }
1761*7c478bd9Sstevel@tonic-gate sbp = netiring.consume;
1762*7c478bd9Sstevel@tonic-gate scc = ring_full_consecutive(&netiring);
1763*7c478bd9Sstevel@tonic-gate if (scc == 0) {
1764*7c478bd9Sstevel@tonic-gate /* No more data coming in */
1765*7c478bd9Sstevel@tonic-gate break;
1766*7c478bd9Sstevel@tonic-gate }
1767*7c478bd9Sstevel@tonic-gate }
1768*7c478bd9Sstevel@tonic-gate
1769*7c478bd9Sstevel@tonic-gate c = *sbp++ & 0xff, scc--; count++;
1770*7c478bd9Sstevel@tonic-gate
1771*7c478bd9Sstevel@tonic-gate if (decrypt_input)
1772*7c478bd9Sstevel@tonic-gate c = (*decrypt_input)(c);
1773*7c478bd9Sstevel@tonic-gate
1774*7c478bd9Sstevel@tonic-gate switch (telrcv_state) {
1775*7c478bd9Sstevel@tonic-gate
1776*7c478bd9Sstevel@tonic-gate case TS_CR:
1777*7c478bd9Sstevel@tonic-gate telrcv_state = TS_DATA;
1778*7c478bd9Sstevel@tonic-gate if (c == '\0') {
1779*7c478bd9Sstevel@tonic-gate break; /* Ignore \0 after CR */
1780*7c478bd9Sstevel@tonic-gate } else if ((c == '\n') &&
1781*7c478bd9Sstevel@tonic-gate my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
1782*7c478bd9Sstevel@tonic-gate TTYADD(c);
1783*7c478bd9Sstevel@tonic-gate break;
1784*7c478bd9Sstevel@tonic-gate }
1785*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
1786*7c478bd9Sstevel@tonic-gate
1787*7c478bd9Sstevel@tonic-gate case TS_DATA:
1788*7c478bd9Sstevel@tonic-gate if (c == IAC) {
1789*7c478bd9Sstevel@tonic-gate telrcv_state = TS_IAC;
1790*7c478bd9Sstevel@tonic-gate break;
1791*7c478bd9Sstevel@tonic-gate }
1792*7c478bd9Sstevel@tonic-gate /*
1793*7c478bd9Sstevel@tonic-gate * The 'crmod' hack (see following) is needed
1794*7c478bd9Sstevel@tonic-gate * since we can't * set CRMOD on output only.
1795*7c478bd9Sstevel@tonic-gate * Machines like MULTICS like to send \r without
1796*7c478bd9Sstevel@tonic-gate * \n; since we must turn off CRMOD to get proper
1797*7c478bd9Sstevel@tonic-gate * input, the mapping is done here (sigh).
1798*7c478bd9Sstevel@tonic-gate */
1799*7c478bd9Sstevel@tonic-gate if ((c == '\r') &&
1800*7c478bd9Sstevel@tonic-gate my_want_state_is_dont(TELOPT_BINARY)) {
1801*7c478bd9Sstevel@tonic-gate if (scc > 0) {
1802*7c478bd9Sstevel@tonic-gate c = *sbp&0xff;
1803*7c478bd9Sstevel@tonic-gate
1804*7c478bd9Sstevel@tonic-gate if (decrypt_input)
1805*7c478bd9Sstevel@tonic-gate c = (*decrypt_input)(c);
1806*7c478bd9Sstevel@tonic-gate
1807*7c478bd9Sstevel@tonic-gate if (c == 0) {
1808*7c478bd9Sstevel@tonic-gate sbp++, scc--; count++;
1809*7c478bd9Sstevel@tonic-gate /* a "true" CR */
1810*7c478bd9Sstevel@tonic-gate TTYADD('\r');
1811*7c478bd9Sstevel@tonic-gate } else if (my_want_state_is_dont(
1812*7c478bd9Sstevel@tonic-gate TELOPT_ECHO) && (c == '\n')) {
1813*7c478bd9Sstevel@tonic-gate sbp++, scc--; count++;
1814*7c478bd9Sstevel@tonic-gate TTYADD('\n');
1815*7c478bd9Sstevel@tonic-gate } else {
1816*7c478bd9Sstevel@tonic-gate
1817*7c478bd9Sstevel@tonic-gate if (decrypt_input)
1818*7c478bd9Sstevel@tonic-gate (*decrypt_input)(-1);
1819*7c478bd9Sstevel@tonic-gate
1820*7c478bd9Sstevel@tonic-gate TTYADD('\r');
1821*7c478bd9Sstevel@tonic-gate if (crmod) {
1822*7c478bd9Sstevel@tonic-gate TTYADD('\n');
1823*7c478bd9Sstevel@tonic-gate }
1824*7c478bd9Sstevel@tonic-gate }
1825*7c478bd9Sstevel@tonic-gate } else {
1826*7c478bd9Sstevel@tonic-gate telrcv_state = TS_CR;
1827*7c478bd9Sstevel@tonic-gate TTYADD('\r');
1828*7c478bd9Sstevel@tonic-gate if (crmod) {
1829*7c478bd9Sstevel@tonic-gate TTYADD('\n');
1830*7c478bd9Sstevel@tonic-gate }
1831*7c478bd9Sstevel@tonic-gate }
1832*7c478bd9Sstevel@tonic-gate } else {
1833*7c478bd9Sstevel@tonic-gate TTYADD(c);
1834*7c478bd9Sstevel@tonic-gate }
1835*7c478bd9Sstevel@tonic-gate continue;
1836*7c478bd9Sstevel@tonic-gate
1837*7c478bd9Sstevel@tonic-gate case TS_IAC:
1838*7c478bd9Sstevel@tonic-gate process_iac:
1839*7c478bd9Sstevel@tonic-gate switch (c) {
1840*7c478bd9Sstevel@tonic-gate
1841*7c478bd9Sstevel@tonic-gate case WILL:
1842*7c478bd9Sstevel@tonic-gate telrcv_state = TS_WILL;
1843*7c478bd9Sstevel@tonic-gate continue;
1844*7c478bd9Sstevel@tonic-gate
1845*7c478bd9Sstevel@tonic-gate case WONT:
1846*7c478bd9Sstevel@tonic-gate telrcv_state = TS_WONT;
1847*7c478bd9Sstevel@tonic-gate continue;
1848*7c478bd9Sstevel@tonic-gate
1849*7c478bd9Sstevel@tonic-gate case DO:
1850*7c478bd9Sstevel@tonic-gate telrcv_state = TS_DO;
1851*7c478bd9Sstevel@tonic-gate continue;
1852*7c478bd9Sstevel@tonic-gate
1853*7c478bd9Sstevel@tonic-gate case DONT:
1854*7c478bd9Sstevel@tonic-gate telrcv_state = TS_DONT;
1855*7c478bd9Sstevel@tonic-gate continue;
1856*7c478bd9Sstevel@tonic-gate
1857*7c478bd9Sstevel@tonic-gate case DM:
1858*7c478bd9Sstevel@tonic-gate /*
1859*7c478bd9Sstevel@tonic-gate * We may have missed an urgent notification,
1860*7c478bd9Sstevel@tonic-gate * so make sure we flush whatever is in the
1861*7c478bd9Sstevel@tonic-gate * buffer currently.
1862*7c478bd9Sstevel@tonic-gate */
1863*7c478bd9Sstevel@tonic-gate printoption("RCVD", IAC, DM);
1864*7c478bd9Sstevel@tonic-gate SYNCHing = 1;
1865*7c478bd9Sstevel@tonic-gate if (ttyflush(1) == -2) {
1866*7c478bd9Sstevel@tonic-gate /* This will not return. */
1867*7c478bd9Sstevel@tonic-gate fatal_tty_error("write");
1868*7c478bd9Sstevel@tonic-gate }
1869*7c478bd9Sstevel@tonic-gate SYNCHing = stilloob();
1870*7c478bd9Sstevel@tonic-gate settimer(gotDM);
1871*7c478bd9Sstevel@tonic-gate break;
1872*7c478bd9Sstevel@tonic-gate
1873*7c478bd9Sstevel@tonic-gate case SB:
1874*7c478bd9Sstevel@tonic-gate SB_CLEAR();
1875*7c478bd9Sstevel@tonic-gate telrcv_state = TS_SB;
1876*7c478bd9Sstevel@tonic-gate continue;
1877*7c478bd9Sstevel@tonic-gate
1878*7c478bd9Sstevel@tonic-gate case IAC:
1879*7c478bd9Sstevel@tonic-gate TTYADD(IAC);
1880*7c478bd9Sstevel@tonic-gate break;
1881*7c478bd9Sstevel@tonic-gate
1882*7c478bd9Sstevel@tonic-gate case NOP:
1883*7c478bd9Sstevel@tonic-gate case GA:
1884*7c478bd9Sstevel@tonic-gate default:
1885*7c478bd9Sstevel@tonic-gate printoption("RCVD", IAC, c);
1886*7c478bd9Sstevel@tonic-gate break;
1887*7c478bd9Sstevel@tonic-gate }
1888*7c478bd9Sstevel@tonic-gate telrcv_state = TS_DATA;
1889*7c478bd9Sstevel@tonic-gate continue;
1890*7c478bd9Sstevel@tonic-gate
1891*7c478bd9Sstevel@tonic-gate case TS_WILL:
1892*7c478bd9Sstevel@tonic-gate printoption("RCVD", WILL, c);
1893*7c478bd9Sstevel@tonic-gate willoption(c);
1894*7c478bd9Sstevel@tonic-gate telrcv_state = TS_DATA;
1895*7c478bd9Sstevel@tonic-gate continue;
1896*7c478bd9Sstevel@tonic-gate
1897*7c478bd9Sstevel@tonic-gate case TS_WONT:
1898*7c478bd9Sstevel@tonic-gate printoption("RCVD", WONT, c);
1899*7c478bd9Sstevel@tonic-gate wontoption(c);
1900*7c478bd9Sstevel@tonic-gate telrcv_state = TS_DATA;
1901*7c478bd9Sstevel@tonic-gate continue;
1902*7c478bd9Sstevel@tonic-gate
1903*7c478bd9Sstevel@tonic-gate case TS_DO:
1904*7c478bd9Sstevel@tonic-gate printoption("RCVD", DO, c);
1905*7c478bd9Sstevel@tonic-gate dooption(c);
1906*7c478bd9Sstevel@tonic-gate if (c == TELOPT_NAWS) {
1907*7c478bd9Sstevel@tonic-gate sendnaws();
1908*7c478bd9Sstevel@tonic-gate } else if (c == TELOPT_LFLOW) {
1909*7c478bd9Sstevel@tonic-gate localflow = 1;
1910*7c478bd9Sstevel@tonic-gate setcommandmode();
1911*7c478bd9Sstevel@tonic-gate setconnmode(0);
1912*7c478bd9Sstevel@tonic-gate }
1913*7c478bd9Sstevel@tonic-gate telrcv_state = TS_DATA;
1914*7c478bd9Sstevel@tonic-gate continue;
1915*7c478bd9Sstevel@tonic-gate
1916*7c478bd9Sstevel@tonic-gate case TS_DONT:
1917*7c478bd9Sstevel@tonic-gate printoption("RCVD", DONT, c);
1918*7c478bd9Sstevel@tonic-gate dontoption(c);
1919*7c478bd9Sstevel@tonic-gate flushline = 1;
1920*7c478bd9Sstevel@tonic-gate setconnmode(0); /* set new tty mode (maybe) */
1921*7c478bd9Sstevel@tonic-gate telrcv_state = TS_DATA;
1922*7c478bd9Sstevel@tonic-gate continue;
1923*7c478bd9Sstevel@tonic-gate
1924*7c478bd9Sstevel@tonic-gate case TS_SB:
1925*7c478bd9Sstevel@tonic-gate if (c == IAC) {
1926*7c478bd9Sstevel@tonic-gate telrcv_state = TS_SE;
1927*7c478bd9Sstevel@tonic-gate } else {
1928*7c478bd9Sstevel@tonic-gate SB_ACCUM(c);
1929*7c478bd9Sstevel@tonic-gate }
1930*7c478bd9Sstevel@tonic-gate continue;
1931*7c478bd9Sstevel@tonic-gate
1932*7c478bd9Sstevel@tonic-gate case TS_SE:
1933*7c478bd9Sstevel@tonic-gate if (c != SE) {
1934*7c478bd9Sstevel@tonic-gate if (c != IAC) {
1935*7c478bd9Sstevel@tonic-gate /*
1936*7c478bd9Sstevel@tonic-gate * This is an error. We only expect to get
1937*7c478bd9Sstevel@tonic-gate * "IAC IAC" or "IAC SE". Several things may
1938*7c478bd9Sstevel@tonic-gate * have happend. An IAC was not doubled, the
1939*7c478bd9Sstevel@tonic-gate * IAC SE was left off, or another option got
1940*7c478bd9Sstevel@tonic-gate * inserted into the suboption are all possibilities.
1941*7c478bd9Sstevel@tonic-gate * If we assume that the IAC was not doubled,
1942*7c478bd9Sstevel@tonic-gate * and really the IAC SE was left off, we could
1943*7c478bd9Sstevel@tonic-gate * get into an infinate loop here. So, instead,
1944*7c478bd9Sstevel@tonic-gate * we terminate the suboption, and process the
1945*7c478bd9Sstevel@tonic-gate * partial suboption if we can.
1946*7c478bd9Sstevel@tonic-gate */
1947*7c478bd9Sstevel@tonic-gate SB_ACCUM(IAC);
1948*7c478bd9Sstevel@tonic-gate SB_ACCUM(c);
1949*7c478bd9Sstevel@tonic-gate subpointer -= 2;
1950*7c478bd9Sstevel@tonic-gate SB_TERM();
1951*7c478bd9Sstevel@tonic-gate
1952*7c478bd9Sstevel@tonic-gate printoption("In SUBOPTION processing, "
1953*7c478bd9Sstevel@tonic-gate "RCVD", IAC, c);
1954*7c478bd9Sstevel@tonic-gate suboption(); /* handle sub-option */
1955*7c478bd9Sstevel@tonic-gate telrcv_state = TS_IAC;
1956*7c478bd9Sstevel@tonic-gate goto process_iac;
1957*7c478bd9Sstevel@tonic-gate }
1958*7c478bd9Sstevel@tonic-gate SB_ACCUM(c);
1959*7c478bd9Sstevel@tonic-gate telrcv_state = TS_SB;
1960*7c478bd9Sstevel@tonic-gate } else {
1961*7c478bd9Sstevel@tonic-gate SB_ACCUM(IAC);
1962*7c478bd9Sstevel@tonic-gate SB_ACCUM(SE);
1963*7c478bd9Sstevel@tonic-gate subpointer -= 2;
1964*7c478bd9Sstevel@tonic-gate SB_TERM();
1965*7c478bd9Sstevel@tonic-gate suboption(); /* handle sub-option */
1966*7c478bd9Sstevel@tonic-gate telrcv_state = TS_DATA;
1967*7c478bd9Sstevel@tonic-gate }
1968*7c478bd9Sstevel@tonic-gate }
1969*7c478bd9Sstevel@tonic-gate }
1970*7c478bd9Sstevel@tonic-gate if (count)
1971*7c478bd9Sstevel@tonic-gate ring_consumed(&netiring, count);
1972*7c478bd9Sstevel@tonic-gate return (returnValue||count);
1973*7c478bd9Sstevel@tonic-gate }
1974*7c478bd9Sstevel@tonic-gate
1975*7c478bd9Sstevel@tonic-gate static int bol = 1, local = 0;
1976*7c478bd9Sstevel@tonic-gate
1977*7c478bd9Sstevel@tonic-gate int
rlogin_susp()1978*7c478bd9Sstevel@tonic-gate rlogin_susp()
1979*7c478bd9Sstevel@tonic-gate {
1980*7c478bd9Sstevel@tonic-gate if (local) {
1981*7c478bd9Sstevel@tonic-gate local = 0;
1982*7c478bd9Sstevel@tonic-gate bol = 1;
1983*7c478bd9Sstevel@tonic-gate command(0, "z\n", 2);
1984*7c478bd9Sstevel@tonic-gate return (1);
1985*7c478bd9Sstevel@tonic-gate }
1986*7c478bd9Sstevel@tonic-gate return (0);
1987*7c478bd9Sstevel@tonic-gate }
1988*7c478bd9Sstevel@tonic-gate
1989*7c478bd9Sstevel@tonic-gate static int
telsnd()1990*7c478bd9Sstevel@tonic-gate telsnd()
1991*7c478bd9Sstevel@tonic-gate {
1992*7c478bd9Sstevel@tonic-gate int tcc;
1993*7c478bd9Sstevel@tonic-gate int count;
1994*7c478bd9Sstevel@tonic-gate int returnValue = 0;
1995*7c478bd9Sstevel@tonic-gate unsigned char *tbp;
1996*7c478bd9Sstevel@tonic-gate
1997*7c478bd9Sstevel@tonic-gate tcc = 0;
1998*7c478bd9Sstevel@tonic-gate count = 0;
1999*7c478bd9Sstevel@tonic-gate while (NETROOM() > 2) {
2000*7c478bd9Sstevel@tonic-gate register int sc;
2001*7c478bd9Sstevel@tonic-gate register int c;
2002*7c478bd9Sstevel@tonic-gate
2003*7c478bd9Sstevel@tonic-gate if (tcc == 0) {
2004*7c478bd9Sstevel@tonic-gate if (count) {
2005*7c478bd9Sstevel@tonic-gate ring_consumed(&ttyiring, count);
2006*7c478bd9Sstevel@tonic-gate returnValue = 1;
2007*7c478bd9Sstevel@tonic-gate count = 0;
2008*7c478bd9Sstevel@tonic-gate }
2009*7c478bd9Sstevel@tonic-gate tbp = ttyiring.consume;
2010*7c478bd9Sstevel@tonic-gate tcc = ring_full_consecutive(&ttyiring);
2011*7c478bd9Sstevel@tonic-gate if (tcc == 0) {
2012*7c478bd9Sstevel@tonic-gate break;
2013*7c478bd9Sstevel@tonic-gate }
2014*7c478bd9Sstevel@tonic-gate }
2015*7c478bd9Sstevel@tonic-gate c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
2016*7c478bd9Sstevel@tonic-gate if (rlogin != _POSIX_VDISABLE) {
2017*7c478bd9Sstevel@tonic-gate if (bol) {
2018*7c478bd9Sstevel@tonic-gate bol = 0;
2019*7c478bd9Sstevel@tonic-gate if (sc == rlogin) {
2020*7c478bd9Sstevel@tonic-gate local = 1;
2021*7c478bd9Sstevel@tonic-gate continue;
2022*7c478bd9Sstevel@tonic-gate }
2023*7c478bd9Sstevel@tonic-gate } else if (local) {
2024*7c478bd9Sstevel@tonic-gate local = 0;
2025*7c478bd9Sstevel@tonic-gate if (sc == '.' || c == termEofChar) {
2026*7c478bd9Sstevel@tonic-gate bol = 1;
2027*7c478bd9Sstevel@tonic-gate command(0, "close\n", 6);
2028*7c478bd9Sstevel@tonic-gate continue;
2029*7c478bd9Sstevel@tonic-gate }
2030*7c478bd9Sstevel@tonic-gate if (sc == termSuspChar) {
2031*7c478bd9Sstevel@tonic-gate bol = 1;
2032*7c478bd9Sstevel@tonic-gate command(0, "z\n", 2);
2033*7c478bd9Sstevel@tonic-gate continue;
2034*7c478bd9Sstevel@tonic-gate }
2035*7c478bd9Sstevel@tonic-gate if (sc == escape) {
2036*7c478bd9Sstevel@tonic-gate command(0, (char *)tbp, tcc);
2037*7c478bd9Sstevel@tonic-gate bol = 1;
2038*7c478bd9Sstevel@tonic-gate count += tcc;
2039*7c478bd9Sstevel@tonic-gate tcc = 0;
2040*7c478bd9Sstevel@tonic-gate flushline = 1;
2041*7c478bd9Sstevel@tonic-gate break;
2042*7c478bd9Sstevel@tonic-gate }
2043*7c478bd9Sstevel@tonic-gate if (sc != rlogin) {
2044*7c478bd9Sstevel@tonic-gate ++tcc;
2045*7c478bd9Sstevel@tonic-gate --tbp;
2046*7c478bd9Sstevel@tonic-gate --count;
2047*7c478bd9Sstevel@tonic-gate c = sc = rlogin;
2048*7c478bd9Sstevel@tonic-gate }
2049*7c478bd9Sstevel@tonic-gate }
2050*7c478bd9Sstevel@tonic-gate if ((sc == '\n') || (sc == '\r'))
2051*7c478bd9Sstevel@tonic-gate bol = 1;
2052*7c478bd9Sstevel@tonic-gate } else if (sc == escape && escape_valid) {
2053*7c478bd9Sstevel@tonic-gate /*
2054*7c478bd9Sstevel@tonic-gate * Double escape is a pass through of a single
2055*7c478bd9Sstevel@tonic-gate * escape character.
2056*7c478bd9Sstevel@tonic-gate */
2057*7c478bd9Sstevel@tonic-gate if (tcc && strip(*tbp) == escape) {
2058*7c478bd9Sstevel@tonic-gate tbp++;
2059*7c478bd9Sstevel@tonic-gate tcc--;
2060*7c478bd9Sstevel@tonic-gate count++;
2061*7c478bd9Sstevel@tonic-gate bol = 0;
2062*7c478bd9Sstevel@tonic-gate } else {
2063*7c478bd9Sstevel@tonic-gate command(0, (char *)tbp, tcc);
2064*7c478bd9Sstevel@tonic-gate bol = 1;
2065*7c478bd9Sstevel@tonic-gate count += tcc;
2066*7c478bd9Sstevel@tonic-gate tcc = 0;
2067*7c478bd9Sstevel@tonic-gate flushline = 1;
2068*7c478bd9Sstevel@tonic-gate break;
2069*7c478bd9Sstevel@tonic-gate }
2070*7c478bd9Sstevel@tonic-gate } else
2071*7c478bd9Sstevel@tonic-gate bol = 0;
2072*7c478bd9Sstevel@tonic-gate #ifdef KLUDGELINEMODE
2073*7c478bd9Sstevel@tonic-gate if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
2074*7c478bd9Sstevel@tonic-gate if (tcc > 0 && strip(*tbp) == echoc) {
2075*7c478bd9Sstevel@tonic-gate tcc--; tbp++; count++;
2076*7c478bd9Sstevel@tonic-gate } else {
2077*7c478bd9Sstevel@tonic-gate dontlecho = !dontlecho;
2078*7c478bd9Sstevel@tonic-gate settimer(echotoggle);
2079*7c478bd9Sstevel@tonic-gate setconnmode(0);
2080*7c478bd9Sstevel@tonic-gate flushline = 1;
2081*7c478bd9Sstevel@tonic-gate break;
2082*7c478bd9Sstevel@tonic-gate }
2083*7c478bd9Sstevel@tonic-gate }
2084*7c478bd9Sstevel@tonic-gate #endif
2085*7c478bd9Sstevel@tonic-gate if (MODE_LOCAL_CHARS(globalmode)) {
2086*7c478bd9Sstevel@tonic-gate if (TerminalSpecialChars(sc) == 0) {
2087*7c478bd9Sstevel@tonic-gate bol = 1;
2088*7c478bd9Sstevel@tonic-gate break;
2089*7c478bd9Sstevel@tonic-gate }
2090*7c478bd9Sstevel@tonic-gate }
2091*7c478bd9Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_BINARY)) {
2092*7c478bd9Sstevel@tonic-gate switch (c) {
2093*7c478bd9Sstevel@tonic-gate case '\n':
2094*7c478bd9Sstevel@tonic-gate /*
2095*7c478bd9Sstevel@tonic-gate * If we are in CRMOD mode (\r ==> \n)
2096*7c478bd9Sstevel@tonic-gate * on our local machine, then probably
2097*7c478bd9Sstevel@tonic-gate * a newline (unix) is CRLF (TELNET).
2098*7c478bd9Sstevel@tonic-gate */
2099*7c478bd9Sstevel@tonic-gate if (MODE_LOCAL_CHARS(globalmode)) {
2100*7c478bd9Sstevel@tonic-gate NETADD('\r');
2101*7c478bd9Sstevel@tonic-gate }
2102*7c478bd9Sstevel@tonic-gate NETADD('\n');
2103*7c478bd9Sstevel@tonic-gate bol = flushline = 1;
2104*7c478bd9Sstevel@tonic-gate break;
2105*7c478bd9Sstevel@tonic-gate case '\r':
2106*7c478bd9Sstevel@tonic-gate if (!crlf) {
2107*7c478bd9Sstevel@tonic-gate NET2ADD('\r', '\0');
2108*7c478bd9Sstevel@tonic-gate } else {
2109*7c478bd9Sstevel@tonic-gate NET2ADD('\r', '\n');
2110*7c478bd9Sstevel@tonic-gate }
2111*7c478bd9Sstevel@tonic-gate bol = flushline = 1;
2112*7c478bd9Sstevel@tonic-gate break;
2113*7c478bd9Sstevel@tonic-gate case IAC:
2114*7c478bd9Sstevel@tonic-gate NET2ADD(IAC, IAC);
2115*7c478bd9Sstevel@tonic-gate break;
2116*7c478bd9Sstevel@tonic-gate default:
2117*7c478bd9Sstevel@tonic-gate NETADD(c);
2118*7c478bd9Sstevel@tonic-gate break;
2119*7c478bd9Sstevel@tonic-gate }
2120*7c478bd9Sstevel@tonic-gate } else if (c == IAC) {
2121*7c478bd9Sstevel@tonic-gate NET2ADD(IAC, IAC);
2122*7c478bd9Sstevel@tonic-gate } else {
2123*7c478bd9Sstevel@tonic-gate NETADD(c);
2124*7c478bd9Sstevel@tonic-gate }
2125*7c478bd9Sstevel@tonic-gate }
2126*7c478bd9Sstevel@tonic-gate if (count)
2127*7c478bd9Sstevel@tonic-gate ring_consumed(&ttyiring, count);
2128*7c478bd9Sstevel@tonic-gate return (returnValue||count); /* Non-zero if we did anything */
2129*7c478bd9Sstevel@tonic-gate }
2130*7c478bd9Sstevel@tonic-gate
2131*7c478bd9Sstevel@tonic-gate /*
2132*7c478bd9Sstevel@tonic-gate * Scheduler()
2133*7c478bd9Sstevel@tonic-gate *
2134*7c478bd9Sstevel@tonic-gate * Try to do something.
2135*7c478bd9Sstevel@tonic-gate *
2136*7c478bd9Sstevel@tonic-gate * If we do something useful, return 1; else return 0.
2137*7c478bd9Sstevel@tonic-gate *
2138*7c478bd9Sstevel@tonic-gate */
2139*7c478bd9Sstevel@tonic-gate
2140*7c478bd9Sstevel@tonic-gate
2141*7c478bd9Sstevel@tonic-gate int
Scheduler(block)2142*7c478bd9Sstevel@tonic-gate Scheduler(block)
2143*7c478bd9Sstevel@tonic-gate int block; /* should we block in the select ? */
2144*7c478bd9Sstevel@tonic-gate {
2145*7c478bd9Sstevel@tonic-gate /*
2146*7c478bd9Sstevel@tonic-gate * One wants to be a bit careful about setting returnValue
2147*7c478bd9Sstevel@tonic-gate * to one, since a one implies we did some useful work,
2148*7c478bd9Sstevel@tonic-gate * and therefore probably won't be called to block next
2149*7c478bd9Sstevel@tonic-gate * time (TN3270 mode only).
2150*7c478bd9Sstevel@tonic-gate */
2151*7c478bd9Sstevel@tonic-gate int returnValue;
2152*7c478bd9Sstevel@tonic-gate int netin, netout, netex, ttyin, ttyout;
2153*7c478bd9Sstevel@tonic-gate
2154*7c478bd9Sstevel@tonic-gate /* Decide which rings should be processed */
2155*7c478bd9Sstevel@tonic-gate
2156*7c478bd9Sstevel@tonic-gate netout = ring_full_count(&netoring) &&
2157*7c478bd9Sstevel@tonic-gate (flushline ||
2158*7c478bd9Sstevel@tonic-gate (my_want_state_is_wont(TELOPT_LINEMODE)
2159*7c478bd9Sstevel@tonic-gate #ifdef KLUDGELINEMODE
2160*7c478bd9Sstevel@tonic-gate /* X */ && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
2161*7c478bd9Sstevel@tonic-gate #endif
2162*7c478bd9Sstevel@tonic-gate /* XXX */) ||
2163*7c478bd9Sstevel@tonic-gate my_want_state_is_will(TELOPT_BINARY));
2164*7c478bd9Sstevel@tonic-gate ttyout = ring_full_count(&ttyoring);
2165*7c478bd9Sstevel@tonic-gate
2166*7c478bd9Sstevel@tonic-gate ttyin = (ring_empty_count(&ttyiring) && !eof_pending);
2167*7c478bd9Sstevel@tonic-gate
2168*7c478bd9Sstevel@tonic-gate netin = !ISend && ring_empty_count(&netiring);
2169*7c478bd9Sstevel@tonic-gate
2170*7c478bd9Sstevel@tonic-gate netex = !SYNCHing;
2171*7c478bd9Sstevel@tonic-gate
2172*7c478bd9Sstevel@tonic-gate if (scheduler_lockout_tty) {
2173*7c478bd9Sstevel@tonic-gate ttyin = ttyout = 0;
2174*7c478bd9Sstevel@tonic-gate }
2175*7c478bd9Sstevel@tonic-gate
2176*7c478bd9Sstevel@tonic-gate /* Call to system code to process rings */
2177*7c478bd9Sstevel@tonic-gate
2178*7c478bd9Sstevel@tonic-gate returnValue = process_rings(netin, netout, netex, ttyin, ttyout,
2179*7c478bd9Sstevel@tonic-gate !block);
2180*7c478bd9Sstevel@tonic-gate
2181*7c478bd9Sstevel@tonic-gate /* Now, look at the input rings, looking for work to do. */
2182*7c478bd9Sstevel@tonic-gate
2183*7c478bd9Sstevel@tonic-gate if (ring_full_count(&ttyiring)) {
2184*7c478bd9Sstevel@tonic-gate returnValue |= telsnd();
2185*7c478bd9Sstevel@tonic-gate } else {
2186*7c478bd9Sstevel@tonic-gate /*
2187*7c478bd9Sstevel@tonic-gate * If ttyiring is empty, check to see if there is a real EOF
2188*7c478bd9Sstevel@tonic-gate * pending. If so, we can maybe do the EOF write now.
2189*7c478bd9Sstevel@tonic-gate */
2190*7c478bd9Sstevel@tonic-gate if (eof_pending) {
2191*7c478bd9Sstevel@tonic-gate eof_pending = 0;
2192*7c478bd9Sstevel@tonic-gate sendeof();
2193*7c478bd9Sstevel@tonic-gate }
2194*7c478bd9Sstevel@tonic-gate }
2195*7c478bd9Sstevel@tonic-gate
2196*7c478bd9Sstevel@tonic-gate if (ring_full_count(&netiring)) {
2197*7c478bd9Sstevel@tonic-gate returnValue |= telrcv();
2198*7c478bd9Sstevel@tonic-gate }
2199*7c478bd9Sstevel@tonic-gate return (returnValue);
2200*7c478bd9Sstevel@tonic-gate }
2201*7c478bd9Sstevel@tonic-gate
2202*7c478bd9Sstevel@tonic-gate /*
2203*7c478bd9Sstevel@tonic-gate * Select from tty and network...
2204*7c478bd9Sstevel@tonic-gate */
2205*7c478bd9Sstevel@tonic-gate void
telnet(user)2206*7c478bd9Sstevel@tonic-gate telnet(user)
2207*7c478bd9Sstevel@tonic-gate char *user;
2208*7c478bd9Sstevel@tonic-gate {
2209*7c478bd9Sstevel@tonic-gate sys_telnet_init();
2210*7c478bd9Sstevel@tonic-gate
2211*7c478bd9Sstevel@tonic-gate {
2212*7c478bd9Sstevel@tonic-gate static char local_host[MAXHOSTNAMELEN] = { 0 };
2213*7c478bd9Sstevel@tonic-gate
2214*7c478bd9Sstevel@tonic-gate if (!local_host[0]) {
2215*7c478bd9Sstevel@tonic-gate (void) gethostname(local_host, sizeof (local_host));
2216*7c478bd9Sstevel@tonic-gate local_host[sizeof (local_host)-1] = 0;
2217*7c478bd9Sstevel@tonic-gate }
2218*7c478bd9Sstevel@tonic-gate auth_encrypt_init(local_host, hostname, "TELNET");
2219*7c478bd9Sstevel@tonic-gate auth_encrypt_user(user);
2220*7c478bd9Sstevel@tonic-gate }
2221*7c478bd9Sstevel@tonic-gate
2222*7c478bd9Sstevel@tonic-gate if (autologin)
2223*7c478bd9Sstevel@tonic-gate send_will(TELOPT_AUTHENTICATION, 1);
2224*7c478bd9Sstevel@tonic-gate
2225*7c478bd9Sstevel@tonic-gate if (telnetport || wantencryption) {
2226*7c478bd9Sstevel@tonic-gate send_do(TELOPT_ENCRYPT, 1);
2227*7c478bd9Sstevel@tonic-gate send_will(TELOPT_ENCRYPT, 1);
2228*7c478bd9Sstevel@tonic-gate }
2229*7c478bd9Sstevel@tonic-gate
2230*7c478bd9Sstevel@tonic-gate if (telnetport) {
2231*7c478bd9Sstevel@tonic-gate if (!reqd_linemode)
2232*7c478bd9Sstevel@tonic-gate send_do(TELOPT_SGA, 1);
2233*7c478bd9Sstevel@tonic-gate send_will(TELOPT_TTYPE, 1);
2234*7c478bd9Sstevel@tonic-gate send_will(TELOPT_NAWS, 1);
2235*7c478bd9Sstevel@tonic-gate send_will(TELOPT_TSPEED, 1);
2236*7c478bd9Sstevel@tonic-gate send_will(TELOPT_LFLOW, 1);
2237*7c478bd9Sstevel@tonic-gate if (!reqd_linemode)
2238*7c478bd9Sstevel@tonic-gate send_will(TELOPT_LINEMODE, 1);
2239*7c478bd9Sstevel@tonic-gate send_will(TELOPT_NEW_ENVIRON, 1);
2240*7c478bd9Sstevel@tonic-gate send_do(TELOPT_STATUS, 1);
2241*7c478bd9Sstevel@tonic-gate if (env_getvalue((unsigned char *)"DISPLAY"))
2242*7c478bd9Sstevel@tonic-gate send_will(TELOPT_XDISPLOC, 1);
2243*7c478bd9Sstevel@tonic-gate if (eight)
2244*7c478bd9Sstevel@tonic-gate tel_enter_binary(eight);
2245*7c478bd9Sstevel@tonic-gate }
2246*7c478bd9Sstevel@tonic-gate
2247*7c478bd9Sstevel@tonic-gate /*
2248*7c478bd9Sstevel@tonic-gate * Note: we assume a tie to the authentication option here. This
2249*7c478bd9Sstevel@tonic-gate * is necessary so that authentication fails, we don't spin
2250*7c478bd9Sstevel@tonic-gate * forever.
2251*7c478bd9Sstevel@tonic-gate */
2252*7c478bd9Sstevel@tonic-gate if (wantencryption) {
2253*7c478bd9Sstevel@tonic-gate boolean_t printed_encrypt = B_FALSE;
2254*7c478bd9Sstevel@tonic-gate extern boolean_t auth_has_failed;
2255*7c478bd9Sstevel@tonic-gate time_t timeout = time(0) + 60;
2256*7c478bd9Sstevel@tonic-gate
2257*7c478bd9Sstevel@tonic-gate send_do(TELOPT_ENCRYPT, 1);
2258*7c478bd9Sstevel@tonic-gate send_will(TELOPT_ENCRYPT, 1);
2259*7c478bd9Sstevel@tonic-gate for (;;) {
2260*7c478bd9Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) {
2261*7c478bd9Sstevel@tonic-gate (void) printf(gettext(
2262*7c478bd9Sstevel@tonic-gate "\nServer refused to negotiate "
2263*7c478bd9Sstevel@tonic-gate "authentication, which is required\n"
2264*7c478bd9Sstevel@tonic-gate "for encryption. Good-bye.\n\r"));
2265*7c478bd9Sstevel@tonic-gate Exit(EXIT_FAILURE);
2266*7c478bd9Sstevel@tonic-gate }
2267*7c478bd9Sstevel@tonic-gate if (auth_has_failed) {
2268*7c478bd9Sstevel@tonic-gate (void) printf(gettext(
2269*7c478bd9Sstevel@tonic-gate "\nAuthentication negotation has failed, "
2270*7c478bd9Sstevel@tonic-gate "which is required for\n"
2271*7c478bd9Sstevel@tonic-gate "encryption. Good-bye.\n\r"));
2272*7c478bd9Sstevel@tonic-gate Exit(EXIT_FAILURE);
2273*7c478bd9Sstevel@tonic-gate }
2274*7c478bd9Sstevel@tonic-gate if (my_want_state_is_dont(TELOPT_ENCRYPT) ||
2275*7c478bd9Sstevel@tonic-gate my_want_state_is_wont(TELOPT_ENCRYPT)) {
2276*7c478bd9Sstevel@tonic-gate (void) printf(gettext(
2277*7c478bd9Sstevel@tonic-gate "\nServer refused to negotiate encryption. "
2278*7c478bd9Sstevel@tonic-gate "Good-bye.\n\r"));
2279*7c478bd9Sstevel@tonic-gate Exit(EXIT_FAILURE);
2280*7c478bd9Sstevel@tonic-gate }
2281*7c478bd9Sstevel@tonic-gate if (encrypt_is_encrypting())
2282*7c478bd9Sstevel@tonic-gate break;
2283*7c478bd9Sstevel@tonic-gate
2284*7c478bd9Sstevel@tonic-gate if (time(0) > timeout) {
2285*7c478bd9Sstevel@tonic-gate (void) printf(gettext(
2286*7c478bd9Sstevel@tonic-gate "\nEncryption could not be enabled. "
2287*7c478bd9Sstevel@tonic-gate "Good-bye.\n\r"));
2288*7c478bd9Sstevel@tonic-gate Exit(EXIT_FAILURE);
2289*7c478bd9Sstevel@tonic-gate }
2290*7c478bd9Sstevel@tonic-gate if (printed_encrypt == B_FALSE) {
2291*7c478bd9Sstevel@tonic-gate printed_encrypt = B_TRUE;
2292*7c478bd9Sstevel@tonic-gate (void) printf(gettext(
2293*7c478bd9Sstevel@tonic-gate "Waiting for encryption to be negotiated...\n"));
2294*7c478bd9Sstevel@tonic-gate /*
2295*7c478bd9Sstevel@tonic-gate * Turn on MODE_TRAPSIG and then turn off localchars
2296*7c478bd9Sstevel@tonic-gate * so that ^C will cause telnet to exit.
2297*7c478bd9Sstevel@tonic-gate */
2298*7c478bd9Sstevel@tonic-gate TerminalNewMode(getconnmode()|MODE_TRAPSIG);
2299*7c478bd9Sstevel@tonic-gate intr_waiting = 1;
2300*7c478bd9Sstevel@tonic-gate }
2301*7c478bd9Sstevel@tonic-gate if (intr_happened) {
2302*7c478bd9Sstevel@tonic-gate (void) printf(gettext(
2303*7c478bd9Sstevel@tonic-gate "\nUser requested an interrupt. Good-bye.\n\r"));
2304*7c478bd9Sstevel@tonic-gate Exit(EXIT_FAILURE);
2305*7c478bd9Sstevel@tonic-gate }
2306*7c478bd9Sstevel@tonic-gate telnet_spin();
2307*7c478bd9Sstevel@tonic-gate }
2308*7c478bd9Sstevel@tonic-gate if (printed_encrypt) {
2309*7c478bd9Sstevel@tonic-gate (void) printf(gettext("done.\n"));
2310*7c478bd9Sstevel@tonic-gate intr_waiting = 0;
2311*7c478bd9Sstevel@tonic-gate setconnmode(0);
2312*7c478bd9Sstevel@tonic-gate }
2313*7c478bd9Sstevel@tonic-gate }
2314*7c478bd9Sstevel@tonic-gate
2315*7c478bd9Sstevel@tonic-gate for (;;) {
2316*7c478bd9Sstevel@tonic-gate int schedValue;
2317*7c478bd9Sstevel@tonic-gate
2318*7c478bd9Sstevel@tonic-gate while ((schedValue = Scheduler(0)) != 0) {
2319*7c478bd9Sstevel@tonic-gate if (schedValue == -1) {
2320*7c478bd9Sstevel@tonic-gate setcommandmode();
2321*7c478bd9Sstevel@tonic-gate return;
2322*7c478bd9Sstevel@tonic-gate }
2323*7c478bd9Sstevel@tonic-gate }
2324*7c478bd9Sstevel@tonic-gate
2325*7c478bd9Sstevel@tonic-gate if (Scheduler(1) == -1) {
2326*7c478bd9Sstevel@tonic-gate setcommandmode();
2327*7c478bd9Sstevel@tonic-gate return;
2328*7c478bd9Sstevel@tonic-gate }
2329*7c478bd9Sstevel@tonic-gate }
2330*7c478bd9Sstevel@tonic-gate }
2331*7c478bd9Sstevel@tonic-gate
2332*7c478bd9Sstevel@tonic-gate #if 0 /* XXX - this not being in is a bug */
2333*7c478bd9Sstevel@tonic-gate /*
2334*7c478bd9Sstevel@tonic-gate * nextitem()
2335*7c478bd9Sstevel@tonic-gate *
2336*7c478bd9Sstevel@tonic-gate * Return the address of the next "item" in the TELNET data
2337*7c478bd9Sstevel@tonic-gate * stream. This will be the address of the next character if
2338*7c478bd9Sstevel@tonic-gate * the current address is a user data character, or it will
2339*7c478bd9Sstevel@tonic-gate * be the address of the character following the TELNET command
2340*7c478bd9Sstevel@tonic-gate * if the current address is a TELNET IAC ("I Am a Command")
2341*7c478bd9Sstevel@tonic-gate * character.
2342*7c478bd9Sstevel@tonic-gate */
2343*7c478bd9Sstevel@tonic-gate
2344*7c478bd9Sstevel@tonic-gate static char *
2345*7c478bd9Sstevel@tonic-gate nextitem(current)
2346*7c478bd9Sstevel@tonic-gate char *current;
2347*7c478bd9Sstevel@tonic-gate {
2348*7c478bd9Sstevel@tonic-gate if ((*current&0xff) != IAC) {
2349*7c478bd9Sstevel@tonic-gate return (current+1);
2350*7c478bd9Sstevel@tonic-gate }
2351*7c478bd9Sstevel@tonic-gate switch (*(current+1)&0xff) {
2352*7c478bd9Sstevel@tonic-gate case DO:
2353*7c478bd9Sstevel@tonic-gate case DONT:
2354*7c478bd9Sstevel@tonic-gate case WILL:
2355*7c478bd9Sstevel@tonic-gate case WONT:
2356*7c478bd9Sstevel@tonic-gate return (current+3);
2357*7c478bd9Sstevel@tonic-gate case SB: /* loop forever looking for the SE */
2358*7c478bd9Sstevel@tonic-gate {
2359*7c478bd9Sstevel@tonic-gate register char *look = current+2;
2360*7c478bd9Sstevel@tonic-gate
2361*7c478bd9Sstevel@tonic-gate for (;;) {
2362*7c478bd9Sstevel@tonic-gate if ((*look++&0xff) == IAC) {
2363*7c478bd9Sstevel@tonic-gate if ((*look++&0xff) == SE) {
2364*7c478bd9Sstevel@tonic-gate return (look);
2365*7c478bd9Sstevel@tonic-gate }
2366*7c478bd9Sstevel@tonic-gate }
2367*7c478bd9Sstevel@tonic-gate }
2368*7c478bd9Sstevel@tonic-gate }
2369*7c478bd9Sstevel@tonic-gate default:
2370*7c478bd9Sstevel@tonic-gate return (current+2);
2371*7c478bd9Sstevel@tonic-gate }
2372*7c478bd9Sstevel@tonic-gate }
2373*7c478bd9Sstevel@tonic-gate #endif /* 0 */
2374*7c478bd9Sstevel@tonic-gate
2375*7c478bd9Sstevel@tonic-gate /*
2376*7c478bd9Sstevel@tonic-gate * netclear()
2377*7c478bd9Sstevel@tonic-gate *
2378*7c478bd9Sstevel@tonic-gate * We are about to do a TELNET SYNCH operation. Clear
2379*7c478bd9Sstevel@tonic-gate * the path to the network.
2380*7c478bd9Sstevel@tonic-gate *
2381*7c478bd9Sstevel@tonic-gate * Things are a bit tricky since we may have sent the first
2382*7c478bd9Sstevel@tonic-gate * byte or so of a previous TELNET command into the network.
2383*7c478bd9Sstevel@tonic-gate * So, we have to scan the network buffer from the beginning
2384*7c478bd9Sstevel@tonic-gate * until we are up to where we want to be.
2385*7c478bd9Sstevel@tonic-gate *
2386*7c478bd9Sstevel@tonic-gate * A side effect of what we do, just to keep things
2387*7c478bd9Sstevel@tonic-gate * simple, is to clear the urgent data pointer. The principal
2388*7c478bd9Sstevel@tonic-gate * caller should be setting the urgent data pointer AFTER calling
2389*7c478bd9Sstevel@tonic-gate * us in any case.
2390*7c478bd9Sstevel@tonic-gate */
2391*7c478bd9Sstevel@tonic-gate
2392*7c478bd9Sstevel@tonic-gate static void
netclear()2393*7c478bd9Sstevel@tonic-gate netclear()
2394*7c478bd9Sstevel@tonic-gate {
2395*7c478bd9Sstevel@tonic-gate #if 0 /* XXX */
2396*7c478bd9Sstevel@tonic-gate register char *thisitem, *next;
2397*7c478bd9Sstevel@tonic-gate char *good;
2398*7c478bd9Sstevel@tonic-gate #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
2399*7c478bd9Sstevel@tonic-gate ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
2400*7c478bd9Sstevel@tonic-gate
2401*7c478bd9Sstevel@tonic-gate thisitem = netobuf;
2402*7c478bd9Sstevel@tonic-gate
2403*7c478bd9Sstevel@tonic-gate while ((next = nextitem(thisitem)) <= netobuf.send) {
2404*7c478bd9Sstevel@tonic-gate thisitem = next;
2405*7c478bd9Sstevel@tonic-gate }
2406*7c478bd9Sstevel@tonic-gate
2407*7c478bd9Sstevel@tonic-gate /* Now, thisitem is first before/at boundary. */
2408*7c478bd9Sstevel@tonic-gate
2409*7c478bd9Sstevel@tonic-gate good = netobuf; /* where the good bytes go */
2410*7c478bd9Sstevel@tonic-gate
2411*7c478bd9Sstevel@tonic-gate while (netoring.add > thisitem) {
2412*7c478bd9Sstevel@tonic-gate if (wewant(thisitem)) {
2413*7c478bd9Sstevel@tonic-gate int length;
2414*7c478bd9Sstevel@tonic-gate
2415*7c478bd9Sstevel@tonic-gate next = thisitem;
2416*7c478bd9Sstevel@tonic-gate do {
2417*7c478bd9Sstevel@tonic-gate next = nextitem(next);
2418*7c478bd9Sstevel@tonic-gate } while (wewant(next) && (nfrontp > next));
2419*7c478bd9Sstevel@tonic-gate length = next-thisitem;
2420*7c478bd9Sstevel@tonic-gate memcpy(good, thisitem, length);
2421*7c478bd9Sstevel@tonic-gate good += length;
2422*7c478bd9Sstevel@tonic-gate thisitem = next;
2423*7c478bd9Sstevel@tonic-gate } else {
2424*7c478bd9Sstevel@tonic-gate thisitem = nextitem(thisitem);
2425*7c478bd9Sstevel@tonic-gate }
2426*7c478bd9Sstevel@tonic-gate }
2427*7c478bd9Sstevel@tonic-gate
2428*7c478bd9Sstevel@tonic-gate #endif /* 0 */
2429*7c478bd9Sstevel@tonic-gate }
2430*7c478bd9Sstevel@tonic-gate
2431*7c478bd9Sstevel@tonic-gate /*
2432*7c478bd9Sstevel@tonic-gate * These routines add various telnet commands to the data stream.
2433*7c478bd9Sstevel@tonic-gate */
2434*7c478bd9Sstevel@tonic-gate
2435*7c478bd9Sstevel@tonic-gate /*
2436*7c478bd9Sstevel@tonic-gate * doflush - Send do timing mark (for network connection flush) & then
2437*7c478bd9Sstevel@tonic-gate * get rid of anything in the output buffer. Return -1 if there was a
2438*7c478bd9Sstevel@tonic-gate * non-EWOULDBLOCK error on the tty flush, and otherwise return 0.
2439*7c478bd9Sstevel@tonic-gate */
2440*7c478bd9Sstevel@tonic-gate static int
doflush()2441*7c478bd9Sstevel@tonic-gate doflush()
2442*7c478bd9Sstevel@tonic-gate {
2443*7c478bd9Sstevel@tonic-gate NET2ADD(IAC, DO);
2444*7c478bd9Sstevel@tonic-gate NETADD(TELOPT_TM);
2445*7c478bd9Sstevel@tonic-gate flushline = 1;
2446*7c478bd9Sstevel@tonic-gate flushout = 1;
2447*7c478bd9Sstevel@tonic-gate
2448*7c478bd9Sstevel@tonic-gate /* Drop pending tty output */
2449*7c478bd9Sstevel@tonic-gate if (ttyflush(1) == -2)
2450*7c478bd9Sstevel@tonic-gate return (-1);
2451*7c478bd9Sstevel@tonic-gate
2452*7c478bd9Sstevel@tonic-gate /* do printoption AFTER flush, otherwise the output gets tossed... */
2453*7c478bd9Sstevel@tonic-gate printoption("SENT", DO, TELOPT_TM);
2454*7c478bd9Sstevel@tonic-gate return (0);
2455*7c478bd9Sstevel@tonic-gate }
2456*7c478bd9Sstevel@tonic-gate
2457*7c478bd9Sstevel@tonic-gate int
xmitAO()2458*7c478bd9Sstevel@tonic-gate xmitAO()
2459*7c478bd9Sstevel@tonic-gate {
2460*7c478bd9Sstevel@tonic-gate NET2ADD(IAC, AO);
2461*7c478bd9Sstevel@tonic-gate printoption("SENT", IAC, AO);
2462*7c478bd9Sstevel@tonic-gate if (autoflush) {
2463*7c478bd9Sstevel@tonic-gate if (doflush() == -1)
2464*7c478bd9Sstevel@tonic-gate return (-1);
2465*7c478bd9Sstevel@tonic-gate }
2466*7c478bd9Sstevel@tonic-gate return (0);
2467*7c478bd9Sstevel@tonic-gate }
2468*7c478bd9Sstevel@tonic-gate
2469*7c478bd9Sstevel@tonic-gate
2470*7c478bd9Sstevel@tonic-gate void
xmitEL()2471*7c478bd9Sstevel@tonic-gate xmitEL()
2472*7c478bd9Sstevel@tonic-gate {
2473*7c478bd9Sstevel@tonic-gate NET2ADD(IAC, EL);
2474*7c478bd9Sstevel@tonic-gate printoption("SENT", IAC, EL);
2475*7c478bd9Sstevel@tonic-gate }
2476*7c478bd9Sstevel@tonic-gate
2477*7c478bd9Sstevel@tonic-gate void
xmitEC()2478*7c478bd9Sstevel@tonic-gate xmitEC()
2479*7c478bd9Sstevel@tonic-gate {
2480*7c478bd9Sstevel@tonic-gate NET2ADD(IAC, EC);
2481*7c478bd9Sstevel@tonic-gate printoption("SENT", IAC, EC);
2482*7c478bd9Sstevel@tonic-gate }
2483*7c478bd9Sstevel@tonic-gate
2484*7c478bd9Sstevel@tonic-gate
2485*7c478bd9Sstevel@tonic-gate int
dosynch()2486*7c478bd9Sstevel@tonic-gate dosynch()
2487*7c478bd9Sstevel@tonic-gate {
2488*7c478bd9Sstevel@tonic-gate netclear(); /* clear the path to the network */
2489*7c478bd9Sstevel@tonic-gate NETADD(IAC);
2490*7c478bd9Sstevel@tonic-gate setneturg();
2491*7c478bd9Sstevel@tonic-gate NETADD(DM);
2492*7c478bd9Sstevel@tonic-gate printoption("SENT", IAC, DM);
2493*7c478bd9Sstevel@tonic-gate return (1);
2494*7c478bd9Sstevel@tonic-gate }
2495*7c478bd9Sstevel@tonic-gate
2496*7c478bd9Sstevel@tonic-gate int want_status_response = 0;
2497*7c478bd9Sstevel@tonic-gate
2498*7c478bd9Sstevel@tonic-gate int
get_status()2499*7c478bd9Sstevel@tonic-gate get_status()
2500*7c478bd9Sstevel@tonic-gate {
2501*7c478bd9Sstevel@tonic-gate unsigned char tmp[16];
2502*7c478bd9Sstevel@tonic-gate register unsigned char *cp;
2503*7c478bd9Sstevel@tonic-gate
2504*7c478bd9Sstevel@tonic-gate if (my_want_state_is_dont(TELOPT_STATUS)) {
2505*7c478bd9Sstevel@tonic-gate (void) printf("Remote side does not support STATUS option\n");
2506*7c478bd9Sstevel@tonic-gate return (0);
2507*7c478bd9Sstevel@tonic-gate }
2508*7c478bd9Sstevel@tonic-gate cp = tmp;
2509*7c478bd9Sstevel@tonic-gate
2510*7c478bd9Sstevel@tonic-gate *cp++ = IAC;
2511*7c478bd9Sstevel@tonic-gate *cp++ = SB;
2512*7c478bd9Sstevel@tonic-gate *cp++ = TELOPT_STATUS;
2513*7c478bd9Sstevel@tonic-gate *cp++ = TELQUAL_SEND;
2514*7c478bd9Sstevel@tonic-gate *cp++ = IAC;
2515*7c478bd9Sstevel@tonic-gate *cp++ = SE;
2516*7c478bd9Sstevel@tonic-gate if (NETROOM() >= cp - tmp) {
2517*7c478bd9Sstevel@tonic-gate ring_supply_data(&netoring, tmp, cp-tmp);
2518*7c478bd9Sstevel@tonic-gate printsub('>', tmp+2, cp - tmp - 2);
2519*7c478bd9Sstevel@tonic-gate }
2520*7c478bd9Sstevel@tonic-gate ++want_status_response;
2521*7c478bd9Sstevel@tonic-gate return (1);
2522*7c478bd9Sstevel@tonic-gate }
2523*7c478bd9Sstevel@tonic-gate
2524*7c478bd9Sstevel@tonic-gate void
intp()2525*7c478bd9Sstevel@tonic-gate intp()
2526*7c478bd9Sstevel@tonic-gate {
2527*7c478bd9Sstevel@tonic-gate NET2ADD(IAC, IP);
2528*7c478bd9Sstevel@tonic-gate printoption("SENT", IAC, IP);
2529*7c478bd9Sstevel@tonic-gate flushline = 1;
2530*7c478bd9Sstevel@tonic-gate if (autoflush) {
2531*7c478bd9Sstevel@tonic-gate /* Ignore return as we're ending off anyway. */
2532*7c478bd9Sstevel@tonic-gate (void) doflush();
2533*7c478bd9Sstevel@tonic-gate }
2534*7c478bd9Sstevel@tonic-gate if (autosynch) {
2535*7c478bd9Sstevel@tonic-gate (void) dosynch();
2536*7c478bd9Sstevel@tonic-gate }
2537*7c478bd9Sstevel@tonic-gate }
2538*7c478bd9Sstevel@tonic-gate
2539*7c478bd9Sstevel@tonic-gate int
sendbrk()2540*7c478bd9Sstevel@tonic-gate sendbrk()
2541*7c478bd9Sstevel@tonic-gate {
2542*7c478bd9Sstevel@tonic-gate NET2ADD(IAC, BREAK);
2543*7c478bd9Sstevel@tonic-gate printoption("SENT", IAC, BREAK);
2544*7c478bd9Sstevel@tonic-gate flushline = 1;
2545*7c478bd9Sstevel@tonic-gate if (autoflush) {
2546*7c478bd9Sstevel@tonic-gate if (doflush() == -1)
2547*7c478bd9Sstevel@tonic-gate return (-1);
2548*7c478bd9Sstevel@tonic-gate }
2549*7c478bd9Sstevel@tonic-gate if (autosynch) {
2550*7c478bd9Sstevel@tonic-gate (void) dosynch();
2551*7c478bd9Sstevel@tonic-gate }
2552*7c478bd9Sstevel@tonic-gate return (0);
2553*7c478bd9Sstevel@tonic-gate }
2554*7c478bd9Sstevel@tonic-gate
2555*7c478bd9Sstevel@tonic-gate void
sendabort()2556*7c478bd9Sstevel@tonic-gate sendabort()
2557*7c478bd9Sstevel@tonic-gate {
2558*7c478bd9Sstevel@tonic-gate NET2ADD(IAC, ABORT);
2559*7c478bd9Sstevel@tonic-gate printoption("SENT", IAC, ABORT);
2560*7c478bd9Sstevel@tonic-gate flushline = 1;
2561*7c478bd9Sstevel@tonic-gate if (autoflush) {
2562*7c478bd9Sstevel@tonic-gate /*
2563*7c478bd9Sstevel@tonic-gate * Since sendabort() gets called while aborting,
2564*7c478bd9Sstevel@tonic-gate * ignore the doflush() return
2565*7c478bd9Sstevel@tonic-gate */
2566*7c478bd9Sstevel@tonic-gate (void) doflush();
2567*7c478bd9Sstevel@tonic-gate }
2568*7c478bd9Sstevel@tonic-gate if (autosynch) {
2569*7c478bd9Sstevel@tonic-gate (void) dosynch();
2570*7c478bd9Sstevel@tonic-gate }
2571*7c478bd9Sstevel@tonic-gate }
2572*7c478bd9Sstevel@tonic-gate
2573*7c478bd9Sstevel@tonic-gate void
sendsusp()2574*7c478bd9Sstevel@tonic-gate sendsusp()
2575*7c478bd9Sstevel@tonic-gate {
2576*7c478bd9Sstevel@tonic-gate NET2ADD(IAC, SUSP);
2577*7c478bd9Sstevel@tonic-gate printoption("SENT", IAC, SUSP);
2578*7c478bd9Sstevel@tonic-gate flushline = 1;
2579*7c478bd9Sstevel@tonic-gate if (autoflush) {
2580*7c478bd9Sstevel@tonic-gate if (doflush() == -1) {
2581*7c478bd9Sstevel@tonic-gate /* The following will not return. */
2582*7c478bd9Sstevel@tonic-gate fatal_tty_error("write");
2583*7c478bd9Sstevel@tonic-gate }
2584*7c478bd9Sstevel@tonic-gate }
2585*7c478bd9Sstevel@tonic-gate if (autosynch) {
2586*7c478bd9Sstevel@tonic-gate (void) dosynch();
2587*7c478bd9Sstevel@tonic-gate }
2588*7c478bd9Sstevel@tonic-gate }
2589*7c478bd9Sstevel@tonic-gate
2590*7c478bd9Sstevel@tonic-gate static void
sendeof()2591*7c478bd9Sstevel@tonic-gate sendeof()
2592*7c478bd9Sstevel@tonic-gate {
2593*7c478bd9Sstevel@tonic-gate NET2ADD(IAC, xEOF);
2594*7c478bd9Sstevel@tonic-gate printoption("SENT", IAC, xEOF);
2595*7c478bd9Sstevel@tonic-gate }
2596*7c478bd9Sstevel@tonic-gate
2597*7c478bd9Sstevel@tonic-gate /*
2598*7c478bd9Sstevel@tonic-gate * Send a window size update to the remote system.
2599*7c478bd9Sstevel@tonic-gate */
2600*7c478bd9Sstevel@tonic-gate
2601*7c478bd9Sstevel@tonic-gate void
sendnaws()2602*7c478bd9Sstevel@tonic-gate sendnaws()
2603*7c478bd9Sstevel@tonic-gate {
2604*7c478bd9Sstevel@tonic-gate unsigned short rows, cols;
2605*7c478bd9Sstevel@tonic-gate unsigned char tmp[16];
2606*7c478bd9Sstevel@tonic-gate register unsigned char *cp;
2607*7c478bd9Sstevel@tonic-gate
2608*7c478bd9Sstevel@tonic-gate if (my_state_is_wont(TELOPT_NAWS))
2609*7c478bd9Sstevel@tonic-gate return;
2610*7c478bd9Sstevel@tonic-gate
2611*7c478bd9Sstevel@tonic-gate #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
2612*7c478bd9Sstevel@tonic-gate if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
2613*7c478bd9Sstevel@tonic-gate
2614*7c478bd9Sstevel@tonic-gate if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */
2615*7c478bd9Sstevel@tonic-gate return;
2616*7c478bd9Sstevel@tonic-gate }
2617*7c478bd9Sstevel@tonic-gate
2618*7c478bd9Sstevel@tonic-gate cp = tmp;
2619*7c478bd9Sstevel@tonic-gate
2620*7c478bd9Sstevel@tonic-gate *cp++ = IAC;
2621*7c478bd9Sstevel@tonic-gate *cp++ = SB;
2622*7c478bd9Sstevel@tonic-gate *cp++ = TELOPT_NAWS;
2623*7c478bd9Sstevel@tonic-gate PUTSHORT(cp, cols);
2624*7c478bd9Sstevel@tonic-gate PUTSHORT(cp, rows);
2625*7c478bd9Sstevel@tonic-gate *cp++ = IAC;
2626*7c478bd9Sstevel@tonic-gate *cp++ = SE;
2627*7c478bd9Sstevel@tonic-gate if (NETROOM() >= cp - tmp) {
2628*7c478bd9Sstevel@tonic-gate ring_supply_data(&netoring, tmp, cp-tmp);
2629*7c478bd9Sstevel@tonic-gate printsub('>', tmp+2, cp - tmp - 2);
2630*7c478bd9Sstevel@tonic-gate }
2631*7c478bd9Sstevel@tonic-gate }
2632*7c478bd9Sstevel@tonic-gate
2633*7c478bd9Sstevel@tonic-gate void
tel_enter_binary(rw)2634*7c478bd9Sstevel@tonic-gate tel_enter_binary(rw)
2635*7c478bd9Sstevel@tonic-gate int rw;
2636*7c478bd9Sstevel@tonic-gate {
2637*7c478bd9Sstevel@tonic-gate if (rw&1)
2638*7c478bd9Sstevel@tonic-gate send_do(TELOPT_BINARY, 1);
2639*7c478bd9Sstevel@tonic-gate if (rw&2)
2640*7c478bd9Sstevel@tonic-gate send_will(TELOPT_BINARY, 1);
2641*7c478bd9Sstevel@tonic-gate }
2642*7c478bd9Sstevel@tonic-gate
2643*7c478bd9Sstevel@tonic-gate void
tel_leave_binary(rw)2644*7c478bd9Sstevel@tonic-gate tel_leave_binary(rw)
2645*7c478bd9Sstevel@tonic-gate int rw;
2646*7c478bd9Sstevel@tonic-gate {
2647*7c478bd9Sstevel@tonic-gate if (rw&1)
2648*7c478bd9Sstevel@tonic-gate send_dont(TELOPT_BINARY, 1);
2649*7c478bd9Sstevel@tonic-gate if (rw&2)
2650*7c478bd9Sstevel@tonic-gate send_wont(TELOPT_BINARY, 1);
2651*7c478bd9Sstevel@tonic-gate }
2652