Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / usr.bin / telnet / telnet.c
blob10676c07b5bdb39218479ea35bba959b1725488e
1 /* $NetBSD: telnet.c,v 1.30 2005/03/29 12:18:28 drochner 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.30 2005/03/29 12:18:28 drochner Exp $");
38 #endif
39 #endif /* not lint */
41 #include <sys/param.h>
43 #include <signal.h>
44 #include <termcap.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
70 #define strip(x) ((my_want_state_is_wont(TELOPT_BINARY)) ? ((x)&0x7f) : (x))
72 static unsigned char subbuffer[SUBBUFSIZE],
73 *subpointer, *subend; /* buffer for sub-options */
74 #define SB_CLEAR() subpointer = subbuffer;
75 #define SB_TERM() { subend = subpointer; SB_CLEAR(); }
76 #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
77 *subpointer++ = (c); \
80 #define SB_GET() ((*subpointer++)&0xff)
81 #define SB_PEEK() ((*subpointer)&0xff)
82 #define SB_EOF() (subpointer >= subend)
83 #define SB_LEN() (subend - subpointer)
85 char options[256]; /* The combined options */
86 char do_dont_resp[256];
87 char will_wont_resp[256];
89 int
90 eight = 0,
91 autologin = 0, /* Autologin anyone? */
92 skiprc = 0,
93 connected,
94 showoptions,
95 In3270, /* Are we in 3270 mode? */
96 ISend, /* trying to send network data in */
97 telnet_debug = 0,
98 crmod,
99 netdata, /* Print out network data flow */
100 crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
101 #ifdef TN3270
102 noasynchtty = 0,/* User specified "-noasynch" on command line */
103 noasynchnet = 0,/* User specified "-noasynch" on command line */
104 askedSGA = 0, /* We have talked about suppress go ahead */
105 #endif /* defined(TN3270) */
106 telnetport,
107 SYNCHing, /* we are in TELNET SYNCH mode */
108 flushout, /* flush output */
109 autoflush = 0, /* flush output when interrupting? */
110 autosynch, /* send interrupt characters with SYNCH? */
111 localflow, /* we handle flow control locally */
112 restartany, /* if flow control enabled, restart on any character */
113 localchars, /* we recognize interrupt/quit */
114 donelclchars, /* the user has set "localchars" */
115 donebinarytoggle, /* the user has put us in binary */
116 dontlecho, /* do we suppress local echoing right now? */
117 globalmode,
118 doaddrlookup = 1, /* do a reverse address lookup? */
119 clienteof = 0;
121 char *prompt = 0;
123 cc_t escape;
124 cc_t rlogin;
125 #ifdef KLUDGELINEMODE
126 cc_t echoc;
127 #endif
130 * Telnet receiver states for fsm
132 #define TS_DATA 0
133 #define TS_IAC 1
134 #define TS_WILL 2
135 #define TS_WONT 3
136 #define TS_DO 4
137 #define TS_DONT 5
138 #define TS_CR 6
139 #define TS_SB 7 /* sub-option collection */
140 #define TS_SE 8 /* looking for sub-option end */
142 static int telrcv_state;
143 #ifdef OLD_ENVIRON
144 unsigned char telopt_environ = TELOPT_NEW_ENVIRON;
145 #else
146 # define telopt_environ TELOPT_NEW_ENVIRON
147 #endif
149 jmp_buf toplevel = { 0 };
151 int flushline;
152 int linemode;
154 #ifdef KLUDGELINEMODE
155 int kludgelinemode = 1;
156 #endif
158 static void dooption(int);
159 static void dontoption(int);
160 static void suboption(void);
161 static int telsnd(void);
162 static void netclear(void);
163 static void doflush(void);
166 * The following are some clocks used to decide how to interpret
167 * the relationship between various variables.
170 Clocks clocks;
172 #ifdef notdef
173 Modelist modelist[] = {
174 { "telnet command mode", COMMAND_LINE },
175 { "character-at-a-time mode", 0 },
176 { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
177 { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
178 { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
179 { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
180 { "3270 mode", 0 },
182 #endif
186 * Initialize telnet environment.
189 void
190 init_telnet(void)
192 env_init();
194 SB_CLEAR();
195 ClearArray(options);
197 connected = In3270 = ISend = localflow = donebinarytoggle = 0;
198 #if defined(AUTHENTICATION) || defined(ENCRYPTION)
199 auth_encrypt_connect(connected);
200 #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
201 restartany = -1;
203 SYNCHing = 0;
205 /* Don't change NetTrace */
207 escape = CONTROL(']');
208 rlogin = _POSIX_VDISABLE;
209 #ifdef KLUDGELINEMODE
210 echoc = CONTROL('E');
211 #endif
213 flushline = 1;
214 telrcv_state = TS_DATA;
218 #ifdef notdef
219 #include <stdarg.h>
221 /*VARARGS*/
222 static void
223 printring(Ring *ring, char *format, ...)
224 va_dcl
226 va_list ap;
227 char buffer[100]; /* where things go */
228 char *ptr;
229 char *string;
230 int i;
232 va_start(ap, format);
234 ptr = buffer;
236 while ((i = *format++) != 0) {
237 if (i == '%') {
238 i = *format++;
239 switch (i) {
240 case 'c':
241 *ptr++ = va_arg(ap, int);
242 break;
243 case 's':
244 string = va_arg(ap, char *);
245 ring_supply_data(ring, buffer, ptr-buffer);
246 ring_supply_data(ring, string, strlen(string));
247 ptr = buffer;
248 break;
249 case 0:
250 ExitString("printring: trailing %%.\n", 1);
251 /*NOTREACHED*/
252 default:
253 ExitString("printring: unknown format character.\n", 1);
254 /*NOTREACHED*/
256 } else {
257 *ptr++ = i;
260 va_end(ap);
261 ring_supply_data(ring, buffer, ptr-buffer);
263 #endif
266 * These routines are in charge of sending option negotiations
267 * to the other side.
269 * The basic idea is that we send the negotiation if either side
270 * is in disagreement as to what the current state should be.
273 void
274 send_do(int c, int init)
276 if (init) {
277 if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
278 my_want_state_is_do(c))
279 return;
280 set_my_want_state_do(c);
281 do_dont_resp[c]++;
283 NET2ADD(IAC, DO);
284 NETADD(c);
285 printoption("SENT", DO, c);
288 void
289 send_dont(int c, int init)
291 if (init) {
292 if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
293 my_want_state_is_dont(c))
294 return;
295 set_my_want_state_dont(c);
296 do_dont_resp[c]++;
298 NET2ADD(IAC, DONT);
299 NETADD(c);
300 printoption("SENT", DONT, c);
303 void
304 send_will(int c, int init)
306 if (init) {
307 if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
308 my_want_state_is_will(c))
309 return;
310 set_my_want_state_will(c);
311 will_wont_resp[c]++;
313 NET2ADD(IAC, WILL);
314 NETADD(c);
315 printoption("SENT", WILL, c);
318 void
319 send_wont(int c, int init)
321 if (init) {
322 if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
323 my_want_state_is_wont(c))
324 return;
325 set_my_want_state_wont(c);
326 will_wont_resp[c]++;
328 NET2ADD(IAC, WONT);
329 NETADD(c);
330 printoption("SENT", WONT, c);
334 void
335 willoption(int option)
337 int new_state_ok = 0;
339 if (do_dont_resp[option]) {
340 --do_dont_resp[option];
341 if (do_dont_resp[option] && my_state_is_do(option))
342 --do_dont_resp[option];
345 if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
347 switch (option) {
349 case TELOPT_ECHO:
350 # if defined(TN3270)
352 * The following is a pain in the rear-end.
353 * Various IBM servers (some versions of Wiscnet,
354 * possibly Fibronics/Spartacus, and who knows who
355 * else) will NOT allow us to send "DO SGA" too early
356 * in the setup proceedings. On the other hand,
357 * 4.2 servers (telnetd) won't set SGA correctly.
358 * So, we are stuck. Empirically (but, based on
359 * a VERY small sample), the IBM servers don't send
360 * out anything about ECHO, so we postpone our sending
361 * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
362 * DO send).
365 if (askedSGA == 0) {
366 askedSGA = 1;
367 if (my_want_state_is_dont(TELOPT_SGA))
368 send_do(TELOPT_SGA, 1);
371 /* Fall through */
372 case TELOPT_EOR:
373 #endif /* defined(TN3270) */
374 case TELOPT_BINARY:
375 case TELOPT_SGA:
376 settimer(modenegotiated);
377 /* FALL THROUGH */
378 case TELOPT_STATUS:
379 #ifdef AUTHENTICATION
380 case TELOPT_AUTHENTICATION:
381 #ifdef ENCRYPTION
382 case TELOPT_ENCRYPT:
383 #endif /* ENCRYPTION */
384 #endif
385 new_state_ok = 1;
386 break;
388 case TELOPT_TM:
389 if (flushout)
390 flushout = 0;
392 * Special case for TM. If we get back a WILL,
393 * pretend we got back a WONT.
395 set_my_want_state_dont(option);
396 set_my_state_dont(option);
397 return; /* Never reply to TM will's/wont's */
399 case TELOPT_LINEMODE:
400 default:
401 break;
404 if (new_state_ok) {
405 set_my_want_state_do(option);
406 send_do(option, 0);
407 setconnmode(0); /* possibly set new tty mode */
408 } else {
409 do_dont_resp[option]++;
410 send_dont(option, 0);
413 set_my_state_do(option);
414 #ifdef ENCRYPTION
415 if (option == TELOPT_ENCRYPT)
416 encrypt_send_support();
417 #endif /* ENCRYPTION */
420 void
421 wontoption(int option)
423 if (do_dont_resp[option]) {
424 --do_dont_resp[option];
425 if (do_dont_resp[option] && my_state_is_dont(option))
426 --do_dont_resp[option];
429 if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
431 switch (option) {
433 #ifdef KLUDGELINEMODE
434 case TELOPT_SGA:
435 if (!kludgelinemode)
436 break;
437 /* FALL THROUGH */
438 #endif
439 case TELOPT_ECHO:
440 settimer(modenegotiated);
441 break;
443 case TELOPT_TM:
444 if (flushout)
445 flushout = 0;
446 set_my_want_state_dont(option);
447 set_my_state_dont(option);
448 return; /* Never reply to TM will's/wont's */
450 default:
451 break;
453 set_my_want_state_dont(option);
454 if (my_state_is_do(option))
455 send_dont(option, 0);
456 setconnmode(0); /* Set new tty mode */
457 } else if (option == TELOPT_TM) {
459 * Special case for TM.
461 if (flushout)
462 flushout = 0;
463 set_my_want_state_dont(option);
465 set_my_state_dont(option);
468 static void
469 dooption(int option)
471 int new_state_ok = 0;
473 if (will_wont_resp[option]) {
474 --will_wont_resp[option];
475 if (will_wont_resp[option] && my_state_is_will(option))
476 --will_wont_resp[option];
479 if (will_wont_resp[option] == 0) {
480 if (my_want_state_is_wont(option)) {
482 switch (option) {
484 case TELOPT_TM:
486 * Special case for TM. We send a WILL, but pretend
487 * we sent WONT.
489 send_will(option, 0);
490 set_my_want_state_wont(TELOPT_TM);
491 set_my_state_wont(TELOPT_TM);
492 return;
494 # if defined(TN3270)
495 case TELOPT_EOR: /* end of record */
496 # endif /* defined(TN3270) */
497 case TELOPT_BINARY: /* binary mode */
498 case TELOPT_NAWS: /* window size */
499 case TELOPT_TSPEED: /* terminal speed */
500 case TELOPT_LFLOW: /* local flow control */
501 case TELOPT_TTYPE: /* terminal type option */
502 case TELOPT_SGA: /* no big deal */
503 #ifdef ENCRYPTION
504 case TELOPT_ENCRYPT: /* encryption variable option */
505 #endif /* ENCRYPTION */
506 new_state_ok = 1;
507 break;
509 case TELOPT_NEW_ENVIRON: /* New environment variable option */
510 #ifdef OLD_ENVIRON
511 if (my_state_is_will(TELOPT_OLD_ENVIRON))
512 send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */
513 goto env_common;
514 case TELOPT_OLD_ENVIRON: /* Old environment variable option */
515 if (my_state_is_will(TELOPT_NEW_ENVIRON))
516 break; /* Don't enable if new one is in use! */
517 env_common:
518 telopt_environ = option;
519 #endif
520 new_state_ok = 1;
521 break;
523 #ifdef AUTHENTICATION
524 case TELOPT_AUTHENTICATION:
525 if (autologin)
526 new_state_ok = 1;
527 break;
528 #endif
530 case TELOPT_XDISPLOC: /* X Display location */
531 if (env_getvalue((unsigned char *)"DISPLAY"))
532 new_state_ok = 1;
533 break;
535 case TELOPT_LINEMODE:
536 #ifdef KLUDGELINEMODE
537 kludgelinemode = 0;
538 send_do(TELOPT_SGA, 1);
539 #endif
540 set_my_want_state_will(TELOPT_LINEMODE);
541 send_will(option, 0);
542 set_my_state_will(TELOPT_LINEMODE);
543 slc_init();
544 return;
546 case TELOPT_ECHO: /* We're never going to echo... */
547 default:
548 break;
551 if (new_state_ok) {
552 set_my_want_state_will(option);
553 send_will(option, 0);
554 setconnmode(0); /* Set new tty mode */
555 } else {
556 will_wont_resp[option]++;
557 send_wont(option, 0);
559 } else {
561 * Handle options that need more things done after the
562 * other side has acknowledged the option.
564 switch (option) {
565 case TELOPT_LINEMODE:
566 #ifdef KLUDGELINEMODE
567 kludgelinemode = 0;
568 send_do(TELOPT_SGA, 1);
569 #endif
570 set_my_state_will(option);
571 slc_init();
572 send_do(TELOPT_SGA, 0);
573 return;
577 set_my_state_will(option);
580 static void
581 dontoption(int option)
584 if (will_wont_resp[option]) {
585 --will_wont_resp[option];
586 if (will_wont_resp[option] && my_state_is_wont(option))
587 --will_wont_resp[option];
590 if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
591 switch (option) {
592 case TELOPT_LINEMODE:
593 linemode = 0; /* put us back to the default state */
594 break;
595 #ifdef OLD_ENVIRON
596 case TELOPT_NEW_ENVIRON:
598 * The new environ option wasn't recognized, try
599 * the old one.
601 send_will(TELOPT_OLD_ENVIRON, 1);
602 telopt_environ = TELOPT_OLD_ENVIRON;
603 break;
604 #endif
606 /* we always accept a DONT */
607 set_my_want_state_wont(option);
608 if (my_state_is_will(option))
609 send_wont(option, 0);
610 setconnmode(0); /* Set new tty mode */
612 set_my_state_wont(option);
616 * Given a buffer returned by tgetent(), this routine will turn
617 * the pipe separated list of names in the buffer into an array
618 * of pointers to null terminated names. We toss out any bad,
619 * duplicate, or verbose names (names with spaces).
622 static char *name_unknown = "UNKNOWN";
623 static char *unknown[] = { 0, 0 };
625 char **
626 mklist(char *buf, char *name)
628 int n;
629 char c, *cp, **argvp, *cp2, **argv, **avt;
631 if (name) {
632 if ((int)strlen(name) > 40) {
633 name = 0;
634 unknown[0] = name_unknown;
635 } else {
636 unknown[0] = name;
637 upcase(name);
639 } else
640 unknown[0] = name_unknown;
642 * Count up the number of names.
644 for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
645 if (*cp == '|')
646 n++;
649 * Allocate an array to put the name pointers into
651 argv = (char **)malloc((n+3)*sizeof(char *));
652 if (argv == 0)
653 return(unknown);
656 * Fill up the array of pointers to names.
658 *argv = 0;
659 argvp = argv+1;
660 n = 0;
661 for (cp = cp2 = buf; (c = *cp); cp++) {
662 if (c == '|' || c == ':') {
663 *cp++ = '\0';
665 * Skip entries that have spaces or are over 40
666 * characters long. If this is our environment
667 * name, then put it up front. Otherwise, as
668 * long as this is not a duplicate name (case
669 * insensitive) add it to the list.
671 if (n || (cp - cp2 > 41))
673 else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
674 *argv = cp2;
675 else if (is_unique(cp2, argv+1, argvp))
676 *argvp++ = cp2;
677 if (c == ':')
678 break;
680 * Skip multiple delimiters. Reset cp2 to
681 * the beginning of the next name. Reset n,
682 * the flag for names with spaces.
684 while ((c = *cp) == '|')
685 cp++;
686 cp2 = cp;
687 n = 0;
690 * Skip entries with spaces or non-ascii values.
691 * Convert lower case letters to upper case.
693 if ((c == ' ') || !isascii(c))
694 n = 1;
695 else if (islower((unsigned char)c))
696 *cp = toupper((unsigned char)c);
700 * Check for an old V6 2 character name. If the second
701 * name points to the beginning of the buffer, and is
702 * only 2 characters long, move it to the end of the array.
704 if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
705 --argvp;
706 for (avt = &argv[1]; avt < argvp; avt++)
707 *avt = *(avt+1);
708 *argvp++ = buf;
712 * Duplicate last name, for TTYPE option, and null
713 * terminate the array. If we didn't find a match on
714 * our terminal name, put that name at the beginning.
716 cp = *(argvp-1);
717 *argvp++ = cp;
718 *argvp = 0;
720 if (*argv == 0) {
721 if (name)
722 *argv = name;
723 else {
724 --argvp;
725 for (avt = argv; avt < argvp; avt++)
726 *avt = *(avt+1);
729 if (*argv)
730 return(argv);
731 else
732 return(unknown);
736 is_unique(char *name, char **as, char **ae)
738 char **ap;
739 int n;
741 n = strlen(name) + 1;
742 for (ap = as; ap < ae; ap++)
743 if (strncasecmp(*ap, name, n) == 0)
744 return(0);
745 return (1);
748 #ifdef TERMCAP
749 char *termbuf;
751 /*ARGSUSED*/
753 setup_term(char *tname, int fd, int *errp)
755 char zz[1024], *zz_ptr;
756 char *ext_tc, *newptr;
758 if ((termbuf = (char *) malloc(1024)) == NULL)
759 goto error;
761 if (tgetent(termbuf, tname) == 1) {
762 /* check for ZZ capability, which indicates 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 if ((newptr = (char *) realloc(termbuf,
768 strlen(ext_tc) + 1))
769 == NULL) {
770 goto error;
773 strlcpy(newptr, ext_tc, strlen(ext_tc) + 1);
774 termbuf = newptr;
777 if (errp)
778 *errp = 1;
779 return(0);
781 error:
782 if (errp)
783 *errp = 0;
784 return(-1);
786 #else
787 #define termbuf ttytype
788 extern char ttytype[];
789 #endif
791 int resettermname = 1;
793 char *
794 gettermname(void)
796 char *tname;
797 static char **tnamep = 0;
798 static char **next;
799 int err;
801 if (resettermname) {
802 resettermname = 0;
803 if (tnamep && tnamep != unknown)
804 free(tnamep);
805 if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) &&
806 (setup_term(tname, 1, &err) == 0)) {
807 tnamep = mklist(termbuf, tname);
808 } else {
809 if (tname && ((int)strlen(tname) <= 40)) {
810 unknown[0] = tname;
811 upcase(tname);
812 } else
813 unknown[0] = name_unknown;
814 tnamep = unknown;
816 next = tnamep;
818 if (*next == 0)
819 next = tnamep;
820 return(*next++);
823 * suboption()
825 * Look at the sub-option buffer, and try to be helpful to the other
826 * side.
828 * Currently we recognize:
830 * Terminal type, send request.
831 * Terminal speed (send request).
832 * Local flow control (is request).
833 * Linemode
836 static void
837 suboption(void)
839 unsigned char subchar;
841 printsub('<', subbuffer, SB_LEN()+2);
842 switch (subchar = SB_GET()) {
843 case TELOPT_TTYPE:
844 if (my_want_state_is_wont(TELOPT_TTYPE))
845 return;
846 if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
847 return;
848 } else {
849 char *name;
850 unsigned char temp[50];
851 int len;
853 #ifdef TN3270
854 if (tn3270_ttype()) {
855 return;
857 #endif /* defined(TN3270) */
858 name = gettermname();
859 len = strlen(name) + 4 + 2;
860 if (len < NETROOM()) {
861 sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
862 TELQUAL_IS, name, IAC, SE);
863 ring_supply_data(&netoring, temp, len);
864 printsub('>', &temp[2], len-2);
865 } else {
866 ExitString("No room in buffer for terminal type.\n", 1);
867 /*NOTREACHED*/
870 break;
871 case TELOPT_TSPEED:
872 if (my_want_state_is_wont(TELOPT_TSPEED))
873 return;
874 if (SB_EOF())
875 return;
876 if (SB_GET() == TELQUAL_SEND) {
877 long ospeed, ispeed;
878 unsigned char temp[50];
879 int len;
881 TerminalSpeeds(&ispeed, &ospeed);
883 sprintf((char *)temp, "%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED,
884 TELQUAL_IS, (long)ospeed, (long)ispeed, IAC, SE);
885 len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
887 if (len < NETROOM()) {
888 ring_supply_data(&netoring, temp, len);
889 printsub('>', temp+2, len - 2);
891 /*@*/ else printf("lm_will: not enough room in buffer\n");
893 break;
894 case TELOPT_LFLOW:
895 if (my_want_state_is_wont(TELOPT_LFLOW))
896 return;
897 if (SB_EOF())
898 return;
899 switch(SB_GET()) {
900 case LFLOW_RESTART_ANY:
901 restartany = 1;
902 break;
903 case LFLOW_RESTART_XON:
904 restartany = 0;
905 break;
906 case LFLOW_ON:
907 localflow = 1;
908 break;
909 case LFLOW_OFF:
910 localflow = 0;
911 break;
912 default:
913 return;
915 setcommandmode();
916 setconnmode(0);
917 break;
919 case TELOPT_LINEMODE:
920 if (my_want_state_is_wont(TELOPT_LINEMODE))
921 return;
922 if (SB_EOF())
923 return;
924 switch (SB_GET()) {
925 case WILL:
926 lm_will(subpointer, SB_LEN());
927 break;
928 case WONT:
929 lm_wont(subpointer, SB_LEN());
930 break;
931 case DO:
932 lm_do(subpointer, SB_LEN());
933 break;
934 case DONT:
935 lm_dont(subpointer, SB_LEN());
936 break;
937 case LM_SLC:
938 slc(subpointer, SB_LEN());
939 break;
940 case LM_MODE:
941 lm_mode(subpointer, SB_LEN(), 0);
942 break;
943 default:
944 break;
946 break;
948 #ifdef OLD_ENVIRON
949 case TELOPT_OLD_ENVIRON:
950 #endif
951 case TELOPT_NEW_ENVIRON:
952 if (SB_EOF())
953 return;
954 switch(SB_PEEK()) {
955 case TELQUAL_IS:
956 case TELQUAL_INFO:
957 if (my_want_state_is_dont(subchar))
958 return;
959 break;
960 case TELQUAL_SEND:
961 if (my_want_state_is_wont(subchar)) {
962 return;
964 break;
965 default:
966 return;
968 env_opt(subpointer, SB_LEN());
969 break;
971 case TELOPT_XDISPLOC:
972 if (my_want_state_is_wont(TELOPT_XDISPLOC))
973 return;
974 if (SB_EOF())
975 return;
976 if (SB_GET() == TELQUAL_SEND) {
977 unsigned char temp[50], *dp;
978 int len;
980 if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) {
982 * Something happened, we no longer have a DISPLAY
983 * variable. So, turn off the option.
985 send_wont(TELOPT_XDISPLOC, 1);
986 break;
988 sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
989 TELQUAL_IS, dp, IAC, SE);
990 len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
992 if (len < NETROOM()) {
993 ring_supply_data(&netoring, temp, len);
994 printsub('>', temp+2, len - 2);
996 /*@*/ else printf("lm_will: not enough room in buffer\n");
998 break;
1000 #ifdef AUTHENTICATION
1001 case TELOPT_AUTHENTICATION: {
1002 if (!autologin)
1003 break;
1004 if (SB_EOF())
1005 return;
1006 switch(SB_GET()) {
1007 case TELQUAL_IS:
1008 if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
1009 return;
1010 auth_is(subpointer, SB_LEN());
1011 break;
1012 case TELQUAL_SEND:
1013 if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
1014 return;
1015 auth_send(subpointer, SB_LEN());
1016 break;
1017 case TELQUAL_REPLY:
1018 if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
1019 return;
1020 auth_reply(subpointer, SB_LEN());
1021 break;
1022 case TELQUAL_NAME:
1023 if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
1024 return;
1025 auth_name(subpointer, SB_LEN());
1026 break;
1029 break;
1030 #endif
1031 #ifdef ENCRYPTION
1032 case TELOPT_ENCRYPT:
1033 if (SB_EOF())
1034 return;
1035 switch(SB_GET()) {
1036 case ENCRYPT_START:
1037 if (my_want_state_is_dont(TELOPT_ENCRYPT))
1038 return;
1039 encrypt_start(subpointer, SB_LEN());
1040 break;
1041 case ENCRYPT_END:
1042 if (my_want_state_is_dont(TELOPT_ENCRYPT))
1043 return;
1044 encrypt_end();
1045 break;
1046 case ENCRYPT_SUPPORT:
1047 if (my_want_state_is_wont(TELOPT_ENCRYPT))
1048 return;
1049 encrypt_support(subpointer, SB_LEN());
1050 break;
1051 case ENCRYPT_REQSTART:
1052 if (my_want_state_is_wont(TELOPT_ENCRYPT))
1053 return;
1054 encrypt_request_start(subpointer, SB_LEN());
1055 break;
1056 case ENCRYPT_REQEND:
1057 if (my_want_state_is_wont(TELOPT_ENCRYPT))
1058 return;
1060 * We can always send an REQEND so that we cannot
1061 * get stuck encrypting. We should only get this
1062 * if we have been able to get in the correct mode
1063 * anyhow.
1065 encrypt_request_end();
1066 break;
1067 case ENCRYPT_IS:
1068 if (my_want_state_is_dont(TELOPT_ENCRYPT))
1069 return;
1070 encrypt_is(subpointer, SB_LEN());
1071 break;
1072 case ENCRYPT_REPLY:
1073 if (my_want_state_is_wont(TELOPT_ENCRYPT))
1074 return;
1075 encrypt_reply(subpointer, SB_LEN());
1076 break;
1077 case ENCRYPT_ENC_KEYID:
1078 if (my_want_state_is_dont(TELOPT_ENCRYPT))
1079 return;
1080 encrypt_enc_keyid(subpointer, SB_LEN());
1081 break;
1082 case ENCRYPT_DEC_KEYID:
1083 if (my_want_state_is_wont(TELOPT_ENCRYPT))
1084 return;
1085 encrypt_dec_keyid(subpointer, SB_LEN());
1086 break;
1087 default:
1088 break;
1090 break;
1091 #endif /* ENCRYPTION */
1092 default:
1093 break;
1097 static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
1099 void
1100 lm_will(unsigned char *cmd, int len)
1102 if (len < 1) {
1103 /*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */
1104 return;
1106 switch(cmd[0]) {
1107 case LM_FORWARDMASK: /* We shouldn't ever get this... */
1108 default:
1109 str_lm[3] = DONT;
1110 str_lm[4] = cmd[0];
1111 if (NETROOM() > sizeof(str_lm)) {
1112 ring_supply_data(&netoring, str_lm, sizeof(str_lm));
1113 printsub('>', &str_lm[2], sizeof(str_lm)-2);
1115 /*@*/ else printf("lm_will: not enough room in buffer\n");
1116 break;
1120 void
1121 lm_wont(unsigned char *cmd, int len)
1123 if (len < 1) {
1124 /*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */
1125 return;
1127 switch(cmd[0]) {
1128 case LM_FORWARDMASK: /* We shouldn't ever get this... */
1129 default:
1130 /* We are always DONT, so don't respond */
1131 return;
1135 void
1136 lm_do(unsigned char *cmd, int len)
1138 if (len < 1) {
1139 /*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */
1140 return;
1142 switch(cmd[0]) {
1143 case LM_FORWARDMASK:
1144 default:
1145 str_lm[3] = WONT;
1146 str_lm[4] = cmd[0];
1147 if (NETROOM() > sizeof(str_lm)) {
1148 ring_supply_data(&netoring, str_lm, sizeof(str_lm));
1149 printsub('>', &str_lm[2], sizeof(str_lm)-2);
1151 /*@*/ else printf("lm_do: not enough room in buffer\n");
1152 break;
1156 void
1157 lm_dont(unsigned char *cmd, int len)
1159 if (len < 1) {
1160 /*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */
1161 return;
1163 switch(cmd[0]) {
1164 case LM_FORWARDMASK:
1165 default:
1166 /* we are always WONT, so don't respond */
1167 break;
1171 static unsigned char str_lm_mode[] = {
1172 IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
1175 void
1176 lm_mode(unsigned char *cmd, int len, int init)
1178 if (len != 1)
1179 return;
1180 if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
1181 return;
1182 if (*cmd&MODE_ACK)
1183 return;
1184 linemode = *cmd&(MODE_MASK&~MODE_ACK);
1185 str_lm_mode[4] = linemode;
1186 if (!init)
1187 str_lm_mode[4] |= MODE_ACK;
1188 if (NETROOM() > sizeof(str_lm_mode)) {
1189 ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
1190 printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
1192 /*@*/ else printf("lm_mode: not enough room in buffer\n");
1193 setconnmode(0); /* set changed mode */
1199 * slc()
1200 * Handle special character suboption of LINEMODE.
1203 struct spc {
1204 cc_t val;
1205 cc_t *valp;
1206 char flags; /* Current flags & level */
1207 char mylevel; /* Maximum level & flags */
1208 } spc_data[NSLC+1];
1210 #define SLC_IMPORT 0
1211 #define SLC_EXPORT 1
1212 #define SLC_RVALUE 2
1213 static int slc_mode = SLC_EXPORT;
1215 void
1216 slc_init(void)
1218 struct spc *spcp;
1220 localchars = 1;
1221 for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
1222 spcp->val = 0;
1223 spcp->valp = 0;
1224 spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
1227 #define initfunc(func, flags) { \
1228 spcp = &spc_data[func]; \
1229 if ((spcp->valp = tcval(func)) != NULL){ \
1230 spcp->val = *spcp->valp; \
1231 spcp->mylevel = SLC_VARIABLE|flags; \
1232 } else { \
1233 spcp->val = 0; \
1234 spcp->mylevel = SLC_DEFAULT; \
1238 initfunc(SLC_SYNCH, 0);
1239 /* No BRK */
1240 initfunc(SLC_AO, 0);
1241 initfunc(SLC_AYT, 0);
1242 /* No EOR */
1243 initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
1244 initfunc(SLC_EOF, 0);
1245 initfunc(SLC_SUSP, SLC_FLUSHIN);
1246 initfunc(SLC_EC, 0);
1247 initfunc(SLC_EL, 0);
1248 initfunc(SLC_EW, 0);
1249 initfunc(SLC_RP, 0);
1250 initfunc(SLC_LNEXT, 0);
1251 initfunc(SLC_XON, 0);
1252 initfunc(SLC_XOFF, 0);
1253 initfunc(SLC_FORW1, 0);
1254 initfunc(SLC_FORW2, 0);
1255 /* No FORW2 */
1257 initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
1258 #undef initfunc
1260 if (slc_mode == SLC_EXPORT)
1261 slc_export();
1262 else
1263 slc_import(1);
1267 void
1268 slcstate(void)
1270 printf("Special characters are %s values\n",
1271 slc_mode == SLC_IMPORT ? "remote default" :
1272 slc_mode == SLC_EXPORT ? "local" :
1273 "remote");
1276 void
1277 slc_mode_export(int n)
1279 slc_mode = SLC_EXPORT;
1280 if (my_state_is_will(TELOPT_LINEMODE))
1281 slc_export();
1284 void
1285 slc_mode_import(int def)
1287 slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
1288 if (my_state_is_will(TELOPT_LINEMODE))
1289 slc_import(def);
1292 unsigned char slc_import_val[] = {
1293 IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
1295 unsigned char slc_import_def[] = {
1296 IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
1299 void
1300 slc_import(int def)
1302 if (NETROOM() > sizeof(slc_import_val)) {
1303 if (def) {
1304 ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
1305 printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
1306 } else {
1307 ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
1308 printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
1311 /*@*/ else printf("slc_import: not enough room\n");
1314 void
1315 slc_export(void)
1317 struct spc *spcp;
1319 TerminalDefaultChars();
1321 slc_start_reply();
1322 for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1323 if (spcp->mylevel != SLC_NOSUPPORT) {
1324 if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1325 spcp->flags = SLC_NOSUPPORT;
1326 else
1327 spcp->flags = spcp->mylevel;
1328 if (spcp->valp)
1329 spcp->val = *spcp->valp;
1330 slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1333 slc_end_reply();
1334 (void)slc_update();
1335 setconnmode(1); /* Make sure the character values are set */
1338 void
1339 slc(unsigned char *cp, int len)
1341 struct spc *spcp;
1342 int func,level;
1344 slc_start_reply();
1346 for (; len >= 3; len -=3, cp +=3) {
1348 func = cp[SLC_FUNC];
1350 if (func == 0) {
1352 * Client side: always ignore 0 function.
1354 continue;
1356 if (func > NSLC) {
1357 if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
1358 slc_add_reply(func, SLC_NOSUPPORT, 0);
1359 continue;
1362 spcp = &spc_data[func];
1364 level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
1366 if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
1367 ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
1368 continue;
1371 if (level == (SLC_DEFAULT|SLC_ACK)) {
1373 * This is an error condition, the SLC_ACK
1374 * bit should never be set for the SLC_DEFAULT
1375 * level. Our best guess to recover is to
1376 * ignore the SLC_ACK bit.
1378 cp[SLC_FLAGS] &= ~SLC_ACK;
1381 if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
1382 spcp->val = (cc_t)cp[SLC_VALUE];
1383 spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */
1384 continue;
1387 level &= ~SLC_ACK;
1389 if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
1390 spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
1391 spcp->val = (cc_t)cp[SLC_VALUE];
1393 if (level == SLC_DEFAULT) {
1394 if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
1395 spcp->flags = spcp->mylevel;
1396 else
1397 spcp->flags = SLC_NOSUPPORT;
1399 slc_add_reply(func, spcp->flags, spcp->val);
1401 slc_end_reply();
1402 if (slc_update())
1403 setconnmode(1); /* set the new character values */
1406 void
1407 slc_check(void)
1409 struct spc *spcp;
1411 slc_start_reply();
1412 for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1413 if (spcp->valp && spcp->val != *spcp->valp) {
1414 spcp->val = *spcp->valp;
1415 if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1416 spcp->flags = SLC_NOSUPPORT;
1417 else
1418 spcp->flags = spcp->mylevel;
1419 slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1422 slc_end_reply();
1423 setconnmode(1);
1427 unsigned char slc_reply[128];
1428 unsigned char *slc_replyp;
1430 void
1431 slc_start_reply(void)
1433 slc_replyp = slc_reply;
1434 *slc_replyp++ = IAC;
1435 *slc_replyp++ = SB;
1436 *slc_replyp++ = TELOPT_LINEMODE;
1437 *slc_replyp++ = LM_SLC;
1440 void
1441 slc_add_reply(unsigned int func, unsigned int flags, cc_t value)
1443 if ((slc_replyp - slc_reply) + 6 > sizeof(slc_reply))
1444 return;
1445 if ((*slc_replyp++ = func) == IAC)
1446 *slc_replyp++ = IAC;
1447 if ((*slc_replyp++ = flags) == IAC)
1448 *slc_replyp++ = IAC;
1449 if ((*slc_replyp++ = (unsigned char)value) == IAC)
1450 *slc_replyp++ = IAC;
1453 void
1454 slc_end_reply(void)
1456 int len;
1458 len = slc_replyp - slc_reply;
1459 if (len <= 4 || (len + 2 > sizeof(slc_reply)))
1460 return;
1461 *slc_replyp++ = IAC;
1462 *slc_replyp++ = SE;
1463 len += 2;
1464 if (NETROOM() > len) {
1465 ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
1466 printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
1468 /*@*/else printf("slc_end_reply: not enough room\n");
1472 slc_update(void)
1474 struct spc *spcp;
1475 int need_update = 0;
1477 for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1478 if (!(spcp->flags&SLC_ACK))
1479 continue;
1480 spcp->flags &= ~SLC_ACK;
1481 if (spcp->valp && (*spcp->valp != spcp->val)) {
1482 *spcp->valp = spcp->val;
1483 need_update = 1;
1486 return(need_update);
1489 #ifdef OLD_ENVIRON
1490 # ifdef ENV_HACK
1492 * Earlier version of telnet/telnetd from the BSD code had
1493 * the definitions of VALUE and VAR reversed. To ensure
1494 * maximum interoperability, we assume that the server is
1495 * an older BSD server, until proven otherwise. The newer
1496 * BSD servers should be able to handle either definition,
1497 * so it is better to use the wrong values if we don't
1498 * know what type of server it is.
1500 int env_auto = 1;
1501 int old_env_var = OLD_ENV_VAR;
1502 int old_env_value = OLD_ENV_VALUE;
1503 # else
1504 # define old_env_var OLD_ENV_VAR
1505 # define old_env_value OLD_ENV_VALUE
1506 # endif
1507 #endif
1509 void
1510 env_opt(unsigned char *buf, int len)
1512 unsigned char *ep = 0, *epc = 0;
1513 int i;
1515 switch(buf[0]&0xff) {
1516 case TELQUAL_SEND:
1517 env_opt_start();
1518 if (len == 1) {
1519 env_opt_add(NULL);
1520 } else for (i = 1; i < len; i++) {
1521 switch (buf[i]&0xff) {
1522 #ifdef OLD_ENVIRON
1523 case OLD_ENV_VAR:
1524 # ifdef ENV_HACK
1525 if (telopt_environ == TELOPT_OLD_ENVIRON
1526 && env_auto) {
1527 /* Server has the same definitions */
1528 old_env_var = OLD_ENV_VAR;
1529 old_env_value = OLD_ENV_VALUE;
1531 /* FALL THROUGH */
1532 # endif
1533 case OLD_ENV_VALUE:
1535 * Although OLD_ENV_VALUE is not legal, we will
1536 * still recognize it, just in case it is an
1537 * old server that has VAR & VALUE mixed up...
1539 /* FALL THROUGH */
1540 #else
1541 case NEW_ENV_VAR:
1542 #endif
1543 case ENV_USERVAR:
1544 if (ep) {
1545 *epc = 0;
1546 env_opt_add(ep);
1548 ep = epc = &buf[i+1];
1549 break;
1550 case ENV_ESC:
1551 i++;
1552 /*FALL THROUGH*/
1553 default:
1554 if (epc)
1555 *epc++ = buf[i];
1556 break;
1559 if (ep) {
1560 *epc = 0;
1561 env_opt_add(ep);
1563 env_opt_end(1);
1564 break;
1566 case TELQUAL_IS:
1567 case TELQUAL_INFO:
1568 /* Ignore for now. We shouldn't get it anyway. */
1569 break;
1571 default:
1572 break;
1576 #define OPT_REPLY_SIZE 256
1577 unsigned char *opt_reply;
1578 unsigned char *opt_replyp;
1579 unsigned char *opt_replyend;
1581 void
1582 env_opt_start(void)
1584 unsigned char *p;
1586 if (opt_reply) {
1587 p = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE);
1588 if (p == NULL)
1589 free(opt_reply);
1590 } else
1591 p = (unsigned char *)malloc(OPT_REPLY_SIZE);
1592 opt_reply = p;
1593 if (opt_reply == NULL) {
1594 /*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n");
1595 opt_reply = opt_replyp = opt_replyend = NULL;
1596 return;
1598 opt_replyp = opt_reply;
1599 opt_replyend = opt_reply + OPT_REPLY_SIZE;
1600 *opt_replyp++ = IAC;
1601 *opt_replyp++ = SB;
1602 *opt_replyp++ = telopt_environ;
1603 *opt_replyp++ = TELQUAL_IS;
1606 void
1607 env_opt_start_info(void)
1609 env_opt_start();
1610 if (opt_replyp)
1611 opt_replyp[-1] = TELQUAL_INFO;
1614 void
1615 env_opt_add(unsigned char *ep)
1617 unsigned char *vp, c;
1618 unsigned int len, olen, elen;
1620 if (opt_reply == NULL) /*XXX*/
1621 return; /*XXX*/
1623 if (ep == NULL || *ep == '\0') {
1624 /* Send user defined variables first. */
1625 env_default(1, 0);
1626 while ((ep = env_default(0, 0)) != NULL)
1627 env_opt_add(ep);
1629 /* Now add the list of well know variables. */
1630 env_default(1, 1);
1631 while ((ep = env_default(0, 1)) != NULL)
1632 env_opt_add(ep);
1633 return;
1635 vp = env_getvalue(ep);
1636 elen = 2 * (vp ? strlen((char *)vp) : 0) +
1637 2 * strlen((char *)ep) + 6;
1638 if ((opt_replyend - opt_replyp) < elen)
1640 unsigned char *p;
1641 len = opt_replyend - opt_reply + elen;
1642 olen = opt_replyp - opt_reply;
1643 p = (unsigned char *)realloc(opt_reply, len);
1644 if (p == NULL)
1645 free(opt_reply);
1646 opt_reply = p;
1647 if (opt_reply == NULL) {
1648 /*@*/ printf("env_opt_add: realloc() failed!!!\n");
1649 opt_reply = opt_replyp = opt_replyend = NULL;
1650 return;
1652 opt_replyp = opt_reply + olen;
1653 opt_replyend = opt_reply + len;
1655 if (opt_welldefined(ep))
1656 #ifdef OLD_ENVIRON
1657 if (telopt_environ == TELOPT_OLD_ENVIRON)
1658 *opt_replyp++ = old_env_var;
1659 else
1660 #endif
1661 *opt_replyp++ = NEW_ENV_VAR;
1662 else
1663 *opt_replyp++ = ENV_USERVAR;
1664 for (;;) {
1665 while ((c = *ep++) != '\0') {
1666 switch(c&0xff) {
1667 case IAC:
1668 *opt_replyp++ = IAC;
1669 break;
1670 case NEW_ENV_VAR:
1671 case NEW_ENV_VALUE:
1672 case ENV_ESC:
1673 case ENV_USERVAR:
1674 *opt_replyp++ = ENV_ESC;
1675 break;
1677 *opt_replyp++ = c;
1679 if ((ep = vp) != NULL) {
1680 #ifdef OLD_ENVIRON
1681 if (telopt_environ == TELOPT_OLD_ENVIRON)
1682 *opt_replyp++ = old_env_value;
1683 else
1684 #endif
1685 *opt_replyp++ = NEW_ENV_VALUE;
1686 vp = NULL;
1687 } else
1688 break;
1693 opt_welldefined(char *ep)
1695 if ((strcmp(ep, "USER") == 0) ||
1696 (strcmp(ep, "DISPLAY") == 0) ||
1697 (strcmp(ep, "PRINTER") == 0) ||
1698 (strcmp(ep, "SYSTEMTYPE") == 0) ||
1699 (strcmp(ep, "JOB") == 0) ||
1700 (strcmp(ep, "ACCT") == 0))
1701 return(1);
1702 return(0);
1704 void
1705 env_opt_end(int emptyok)
1707 int len;
1709 len = opt_replyp - opt_reply + 2;
1710 if (emptyok || len > 6) {
1711 *opt_replyp++ = IAC;
1712 *opt_replyp++ = SE;
1713 if (NETROOM() > len) {
1714 ring_supply_data(&netoring, opt_reply, len);
1715 printsub('>', &opt_reply[2], len - 2);
1717 /*@*/ else printf("slc_end_reply: not enough room\n");
1719 if (opt_reply) {
1720 free(opt_reply);
1721 opt_reply = opt_replyp = opt_replyend = NULL;
1728 telrcv(void)
1730 int c;
1731 int scc;
1732 unsigned char *sbp = NULL;
1733 int count;
1734 int returnValue = 0;
1736 scc = 0;
1737 count = 0;
1738 while (TTYROOM() > 2) {
1739 if (scc == 0) {
1740 if (count) {
1741 ring_consumed(&netiring, count);
1742 returnValue = 1;
1743 count = 0;
1745 sbp = netiring.consume;
1746 scc = ring_full_consecutive(&netiring);
1747 if (scc == 0) {
1748 /* No more data coming in */
1749 break;
1753 c = *sbp++ & 0xff, scc--; count++;
1754 #ifdef ENCRYPTION
1755 if (decrypt_input)
1756 c = (*decrypt_input)(c);
1757 #endif /* ENCRYPTION */
1759 switch (telrcv_state) {
1761 case TS_CR:
1762 telrcv_state = TS_DATA;
1763 if (c == '\0') {
1764 break; /* Ignore \0 after CR */
1766 else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
1767 TTYADD(c);
1768 break;
1770 /* Else, fall through */
1772 case TS_DATA:
1773 if (c == IAC) {
1774 telrcv_state = TS_IAC;
1775 break;
1777 # if defined(TN3270)
1778 if (In3270) {
1779 *Ifrontp++ = c;
1780 while (scc > 0) {
1781 c = *sbp++ & 0377, scc--; count++;
1782 #ifdef ENCRYPTION
1783 if (decrypt_input)
1784 c = (*decrypt_input)(c);
1785 #endif /* ENCRYPTION */
1786 if (c == IAC) {
1787 telrcv_state = TS_IAC;
1788 break;
1790 *Ifrontp++ = c;
1792 } else
1793 # endif /* defined(TN3270) */
1795 * The 'crmod' hack (see following) is needed
1796 * since we can't * set CRMOD on output only.
1797 * Machines like MULTICS like to send \r without
1798 * \n; since we must turn off CRMOD to get proper
1799 * input, the mapping is done here (sigh).
1801 if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
1802 if (scc > 0) {
1803 c = *sbp&0xff;
1804 #ifdef ENCRYPTION
1805 if (decrypt_input)
1806 c = (*decrypt_input)(c);
1807 #endif /* ENCRYPTION */
1808 if (c == 0) {
1809 sbp++, scc--; count++;
1810 /* a "true" CR */
1811 TTYADD('\r');
1812 } else if (my_want_state_is_dont(TELOPT_ECHO) &&
1813 (c == '\n')) {
1814 sbp++, scc--; count++;
1815 TTYADD('\n');
1816 } else {
1817 #ifdef ENCRYPTION
1818 if (decrypt_input)
1819 (*decrypt_input)(-1);
1820 #endif /* ENCRYPTION */
1822 TTYADD('\r');
1823 if (crmod) {
1824 TTYADD('\n');
1827 } else {
1828 telrcv_state = TS_CR;
1829 TTYADD('\r');
1830 if (crmod) {
1831 TTYADD('\n');
1834 } else {
1835 TTYADD(c);
1837 continue;
1839 case TS_IAC:
1840 process_iac:
1841 switch (c) {
1843 case WILL:
1844 telrcv_state = TS_WILL;
1845 continue;
1847 case WONT:
1848 telrcv_state = TS_WONT;
1849 continue;
1851 case DO:
1852 telrcv_state = TS_DO;
1853 continue;
1855 case DONT:
1856 telrcv_state = TS_DONT;
1857 continue;
1859 case DM:
1861 * We may have missed an urgent notification,
1862 * so make sure we flush whatever is in the
1863 * buffer currently.
1865 printoption("RCVD", IAC, DM);
1866 SYNCHing = 1;
1867 (void) ttyflush(1);
1868 SYNCHing = stilloob();
1869 settimer(gotDM);
1870 break;
1872 case SB:
1873 SB_CLEAR();
1874 telrcv_state = TS_SB;
1875 continue;
1877 # if defined(TN3270)
1878 case EOR:
1879 if (In3270) {
1880 if (Ibackp == Ifrontp) {
1881 Ibackp = Ifrontp = Ibuf;
1882 ISend = 0; /* should have been! */
1883 } else {
1884 Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
1885 ISend = 1;
1888 printoption("RCVD", IAC, EOR);
1889 break;
1890 # endif /* defined(TN3270) */
1892 case IAC:
1893 # if !defined(TN3270)
1894 TTYADD(IAC);
1895 # else /* !defined(TN3270) */
1896 if (In3270) {
1897 *Ifrontp++ = IAC;
1898 } else {
1899 TTYADD(IAC);
1901 # endif /* !defined(TN3270) */
1902 break;
1904 case NOP:
1905 case GA:
1906 default:
1907 printoption("RCVD", IAC, c);
1908 break;
1910 telrcv_state = TS_DATA;
1911 continue;
1913 case TS_WILL:
1914 printoption("RCVD", WILL, c);
1915 willoption(c);
1916 SetIn3270();
1917 telrcv_state = TS_DATA;
1918 continue;
1920 case TS_WONT:
1921 printoption("RCVD", WONT, c);
1922 wontoption(c);
1923 SetIn3270();
1924 telrcv_state = TS_DATA;
1925 continue;
1927 case TS_DO:
1928 printoption("RCVD", DO, c);
1929 dooption(c);
1930 SetIn3270();
1931 if (c == TELOPT_NAWS) {
1932 sendnaws();
1933 } else if (c == TELOPT_LFLOW) {
1934 localflow = 1;
1935 setcommandmode();
1936 setconnmode(0);
1938 telrcv_state = TS_DATA;
1939 continue;
1941 case TS_DONT:
1942 printoption("RCVD", DONT, c);
1943 dontoption(c);
1944 flushline = 1;
1945 setconnmode(0); /* set new tty mode (maybe) */
1946 SetIn3270();
1947 telrcv_state = TS_DATA;
1948 continue;
1950 case TS_SB:
1951 if (c == IAC) {
1952 telrcv_state = TS_SE;
1953 } else {
1954 SB_ACCUM(c);
1956 continue;
1958 case TS_SE:
1959 if (c != SE) {
1960 if (c != IAC) {
1962 * This is an error. We only expect to get
1963 * "IAC IAC" or "IAC SE". Several things may
1964 * have happened. An IAC was not doubled, the
1965 * IAC SE was left off, or another option got
1966 * inserted into the suboption are all possibilities.
1967 * If we assume that the IAC was not doubled,
1968 * and really the IAC SE was left off, we could
1969 * get into an infinite loop here. So, instead,
1970 * we terminate the suboption, and process the
1971 * partial suboption if we can.
1973 SB_ACCUM(IAC);
1974 SB_ACCUM(c);
1975 subpointer -= 2;
1976 SB_TERM();
1978 printoption("In SUBOPTION processing, RCVD", IAC, c);
1979 suboption(); /* handle sub-option */
1980 SetIn3270();
1981 telrcv_state = TS_IAC;
1982 goto process_iac;
1984 SB_ACCUM(c);
1985 telrcv_state = TS_SB;
1986 } else {
1987 SB_ACCUM(IAC);
1988 SB_ACCUM(SE);
1989 subpointer -= 2;
1990 SB_TERM();
1991 suboption(); /* handle sub-option */
1992 SetIn3270();
1993 telrcv_state = TS_DATA;
1997 if (count)
1998 ring_consumed(&netiring, count);
1999 return returnValue||count;
2002 static int bol = 1, local = 0;
2005 rlogin_susp(void)
2007 if (local) {
2008 local = 0;
2009 bol = 1;
2010 command(0, "z\n", 2);
2011 return(1);
2013 return(0);
2016 static int
2017 telsnd(void)
2019 int tcc;
2020 int count;
2021 int returnValue = 0;
2022 unsigned char *tbp = NULL;
2024 tcc = 0;
2025 count = 0;
2026 while (NETROOM() > 2) {
2027 int sc;
2028 int c;
2030 if (tcc == 0) {
2031 if (count) {
2032 ring_consumed(&ttyiring, count);
2033 returnValue = 1;
2034 count = 0;
2036 tbp = ttyiring.consume;
2037 tcc = ring_full_consecutive(&ttyiring);
2038 if (tcc == 0) {
2039 break;
2042 c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
2043 if (rlogin != _POSIX_VDISABLE) {
2044 if (bol) {
2045 bol = 0;
2046 if (sc == rlogin) {
2047 local = 1;
2048 continue;
2050 } else if (local) {
2051 local = 0;
2052 if (sc == '.' || c == termEofChar) {
2053 bol = 1;
2054 command(0, "close\n", 6);
2055 continue;
2057 if (sc == termSuspChar) {
2058 bol = 1;
2059 command(0, "z\n", 2);
2060 continue;
2062 if (sc == escape) {
2063 command(0, (char *)tbp, tcc);
2064 bol = 1;
2065 count += tcc;
2066 tcc = 0;
2067 flushline = 1;
2068 break;
2070 if (sc != rlogin) {
2071 ++tcc;
2072 --tbp;
2073 --count;
2074 c = sc = rlogin;
2077 if ((sc == '\n') || (sc == '\r'))
2078 bol = 1;
2079 } else if (sc == escape && escape != _POSIX_VDISABLE) {
2081 * Double escape is a pass through of a single escape character.
2083 if (tcc && strip(*tbp) == escape) {
2084 tbp++;
2085 tcc--;
2086 count++;
2087 bol = 0;
2088 } else {
2089 command(0, (char *)tbp, tcc);
2090 bol = 1;
2091 count += tcc;
2092 tcc = 0;
2093 flushline = 1;
2094 break;
2096 } else
2097 bol = 0;
2098 #ifdef KLUDGELINEMODE
2099 if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
2100 if (tcc > 0 && strip(*tbp) == echoc) {
2101 tcc--; tbp++; count++;
2102 } else {
2103 dontlecho = !dontlecho;
2104 settimer(echotoggle);
2105 setconnmode(0);
2106 flushline = 1;
2107 break;
2110 #endif
2111 if (sc != _POSIX_VDISABLE && MODE_LOCAL_CHARS(globalmode)) {
2112 if (TerminalSpecialChars(sc) == 0) {
2113 bol = 1;
2114 break;
2117 if (my_want_state_is_wont(TELOPT_BINARY)) {
2118 switch (c) {
2119 case '\n':
2121 * If we are in CRMOD mode (\r ==> \n)
2122 * on our local machine, then probably
2123 * a newline (unix) is CRLF (TELNET).
2125 if (MODE_LOCAL_CHARS(globalmode)) {
2126 NETADD('\r');
2128 NETADD('\n');
2129 bol = flushline = 1;
2130 break;
2131 case '\r':
2132 if (!crlf) {
2133 NET2ADD('\r', '\0');
2134 } else {
2135 NET2ADD('\r', '\n');
2137 bol = flushline = 1;
2138 break;
2139 case IAC:
2140 NET2ADD(IAC, IAC);
2141 break;
2142 default:
2143 NETADD(c);
2144 break;
2146 } else if (c == IAC) {
2147 NET2ADD(IAC, IAC);
2148 } else {
2149 NETADD(c);
2152 if (count)
2153 ring_consumed(&ttyiring, count);
2154 return returnValue||count; /* Non-zero if we did anything */
2158 * Scheduler()
2160 * Try to do something.
2162 * If we do something useful, return 1; else return 0.
2168 Scheduler(int block) /* should we block in the select ? */
2170 /* One wants to be a bit careful about setting returnValue
2171 * to one, since a one implies we did some useful work,
2172 * and therefore probably won't be called to block next
2173 * time (TN3270 mode only).
2175 int returnValue;
2176 int netin, netout, netex, ttyin, ttyout;
2178 /* Decide which rings should be processed */
2180 netout = ring_full_count(&netoring) &&
2181 (flushline ||
2182 (my_want_state_is_wont(TELOPT_LINEMODE)
2183 #ifdef KLUDGELINEMODE
2184 && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
2185 #endif
2186 ) ||
2187 my_want_state_is_will(TELOPT_BINARY));
2188 ttyout = ring_full_count(&ttyoring);
2190 #ifdef TN3270
2191 ttyin = ring_empty_count(&ttyiring) && (clienteof == 0) && (shell_active == 0);
2192 #else /* defined(TN3270) */
2193 ttyin = ring_empty_count(&ttyiring) && (clienteof == 0);
2194 #endif /* defined(TN3270) */
2196 #ifdef TN3270
2197 netin = ring_empty_count(&netiring);
2198 # else /* !defined(TN3270) */
2199 netin = !ISend && ring_empty_count(&netiring);
2200 # endif /* !defined(TN3270) */
2202 netex = !SYNCHing;
2204 /* If we have seen a signal recently, reset things */
2205 # ifdef TN3270
2206 if (HaveInput) {
2207 HaveInput = 0;
2208 (void) signal(SIGIO, inputAvailable);
2210 #endif /* defined(TN3270) */
2212 /* Call to system code to process rings */
2214 returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
2216 /* Now, look at the input rings, looking for work to do. */
2218 if (ring_full_count(&ttyiring)) {
2219 # if defined(TN3270)
2220 if (In3270) {
2221 int c;
2223 c = DataFromTerminal(ttyiring.consume,
2224 ring_full_consecutive(&ttyiring));
2225 if (c) {
2226 returnValue = 1;
2227 ring_consumed(&ttyiring, c);
2229 } else {
2230 # endif /* defined(TN3270) */
2231 returnValue |= telsnd();
2232 # if defined(TN3270)
2234 # endif /* defined(TN3270) */
2237 if (ring_full_count(&netiring)) {
2238 # if !defined(TN3270)
2239 returnValue |= telrcv();
2240 # else /* !defined(TN3270) */
2241 returnValue = Push3270();
2242 # endif /* !defined(TN3270) */
2244 return returnValue;
2248 * Select from tty and network...
2250 void
2251 telnet(const char *user)
2253 sys_telnet_init();
2255 #if defined(AUTHENTICATION) || defined(ENCRYPTION)
2257 static char local_host[MAXHOSTNAMELEN + 1] = { 0 };
2259 if (!local_host[0]) {
2260 gethostname(local_host, sizeof(local_host));
2261 local_host[sizeof(local_host)-1] = 0;
2263 auth_encrypt_init(local_host, hostname, "TELNET", 0);
2264 auth_encrypt_user(user);
2266 #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
2267 # if !defined(TN3270)
2268 if (telnetport) {
2269 #ifdef AUTHENTICATION
2270 if (autologin)
2271 send_will(TELOPT_AUTHENTICATION, 1);
2272 #endif
2273 #ifdef ENCRYPTION
2274 send_do(TELOPT_ENCRYPT, 1);
2275 send_will(TELOPT_ENCRYPT, 1);
2276 #endif /* ENCRYPTION */
2277 send_do(TELOPT_SGA, 1);
2278 send_will(TELOPT_TTYPE, 1);
2279 send_will(TELOPT_NAWS, 1);
2280 send_will(TELOPT_TSPEED, 1);
2281 send_will(TELOPT_LFLOW, 1);
2282 send_will(TELOPT_LINEMODE, 1);
2283 send_will(TELOPT_NEW_ENVIRON, 1);
2284 send_do(TELOPT_STATUS, 1);
2285 if (env_getvalue((unsigned char *)"DISPLAY"))
2286 send_will(TELOPT_XDISPLOC, 1);
2287 if (eight)
2288 tel_enter_binary(eight);
2290 # endif /* !defined(TN3270) */
2292 # if !defined(TN3270)
2293 for (;;) {
2294 int schedValue;
2296 while ((schedValue = Scheduler(0)) != 0) {
2297 if (schedValue == -1) {
2298 setcommandmode();
2299 return;
2303 if (Scheduler(1) == -1) {
2304 setcommandmode();
2305 return;
2308 # else /* !defined(TN3270) */
2309 for (;;) {
2310 int schedValue;
2312 while (!In3270 && !shell_active) {
2313 if (Scheduler(1) == -1) {
2314 setcommandmode();
2315 return;
2319 while ((schedValue = Scheduler(0)) != 0) {
2320 if (schedValue == -1) {
2321 setcommandmode();
2322 return;
2325 /* If there is data waiting to go out to terminal, don't
2326 * schedule any more data for the terminal.
2328 if (ring_full_count(&ttyoring)) {
2329 schedValue = 1;
2330 } else {
2331 if (shell_active) {
2332 if (shell_continue() == 0) {
2333 ConnectScreen();
2335 } else if (In3270) {
2336 schedValue = DoTerminalOutput();
2339 if (schedValue && (shell_active == 0)) {
2340 if (Scheduler(1) == -1) {
2341 setcommandmode();
2342 return;
2346 # endif /* !defined(TN3270) */
2349 #if 0 /* XXX - this not being in is a bug */
2351 * nextitem()
2353 * Return the address of the next "item" in the TELNET data
2354 * stream. This will be the address of the next character if
2355 * the current address is a user data character, or it will
2356 * be the address of the character following the TELNET command
2357 * if the current address is a TELNET IAC ("I Am a Command")
2358 * character.
2361 static char *
2362 nextitem(char *current)
2364 if ((*current&0xff) != IAC) {
2365 return current+1;
2367 switch (*(current+1)&0xff) {
2368 case DO:
2369 case DONT:
2370 case WILL:
2371 case WONT:
2372 return current+3;
2373 case SB: /* loop forever looking for the SE */
2375 char *look = current+2;
2377 for (;;) {
2378 if ((*look++&0xff) == IAC) {
2379 if ((*look++&0xff) == SE) {
2380 return look;
2385 default:
2386 return current+2;
2389 #endif /* 0 */
2392 * netclear()
2394 * We are about to do a TELNET SYNCH operation. Clear
2395 * the path to the network.
2397 * Things are a bit tricky since we may have sent the first
2398 * byte or so of a previous TELNET command into the network.
2399 * So, we have to scan the network buffer from the beginning
2400 * until we are up to where we want to be.
2402 * A side effect of what we do, just to keep things
2403 * simple, is to clear the urgent data pointer. The principal
2404 * caller should be setting the urgent data pointer AFTER calling
2405 * us in any case.
2408 static void
2409 netclear(void)
2411 #if 0 /* XXX */
2412 char *thisitem, *next;
2413 char *good;
2414 #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
2415 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
2417 thisitem = netobuf;
2419 while ((next = nextitem(thisitem)) <= netobuf.send) {
2420 thisitem = next;
2423 /* Now, thisitem is first before/at boundary. */
2425 good = netobuf; /* where the good bytes go */
2427 while (netoring.add > thisitem) {
2428 if (wewant(thisitem)) {
2429 int length;
2431 next = thisitem;
2432 do {
2433 next = nextitem(next);
2434 } while (wewant(next) && (nfrontp > next));
2435 length = next-thisitem;
2436 memmove(good, thisitem, length);
2437 good += length;
2438 thisitem = next;
2439 } else {
2440 thisitem = nextitem(thisitem);
2444 #endif /* 0 */
2448 * These routines add various telnet commands to the data stream.
2451 static void
2452 doflush(void)
2454 NET2ADD(IAC, DO);
2455 NETADD(TELOPT_TM);
2456 flushline = 1;
2457 flushout = 1;
2458 (void) ttyflush(1); /* Flush/drop output */
2459 /* do printoption AFTER flush, otherwise the output gets tossed... */
2460 printoption("SENT", DO, TELOPT_TM);
2463 void
2464 xmitAO(void)
2466 NET2ADD(IAC, AO);
2467 printoption("SENT", IAC, AO);
2468 if (autoflush) {
2469 doflush();
2474 void
2475 xmitEL(void)
2477 NET2ADD(IAC, EL);
2478 printoption("SENT", IAC, EL);
2481 void
2482 xmitEC(void)
2484 NET2ADD(IAC, EC);
2485 printoption("SENT", IAC, EC);
2490 dosynch(char *s)
2492 netclear(); /* clear the path to the network */
2493 NETADD(IAC);
2494 setneturg();
2495 NETADD(DM);
2496 printoption("SENT", IAC, DM);
2497 return 1;
2500 int want_status_response = 0;
2503 get_status(char *s)
2505 unsigned char tmp[16];
2506 unsigned char *cp;
2508 if (my_want_state_is_dont(TELOPT_STATUS)) {
2509 printf("Remote side does not support STATUS option\n");
2510 return 0;
2512 cp = tmp;
2514 *cp++ = IAC;
2515 *cp++ = SB;
2516 *cp++ = TELOPT_STATUS;
2517 *cp++ = TELQUAL_SEND;
2518 *cp++ = IAC;
2519 *cp++ = SE;
2520 if (NETROOM() >= cp - tmp) {
2521 ring_supply_data(&netoring, tmp, cp-tmp);
2522 printsub('>', tmp+2, cp - tmp - 2);
2524 ++want_status_response;
2525 return 1;
2528 void
2529 intp(void)
2531 NET2ADD(IAC, IP);
2532 printoption("SENT", IAC, IP);
2533 flushline = 1;
2534 if (autoflush) {
2535 doflush();
2537 if (autosynch) {
2538 dosynch(NULL);
2542 void
2543 sendbrk(void)
2545 NET2ADD(IAC, BREAK);
2546 printoption("SENT", IAC, BREAK);
2547 flushline = 1;
2548 if (autoflush) {
2549 doflush();
2551 if (autosynch) {
2552 dosynch(NULL);
2556 void
2557 sendabort(void)
2559 NET2ADD(IAC, ABORT);
2560 printoption("SENT", IAC, ABORT);
2561 flushline = 1;
2562 if (autoflush) {
2563 doflush();
2565 if (autosynch) {
2566 dosynch(NULL);
2570 void
2571 sendsusp(void)
2573 NET2ADD(IAC, SUSP);
2574 printoption("SENT", IAC, SUSP);
2575 flushline = 1;
2576 if (autoflush) {
2577 doflush();
2579 if (autosynch) {
2580 dosynch(NULL);
2584 void
2585 sendeof(void)
2587 NET2ADD(IAC, xEOF);
2588 printoption("SENT", IAC, xEOF);
2591 void
2592 sendayt(void)
2594 NET2ADD(IAC, AYT);
2595 printoption("SENT", IAC, AYT);
2599 * Send a window size update to the remote system.
2602 void
2603 sendnaws(void)
2605 long rows, cols;
2606 unsigned char tmp[16];
2607 unsigned char *cp;
2609 if (my_state_is_wont(TELOPT_NAWS))
2610 return;
2612 #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
2613 if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
2615 if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */
2616 return;
2619 cp = tmp;
2621 *cp++ = IAC;
2622 *cp++ = SB;
2623 *cp++ = TELOPT_NAWS;
2624 PUTSHORT(cp, cols);
2625 PUTSHORT(cp, rows);
2626 *cp++ = IAC;
2627 *cp++ = SE;
2628 if (NETROOM() >= cp - tmp) {
2629 ring_supply_data(&netoring, tmp, cp-tmp);
2630 printsub('>', tmp+2, cp - tmp - 2);
2634 void
2635 tel_enter_binary(int rw)
2637 if (rw&1)
2638 send_do(TELOPT_BINARY, 1);
2639 if (rw&2)
2640 send_will(TELOPT_BINARY, 1);
2643 void
2644 tel_leave_binary(int rw)
2646 if (rw&1)
2647 send_dont(TELOPT_BINARY, 1);
2648 if (rw&2)
2649 send_wont(TELOPT_BINARY, 1);