2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 static char sccsid[] = "@(#)state.c 8.2 (Berkeley) 12/15/93";
38 static const char rcsid[] =
43 #if defined(AUTHENTICATION)
44 #include <libtelnet/auth.h>
47 unsigned char doopt[] = { IAC, DO, '%', 'c', 0 };
48 unsigned char dont[] = { IAC, DONT, '%', 'c', 0 };
49 unsigned char will[] = { IAC, WILL, '%', 'c', 0 };
50 unsigned char wont[] = { IAC, WONT, '%', 'c', 0 };
54 * Buffer for sub-options, and macros
55 * for suboptions buffer manipulations
57 unsigned char subbuffer[512], *subpointer= subbuffer, *subend= subbuffer;
59 #define SB_CLEAR() subpointer = subbuffer
60 #define SB_TERM() { subend = subpointer; SB_CLEAR(); }
61 #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
62 *subpointer++ = (c); \
64 #define SB_GET() ((*subpointer++)&0xff)
65 #define SB_EOF() (subpointer >= subend)
66 #define SB_LEN() (subend - subpointer)
69 unsigned char *subsave;
70 #define SB_SAVE() subsave = subpointer;
71 #define SB_RESTORE() subpointer = subsave;
78 #define TS_DATA 0 /* base state */
79 #define TS_IAC 1 /* look for double IAC's */
80 #define TS_CR 2 /* CR-LF ->'s CR */
81 #define TS_SB 3 /* throw away begin's... */
82 #define TS_SE 4 /* ...end's (suboption negotiation) */
83 #define TS_WILL 5 /* will option negotiation */
84 #define TS_WONT 6 /* wont " */
85 #define TS_DO 7 /* do " */
86 #define TS_DONT 8 /* dont " */
92 static int state = TS_DATA;
93 #if defined(CRAY2) && defined(UNICOS5)
94 char *opfrontp = pfrontp;
98 if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
100 c = *netip++ & 0377, ncc--;
105 /* Strip off \n or \0 after a \r */
106 if ((c == 0) || (c == '\n')) {
117 * We now map \r\n ==> \r for pragmatic reasons.
118 * Many client implementations send \r\n when
119 * the user hits the CarriageReturn key.
121 * We USED to map \r\n ==> \n, since \r\n says
122 * that we want to be in column 1 of the next
123 * printable line, and \n is the standard
124 * unix way of saying that (\r is only good
125 * if CRMOD is set, which it normally is).
127 if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) {
131 * If we are operating in linemode,
132 * convert to local end-of-line.
134 if (linemode && (ncc > 0) && (('\n' == nc) ||
135 ((0 == nc) && tty_iscrnl())) ) {
151 * Send the process on the pty side an
152 * interrupt. Do this with a NULL or
153 * interrupt char; depending on the tty mode.
157 printoption("td: recv IAC", c));
163 printoption("td: recv IAC", c));
172 printoption("td: recv IAC", c));
182 printoption("td: recv IAC", c));
183 ptyflush(); /* half-hearted */
186 if (slctab[SLC_AO].sptr &&
187 *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) {
189 (unsigned char)*slctab[SLC_AO].sptr;
192 netclear(); /* clear buffer back */
195 neturg = nfrontp-1; /* off by one XXX */
197 printoption("td: send IAC", DM));
202 * Erase Character and
211 printoption("td: recv IAC", c));
212 ptyflush(); /* half-hearted */
215 ch = *slctab[SLC_EC].sptr;
217 ch = *slctab[SLC_EL].sptr;
218 if (ch != (cc_t)(_POSIX_VDISABLE))
219 *pfrontp++ = (unsigned char)ch;
224 * Check for urgent data...
228 printoption("td: recv IAC", c));
229 SYNCHing = stilloob(net);
235 * Begin option subnegotiation...
258 if (his_state_is_will(TELOPT_EOR))
263 * Handle RFC 10xx Telnet linemode option additions
264 * to command stream (EOF, SUSP, ABORT).
297 * bad form of suboption negotiation.
298 * handle it in such a way as to avoid
299 * damage to local state. Parse
300 * suboption buffer found so far,
301 * then treat remaining stream as
302 * another command sequence.
305 /* for DIAGNOSTICS */
318 /* for DIAGNOSTICS */
324 suboption(); /* handle sub-option */
350 syslog(LOG_ERR, "panic state=%d", state);
351 printf("telnetd: panic state=%d\n", state);
355 #if defined(CRAY2) && defined(UNICOS5)
357 char xptyobuf[BUFSIZ+NETSLOP];
360 int n = pfrontp - opfrontp, oc;
361 bcopy(opfrontp, xptyobuf, n);
363 pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP,
365 for (cp = xbuf2; oc > 0; --oc)
366 if ((*nfrontp++ = *cp++) == IAC)
369 #endif /* defined(CRAY2) && defined(UNICOS5) */
370 } /* end of telrcv */
373 * The will/wont/do/dont state machines are based on Dave Borman's
374 * Telnet option processing state machine.
376 * These correspond to the following states:
377 * my_state = the last negotiated state
378 * want_state = what I want the state to go to
379 * want_resp = how many requests I have sent
380 * All state defaults are negative, and resp defaults to 0.
382 * When initiating a request to change state to new_state:
384 * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) {
387 * want_state = new_state;
392 * When receiving new_state:
396 * if (want_resp && (new_state == my_state))
399 * if ((want_resp == 0) && (new_state != want_state)) {
400 * if (ok_to_switch_to new_state)
401 * want_state = new_state;
406 * my_state = new_state;
408 * Note that new_state is implied in these functions by the function itself.
409 * will and do imply positive new_state, wont and dont imply negative.
411 * Finally, there is one catch. If we send a negative response to a
412 * positive request, my_state will be the positive while want_state will
413 * remain negative. my_state will revert to negative when the negative
414 * acknowlegment arrives from the peer. Thus, my_state generally tells
415 * us not only the last negotiated state, but also tells us what the peer
416 * wants to be doing as well. It is important to understand this difference
417 * as we may wish to be processing data streams based on our desired state
418 * (want_state) or based on what the peer thinks the state is (my_state).
420 * This all works fine because if the peer sends a positive request, the data
421 * that we receive prior to negative acknowlegment will probably be affected
422 * by the positive state, and we can process it as such (if we can; if we
423 * can't then it really doesn't matter). If it is that important, then the
424 * peer probably should be buffering until this option state negotiation
429 send_do(option, init)
433 if ((do_dont_resp[option] == 0 && his_state_is_will(option)) ||
434 his_want_state_is_will(option))
437 * Special case for TELOPT_TM: We send a DO, but pretend
438 * that we sent a DONT, so that we can send more DOs if
441 if (option == TELOPT_TM)
442 set_his_want_state_wont(option);
444 set_his_want_state_will(option);
445 do_dont_resp[option]++;
447 (void) sprintf(nfrontp, (char *)doopt, option);
448 nfrontp += sizeof (dont) - 2;
450 DIAG(TD_OPTIONS, printoption("td: send do", option));
453 #ifdef AUTHENTICATION
454 extern void auth_request();
457 extern void doclientstat();
468 * process input from peer.
471 DIAG(TD_OPTIONS, printoption("td: recv will", option));
473 if (do_dont_resp[option]) {
474 do_dont_resp[option]--;
475 if (do_dont_resp[option] && his_state_is_will(option))
476 do_dont_resp[option]--;
478 if (do_dont_resp[option] == 0) {
479 if (his_want_state_is_wont(option)) {
491 * See comments below for more info.
493 not42 = 0; /* looks like a 4.2 system */
497 #if defined(LINEMODE) && defined(KLUDGELINEMODE)
499 * This telnetd implementation does not really
500 * support timing marks, it just uses them to
501 * support the kludge linemode stuff. If we
502 * receive a will or wont TM in response to our
503 * do TM request that may have been sent to
504 * determine kludge linemode support, process
505 * it, otherwise TM should get a negative
509 * Handle the linemode kludge stuff.
510 * If we are not currently supporting any
511 * linemode at all, then we assume that this
512 * is the client telling us to use kludge
513 * linemode in response to our query. Set the
514 * linemode type that is to be supported, note
515 * that the client wishes to use linemode, and
516 * eat the will TM as though it never arrived.
518 if (lmodetype < KLUDGE_LINEMODE) {
519 lmodetype = KLUDGE_LINEMODE;
520 clientstat(TELOPT_LINEMODE, WILL, 0);
521 send_wont(TELOPT_SGA, 1);
522 } else if (lmodetype == NO_AUTOKLUDGE) {
523 lmodetype = KLUDGE_OK;
525 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
527 * We never respond to a WILL TM, and
528 * we leave the state WONT.
534 * If we are going to support flow control
535 * option, then don't worry peer that we can't
536 * change the flow control characters.
538 slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
539 slctab[SLC_XON].defset.flag |= SLC_DEFAULT;
540 slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
541 slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT;
546 case TELOPT_XDISPLOC:
547 case TELOPT_NEW_ENVIRON:
548 case TELOPT_OLD_ENVIRON:
553 case TELOPT_LINEMODE:
554 # ifdef KLUDGELINEMODE
556 * Note client's desire to use linemode.
558 lmodetype = REAL_LINEMODE;
559 # endif /* KLUDGELINEMODE */
563 #endif /* LINEMODE */
565 #ifdef AUTHENTICATION
566 case TELOPT_AUTHENTICATION:
577 set_his_want_state_will(option);
580 do_dont_resp[option]++;
581 send_dont(option, 0);
585 * Option processing that should happen when
586 * we receive conformation of a change in
587 * state that we had requested.
591 not42 = 0; /* looks like a 4.2 system */
593 * Egads, he responded "WILL ECHO". Turn
596 send_dont(option, 1);
598 * "WILL ECHO". Kludge upon kludge!
599 * A 4.2 client is now echoing user input at
600 * the tty. This is probably undesireable and
601 * it should be stopped. The client will
602 * respond WONT TM to the DO TM that we send to
603 * check for kludge linemode. When the WONT TM
604 * arrives, linemode will be turned off and a
605 * change propogated to the pty. This change
606 * will cause us to process the new pty state
607 * in localstat(), which will notice that
608 * linemode is off and send a WILL ECHO
609 * so that we are properly in character mode and
614 case TELOPT_LINEMODE:
615 # ifdef KLUDGELINEMODE
617 * Note client's desire to use linemode.
619 lmodetype = REAL_LINEMODE;
620 # endif /* KLUDGELINEMODE */
623 #endif /* LINEMODE */
625 #ifdef AUTHENTICATION
626 case TELOPT_AUTHENTICATION:
637 set_his_state_will(option);
640 } /* end of willoption */
643 send_dont(option, init)
647 if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) ||
648 his_want_state_is_wont(option))
650 set_his_want_state_wont(option);
651 do_dont_resp[option]++;
653 (void) sprintf(nfrontp, (char *)dont, option);
654 nfrontp += sizeof (doopt) - 2;
656 DIAG(TD_OPTIONS, printoption("td: send dont", option));
664 * Process client input.
667 DIAG(TD_OPTIONS, printoption("td: recv wont", option));
669 if (do_dont_resp[option]) {
670 do_dont_resp[option]--;
671 if (do_dont_resp[option] && his_state_is_wont(option))
672 do_dont_resp[option]--;
674 if (do_dont_resp[option] == 0) {
675 if (his_want_state_is_will(option)) {
676 /* it is always ok to change to negative state */
679 not42 = 1; /* doesn't seem to be a 4.2 system */
689 case TELOPT_LINEMODE:
690 # ifdef KLUDGELINEMODE
692 * If real linemode is supported, then client is
693 * asking to turn linemode off.
695 if (lmodetype != REAL_LINEMODE)
697 lmodetype = KLUDGE_LINEMODE;
698 # endif /* KLUDGELINEMODE */
699 clientstat(TELOPT_LINEMODE, WONT, 0);
701 #endif /* LINEMODE */
705 * If we get a WONT TM, and had sent a DO TM,
706 * don't respond with a DONT TM, just leave it
707 * as is. Short circut the state machine to
710 set_his_want_state_wont(TELOPT_TM);
715 * If we are not going to support flow control
716 * option, then let peer know that we can't
717 * change the flow control characters.
719 slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
720 slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE;
721 slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
722 slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE;
725 #if defined(AUTHENTICATION)
726 case TELOPT_AUTHENTICATION:
727 auth_finished(0, AUTH_REJECT);
732 * For options that we might spin waiting for
733 * sub-negotiation, if the client turns off the
734 * option rather than responding to the request,
735 * we have to treat it here as if we got a response
736 * to the sub-negotiation, (by updating the timers)
737 * so that we'll break out of the loop.
740 settimer(ttypesubopt);
744 settimer(tspeedsubopt);
747 case TELOPT_XDISPLOC:
748 settimer(xdisplocsubopt);
751 case TELOPT_OLD_ENVIRON:
752 settimer(oenvironsubopt);
755 case TELOPT_NEW_ENVIRON:
756 settimer(environsubopt);
762 set_his_want_state_wont(option);
763 if (his_state_is_will(option))
764 send_dont(option, 0);
768 #if defined(LINEMODE) && defined(KLUDGELINEMODE)
769 if (lmodetype < NO_AUTOKLUDGE) {
770 lmodetype = NO_LINEMODE;
771 clientstat(TELOPT_LINEMODE, WONT, 0);
772 send_will(TELOPT_SGA, 1);
773 send_will(TELOPT_ECHO, 1);
775 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
778 #if defined(AUTHENTICATION)
779 case TELOPT_AUTHENTICATION:
780 auth_finished(0, AUTH_REJECT);
788 set_his_state_wont(option);
790 } /* end of wontoption */
793 send_will(option, init)
797 if ((will_wont_resp[option] == 0 && my_state_is_will(option))||
798 my_want_state_is_will(option))
800 set_my_want_state_will(option);
801 will_wont_resp[option]++;
803 (void) sprintf(nfrontp, (char *)will, option);
804 nfrontp += sizeof (doopt) - 2;
806 DIAG(TD_OPTIONS, printoption("td: send will", option));
809 #if !defined(LINEMODE) || !defined(KLUDGELINEMODE)
811 * When we get a DONT SGA, we will try once to turn it
812 * back on. If the other side responds DONT SGA, we
813 * leave it at that. This is so that when we talk to
814 * clients that understand KLUDGELINEMODE but not LINEMODE,
815 * we'll keep them in char-at-a-time mode.
827 * Process client input.
830 DIAG(TD_OPTIONS, printoption("td: recv do", option));
832 if (will_wont_resp[option]) {
833 will_wont_resp[option]--;
834 if (will_wont_resp[option] && my_state_is_will(option))
835 will_wont_resp[option]--;
837 if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) {
841 # ifdef KLUDGELINEMODE
842 if (lmodetype == NO_LINEMODE)
844 if (his_state_is_wont(TELOPT_LINEMODE))
863 #if defined(LINEMODE) && defined(KLUDGELINEMODE)
865 * If kludge linemode is in use, then we must
866 * process an incoming do SGA for linemode
869 if (lmodetype == KLUDGE_LINEMODE) {
871 * Receipt of "do SGA" in kludge
872 * linemode is the peer asking us to
873 * turn off linemode. Make note of
876 clientstat(TELOPT_LINEMODE, WONT, 0);
878 * If linemode did not get turned off
879 * then don't tell peer that we did.
880 * Breaking here forces a wont SGA to
888 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
898 * Special case for TM. We send a WILL, but
899 * pretend we sent a WONT.
901 send_will(option, 0);
902 set_my_want_state_wont(option);
903 set_my_state_wont(option);
908 * When we get a LOGOUT option, respond
909 * with a WILL LOGOUT, make sure that
910 * it gets written out to the network,
911 * and then just go away...
913 set_my_want_state_will(TELOPT_LOGOUT);
914 send_will(TELOPT_LOGOUT, 0);
915 set_my_state_will(TELOPT_LOGOUT);
921 case TELOPT_LINEMODE:
926 case TELOPT_XDISPLOC:
927 #ifdef TELOPT_ENVIRON
928 case TELOPT_NEW_ENVIRON:
930 case TELOPT_OLD_ENVIRON:
935 set_my_want_state_will(option);
936 send_will(option, 0);
938 will_wont_resp[option]++;
939 send_wont(option, 0);
942 set_my_state_will(option);
944 } /* end of dooption */
947 send_wont(option, init)
951 if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) ||
952 my_want_state_is_wont(option))
954 set_my_want_state_wont(option);
955 will_wont_resp[option]++;
957 (void) sprintf(nfrontp, (char *)wont, option);
958 nfrontp += sizeof (wont) - 2;
960 DIAG(TD_OPTIONS, printoption("td: send wont", option));
968 * Process client input.
972 DIAG(TD_OPTIONS, printoption("td: recv dont", option));
974 if (will_wont_resp[option]) {
975 will_wont_resp[option]--;
976 if (will_wont_resp[option] && my_state_is_wont(option))
977 will_wont_resp[option]--;
979 if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) {
987 case TELOPT_ECHO: /* we should stop echoing */
989 # ifdef KLUDGELINEMODE
990 if ((lmodetype != REAL_LINEMODE) &&
991 (lmodetype != KLUDGE_LINEMODE))
993 if (his_state_is_wont(TELOPT_LINEMODE))
1004 #if defined(LINEMODE) && defined(KLUDGELINEMODE)
1006 * If kludge linemode is in use, then we
1007 * must process an incoming do SGA for
1008 * linemode purposes.
1010 if ((lmodetype == KLUDGE_LINEMODE) ||
1011 (lmodetype == KLUDGE_OK)) {
1013 * The client is asking us to turn
1016 lmodetype = KLUDGE_LINEMODE;
1017 clientstat(TELOPT_LINEMODE, WILL, 0);
1019 * If we did not turn line mode on,
1020 * then what do we say? Will SGA?
1021 * This violates design of telnet.
1022 * Gross. Very Gross.
1027 set_my_want_state_wont(option);
1028 if (my_state_is_will(option))
1029 send_wont(option, 0);
1030 set_my_state_wont(option);
1031 if (turn_on_sga ^= 1)
1032 send_will(option, 1);
1034 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
1040 set_my_want_state_wont(option);
1041 if (my_state_is_will(option))
1042 send_wont(option, 0);
1044 set_my_state_wont(option);
1046 } /* end of dontoption */
1050 int env_ovalue = -1;
1051 #else /* ENV_HACK */
1052 # define env_ovar OLD_ENV_VAR
1053 # define env_ovalue OLD_ENV_VALUE
1054 #endif /* ENV_HACK */
1059 * Look at the sub-option buffer, and try to be helpful to the other
1062 * Currently we recognize:
1072 register int subchar;
1074 DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);});
1078 case TELOPT_TSPEED: {
1079 register int xspeed, rspeed;
1081 if (his_state_is_wont(TELOPT_TSPEED)) /* Ignore if option disabled */
1084 settimer(tspeedsubopt);
1086 if (SB_EOF() || SB_GET() != TELQUAL_IS)
1089 xspeed = atoi((char *)subpointer);
1091 while (SB_GET() != ',' && !SB_EOF());
1095 rspeed = atoi((char *)subpointer);
1096 clientstat(TELOPT_TSPEED, xspeed, rspeed);
1100 } /* end of case TELOPT_TSPEED */
1102 case TELOPT_TTYPE: { /* Yaaaay! */
1103 static char terminalname[41];
1105 if (his_state_is_wont(TELOPT_TTYPE)) /* Ignore if option disabled */
1107 settimer(ttypesubopt);
1109 if (SB_EOF() || SB_GET() != TELQUAL_IS) {
1110 return; /* ??? XXX but, this is the most robust */
1113 terminaltype = terminalname;
1115 while ((terminaltype < (terminalname + sizeof terminalname-1)) &&
1123 *terminaltype++ = c; /* accumulate name */
1126 terminaltype = terminalname;
1128 } /* end of case TELOPT_TTYPE */
1131 register int xwinsize, ywinsize;
1133 if (his_state_is_wont(TELOPT_NAWS)) /* Ignore if option disabled */
1138 xwinsize = SB_GET() << 8;
1141 xwinsize |= SB_GET();
1144 ywinsize = SB_GET() << 8;
1147 ywinsize |= SB_GET();
1148 clientstat(TELOPT_NAWS, xwinsize, ywinsize);
1152 } /* end of case TELOPT_NAWS */
1155 case TELOPT_LINEMODE: {
1156 register int request;
1158 if (his_state_is_wont(TELOPT_LINEMODE)) /* Ignore if option disabled */
1161 * Process linemode suboptions.
1164 break; /* garbage was sent */
1165 request = SB_GET(); /* get will/wont */
1168 break; /* another garbage check */
1170 if (request == LM_SLC) { /* SLC is not preceeded by WILL or WONT */
1172 * Process suboption buffer of slc's
1175 do_opt_slc(subpointer, subend - subpointer);
1178 } else if (request == LM_MODE) {
1181 useeditmode = SB_GET(); /* get mode flag */
1182 clientstat(LM_MODE, 0, 0);
1188 switch (SB_GET()) { /* what suboption? */
1189 case LM_FORWARDMASK:
1191 * According to spec, only server can send request for
1192 * forwardmask, and client can only return a positive response.
1193 * So don't worry about it.
1200 } /* end of case TELOPT_LINEMODE */
1202 case TELOPT_STATUS: {
1210 if (my_state_is_will(TELOPT_STATUS))
1221 } /* end of case TELOPT_STATUS */
1223 case TELOPT_XDISPLOC: {
1224 if (SB_EOF() || SB_GET() != TELQUAL_IS)
1226 settimer(xdisplocsubopt);
1227 subpointer[SB_LEN()] = '\0';
1228 (void)setenv("DISPLAY", (char *)subpointer, 1);
1230 } /* end of case TELOPT_XDISPLOC */
1232 #ifdef TELOPT_NEW_ENVIRON
1233 case TELOPT_NEW_ENVIRON:
1235 case TELOPT_OLD_ENVIRON: {
1237 register char *cp, *varp, *valp;
1242 if (c == TELQUAL_IS) {
1243 if (subchar == TELOPT_OLD_ENVIRON)
1244 settimer(oenvironsubopt);
1246 settimer(environsubopt);
1247 } else if (c != TELQUAL_INFO) {
1251 #ifdef TELOPT_NEW_ENVIRON
1252 if (subchar == TELOPT_NEW_ENVIRON) {
1255 if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR))
1263 * We only want to do this if we haven't already decided
1264 * whether or not the other side has its VALUE and VAR
1268 register int last = -1; /* invalid value */
1270 int got_var = 0, got_value = 0, got_uservar = 0;
1273 * The other side might have its VALUE and VAR values
1274 * reversed. To be interoperable, we need to determine
1275 * which way it is. If the first recognized character
1276 * is a VAR or VALUE, then that will tell us what
1277 * type of client it is. If the fist recognized
1278 * character is a USERVAR, then we continue scanning
1279 * the suboption looking for two consecutive
1280 * VAR or VALUE fields. We should not get two
1281 * consecutive VALUE fields, so finding two
1282 * consecutive VALUE or VAR fields will tell us
1283 * what the client is.
1290 if (last < 0 || last == OLD_ENV_VAR
1291 || (empty && (last == OLD_ENV_VALUE)))
1297 if (last < 0 || last == OLD_ENV_VALUE
1298 || (empty && (last == OLD_ENV_VAR)))
1299 goto env_ovar_wrong;
1301 last = OLD_ENV_VALUE;
1304 /* count strings of USERVAR as one */
1305 if (last != ENV_USERVAR)
1308 if (last == OLD_ENV_VALUE)
1310 if (last == OLD_ENV_VAR)
1311 goto env_ovar_wrong;
1326 if (last == OLD_ENV_VALUE)
1328 if (last == OLD_ENV_VAR)
1329 goto env_ovar_wrong;
1332 * Ok, the first thing was a USERVAR, and there
1333 * are not two consecutive VAR or VALUE commands,
1334 * and none of the VAR or VALUE commands are empty.
1335 * If the client has sent us a well-formed option,
1336 * then the number of VALUEs received should always
1337 * be less than or equal to the number of VARs and
1338 * USERVARs received.
1340 * If we got exactly as many VALUEs as VARs and
1341 * USERVARs, the client has the same definitions.
1343 * If we got exactly as many VARs as VALUEs and
1344 * USERVARS, the client has reversed definitions.
1346 if (got_uservar + got_var == got_value) {
1348 env_ovar = OLD_ENV_VAR;
1349 env_ovalue = OLD_ENV_VALUE;
1350 } else if (got_uservar + got_value == got_var) {
1352 env_ovar = OLD_ENV_VALUE;
1353 env_ovalue = OLD_ENV_VAR;
1354 DIAG(TD_OPTIONS, {sprintf(nfrontp,
1355 "ENVIRON VALUE and VAR are reversed!\r\n");
1356 nfrontp += strlen(nfrontp);});
1365 if ((c == env_ovar) || (c == ENV_USERVAR))
1373 cp = varp = (char *)subpointer;
1378 if (subchar == TELOPT_OLD_ENVIRON) {
1381 else if (c == env_ovalue)
1388 cp = valp = (char *)subpointer;
1395 (void)setenv(varp, valp, 1);
1398 cp = varp = (char *)subpointer;
1414 (void)setenv(varp, valp, 1);
1418 } /* end of case TELOPT_NEW_ENVIRON */
1419 #if defined(AUTHENTICATION)
1420 case TELOPT_AUTHENTICATION:
1427 * These are sent by us and cannot be sent by
1432 auth_is(subpointer, SB_LEN());
1435 auth_name(subpointer, SB_LEN());
1443 } /* end of switch */
1445 } /* end of suboption */
1450 clientstat(TELOPT_LINEMODE, WILL, 0);
1453 #define ADD(c) *ncp++ = c
1454 #define ADD_DATA(c) { *ncp++ = c; if (c == SE) *ncp++ = c; }
1458 unsigned char statusbuf[256];
1459 register unsigned char *ncp;
1460 register unsigned char i;
1464 netflush(); /* get rid of anything waiting to go out */
1472 * We check the want_state rather than the current state,
1473 * because if we received a DO/WILL for an option that we
1474 * don't support, and the other side didn't send a DONT/WONT
1475 * in response to our WONT/DONT, then the "state" will be
1476 * WILL/DO, and the "want_state" will be WONT/DONT. We
1477 * need to go by the latter.
1479 for (i = 0; i < (unsigned char)NTELOPTS; i++) {
1480 if (my_want_state_is_will(i)) {
1486 if (his_want_state_is_will(i)) {
1494 if (his_want_state_is_will(TELOPT_LFLOW)) {
1504 if (restartany >= 0) {
1508 ADD(LFLOW_RESTART_ANY);
1510 ADD(LFLOW_RESTART_XON);
1518 if (his_want_state_is_will(TELOPT_LINEMODE)) {
1519 unsigned char *cp, *cpe;
1523 ADD(TELOPT_LINEMODE);
1526 if (editmode == IAC)
1531 ADD(TELOPT_LINEMODE);
1536 for (cpe = cp + len; cp < cpe; cp++)
1540 #endif /* LINEMODE */
1545 writenet(statusbuf, ncp - statusbuf);
1546 netflush(); /* Send it on its way */
1549 {printsub('>', statusbuf, ncp - statusbuf); netflush();});