Remove building with NOCRYPTO option
[minix.git] / usr.bin / telnet / telnet.c
blobbfc363e791b9200ba889b2f06efbba7ce2177d74
1 /* $NetBSD: telnet.c,v 1.36 2012/01/10 13:49:32 christos Exp $ */
3 /*
4 * Copyright (c) 1988, 1990, 1993
5 * The Regents of the University of California. All rights reserved.
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. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)telnet.c 8.4 (Berkeley) 5/30/95";
36 #else
37 __RCSID("$NetBSD: telnet.c,v 1.36 2012/01/10 13:49:32 christos Exp $");
38 #endif
39 #endif /* not lint */
41 #include <sys/param.h>
43 #include <signal.h>
44 #include <term.h>
45 #include <unistd.h>
46 /* By the way, we need to include curses.h before telnet.h since,
47 * among other things, telnet.h #defines 'DO', which is a variable
48 * declared in curses.h.
51 #include <arpa/telnet.h>
53 #include <ctype.h>
55 #include "ring.h"
56 #include "defines.h"
57 #include "externs.h"
58 #include "types.h"
59 #include "general.h"
61 #include <libtelnet/misc.h>
62 #ifdef AUTHENTICATION
63 #include <libtelnet/auth.h>
64 #endif
65 #ifdef ENCRYPTION
66 #include <libtelnet/encrypt.h>
67 #endif
69 #define strip(x) ((my_want_state_is_wont(TELOPT_BINARY)) ? ((x)&0x7f) : (x))
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); \
79 #define SB_GET() ((*subpointer++)&0xff)
80 #define SB_PEEK() ((*subpointer)&0xff)
81 #define SB_EOF() (subpointer >= subend)
82 #define SB_LEN() (subend - subpointer)
84 char options[256]; /* The combined options */
85 char do_dont_resp[256];
86 char will_wont_resp[256];
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 telnet_debug = 0,
97 crmod,
98 netdata, /* Print out network data flow */
99 crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
100 #ifdef 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;
120 char *prompt = 0;
122 cc_t escape;
123 cc_t rlogin;
124 #ifdef KLUDGELINEMODE
125 cc_t echoc;
126 #endif
129 * Telnet receiver states for fsm
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 */
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
148 jmp_buf toplevel = { 0 };
150 int flushline;
151 int linemode;
153 #ifdef KLUDGELINEMODE
154 int kludgelinemode = 1;
155 #endif
157 static void dooption(int);
158 static void dontoption(int);
159 static void suboption(void);
160 static int telsnd(void);
161 static void netclear(void);
162 static void doflush(void);
165 * The following are some clocks used to decide how to interpret
166 * the relationship between various variables.
169 Clocks clocks;
171 #ifdef notdef
172 Modelist modelist[] = {
173 { "telnet command mode", COMMAND_LINE },
174 { "character-at-a-time mode", 0 },
175 { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
176 { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
177 { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
178 { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
179 { "3270 mode", 0 },
181 #endif
185 * Initialize telnet environment.
188 void
189 init_telnet(void)
191 env_init();
193 SB_CLEAR();
194 ClearArray(options);
196 connected = In3270 = ISend = localflow = donebinarytoggle = 0;
197 #if defined(AUTHENTICATION) || defined(ENCRYPTION)
198 auth_encrypt_connect(connected);
199 #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
200 restartany = -1;
202 SYNCHing = 0;
204 /* Don't change NetTrace */
206 escape = CONTROL(']');
207 rlogin = _POSIX_VDISABLE;
208 #ifdef KLUDGELINEMODE
209 echoc = CONTROL('E');
210 #endif
212 flushline = 1;
213 telrcv_state = TS_DATA;
217 #ifdef notdef
218 #include <stdarg.h>
220 /*VARARGS*/
221 static void
222 printring(Ring *ring, char *format, ...)
223 va_dcl
225 va_list ap;
226 char buffer[100]; /* where things go */
227 char *ptr;
228 char *string;
229 int i;
231 va_start(ap, format);
233 ptr = buffer;
235 while ((i = *format++) != 0) {
236 if (i == '%') {
237 i = *format++;
238 switch (i) {
239 case 'c':
240 *ptr++ = va_arg(ap, int);
241 break;
242 case 's':
243 string = va_arg(ap, char *);
244 ring_supply_data(ring, buffer, ptr-buffer);
245 ring_supply_data(ring, string, strlen(string));
246 ptr = buffer;
247 break;
248 case 0:
249 ExitString("printring: trailing %%.\n", 1);
250 /*NOTREACHED*/
251 default:
252 ExitString("printring: unknown format character.\n", 1);
253 /*NOTREACHED*/
255 } else {
256 *ptr++ = i;
259 va_end(ap);
260 ring_supply_data(ring, buffer, ptr-buffer);
262 #endif
265 * These routines are in charge of sending option negotiations
266 * to the other side.
268 * The basic idea is that we send the negotiation if either side
269 * is in disagreement as to what the current state should be.
272 void
273 send_do(int c, int init)
275 if (init) {
276 if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
277 my_want_state_is_do(c))
278 return;
279 set_my_want_state_do(c);
280 do_dont_resp[c]++;
282 NET2ADD(IAC, DO);
283 NETADD(c);
284 printoption("SENT", DO, c);
287 void
288 send_dont(int c, int init)
290 if (init) {
291 if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
292 my_want_state_is_dont(c))
293 return;
294 set_my_want_state_dont(c);
295 do_dont_resp[c]++;
297 NET2ADD(IAC, DONT);
298 NETADD(c);
299 printoption("SENT", DONT, c);
302 void
303 send_will(int c, int init)
305 if (init) {
306 if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
307 my_want_state_is_will(c))
308 return;
309 set_my_want_state_will(c);
310 will_wont_resp[c]++;
312 NET2ADD(IAC, WILL);
313 NETADD(c);
314 printoption("SENT", WILL, c);
317 void
318 send_wont(int c, int init)
320 if (init) {
321 if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
322 my_want_state_is_wont(c))
323 return;
324 set_my_want_state_wont(c);
325 will_wont_resp[c]++;
327 NET2ADD(IAC, WONT);
328 NETADD(c);
329 printoption("SENT", WONT, c);
333 void
334 willoption(int option)
336 int new_state_ok = 0;
338 if (do_dont_resp[option]) {
339 --do_dont_resp[option];
340 if (do_dont_resp[option] && my_state_is_do(option))
341 --do_dont_resp[option];
344 if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
346 switch (option) {
348 case TELOPT_ECHO:
349 # if defined(TN3270)
351 * The following is a pain in the rear-end.
352 * Various IBM servers (some versions of Wiscnet,
353 * possibly Fibronics/Spartacus, and who knows who
354 * else) will NOT allow us to send "DO SGA" too early
355 * in the setup proceedings. On the other hand,
356 * 4.2 servers (telnetd) won't set SGA correctly.
357 * So, we are stuck. Empirically (but, based on
358 * a VERY small sample), the IBM servers don't send
359 * out anything about ECHO, so we postpone our sending
360 * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
361 * DO send).
364 if (askedSGA == 0) {
365 askedSGA = 1;
366 if (my_want_state_is_dont(TELOPT_SGA))
367 send_do(TELOPT_SGA, 1);
370 /* Fall through */
371 case TELOPT_EOR:
372 #endif /* defined(TN3270) */
373 case TELOPT_BINARY:
374 case TELOPT_SGA:
375 settimer(modenegotiated);
376 /* FALL THROUGH */
377 case TELOPT_STATUS:
378 #ifdef AUTHENTICATION
379 case TELOPT_AUTHENTICATION:
380 #ifdef ENCRYPTION
381 case TELOPT_ENCRYPT:
382 #endif /* ENCRYPTION */
383 #endif
384 new_state_ok = 1;
385 break;
387 case TELOPT_TM:
388 if (flushout)
389 flushout = 0;
391 * Special case for TM. If we get back a WILL,
392 * pretend we got back a WONT.
394 set_my_want_state_dont(option);
395 set_my_state_dont(option);
396 return; /* Never reply to TM will's/wont's */
398 case TELOPT_LINEMODE:
399 default:
400 break;
403 if (new_state_ok) {
404 set_my_want_state_do(option);
405 send_do(option, 0);
406 setconnmode(0); /* possibly set new tty mode */
407 } else {
408 do_dont_resp[option]++;
409 send_dont(option, 0);
412 set_my_state_do(option);
413 #ifdef ENCRYPTION
414 if (option == TELOPT_ENCRYPT)
415 encrypt_send_support();
416 #endif /* ENCRYPTION */
419 void
420 wontoption(int option)
422 if (do_dont_resp[option]) {
423 --do_dont_resp[option];
424 if (do_dont_resp[option] && my_state_is_dont(option))
425 --do_dont_resp[option];
428 if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
430 switch (option) {
432 #ifdef KLUDGELINEMODE
433 case TELOPT_SGA:
434 if (!kludgelinemode)
435 break;
436 /* FALL THROUGH */
437 #endif
438 case TELOPT_ECHO:
439 settimer(modenegotiated);
440 break;
442 case TELOPT_TM:
443 if (flushout)
444 flushout = 0;
445 set_my_want_state_dont(option);
446 set_my_state_dont(option);
447 return; /* Never reply to TM will's/wont's */
449 default:
450 break;
452 set_my_want_state_dont(option);
453 if (my_state_is_do(option))
454 send_dont(option, 0);
455 setconnmode(0); /* Set new tty mode */
456 } else if (option == TELOPT_TM) {
458 * Special case for TM.
460 if (flushout)
461 flushout = 0;
462 set_my_want_state_dont(option);
464 set_my_state_dont(option);
467 static void
468 dooption(int option)
470 int new_state_ok = 0;
472 if (will_wont_resp[option]) {
473 --will_wont_resp[option];
474 if (will_wont_resp[option] && my_state_is_will(option))
475 --will_wont_resp[option];
478 if (will_wont_resp[option] == 0) {
479 if (my_want_state_is_wont(option)) {
481 switch (option) {
483 case TELOPT_TM:
485 * Special case for TM. We send a WILL, but pretend
486 * we sent WONT.
488 send_will(option, 0);
489 set_my_want_state_wont(TELOPT_TM);
490 set_my_state_wont(TELOPT_TM);
491 return;
493 # if defined(TN3270)
494 case TELOPT_EOR: /* end of record */
495 # endif /* defined(TN3270) */
496 case TELOPT_BINARY: /* binary mode */
497 case TELOPT_NAWS: /* window size */
498 case TELOPT_TSPEED: /* terminal speed */
499 case TELOPT_LFLOW: /* local flow control */
500 case TELOPT_TTYPE: /* terminal type option */
501 case TELOPT_SGA: /* no big deal */
502 #ifdef ENCRYPTION
503 case TELOPT_ENCRYPT: /* encryption variable option */
504 #endif /* ENCRYPTION */
505 new_state_ok = 1;
506 break;
508 case TELOPT_NEW_ENVIRON: /* New environment variable option */
509 #ifdef OLD_ENVIRON
510 if (my_state_is_will(TELOPT_OLD_ENVIRON))
511 send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */
512 goto env_common;
513 case TELOPT_OLD_ENVIRON: /* Old environment variable option */
514 if (my_state_is_will(TELOPT_NEW_ENVIRON))
515 break; /* Don't enable if new one is in use! */
516 env_common:
517 telopt_environ = option;
518 #endif
519 new_state_ok = 1;
520 break;
522 #ifdef AUTHENTICATION
523 case TELOPT_AUTHENTICATION:
524 if (autologin)
525 new_state_ok = 1;
526 break;
527 #endif
529 case TELOPT_XDISPLOC: /* X Display location */
530 if (env_getvalue((const unsigned char *)"DISPLAY"))
531 new_state_ok = 1;
532 break;
534 case TELOPT_LINEMODE:
535 #ifdef KLUDGELINEMODE
536 kludgelinemode = 0;
537 send_do(TELOPT_SGA, 1);
538 #endif
539 set_my_want_state_will(TELOPT_LINEMODE);
540 send_will(option, 0);
541 set_my_state_will(TELOPT_LINEMODE);
542 slc_init();
543 return;
545 case TELOPT_ECHO: /* We're never going to echo... */
546 default:
547 break;
550 if (new_state_ok) {
551 set_my_want_state_will(option);
552 send_will(option, 0);
553 setconnmode(0); /* Set new tty mode */
554 } else {
555 will_wont_resp[option]++;
556 send_wont(option, 0);
558 } else {
560 * Handle options that need more things done after the
561 * other side has acknowledged the option.
563 switch (option) {
564 case TELOPT_LINEMODE:
565 #ifdef KLUDGELINEMODE
566 kludgelinemode = 0;
567 send_do(TELOPT_SGA, 1);
568 #endif
569 set_my_state_will(option);
570 slc_init();
571 send_do(TELOPT_SGA, 0);
572 return;
576 set_my_state_will(option);
579 static void
580 dontoption(int option)
583 if (will_wont_resp[option]) {
584 --will_wont_resp[option];
585 if (will_wont_resp[option] && my_state_is_wont(option))
586 --will_wont_resp[option];
589 if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
590 switch (option) {
591 case TELOPT_LINEMODE:
592 linemode = 0; /* put us back to the default state */
593 break;
594 #ifdef OLD_ENVIRON
595 case TELOPT_NEW_ENVIRON:
597 * The new environ option wasn't recognized, try
598 * the old one.
600 send_will(TELOPT_OLD_ENVIRON, 1);
601 telopt_environ = TELOPT_OLD_ENVIRON;
602 break;
603 #endif
605 /* we always accept a DONT */
606 set_my_want_state_wont(option);
607 if (my_state_is_will(option))
608 send_wont(option, 0);
609 setconnmode(0); /* Set new tty mode */
611 set_my_state_wont(option);
615 * Given a buffer returned by tgetent(), this routine will turn
616 * the pipe separated list of names in the buffer into an array
617 * of pointers to null terminated names. We toss out any bad,
618 * duplicate, or verbose names (names with spaces).
621 static char name_unknown[] = "UNKNOWN";
622 static char *unknown[] = { 0, 0 };
624 char **
625 mklist(char *buf, char *name)
627 int n;
628 char c, *cp, **argvp, *cp2, **argv, **avt;
630 if (name) {
631 if ((int)strlen(name) > 40) {
632 name = 0;
633 unknown[0] = name_unknown;
634 } else {
635 unknown[0] = name;
636 upcase(name);
638 } else
639 unknown[0] = name_unknown;
641 * Count up the number of names.
643 for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
644 if (*cp == '|')
645 n++;
648 * Allocate an array to put the name pointers into
650 argv = (char **)malloc((n+3)*sizeof(char *));
651 if (argv == 0)
652 return(unknown);
655 * Fill up the array of pointers to names.
657 *argv = 0;
658 argvp = argv+1;
659 n = 0;
660 for (cp = cp2 = buf; (c = *cp); cp++) {
661 if (c == '|' || c == ':') {
662 *cp++ = '\0';
664 * Skip entries that have spaces or are over 40
665 * characters long. If this is our environment
666 * name, then put it up front. Otherwise, as
667 * long as this is not a duplicate name (case
668 * insensitive) add it to the list.
670 if (n || (cp - cp2 > 41))
672 else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
673 *argv = cp2;
674 else if (is_unique(cp2, argv+1, argvp))
675 *argvp++ = cp2;
676 if (c == ':')
677 break;
679 * Skip multiple delimiters. Reset cp2 to
680 * the beginning of the next name. Reset n,
681 * the flag for names with spaces.
683 while ((c = *cp) == '|')
684 cp++;
685 cp2 = cp;
686 n = 0;
689 * Skip entries with spaces or non-ascii values.
690 * Convert lower case letters to upper case.
692 if ((c == ' ') || !isascii(c))
693 n = 1;
694 else if (islower((unsigned char)c))
695 *cp = toupper((unsigned char)c);
699 * Check for an old V6 2 character name. If the second
700 * name points to the beginning of the buffer, and is
701 * only 2 characters long, move it to the end of the array.
703 if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
704 --argvp;
705 for (avt = &argv[1]; avt < argvp; avt++)
706 *avt = *(avt+1);
707 *argvp++ = buf;
711 * Duplicate last name, for TTYPE option, and null
712 * terminate the array. If we didn't find a match on
713 * our terminal name, put that name at the beginning.
715 cp = *(argvp-1);
716 *argvp++ = cp;
717 *argvp = 0;
719 if (*argv == 0) {
720 if (name)
721 *argv = name;
722 else {
723 --argvp;
724 for (avt = argv; avt < argvp; avt++)
725 *avt = *(avt+1);
728 if (*argv)
729 return(argv);
730 else
731 return(unknown);
735 is_unique(char *name, char **as, char **ae)
737 char **ap;
738 int n;
740 n = strlen(name) + 1;
741 for (ap = as; ap < ae; ap++)
742 if (strncasecmp(*ap, name, n) == 0)
743 return(0);
744 return (1);
747 #ifdef TERMCAP
748 char *termbuf;
750 /*ARGSUSED*/
752 setupterm(char *tname, int fd, int *errp)
754 char zz[1024], *zz_ptr;
755 char *ext_tc, *newptr;
756 size_t len;
758 if ((termbuf = malloc(1024)) == NULL)
759 goto error;
761 if (tgetent(termbuf, tname) == 1) {
762 /* check for ZZ capability, indicating termcap truncated */
763 zz_ptr = zz;
764 if (tgetstr("ZZ", &zz_ptr) != NULL) {
765 /* it was, fish back the full termcap */
766 sscanf(zz, "%p", &ext_tc);
767 len = strlen(ext_tc) + 1;
768 if ((newptr = realloc(termbuf, len)) == NULL)
769 goto error;
771 memcpy(newptr, ext_tc, len);
772 termbuf = newptr;
775 if (errp)
776 *errp = 1;
777 return(0);
779 error:
780 if (errp)
781 *errp = 0;
782 return(-1);
784 #else
785 #define termbuf ttytype
786 extern char ttytype[];
787 #endif
789 int resettermname = 1;
791 char *
792 gettermname(void)
794 char *tname;
795 static char **tnamep = 0;
796 static char **next;
797 int err;
799 if (resettermname) {
800 resettermname = 0;
801 if (tnamep && tnamep != unknown)
802 free(tnamep);
803 if ((tname = (char *)env_getvalue((const unsigned char *)"TERM")) &&
804 (setupterm(tname, 1, &err) == 0)) {
805 tnamep = mklist(termbuf, tname);
806 } else {
807 if (tname && ((int)strlen(tname) <= 40)) {
808 unknown[0] = tname;
809 upcase(tname);
810 } else
811 unknown[0] = name_unknown;
812 tnamep = unknown;
814 next = tnamep;
816 if (*next == 0)
817 next = tnamep;
818 return(*next++);
821 * suboption()
823 * Look at the sub-option buffer, and try to be helpful to the other
824 * side.
826 * Currently we recognize:
828 * Terminal type, send request.
829 * Terminal speed (send request).
830 * Local flow control (is request).
831 * Linemode
834 static void
835 suboption(void)
837 unsigned char subchar;
839 printsub('<', subbuffer, SB_LEN()+2);
840 switch (subchar = SB_GET()) {
841 case TELOPT_TTYPE:
842 if (my_want_state_is_wont(TELOPT_TTYPE))
843 return;
844 if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
845 return;
846 } else {
847 char *name;
848 unsigned char temp[50];
849 int len;
851 #ifdef TN3270
852 if (tn3270_ttype()) {
853 return;
855 #endif /* defined(TN3270) */
856 name = gettermname();
857 len = strlen(name) + 4 + 2;
858 if (len < NETROOM()) {
859 sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
860 TELQUAL_IS, name, IAC, SE);
861 ring_supply_data(&netoring, temp, len);
862 printsub('>', &temp[2], len-2);
863 } else {
864 ExitString("No room in buffer for terminal type.\n", 1);
865 /*NOTREACHED*/
868 break;
869 case TELOPT_TSPEED:
870 if (my_want_state_is_wont(TELOPT_TSPEED))
871 return;
872 if (SB_EOF())
873 return;
874 if (SB_GET() == TELQUAL_SEND) {
875 long osp, isp;
876 unsigned char temp[50];
877 int len;
879 TerminalSpeeds(&isp, &osp);
881 sprintf((char *)temp, "%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED,
882 TELQUAL_IS, osp, isp, IAC, SE);
883 len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
885 if (len < NETROOM()) {
886 ring_supply_data(&netoring, temp, len);
887 printsub('>', temp+2, len - 2);
889 /*@*/ else printf("lm_will: not enough room in buffer\n");
891 break;
892 case TELOPT_LFLOW:
893 if (my_want_state_is_wont(TELOPT_LFLOW))
894 return;
895 if (SB_EOF())
896 return;
897 switch(SB_GET()) {
898 case LFLOW_RESTART_ANY:
899 restartany = 1;
900 break;
901 case LFLOW_RESTART_XON:
902 restartany = 0;
903 break;
904 case LFLOW_ON:
905 localflow = 1;
906 break;
907 case LFLOW_OFF:
908 localflow = 0;
909 break;
910 default:
911 return;
913 setcommandmode();
914 setconnmode(0);
915 break;
917 case TELOPT_LINEMODE:
918 if (my_want_state_is_wont(TELOPT_LINEMODE))
919 return;
920 if (SB_EOF())
921 return;
922 switch (SB_GET()) {
923 case WILL:
924 lm_will(subpointer, SB_LEN());
925 break;
926 case WONT:
927 lm_wont(subpointer, SB_LEN());
928 break;
929 case DO:
930 lm_do(subpointer, SB_LEN());
931 break;
932 case DONT:
933 lm_dont(subpointer, SB_LEN());
934 break;
935 case LM_SLC:
936 slc(subpointer, SB_LEN());
937 break;
938 case LM_MODE:
939 lm_mode(subpointer, SB_LEN(), 0);
940 break;
941 default:
942 break;
944 break;
946 #ifdef OLD_ENVIRON
947 case TELOPT_OLD_ENVIRON:
948 #endif
949 case TELOPT_NEW_ENVIRON:
950 if (SB_EOF())
951 return;
952 switch(SB_PEEK()) {
953 case TELQUAL_IS:
954 case TELQUAL_INFO:
955 if (my_want_state_is_dont(subchar))
956 return;
957 break;
958 case TELQUAL_SEND:
959 if (my_want_state_is_wont(subchar)) {
960 return;
962 break;
963 default:
964 return;
966 env_opt(subpointer, SB_LEN());
967 break;
969 case TELOPT_XDISPLOC:
970 if (my_want_state_is_wont(TELOPT_XDISPLOC))
971 return;
972 if (SB_EOF())
973 return;
974 if (SB_GET() == TELQUAL_SEND) {
975 unsigned char temp[50], *dp;
976 int len;
978 if ((dp = env_getvalue((const unsigned char *)"DISPLAY")) == NULL) {
980 * Something happened, we no longer have a DISPLAY
981 * variable. So, turn off the option.
983 send_wont(TELOPT_XDISPLOC, 1);
984 break;
986 sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
987 TELQUAL_IS, dp, IAC, SE);
988 len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
990 if (len < NETROOM()) {
991 ring_supply_data(&netoring, temp, len);
992 printsub('>', temp+2, len - 2);
994 /*@*/ else printf("lm_will: not enough room in buffer\n");
996 break;
998 #ifdef AUTHENTICATION
999 case TELOPT_AUTHENTICATION: {
1000 if (!autologin)
1001 break;
1002 if (SB_EOF())
1003 return;
1004 switch(SB_GET()) {
1005 case TELQUAL_IS:
1006 if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
1007 return;
1008 auth_is(subpointer, SB_LEN());
1009 break;
1010 case TELQUAL_SEND:
1011 if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
1012 return;
1013 auth_send(subpointer, SB_LEN());
1014 break;
1015 case TELQUAL_REPLY:
1016 if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
1017 return;
1018 auth_reply(subpointer, SB_LEN());
1019 break;
1020 case TELQUAL_NAME:
1021 if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
1022 return;
1023 auth_name(subpointer, SB_LEN());
1024 break;
1027 break;
1028 #endif
1029 #ifdef ENCRYPTION
1030 case TELOPT_ENCRYPT:
1031 if (SB_EOF())
1032 return;
1033 switch(SB_GET()) {
1034 case ENCRYPT_START:
1035 if (my_want_state_is_dont(TELOPT_ENCRYPT))
1036 return;
1037 encrypt_start(subpointer, SB_LEN());
1038 break;
1039 case ENCRYPT_END:
1040 if (my_want_state_is_dont(TELOPT_ENCRYPT))
1041 return;
1042 encrypt_end();
1043 break;
1044 case ENCRYPT_SUPPORT:
1045 if (my_want_state_is_wont(TELOPT_ENCRYPT))
1046 return;
1047 encrypt_support(subpointer, SB_LEN());
1048 break;
1049 case ENCRYPT_REQSTART:
1050 if (my_want_state_is_wont(TELOPT_ENCRYPT))
1051 return;
1052 encrypt_request_start(subpointer, SB_LEN());
1053 break;
1054 case ENCRYPT_REQEND:
1055 if (my_want_state_is_wont(TELOPT_ENCRYPT))
1056 return;
1058 * We can always send an REQEND so that we cannot
1059 * get stuck encrypting. We should only get this
1060 * if we have been able to get in the correct mode
1061 * anyhow.
1063 encrypt_request_end();
1064 break;
1065 case ENCRYPT_IS:
1066 if (my_want_state_is_dont(TELOPT_ENCRYPT))
1067 return;
1068 encrypt_is(subpointer, SB_LEN());
1069 break;
1070 case ENCRYPT_REPLY:
1071 if (my_want_state_is_wont(TELOPT_ENCRYPT))
1072 return;
1073 encrypt_reply(subpointer, SB_LEN());
1074 break;
1075 case ENCRYPT_ENC_KEYID:
1076 if (my_want_state_is_dont(TELOPT_ENCRYPT))
1077 return;
1078 encrypt_enc_keyid(subpointer, SB_LEN());
1079 break;
1080 case ENCRYPT_DEC_KEYID:
1081 if (my_want_state_is_wont(TELOPT_ENCRYPT))
1082 return;
1083 encrypt_dec_keyid(subpointer, SB_LEN());
1084 break;
1085 default:
1086 break;
1088 break;
1089 #endif /* ENCRYPTION */
1090 default:
1091 break;
1095 static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
1097 void
1098 lm_will(unsigned char *cmd, int len)
1100 if (len < 1) {
1101 /*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */
1102 return;
1104 switch(cmd[0]) {
1105 case LM_FORWARDMASK: /* We shouldn't ever get this... */
1106 default:
1107 str_lm[3] = DONT;
1108 str_lm[4] = cmd[0];
1109 if ((size_t)NETROOM() > sizeof(str_lm)) {
1110 ring_supply_data(&netoring, str_lm, sizeof(str_lm));
1111 printsub('>', &str_lm[2], sizeof(str_lm)-2);
1113 /*@*/ else printf("lm_will: not enough room in buffer\n");
1114 break;
1118 void
1119 lm_wont(unsigned char *cmd, int len)
1121 if (len < 1) {
1122 /*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */
1123 return;
1125 switch(cmd[0]) {
1126 case LM_FORWARDMASK: /* We shouldn't ever get this... */
1127 default:
1128 /* We are always DONT, so don't respond */
1129 return;
1133 void
1134 lm_do(unsigned char *cmd, int len)
1136 if (len < 1) {
1137 /*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */
1138 return;
1140 switch(cmd[0]) {
1141 case LM_FORWARDMASK:
1142 default:
1143 str_lm[3] = WONT;
1144 str_lm[4] = cmd[0];
1145 if ((size_t)NETROOM() > sizeof(str_lm)) {
1146 ring_supply_data(&netoring, str_lm, sizeof(str_lm));
1147 printsub('>', &str_lm[2], sizeof(str_lm)-2);
1149 /*@*/ else printf("lm_do: not enough room in buffer\n");
1150 break;
1154 void
1155 lm_dont(unsigned char *cmd, int len)
1157 if (len < 1) {
1158 /*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */
1159 return;
1161 switch(cmd[0]) {
1162 case LM_FORWARDMASK:
1163 default:
1164 /* we are always WONT, so don't respond */
1165 break;
1169 static unsigned char str_lm_mode[] = {
1170 IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
1173 void
1174 lm_mode(unsigned char *cmd, int len, int init)
1176 if (len != 1)
1177 return;
1178 if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
1179 return;
1180 if (*cmd&MODE_ACK)
1181 return;
1182 linemode = *cmd&(MODE_MASK&~MODE_ACK);
1183 str_lm_mode[4] = linemode;
1184 if (!init)
1185 str_lm_mode[4] |= MODE_ACK;
1186 if ((size_t)NETROOM() > sizeof(str_lm_mode)) {
1187 ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
1188 printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
1190 /*@*/ else printf("lm_mode: not enough room in buffer\n");
1191 setconnmode(0); /* set changed mode */
1197 * slc()
1198 * Handle special character suboption of LINEMODE.
1201 struct spc {
1202 cc_t val;
1203 cc_t *valp;
1204 char flags; /* Current flags & level */
1205 char mylevel; /* Maximum level & flags */
1206 } spc_data[NSLC+1];
1208 #define SLC_IMPORT 0
1209 #define SLC_EXPORT 1
1210 #define SLC_RVALUE 2
1211 static int slc_mode = SLC_EXPORT;
1213 void
1214 slc_init(void)
1216 struct spc *spcp;
1218 localchars = 1;
1219 for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
1220 spcp->val = 0;
1221 spcp->valp = 0;
1222 spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
1225 #define initfunc(func, flags) { \
1226 spcp = &spc_data[func]; \
1227 if ((spcp->valp = tcval(func)) != NULL){ \
1228 spcp->val = *spcp->valp; \
1229 spcp->mylevel = SLC_VARIABLE|flags; \
1230 } else { \
1231 spcp->val = 0; \
1232 spcp->mylevel = SLC_DEFAULT; \
1236 initfunc(SLC_SYNCH, 0);
1237 /* No BRK */
1238 initfunc(SLC_AO, 0);
1239 initfunc(SLC_AYT, 0);
1240 /* No EOR */
1241 initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
1242 initfunc(SLC_EOF, 0);
1243 initfunc(SLC_SUSP, SLC_FLUSHIN);
1244 initfunc(SLC_EC, 0);
1245 initfunc(SLC_EL, 0);
1246 initfunc(SLC_EW, 0);
1247 initfunc(SLC_RP, 0);
1248 initfunc(SLC_LNEXT, 0);
1249 initfunc(SLC_XON, 0);
1250 initfunc(SLC_XOFF, 0);
1251 initfunc(SLC_FORW1, 0);
1252 initfunc(SLC_FORW2, 0);
1253 /* No FORW2 */
1255 initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
1256 #undef initfunc
1258 if (slc_mode == SLC_EXPORT)
1259 slc_export();
1260 else
1261 slc_import(1);
1265 void
1266 slcstate(void)
1268 printf("Special characters are %s values\n",
1269 slc_mode == SLC_IMPORT ? "remote default" :
1270 slc_mode == SLC_EXPORT ? "local" :
1271 "remote");
1274 void
1275 slc_mode_export(int n)
1277 slc_mode = SLC_EXPORT;
1278 if (my_state_is_will(TELOPT_LINEMODE))
1279 slc_export();
1282 void
1283 slc_mode_import(int def)
1285 slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
1286 if (my_state_is_will(TELOPT_LINEMODE))
1287 slc_import(def);
1290 unsigned char slc_import_val[] = {
1291 IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
1293 unsigned char slc_import_def[] = {
1294 IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
1297 void
1298 slc_import(int def)
1300 if ((size_t)NETROOM() > sizeof(slc_import_val)) {
1301 if (def) {
1302 ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
1303 printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
1304 } else {
1305 ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
1306 printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
1309 /*@*/ else printf("slc_import: not enough room\n");
1312 void
1313 slc_export(void)
1315 struct spc *spcp;
1317 TerminalDefaultChars();
1319 slc_start_reply();
1320 for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1321 if (spcp->mylevel != SLC_NOSUPPORT) {
1322 if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1323 spcp->flags = SLC_NOSUPPORT;
1324 else
1325 spcp->flags = spcp->mylevel;
1326 if (spcp->valp)
1327 spcp->val = *spcp->valp;
1328 slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1331 slc_end_reply();
1332 (void)slc_update();
1333 setconnmode(1); /* Make sure the character values are set */
1336 void
1337 slc(unsigned char *cp, int len)
1339 struct spc *spcp;
1340 int func,level;
1342 slc_start_reply();
1344 for (; len >= 3; len -=3, cp +=3) {
1346 func = cp[SLC_FUNC];
1348 if (func == 0) {
1350 * Client side: always ignore 0 function.
1352 continue;
1354 if (func > NSLC) {
1355 if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
1356 slc_add_reply(func, SLC_NOSUPPORT, 0);
1357 continue;
1360 spcp = &spc_data[func];
1362 level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
1364 if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
1365 ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
1366 continue;
1369 if (level == (SLC_DEFAULT|SLC_ACK)) {
1371 * This is an error condition, the SLC_ACK
1372 * bit should never be set for the SLC_DEFAULT
1373 * level. Our best guess to recover is to
1374 * ignore the SLC_ACK bit.
1376 cp[SLC_FLAGS] &= ~SLC_ACK;
1379 if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
1380 spcp->val = (cc_t)cp[SLC_VALUE];
1381 spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */
1382 continue;
1385 level &= ~SLC_ACK;
1387 if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
1388 spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
1389 spcp->val = (cc_t)cp[SLC_VALUE];
1391 if (level == SLC_DEFAULT) {
1392 if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
1393 spcp->flags = spcp->mylevel;
1394 else
1395 spcp->flags = SLC_NOSUPPORT;
1397 slc_add_reply(func, spcp->flags, spcp->val);
1399 slc_end_reply();
1400 if (slc_update())
1401 setconnmode(1); /* set the new character values */
1404 void
1405 slc_check(void)
1407 struct spc *spcp;
1409 slc_start_reply();
1410 for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1411 if (spcp->valp && spcp->val != *spcp->valp) {
1412 spcp->val = *spcp->valp;
1413 if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1414 spcp->flags = SLC_NOSUPPORT;
1415 else
1416 spcp->flags = spcp->mylevel;
1417 slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1420 slc_end_reply();
1421 setconnmode(1);
1425 unsigned char slc_reply[128];
1426 unsigned char *slc_replyp;
1428 void
1429 slc_start_reply(void)
1431 slc_replyp = slc_reply;
1432 *slc_replyp++ = IAC;
1433 *slc_replyp++ = SB;
1434 *slc_replyp++ = TELOPT_LINEMODE;
1435 *slc_replyp++ = LM_SLC;
1438 void
1439 slc_add_reply(unsigned int func, unsigned int flags, cc_t value)
1441 if ((size_t)(slc_replyp - slc_reply) + 6 > sizeof(slc_reply))
1442 return;
1443 if ((*slc_replyp++ = func) == IAC)
1444 *slc_replyp++ = IAC;
1445 if ((*slc_replyp++ = flags) == IAC)
1446 *slc_replyp++ = IAC;
1447 if ((*slc_replyp++ = (unsigned char)value) == IAC)
1448 *slc_replyp++ = IAC;
1451 void
1452 slc_end_reply(void)
1454 int len;
1456 len = slc_replyp - slc_reply;
1457 if (len <= 4 || ((size_t)len + 2 > sizeof(slc_reply)))
1458 return;
1459 *slc_replyp++ = IAC;
1460 *slc_replyp++ = SE;
1461 len += 2;
1462 if (NETROOM() > len) {
1463 ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
1464 printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
1466 /*@*/else printf("slc_end_reply: not enough room\n");
1470 slc_update(void)
1472 struct spc *spcp;
1473 int need_update = 0;
1475 for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1476 if (!(spcp->flags&SLC_ACK))
1477 continue;
1478 spcp->flags &= ~SLC_ACK;
1479 if (spcp->valp && (*spcp->valp != spcp->val)) {
1480 *spcp->valp = spcp->val;
1481 need_update = 1;
1484 return(need_update);
1487 #ifdef OLD_ENVIRON
1488 # ifdef ENV_HACK
1490 * Earlier version of telnet/telnetd from the BSD code had
1491 * the definitions of VALUE and VAR reversed. To ensure
1492 * maximum interoperability, we assume that the server is
1493 * an older BSD server, until proven otherwise. The newer
1494 * BSD servers should be able to handle either definition,
1495 * so it is better to use the wrong values if we don't
1496 * know what type of server it is.
1498 int env_auto = 1;
1499 int old_env_var = OLD_ENV_VAR;
1500 int old_env_value = OLD_ENV_VALUE;
1501 # else
1502 # define old_env_var OLD_ENV_VAR
1503 # define old_env_value OLD_ENV_VALUE
1504 # endif
1505 #endif
1507 void
1508 env_opt(unsigned char *buf, int len)
1510 unsigned char *ep = 0, *epc = 0;
1511 int i;
1513 switch(buf[0]&0xff) {
1514 case TELQUAL_SEND:
1515 env_opt_start();
1516 if (len == 1) {
1517 env_opt_add(NULL);
1518 } else for (i = 1; i < len; i++) {
1519 switch (buf[i]&0xff) {
1520 #ifdef OLD_ENVIRON
1521 case OLD_ENV_VAR:
1522 # ifdef ENV_HACK
1523 if (telopt_environ == TELOPT_OLD_ENVIRON
1524 && env_auto) {
1525 /* Server has the same definitions */
1526 old_env_var = OLD_ENV_VAR;
1527 old_env_value = OLD_ENV_VALUE;
1529 /* FALL THROUGH */
1530 # endif
1531 case OLD_ENV_VALUE:
1533 * Although OLD_ENV_VALUE is not legal, we will
1534 * still recognize it, just in case it is an
1535 * old server that has VAR & VALUE mixed up...
1537 /* FALL THROUGH */
1538 #else
1539 case NEW_ENV_VAR:
1540 #endif
1541 case ENV_USERVAR:
1542 if (ep) {
1543 *epc = 0;
1544 env_opt_add(ep);
1546 ep = epc = &buf[i+1];
1547 break;
1548 case ENV_ESC:
1549 i++;
1550 /*FALL THROUGH*/
1551 default:
1552 if (epc)
1553 *epc++ = buf[i];
1554 break;
1557 if (ep) {
1558 *epc = 0;
1559 env_opt_add(ep);
1561 env_opt_end(1);
1562 break;
1564 case TELQUAL_IS:
1565 case TELQUAL_INFO:
1566 /* Ignore for now. We shouldn't get it anyway. */
1567 break;
1569 default:
1570 break;
1574 #define OPT_REPLY_SIZE 256
1575 unsigned char *opt_reply;
1576 unsigned char *opt_replyp;
1577 unsigned char *opt_replyend;
1579 void
1580 env_opt_start(void)
1582 unsigned char *p;
1584 if (opt_reply) {
1585 p = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE);
1586 if (p == NULL)
1587 free(opt_reply);
1588 } else
1589 p = (unsigned char *)malloc(OPT_REPLY_SIZE);
1590 opt_reply = p;
1591 if (opt_reply == NULL) {
1592 /*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n");
1593 opt_reply = opt_replyp = opt_replyend = NULL;
1594 return;
1596 opt_replyp = opt_reply;
1597 opt_replyend = opt_reply + OPT_REPLY_SIZE;
1598 *opt_replyp++ = IAC;
1599 *opt_replyp++ = SB;
1600 *opt_replyp++ = telopt_environ;
1601 *opt_replyp++ = TELQUAL_IS;
1604 void
1605 env_opt_start_info(void)
1607 env_opt_start();
1608 if (opt_replyp)
1609 opt_replyp[-1] = TELQUAL_INFO;
1612 void
1613 env_opt_add(unsigned char *ep)
1615 unsigned char *vp, c;
1616 unsigned int len, olen, elen;
1618 if (opt_reply == NULL) /*XXX*/
1619 return; /*XXX*/
1621 if (ep == NULL || *ep == '\0') {
1622 /* Send user defined variables first. */
1623 env_default(1, 0);
1624 while ((ep = env_default(0, 0)) != NULL)
1625 env_opt_add(ep);
1627 /* Now add the list of well know variables. */
1628 env_default(1, 1);
1629 while ((ep = env_default(0, 1)) != NULL)
1630 env_opt_add(ep);
1631 return;
1633 vp = env_getvalue(ep);
1634 elen = 2 * (vp ? strlen((char *)vp) : 0) +
1635 2 * strlen((char *)ep) + 6;
1636 if ((unsigned int)(opt_replyend - opt_replyp) < elen)
1638 unsigned char *p;
1639 len = opt_replyend - opt_reply + elen;
1640 olen = opt_replyp - opt_reply;
1641 p = (unsigned char *)realloc(opt_reply, len);
1642 if (p == NULL)
1643 free(opt_reply);
1644 opt_reply = p;
1645 if (opt_reply == NULL) {
1646 /*@*/ printf("env_opt_add: realloc() failed!!!\n");
1647 opt_reply = opt_replyp = opt_replyend = NULL;
1648 return;
1650 opt_replyp = opt_reply + olen;
1651 opt_replyend = opt_reply + len;
1653 if (opt_welldefined(ep))
1654 #ifdef OLD_ENVIRON
1655 if (telopt_environ == TELOPT_OLD_ENVIRON)
1656 *opt_replyp++ = old_env_var;
1657 else
1658 #endif
1659 *opt_replyp++ = NEW_ENV_VAR;
1660 else
1661 *opt_replyp++ = ENV_USERVAR;
1662 for (;;) {
1663 while ((c = *ep++) != '\0') {
1664 switch(c&0xff) {
1665 case IAC:
1666 *opt_replyp++ = IAC;
1667 break;
1668 case NEW_ENV_VAR:
1669 case NEW_ENV_VALUE:
1670 case ENV_ESC:
1671 case ENV_USERVAR:
1672 *opt_replyp++ = ENV_ESC;
1673 break;
1675 *opt_replyp++ = c;
1677 if ((ep = vp) != NULL) {
1678 #ifdef OLD_ENVIRON
1679 if (telopt_environ == TELOPT_OLD_ENVIRON)
1680 *opt_replyp++ = old_env_value;
1681 else
1682 #endif
1683 *opt_replyp++ = NEW_ENV_VALUE;
1684 vp = NULL;
1685 } else
1686 break;
1691 opt_welldefined(const char *ep)
1693 if ((strcmp(ep, "USER") == 0) ||
1694 (strcmp(ep, "DISPLAY") == 0) ||
1695 (strcmp(ep, "PRINTER") == 0) ||
1696 (strcmp(ep, "SYSTEMTYPE") == 0) ||
1697 (strcmp(ep, "JOB") == 0) ||
1698 (strcmp(ep, "ACCT") == 0))
1699 return(1);
1700 return(0);
1702 void
1703 env_opt_end(int emptyok)
1705 int len;
1707 len = opt_replyp - opt_reply + 2;
1708 if (emptyok || len > 6) {
1709 *opt_replyp++ = IAC;
1710 *opt_replyp++ = SE;
1711 if (NETROOM() > len) {
1712 ring_supply_data(&netoring, opt_reply, len);
1713 printsub('>', &opt_reply[2], len - 2);
1715 /*@*/ else printf("slc_end_reply: not enough room\n");
1717 if (opt_reply) {
1718 free(opt_reply);
1719 opt_reply = opt_replyp = opt_replyend = NULL;
1726 telrcv(void)
1728 int c;
1729 int scc;
1730 unsigned char *sbp = NULL;
1731 int count;
1732 int returnValue = 0;
1734 scc = 0;
1735 count = 0;
1736 while (TTYROOM() > 2) {
1737 if (scc == 0) {
1738 if (count) {
1739 ring_consumed(&netiring, count);
1740 returnValue = 1;
1741 count = 0;
1743 sbp = netiring.consume;
1744 scc = ring_full_consecutive(&netiring);
1745 if (scc == 0) {
1746 /* No more data coming in */
1747 break;
1751 c = *sbp++ & 0xff, scc--; count++;
1752 #ifdef ENCRYPTION
1753 if (decrypt_input)
1754 c = (*decrypt_input)(c);
1755 #endif /* ENCRYPTION */
1757 switch (telrcv_state) {
1759 case TS_CR:
1760 telrcv_state = TS_DATA;
1761 if (c == '\0') {
1762 break; /* Ignore \0 after CR */
1764 else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
1765 TTYADD(c);
1766 break;
1768 /* Else, fall through */
1770 case TS_DATA:
1771 if (c == IAC) {
1772 telrcv_state = TS_IAC;
1773 break;
1775 # if defined(TN3270)
1776 if (In3270) {
1777 *Ifrontp++ = c;
1778 while (scc > 0) {
1779 c = *sbp++ & 0377, scc--; count++;
1780 #ifdef ENCRYPTION
1781 if (decrypt_input)
1782 c = (*decrypt_input)(c);
1783 #endif /* ENCRYPTION */
1784 if (c == IAC) {
1785 telrcv_state = TS_IAC;
1786 break;
1788 *Ifrontp++ = c;
1790 } else
1791 # endif /* defined(TN3270) */
1793 * The 'crmod' hack (see following) is needed
1794 * since we can't * set CRMOD on output only.
1795 * Machines like MULTICS like to send \r without
1796 * \n; since we must turn off CRMOD to get proper
1797 * input, the mapping is done here (sigh).
1799 if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
1800 if (scc > 0) {
1801 c = *sbp&0xff;
1802 #ifdef ENCRYPTION
1803 if (decrypt_input)
1804 c = (*decrypt_input)(c);
1805 #endif /* ENCRYPTION */
1806 if (c == 0) {
1807 sbp++, scc--; count++;
1808 /* a "true" CR */
1809 TTYADD('\r');
1810 } else if (my_want_state_is_dont(TELOPT_ECHO) &&
1811 (c == '\n')) {
1812 sbp++, scc--; count++;
1813 TTYADD('\n');
1814 } else {
1815 #ifdef ENCRYPTION
1816 if (decrypt_input)
1817 (*decrypt_input)(-1);
1818 #endif /* ENCRYPTION */
1820 TTYADD('\r');
1821 if (crmod) {
1822 TTYADD('\n');
1825 } else {
1826 telrcv_state = TS_CR;
1827 TTYADD('\r');
1828 if (crmod) {
1829 TTYADD('\n');
1832 } else {
1833 TTYADD(c);
1835 continue;
1837 case TS_IAC:
1838 process_iac:
1839 switch (c) {
1841 case WILL:
1842 telrcv_state = TS_WILL;
1843 continue;
1845 case WONT:
1846 telrcv_state = TS_WONT;
1847 continue;
1849 case DO:
1850 telrcv_state = TS_DO;
1851 continue;
1853 case DONT:
1854 telrcv_state = TS_DONT;
1855 continue;
1857 case DM:
1859 * We may have missed an urgent notification,
1860 * so make sure we flush whatever is in the
1861 * buffer currently.
1863 printoption("RCVD", IAC, DM);
1864 SYNCHing = 1;
1865 (void) ttyflush(1);
1866 SYNCHing = stilloob();
1867 settimer(gotDM);
1868 break;
1870 case SB:
1871 SB_CLEAR();
1872 telrcv_state = TS_SB;
1873 continue;
1875 # if defined(TN3270)
1876 case EOR:
1877 if (In3270) {
1878 if (Ibackp == Ifrontp) {
1879 Ibackp = Ifrontp = Ibuf;
1880 ISend = 0; /* should have been! */
1881 } else {
1882 Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
1883 ISend = 1;
1886 printoption("RCVD", IAC, EOR);
1887 break;
1888 # endif /* defined(TN3270) */
1890 case IAC:
1891 # if !defined(TN3270)
1892 TTYADD(IAC);
1893 # else /* !defined(TN3270) */
1894 if (In3270) {
1895 *Ifrontp++ = IAC;
1896 } else {
1897 TTYADD(IAC);
1899 # endif /* !defined(TN3270) */
1900 break;
1902 case NOP:
1903 case GA:
1904 default:
1905 printoption("RCVD", IAC, c);
1906 break;
1908 telrcv_state = TS_DATA;
1909 continue;
1911 case TS_WILL:
1912 printoption("RCVD", WILL, c);
1913 willoption(c);
1914 SetIn3270();
1915 telrcv_state = TS_DATA;
1916 continue;
1918 case TS_WONT:
1919 printoption("RCVD", WONT, c);
1920 wontoption(c);
1921 SetIn3270();
1922 telrcv_state = TS_DATA;
1923 continue;
1925 case TS_DO:
1926 printoption("RCVD", DO, c);
1927 dooption(c);
1928 SetIn3270();
1929 if (c == TELOPT_NAWS) {
1930 sendnaws();
1931 } else if (c == TELOPT_LFLOW) {
1932 localflow = 1;
1933 setcommandmode();
1934 setconnmode(0);
1936 telrcv_state = TS_DATA;
1937 continue;
1939 case TS_DONT:
1940 printoption("RCVD", DONT, c);
1941 dontoption(c);
1942 flushline = 1;
1943 setconnmode(0); /* set new tty mode (maybe) */
1944 SetIn3270();
1945 telrcv_state = TS_DATA;
1946 continue;
1948 case TS_SB:
1949 if (c == IAC) {
1950 telrcv_state = TS_SE;
1951 } else {
1952 SB_ACCUM(c);
1954 continue;
1956 case TS_SE:
1957 if (c != SE) {
1958 if (c != IAC) {
1960 * This is an error. We only expect to get
1961 * "IAC IAC" or "IAC SE". Several things may
1962 * have happened. An IAC was not doubled, the
1963 * IAC SE was left off, or another option got
1964 * inserted into the suboption are all possibilities.
1965 * If we assume that the IAC was not doubled,
1966 * and really the IAC SE was left off, we could
1967 * get into an infinite loop here. So, instead,
1968 * we terminate the suboption, and process the
1969 * partial suboption if we can.
1971 SB_ACCUM(IAC);
1972 SB_ACCUM(c);
1973 subpointer -= 2;
1974 SB_TERM();
1976 printoption("In SUBOPTION processing, RCVD", IAC, c);
1977 suboption(); /* handle sub-option */
1978 SetIn3270();
1979 telrcv_state = TS_IAC;
1980 goto process_iac;
1982 SB_ACCUM(c);
1983 telrcv_state = TS_SB;
1984 } else {
1985 SB_ACCUM(IAC);
1986 SB_ACCUM(SE);
1987 subpointer -= 2;
1988 SB_TERM();
1989 suboption(); /* handle sub-option */
1990 SetIn3270();
1991 telrcv_state = TS_DATA;
1995 if (count)
1996 ring_consumed(&netiring, count);
1997 return returnValue||count;
2000 static int bol = 1, local = 0;
2003 rlogin_susp(void)
2005 if (local) {
2006 local = 0;
2007 bol = 1;
2008 command(0, "z\n", 2);
2009 return(1);
2011 return(0);
2014 static int
2015 telsnd(void)
2017 int tcc;
2018 int count;
2019 int returnValue = 0;
2020 unsigned char *tbp = NULL;
2022 tcc = 0;
2023 count = 0;
2024 while (NETROOM() > 2) {
2025 int sc;
2026 int c;
2028 if (tcc == 0) {
2029 if (count) {
2030 ring_consumed(&ttyiring, count);
2031 returnValue = 1;
2032 count = 0;
2034 tbp = ttyiring.consume;
2035 tcc = ring_full_consecutive(&ttyiring);
2036 if (tcc == 0) {
2037 break;
2040 c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
2041 if (rlogin != _POSIX_VDISABLE) {
2042 if (bol) {
2043 bol = 0;
2044 if (sc == rlogin) {
2045 local = 1;
2046 continue;
2048 } else if (local) {
2049 local = 0;
2050 if (sc == '.' || c == termEofChar) {
2051 bol = 1;
2052 command(0, "close\n", 6);
2053 continue;
2055 if (sc == termSuspChar) {
2056 bol = 1;
2057 command(0, "z\n", 2);
2058 continue;
2060 if (sc == escape) {
2061 command(0, (char *)tbp, tcc);
2062 bol = 1;
2063 count += tcc;
2064 tcc = 0;
2065 flushline = 1;
2066 break;
2068 if (sc != rlogin) {
2069 ++tcc;
2070 --tbp;
2071 --count;
2072 c = sc = rlogin;
2075 if ((sc == '\n') || (sc == '\r'))
2076 bol = 1;
2077 } else if (sc == escape && escape != _POSIX_VDISABLE) {
2079 * Double escape is a pass through of a single escape character.
2081 if (tcc && strip(*tbp) == escape) {
2082 tbp++;
2083 tcc--;
2084 count++;
2085 bol = 0;
2086 } else {
2087 command(0, (char *)tbp, tcc);
2088 bol = 1;
2089 count += tcc;
2090 tcc = 0;
2091 flushline = 1;
2092 break;
2094 } else
2095 bol = 0;
2096 #ifdef KLUDGELINEMODE
2097 if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
2098 if (tcc > 0 && strip(*tbp) == echoc) {
2099 tcc--; tbp++; count++;
2100 } else {
2101 dontlecho = !dontlecho;
2102 settimer(echotoggle);
2103 setconnmode(0);
2104 flushline = 1;
2105 break;
2108 #endif
2109 if (sc != _POSIX_VDISABLE && MODE_LOCAL_CHARS(globalmode)) {
2110 if (TerminalSpecialChars(sc) == 0) {
2111 bol = 1;
2112 break;
2115 if (my_want_state_is_wont(TELOPT_BINARY)) {
2116 switch (c) {
2117 case '\n':
2119 * If we are in CRMOD mode (\r ==> \n)
2120 * on our local machine, then probably
2121 * a newline (unix) is CRLF (TELNET).
2123 if (MODE_LOCAL_CHARS(globalmode)) {
2124 NETADD('\r');
2126 NETADD('\n');
2127 bol = flushline = 1;
2128 break;
2129 case '\r':
2130 if (!crlf) {
2131 NET2ADD('\r', '\0');
2132 } else {
2133 NET2ADD('\r', '\n');
2135 bol = flushline = 1;
2136 break;
2137 case IAC:
2138 NET2ADD(IAC, IAC);
2139 break;
2140 default:
2141 NETADD(c);
2142 break;
2144 } else if (c == IAC) {
2145 NET2ADD(IAC, IAC);
2146 } else {
2147 NETADD(c);
2150 if (count)
2151 ring_consumed(&ttyiring, count);
2152 return returnValue||count; /* Non-zero if we did anything */
2156 * Scheduler()
2158 * Try to do something.
2160 * If we do something useful, return 1; else return 0.
2166 Scheduler(int block) /* should we block in the select ? */
2168 /* One wants to be a bit careful about setting returnValue
2169 * to one, since a one implies we did some useful work,
2170 * and therefore probably won't be called to block next
2171 * time (TN3270 mode only).
2173 int returnValue;
2174 int netin, netout, netex, ttyin, ttyout;
2176 /* Decide which rings should be processed */
2178 netout = ring_full_count(&netoring) &&
2179 (flushline ||
2180 (my_want_state_is_wont(TELOPT_LINEMODE)
2181 #ifdef KLUDGELINEMODE
2182 && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
2183 #endif
2184 ) ||
2185 my_want_state_is_will(TELOPT_BINARY));
2186 ttyout = ring_full_count(&ttyoring);
2188 #ifdef TN3270
2189 ttyin = ring_empty_count(&ttyiring) && (clienteof == 0) && (shell_active == 0);
2190 #else /* defined(TN3270) */
2191 ttyin = ring_empty_count(&ttyiring) && (clienteof == 0);
2192 #endif /* defined(TN3270) */
2194 #ifdef TN3270
2195 netin = ring_empty_count(&netiring);
2196 # else /* !defined(TN3270) */
2197 netin = !ISend && ring_empty_count(&netiring);
2198 # endif /* !defined(TN3270) */
2200 netex = !SYNCHing;
2202 /* If we have seen a signal recently, reset things */
2203 # ifdef TN3270
2204 if (HaveInput) {
2205 HaveInput = 0;
2206 (void) signal(SIGIO, inputAvailable);
2208 #endif /* defined(TN3270) */
2210 /* Call to system code to process rings */
2212 returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
2214 /* Now, look at the input rings, looking for work to do. */
2216 if (ring_full_count(&ttyiring)) {
2217 # if defined(TN3270)
2218 if (In3270) {
2219 int c;
2221 c = DataFromTerminal(ttyiring.consume,
2222 ring_full_consecutive(&ttyiring));
2223 if (c) {
2224 returnValue = 1;
2225 ring_consumed(&ttyiring, c);
2227 } else {
2228 # endif /* defined(TN3270) */
2229 returnValue |= telsnd();
2230 # if defined(TN3270)
2232 # endif /* defined(TN3270) */
2235 if (ring_full_count(&netiring)) {
2236 # if !defined(TN3270)
2237 returnValue |= telrcv();
2238 # else /* !defined(TN3270) */
2239 returnValue = Push3270();
2240 # endif /* !defined(TN3270) */
2242 return returnValue;
2246 * Select from tty and network...
2248 void
2249 telnet(const char *user)
2251 sys_telnet_init();
2253 #if defined(AUTHENTICATION) || defined(ENCRYPTION)
2255 static char local_host[MAXHOSTNAMELEN + 1] = { 0 };
2257 if (!local_host[0]) {
2258 gethostname(local_host, sizeof(local_host));
2259 local_host[sizeof(local_host)-1] = 0;
2261 auth_encrypt_init(local_host, hostname, "TELNET", 0);
2262 auth_encrypt_user(user);
2264 #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
2265 # if !defined(TN3270)
2266 if (telnetport) {
2267 #ifdef AUTHENTICATION
2268 if (autologin)
2269 send_will(TELOPT_AUTHENTICATION, 1);
2270 #endif
2271 #ifdef ENCRYPTION
2272 send_do(TELOPT_ENCRYPT, 1);
2273 send_will(TELOPT_ENCRYPT, 1);
2274 #endif /* ENCRYPTION */
2275 send_do(TELOPT_SGA, 1);
2276 send_will(TELOPT_TTYPE, 1);
2277 send_will(TELOPT_NAWS, 1);
2278 send_will(TELOPT_TSPEED, 1);
2279 send_will(TELOPT_LFLOW, 1);
2280 send_will(TELOPT_LINEMODE, 1);
2281 send_will(TELOPT_NEW_ENVIRON, 1);
2282 send_do(TELOPT_STATUS, 1);
2283 if (env_getvalue((const unsigned char *)"DISPLAY"))
2284 send_will(TELOPT_XDISPLOC, 1);
2285 if (eight)
2286 tel_enter_binary(eight);
2288 # endif /* !defined(TN3270) */
2290 # if !defined(TN3270)
2291 for (;;) {
2292 int schedValue;
2294 while ((schedValue = Scheduler(0)) != 0) {
2295 if (schedValue == -1) {
2296 setcommandmode();
2297 return;
2301 if (Scheduler(1) == -1) {
2302 setcommandmode();
2303 return;
2306 # else /* !defined(TN3270) */
2307 for (;;) {
2308 int schedValue;
2310 while (!In3270 && !shell_active) {
2311 if (Scheduler(1) == -1) {
2312 setcommandmode();
2313 return;
2317 while ((schedValue = Scheduler(0)) != 0) {
2318 if (schedValue == -1) {
2319 setcommandmode();
2320 return;
2323 /* If there is data waiting to go out to terminal, don't
2324 * schedule any more data for the terminal.
2326 if (ring_full_count(&ttyoring)) {
2327 schedValue = 1;
2328 } else {
2329 if (shell_active) {
2330 if (shell_continue() == 0) {
2331 ConnectScreen();
2333 } else if (In3270) {
2334 schedValue = DoTerminalOutput();
2337 if (schedValue && (shell_active == 0)) {
2338 if (Scheduler(1) == -1) {
2339 setcommandmode();
2340 return;
2344 # endif /* !defined(TN3270) */
2347 #if 0 /* XXX - this not being in is a bug */
2349 * nextitem()
2351 * Return the address of the next "item" in the TELNET data
2352 * stream. This will be the address of the next character if
2353 * the current address is a user data character, or it will
2354 * be the address of the character following the TELNET command
2355 * if the current address is a TELNET IAC ("I Am a Command")
2356 * character.
2359 static char *
2360 nextitem(char *current)
2362 if ((*current&0xff) != IAC) {
2363 return current+1;
2365 switch (*(current+1)&0xff) {
2366 case DO:
2367 case DONT:
2368 case WILL:
2369 case WONT:
2370 return current+3;
2371 case SB: /* loop forever looking for the SE */
2373 char *look = current+2;
2375 for (;;) {
2376 if ((*look++&0xff) == IAC) {
2377 if ((*look++&0xff) == SE) {
2378 return look;
2383 default:
2384 return current+2;
2387 #endif /* 0 */
2390 * netclear()
2392 * We are about to do a TELNET SYNCH operation. Clear
2393 * the path to the network.
2395 * Things are a bit tricky since we may have sent the first
2396 * byte or so of a previous TELNET command into the network.
2397 * So, we have to scan the network buffer from the beginning
2398 * until we are up to where we want to be.
2400 * A side effect of what we do, just to keep things
2401 * simple, is to clear the urgent data pointer. The principal
2402 * caller should be setting the urgent data pointer AFTER calling
2403 * us in any case.
2406 static void
2407 netclear(void)
2409 #if 0 /* XXX */
2410 char *thisitem, *next;
2411 char *good;
2412 #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
2413 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
2415 thisitem = netobuf;
2417 while ((next = nextitem(thisitem)) <= netobuf.send) {
2418 thisitem = next;
2421 /* Now, thisitem is first before/at boundary. */
2423 good = netobuf; /* where the good bytes go */
2425 while (netoring.add > thisitem) {
2426 if (wewant(thisitem)) {
2427 int length;
2429 next = thisitem;
2430 do {
2431 next = nextitem(next);
2432 } while (wewant(next) && (nfrontp > next));
2433 length = next-thisitem;
2434 memmove(good, thisitem, length);
2435 good += length;
2436 thisitem = next;
2437 } else {
2438 thisitem = nextitem(thisitem);
2442 #endif /* 0 */
2446 * These routines add various telnet commands to the data stream.
2449 static void
2450 doflush(void)
2452 NET2ADD(IAC, DO);
2453 NETADD(TELOPT_TM);
2454 flushline = 1;
2455 flushout = 1;
2456 (void) ttyflush(1); /* Flush/drop output */
2457 /* do printoption AFTER flush, otherwise the output gets tossed... */
2458 printoption("SENT", DO, TELOPT_TM);
2461 void
2462 xmitAO(void)
2464 NET2ADD(IAC, AO);
2465 printoption("SENT", IAC, AO);
2466 if (autoflush) {
2467 doflush();
2472 void
2473 xmitEL(void)
2475 NET2ADD(IAC, EL);
2476 printoption("SENT", IAC, EL);
2479 void
2480 xmitEC(void)
2482 NET2ADD(IAC, EC);
2483 printoption("SENT", IAC, EC);
2488 dosynch(char *s)
2490 netclear(); /* clear the path to the network */
2491 NETADD(IAC);
2492 setneturg();
2493 NETADD(DM);
2494 printoption("SENT", IAC, DM);
2495 return 1;
2498 int want_status_response = 0;
2501 get_status(char *s)
2503 unsigned char tmp[16];
2504 unsigned char *cp;
2506 if (my_want_state_is_dont(TELOPT_STATUS)) {
2507 printf("Remote side does not support STATUS option\n");
2508 return 0;
2510 cp = tmp;
2512 *cp++ = IAC;
2513 *cp++ = SB;
2514 *cp++ = TELOPT_STATUS;
2515 *cp++ = TELQUAL_SEND;
2516 *cp++ = IAC;
2517 *cp++ = SE;
2518 if (NETROOM() >= cp - tmp) {
2519 ring_supply_data(&netoring, tmp, cp-tmp);
2520 printsub('>', tmp+2, cp - tmp - 2);
2522 ++want_status_response;
2523 return 1;
2526 void
2527 intp(void)
2529 NET2ADD(IAC, IP);
2530 printoption("SENT", IAC, IP);
2531 flushline = 1;
2532 if (autoflush) {
2533 doflush();
2535 if (autosynch) {
2536 dosynch(NULL);
2540 void
2541 sendbrk(void)
2543 NET2ADD(IAC, BREAK);
2544 printoption("SENT", IAC, BREAK);
2545 flushline = 1;
2546 if (autoflush) {
2547 doflush();
2549 if (autosynch) {
2550 dosynch(NULL);
2554 void
2555 sendabort(void)
2557 NET2ADD(IAC, ABORT);
2558 printoption("SENT", IAC, ABORT);
2559 flushline = 1;
2560 if (autoflush) {
2561 doflush();
2563 if (autosynch) {
2564 dosynch(NULL);
2568 void
2569 sendsusp(void)
2571 NET2ADD(IAC, SUSP);
2572 printoption("SENT", IAC, SUSP);
2573 flushline = 1;
2574 if (autoflush) {
2575 doflush();
2577 if (autosynch) {
2578 dosynch(NULL);
2582 void
2583 sendeof(void)
2585 NET2ADD(IAC, xEOF);
2586 printoption("SENT", IAC, xEOF);
2589 void
2590 sendayt(void)
2592 NET2ADD(IAC, AYT);
2593 printoption("SENT", IAC, AYT);
2597 * Send a window size update to the remote system.
2600 void
2601 sendnaws(void)
2603 long rows, cols;
2604 unsigned char tmp[16];
2605 unsigned char *cp;
2607 if (my_state_is_wont(TELOPT_NAWS))
2608 return;
2610 #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
2611 if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
2613 if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */
2614 return;
2617 cp = tmp;
2619 *cp++ = IAC;
2620 *cp++ = SB;
2621 *cp++ = TELOPT_NAWS;
2622 PUTSHORT(cp, cols);
2623 PUTSHORT(cp, rows);
2624 *cp++ = IAC;
2625 *cp++ = SE;
2626 if (NETROOM() >= cp - tmp) {
2627 ring_supply_data(&netoring, tmp, cp-tmp);
2628 printsub('>', tmp+2, cp - tmp - 2);
2632 void
2633 tel_enter_binary(int rw)
2635 if (rw&1)
2636 send_do(TELOPT_BINARY, 1);
2637 if (rw&2)
2638 send_will(TELOPT_BINARY, 1);
2641 void
2642 tel_leave_binary(int rw)
2644 if (rw&1)
2645 send_dont(TELOPT_BINARY, 1);
2646 if (rw&2)
2647 send_wont(TELOPT_BINARY, 1);