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