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