]>
git.saurik.com Git - apple/network_cmds.git/blob - telnetd.tproj/state.c
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * Copyright (c) 1989, 1993
26 * The Regents of the University of California. All rights reserved.
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgement:
38 * This product includes software developed by the University of
39 * California, Berkeley and its contributors.
40 * 4. Neither the name of the University nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 static char sccsid
[] = "@(#)state.c 8.5 (Berkeley) 5/30/95";
62 #if defined(AUTHENTICATION)
63 #include <libtelnet/auth.h>
66 unsigned char doopt
[] = { IAC
, DO
, '%', 'c', 0 };
67 unsigned char dont
[] = { IAC
, DONT
, '%', 'c', 0 };
68 unsigned char will
[] = { IAC
, WILL
, '%', 'c', 0 };
69 unsigned char wont
[] = { IAC
, WONT
, '%', 'c', 0 };
73 * Buffer for sub-options, and macros
74 * for suboptions buffer manipulations
76 unsigned char subbuffer
[512], *subpointer
= subbuffer
, *subend
= subbuffer
;
78 #define SB_CLEAR() subpointer = subbuffer
79 #define SB_TERM() { subend = subpointer; SB_CLEAR(); }
80 #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
81 *subpointer++ = (c); \
83 #define SB_GET() ((*subpointer++)&0xff)
84 #define SB_EOF() (subpointer >= subend)
85 #define SB_LEN() (subend - subpointer)
88 unsigned char *subsave
;
89 #define SB_SAVE() subsave = subpointer;
90 #define SB_RESTORE() subpointer = subsave;
97 #define TS_DATA 0 /* base state */
98 #define TS_IAC 1 /* look for double IAC's */
99 #define TS_CR 2 /* CR-LF ->'s CR */
100 #define TS_SB 3 /* throw away begin's... */
101 #define TS_SE 4 /* ...end's (suboption negotiation) */
102 #define TS_WILL 5 /* will option negotiation */
103 #define TS_WONT 6 /* wont " */
104 #define TS_DO 7 /* do " */
105 #define TS_DONT 8 /* dont " */
111 static int state
= TS_DATA
;
112 #if defined(CRAY2) && defined(UNICOS5)
113 char *opfrontp
= pfrontp
;
117 if ((&ptyobuf
[BUFSIZ
] - pfrontp
) < 2)
119 c
= *netip
++ & 0377, ncc
--;
122 c
= (*decrypt_input
)(c
);
123 #endif /* ENCRYPTION */
128 /* Strip off \n or \0 after a \r */
129 if ((c
== 0) || (c
== '\n')) {
140 * We now map \r\n ==> \r for pragmatic reasons.
141 * Many client implementations send \r\n when
142 * the user hits the CarriageReturn key.
144 * We USED to map \r\n ==> \n, since \r\n says
145 * that we want to be in column 1 of the next
146 * printable line, and \n is the standard
147 * unix way of saying that (\r is only good
148 * if CRMOD is set, which it normally is).
150 if ((c
== '\r') && his_state_is_wont(TELOPT_BINARY
)) {
154 nc
= (*decrypt_input
)(nc
& 0xff);
155 #endif /* ENCRYPTION */
158 * If we are operating in linemode,
159 * convert to local end-of-line.
161 if (linemode
&& (ncc
> 0) && (('\n' == nc
) ||
162 ((0 == nc
) && tty_iscrnl())) ) {
170 (void)(*decrypt_input
)(-1);
171 #endif /* ENCRYPTION */
182 * Send the process on the pty side an
183 * interrupt. Do this with a NULL or
184 * interrupt char; depending on the tty mode.
188 printoption("td: recv IAC", c
));
194 printoption("td: recv IAC", c
));
203 printoption("td: recv IAC", c
));
213 printoption("td: recv IAC", c
));
214 ptyflush(); /* half-hearted */
217 if (slctab
[SLC_AO
].sptr
&&
218 *slctab
[SLC_AO
].sptr
!= (cc_t
)(_POSIX_VDISABLE
)) {
220 (unsigned char)*slctab
[SLC_AO
].sptr
;
223 netclear(); /* clear buffer back */
226 neturg
= nfrontp
-1; /* off by one XXX */
228 printoption("td: send IAC", DM
));
233 * Erase Character and
242 printoption("td: recv IAC", c
));
243 ptyflush(); /* half-hearted */
246 ch
= *slctab
[SLC_EC
].sptr
;
248 ch
= *slctab
[SLC_EL
].sptr
;
249 if (ch
!= (cc_t
)(_POSIX_VDISABLE
))
250 *pfrontp
++ = (unsigned char)ch
;
255 * Check for urgent data...
259 printoption("td: recv IAC", c
));
260 SYNCHing
= stilloob(net
);
266 * Begin option subnegotiation...
289 if (his_state_is_will(TELOPT_EOR
))
294 * Handle RFC 10xx Telnet linemode option additions
295 * to command stream (EOF, SUSP, ABORT).
328 * bad form of suboption negotiation.
329 * handle it in such a way as to avoid
330 * damage to local state. Parse
331 * suboption buffer found so far,
332 * then treat remaining stream as
333 * another command sequence.
336 /* for DIAGNOSTICS */
349 /* for DIAGNOSTICS */
355 suboption(); /* handle sub-option */
381 syslog(LOG_ERR
, "telnetd: panic state=%d\n", state
);
382 printf("telnetd: panic state=%d\n", state
);
386 #if defined(CRAY2) && defined(UNICOS5)
388 char xptyobuf
[BUFSIZ
+NETSLOP
];
391 int n
= pfrontp
- opfrontp
, oc
;
392 memmove(xptyobuf
, opfrontp
, n
);
394 pfrontp
+= term_input(xptyobuf
, pfrontp
, n
, BUFSIZ
+NETSLOP
,
396 for (cp
= xbuf2
; oc
> 0; --oc
)
397 if ((*nfrontp
++ = *cp
++) == IAC
)
400 #endif /* defined(CRAY2) && defined(UNICOS5) */
401 } /* end of telrcv */
404 * The will/wont/do/dont state machines are based on Dave Borman's
405 * Telnet option processing state machine.
407 * These correspond to the following states:
408 * my_state = the last negotiated state
409 * want_state = what I want the state to go to
410 * want_resp = how many requests I have sent
411 * All state defaults are negative, and resp defaults to 0.
413 * When initiating a request to change state to new_state:
415 * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) {
418 * want_state = new_state;
423 * When receiving new_state:
427 * if (want_resp && (new_state == my_state))
430 * if ((want_resp == 0) && (new_state != want_state)) {
431 * if (ok_to_switch_to new_state)
432 * want_state = new_state;
437 * my_state = new_state;
439 * Note that new_state is implied in these functions by the function itself.
440 * will and do imply positive new_state, wont and dont imply negative.
442 * Finally, there is one catch. If we send a negative response to a
443 * positive request, my_state will be the positive while want_state will
444 * remain negative. my_state will revert to negative when the negative
445 * acknowlegment arrives from the peer. Thus, my_state generally tells
446 * us not only the last negotiated state, but also tells us what the peer
447 * wants to be doing as well. It is important to understand this difference
448 * as we may wish to be processing data streams based on our desired state
449 * (want_state) or based on what the peer thinks the state is (my_state).
451 * This all works fine because if the peer sends a positive request, the data
452 * that we receive prior to negative acknowlegment will probably be affected
453 * by the positive state, and we can process it as such (if we can; if we
454 * can't then it really doesn't matter). If it is that important, then the
455 * peer probably should be buffering until this option state negotiation
460 send_do(option
, init
)
464 if ((do_dont_resp
[option
] == 0 && his_state_is_will(option
)) ||
465 his_want_state_is_will(option
))
468 * Special case for TELOPT_TM: We send a DO, but pretend
469 * that we sent a DONT, so that we can send more DOs if
472 if (option
== TELOPT_TM
)
473 set_his_want_state_wont(option
);
475 set_his_want_state_will(option
);
476 do_dont_resp
[option
]++;
478 (void) sprintf(nfrontp
, (char *)doopt
, option
);
479 nfrontp
+= sizeof (dont
) - 2;
481 DIAG(TD_OPTIONS
, printoption("td: send do", option
));
484 #ifdef AUTHENTICATION
485 extern void auth_request();
488 extern void doclientstat();
491 extern void encrypt_send_support();
492 #endif /* ENCRYPTION */
502 * process input from peer.
505 DIAG(TD_OPTIONS
, printoption("td: recv will", option
));
507 if (do_dont_resp
[option
]) {
508 do_dont_resp
[option
]--;
509 if (do_dont_resp
[option
] && his_state_is_will(option
))
510 do_dont_resp
[option
]--;
512 if (do_dont_resp
[option
] == 0) {
513 if (his_want_state_is_wont(option
)) {
525 * See comments below for more info.
527 not42
= 0; /* looks like a 4.2 system */
531 #if defined(LINEMODE) && defined(KLUDGELINEMODE)
533 * This telnetd implementation does not really
534 * support timing marks, it just uses them to
535 * support the kludge linemode stuff. If we
536 * receive a will or wont TM in response to our
537 * do TM request that may have been sent to
538 * determine kludge linemode support, process
539 * it, otherwise TM should get a negative
543 * Handle the linemode kludge stuff.
544 * If we are not currently supporting any
545 * linemode at all, then we assume that this
546 * is the client telling us to use kludge
547 * linemode in response to our query. Set the
548 * linemode type that is to be supported, note
549 * that the client wishes to use linemode, and
550 * eat the will TM as though it never arrived.
552 if (lmodetype
< KLUDGE_LINEMODE
) {
553 lmodetype
= KLUDGE_LINEMODE
;
554 clientstat(TELOPT_LINEMODE
, WILL
, 0);
555 send_wont(TELOPT_SGA
, 1);
556 } else if (lmodetype
== NO_AUTOKLUDGE
) {
557 lmodetype
= KLUDGE_OK
;
559 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
561 * We never respond to a WILL TM, and
562 * we leave the state WONT.
568 * If we are going to support flow control
569 * option, then don't worry peer that we can't
570 * change the flow control characters.
572 slctab
[SLC_XON
].defset
.flag
&= ~SLC_LEVELBITS
;
573 slctab
[SLC_XON
].defset
.flag
|= SLC_DEFAULT
;
574 slctab
[SLC_XOFF
].defset
.flag
&= ~SLC_LEVELBITS
;
575 slctab
[SLC_XOFF
].defset
.flag
|= SLC_DEFAULT
;
580 case TELOPT_XDISPLOC
:
581 case TELOPT_NEW_ENVIRON
:
582 case TELOPT_OLD_ENVIRON
:
587 case TELOPT_LINEMODE
:
588 # ifdef KLUDGELINEMODE
590 * Note client's desire to use linemode.
592 lmodetype
= REAL_LINEMODE
;
593 # endif /* KLUDGELINEMODE */
597 #endif /* LINEMODE */
599 #ifdef AUTHENTICATION
600 case TELOPT_AUTHENTICATION
:
608 func
= encrypt_send_support
;
611 #endif /* ENCRYPTION */
617 set_his_want_state_will(option
);
620 do_dont_resp
[option
]++;
621 send_dont(option
, 0);
625 * Option processing that should happen when
626 * we receive conformation of a change in
627 * state that we had requested.
631 not42
= 0; /* looks like a 4.2 system */
633 * Egads, he responded "WILL ECHO". Turn
636 send_dont(option
, 1);
638 * "WILL ECHO". Kludge upon kludge!
639 * A 4.2 client is now echoing user input at
640 * the tty. This is probably undesireable and
641 * it should be stopped. The client will
642 * respond WONT TM to the DO TM that we send to
643 * check for kludge linemode. When the WONT TM
644 * arrives, linemode will be turned off and a
645 * change propogated to the pty. This change
646 * will cause us to process the new pty state
647 * in localstat(), which will notice that
648 * linemode is off and send a WILL ECHO
649 * so that we are properly in character mode and
654 case TELOPT_LINEMODE
:
655 # ifdef KLUDGELINEMODE
657 * Note client's desire to use linemode.
659 lmodetype
= REAL_LINEMODE
;
660 # endif /* KLUDGELINEMODE */
663 #endif /* LINEMODE */
665 #ifdef AUTHENTICATION
666 case TELOPT_AUTHENTICATION
:
673 func
= encrypt_send_support
;
675 #endif /* ENCRYPTION */
682 set_his_state_will(option
);
685 } /* end of willoption */
688 send_dont(option
, init
)
692 if ((do_dont_resp
[option
] == 0 && his_state_is_wont(option
)) ||
693 his_want_state_is_wont(option
))
695 set_his_want_state_wont(option
);
696 do_dont_resp
[option
]++;
698 (void) sprintf(nfrontp
, (char *)dont
, option
);
699 nfrontp
+= sizeof (doopt
) - 2;
701 DIAG(TD_OPTIONS
, printoption("td: send dont", option
));
709 * Process client input.
712 DIAG(TD_OPTIONS
, printoption("td: recv wont", option
));
714 if (do_dont_resp
[option
]) {
715 do_dont_resp
[option
]--;
716 if (do_dont_resp
[option
] && his_state_is_wont(option
))
717 do_dont_resp
[option
]--;
719 if (do_dont_resp
[option
] == 0) {
720 if (his_want_state_is_will(option
)) {
721 /* it is always ok to change to negative state */
724 not42
= 1; /* doesn't seem to be a 4.2 system */
734 case TELOPT_LINEMODE
:
735 # ifdef KLUDGELINEMODE
737 * If real linemode is supported, then client is
738 * asking to turn linemode off.
740 if (lmodetype
!= REAL_LINEMODE
)
742 # endif /* KLUDGELINEMODE */
743 clientstat(TELOPT_LINEMODE
, WONT
, 0);
745 #endif /* LINEMODE */
749 * If we get a WONT TM, and had sent a DO TM,
750 * don't respond with a DONT TM, just leave it
751 * as is. Short circut the state machine to
754 set_his_want_state_wont(TELOPT_TM
);
759 * If we are not going to support flow control
760 * option, then let peer know that we can't
761 * change the flow control characters.
763 slctab
[SLC_XON
].defset
.flag
&= ~SLC_LEVELBITS
;
764 slctab
[SLC_XON
].defset
.flag
|= SLC_CANTCHANGE
;
765 slctab
[SLC_XOFF
].defset
.flag
&= ~SLC_LEVELBITS
;
766 slctab
[SLC_XOFF
].defset
.flag
|= SLC_CANTCHANGE
;
769 #if defined(AUTHENTICATION)
770 case TELOPT_AUTHENTICATION
:
771 auth_finished(0, AUTH_REJECT
);
776 * For options that we might spin waiting for
777 * sub-negotiation, if the client turns off the
778 * option rather than responding to the request,
779 * we have to treat it here as if we got a response
780 * to the sub-negotiation, (by updating the timers)
781 * so that we'll break out of the loop.
784 settimer(ttypesubopt
);
788 settimer(tspeedsubopt
);
791 case TELOPT_XDISPLOC
:
792 settimer(xdisplocsubopt
);
795 case TELOPT_OLD_ENVIRON
:
796 settimer(oenvironsubopt
);
799 case TELOPT_NEW_ENVIRON
:
800 settimer(environsubopt
);
806 set_his_want_state_wont(option
);
807 if (his_state_is_will(option
))
808 send_dont(option
, 0);
812 #if defined(LINEMODE) && defined(KLUDGELINEMODE)
813 if (lmodetype
< NO_AUTOKLUDGE
) {
814 lmodetype
= NO_LINEMODE
;
815 clientstat(TELOPT_LINEMODE
, WONT
, 0);
816 send_will(TELOPT_SGA
, 1);
817 send_will(TELOPT_ECHO
, 1);
819 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
822 #if defined(AUTHENTICATION)
823 case TELOPT_AUTHENTICATION
:
824 auth_finished(0, AUTH_REJECT
);
832 set_his_state_wont(option
);
834 } /* end of wontoption */
837 send_will(option
, init
)
841 if ((will_wont_resp
[option
] == 0 && my_state_is_will(option
))||
842 my_want_state_is_will(option
))
844 set_my_want_state_will(option
);
845 will_wont_resp
[option
]++;
847 (void) sprintf(nfrontp
, (char *)will
, option
);
848 nfrontp
+= sizeof (doopt
) - 2;
850 DIAG(TD_OPTIONS
, printoption("td: send will", option
));
853 #if !defined(LINEMODE) || !defined(KLUDGELINEMODE)
855 * When we get a DONT SGA, we will try once to turn it
856 * back on. If the other side responds DONT SGA, we
857 * leave it at that. This is so that when we talk to
858 * clients that understand KLUDGELINEMODE but not LINEMODE,
859 * we'll keep them in char-at-a-time mode.
871 * Process client input.
874 DIAG(TD_OPTIONS
, printoption("td: recv do", option
));
876 if (will_wont_resp
[option
]) {
877 will_wont_resp
[option
]--;
878 if (will_wont_resp
[option
] && my_state_is_will(option
))
879 will_wont_resp
[option
]--;
881 if ((will_wont_resp
[option
] == 0) && (my_want_state_is_wont(option
))) {
885 # ifdef KLUDGELINEMODE
886 if (lmodetype
== NO_LINEMODE
)
888 if (his_state_is_wont(TELOPT_LINEMODE
))
907 #if defined(LINEMODE) && defined(KLUDGELINEMODE)
909 * If kludge linemode is in use, then we must
910 * process an incoming do SGA for linemode
913 if (lmodetype
== KLUDGE_LINEMODE
) {
915 * Receipt of "do SGA" in kludge
916 * linemode is the peer asking us to
917 * turn off linemode. Make note of
920 clientstat(TELOPT_LINEMODE
, WONT
, 0);
922 * If linemode did not get turned off
923 * then don't tell peer that we did.
924 * Breaking here forces a wont SGA to
932 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
942 * Special case for TM. We send a WILL, but
943 * pretend we sent a WONT.
945 send_will(option
, 0);
946 set_my_want_state_wont(option
);
947 set_my_state_wont(option
);
952 * When we get a LOGOUT option, respond
953 * with a WILL LOGOUT, make sure that
954 * it gets written out to the network,
955 * and then just go away...
957 set_my_want_state_will(TELOPT_LOGOUT
);
958 send_will(TELOPT_LOGOUT
, 0);
959 set_my_state_will(TELOPT_LOGOUT
);
969 #endif /* ENCRYPTION */
970 case TELOPT_LINEMODE
:
975 case TELOPT_XDISPLOC
:
976 #ifdef TELOPT_ENVIRON
977 case TELOPT_NEW_ENVIRON
:
979 case TELOPT_OLD_ENVIRON
:
984 set_my_want_state_will(option
);
985 send_will(option
, 0);
987 will_wont_resp
[option
]++;
988 send_wont(option
, 0);
991 set_my_state_will(option
);
993 } /* end of dooption */
996 send_wont(option
, init
)
1000 if ((will_wont_resp
[option
] == 0 && my_state_is_wont(option
)) ||
1001 my_want_state_is_wont(option
))
1003 set_my_want_state_wont(option
);
1004 will_wont_resp
[option
]++;
1006 (void) sprintf(nfrontp
, (char *)wont
, option
);
1007 nfrontp
+= sizeof (wont
) - 2;
1009 DIAG(TD_OPTIONS
, printoption("td: send wont", option
));
1017 * Process client input.
1021 DIAG(TD_OPTIONS
, printoption("td: recv dont", option
));
1023 if (will_wont_resp
[option
]) {
1024 will_wont_resp
[option
]--;
1025 if (will_wont_resp
[option
] && my_state_is_wont(option
))
1026 will_wont_resp
[option
]--;
1028 if ((will_wont_resp
[option
] == 0) && (my_want_state_is_will(option
))) {
1036 case TELOPT_ECHO
: /* we should stop echoing */
1038 # ifdef KLUDGELINEMODE
1039 if ((lmodetype
!= REAL_LINEMODE
) &&
1040 (lmodetype
!= KLUDGE_LINEMODE
))
1042 if (his_state_is_wont(TELOPT_LINEMODE
))
1053 #if defined(LINEMODE) && defined(KLUDGELINEMODE)
1055 * If kludge linemode is in use, then we
1056 * must process an incoming do SGA for
1057 * linemode purposes.
1059 if ((lmodetype
== KLUDGE_LINEMODE
) ||
1060 (lmodetype
== KLUDGE_OK
)) {
1062 * The client is asking us to turn
1065 lmodetype
= KLUDGE_LINEMODE
;
1066 clientstat(TELOPT_LINEMODE
, WILL
, 0);
1068 * If we did not turn line mode on,
1069 * then what do we say? Will SGA?
1070 * This violates design of telnet.
1071 * Gross. Very Gross.
1076 set_my_want_state_wont(option
);
1077 if (my_state_is_will(option
))
1078 send_wont(option
, 0);
1079 set_my_state_wont(option
);
1080 if (turn_on_sga
^= 1)
1081 send_will(option
, 1);
1083 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
1089 set_my_want_state_wont(option
);
1090 if (my_state_is_will(option
))
1091 send_wont(option
, 0);
1093 set_my_state_wont(option
);
1095 } /* end of dontoption */
1099 int env_ovalue
= -1;
1100 #else /* ENV_HACK */
1101 # define env_ovar OLD_ENV_VAR
1102 # define env_ovalue OLD_ENV_VALUE
1103 #endif /* ENV_HACK */
1108 * Look at the sub-option buffer, and try to be helpful to the other
1111 * Currently we recognize:
1121 register int subchar
;
1123 DIAG(TD_OPTIONS
, {netflush(); printsub('<', subpointer
, SB_LEN()+2);});
1127 case TELOPT_TSPEED
: {
1128 register int xspeed
, rspeed
;
1130 if (his_state_is_wont(TELOPT_TSPEED
)) /* Ignore if option disabled */
1133 settimer(tspeedsubopt
);
1135 if (SB_EOF() || SB_GET() != TELQUAL_IS
)
1138 xspeed
= atoi((char *)subpointer
);
1140 while (SB_GET() != ',' && !SB_EOF());
1144 rspeed
= atoi((char *)subpointer
);
1145 clientstat(TELOPT_TSPEED
, xspeed
, rspeed
);
1149 } /* end of case TELOPT_TSPEED */
1151 case TELOPT_TTYPE
: { /* Yaaaay! */
1152 static char terminalname
[41];
1154 if (his_state_is_wont(TELOPT_TTYPE
)) /* Ignore if option disabled */
1156 settimer(ttypesubopt
);
1158 if (SB_EOF() || SB_GET() != TELQUAL_IS
) {
1159 return; /* ??? XXX but, this is the most robust */
1162 terminaltype
= terminalname
;
1164 while ((terminaltype
< (terminalname
+ sizeof terminalname
-1)) &&
1172 *terminaltype
++ = c
; /* accumulate name */
1175 terminaltype
= terminalname
;
1177 } /* end of case TELOPT_TTYPE */
1180 register int xwinsize
, ywinsize
;
1182 if (his_state_is_wont(TELOPT_NAWS
)) /* Ignore if option disabled */
1187 xwinsize
= SB_GET() << 8;
1190 xwinsize
|= SB_GET();
1193 ywinsize
= SB_GET() << 8;
1196 ywinsize
|= SB_GET();
1197 clientstat(TELOPT_NAWS
, xwinsize
, ywinsize
);
1201 } /* end of case TELOPT_NAWS */
1204 case TELOPT_LINEMODE
: {
1205 register int request
;
1207 if (his_state_is_wont(TELOPT_LINEMODE
)) /* Ignore if option disabled */
1210 * Process linemode suboptions.
1213 break; /* garbage was sent */
1214 request
= SB_GET(); /* get will/wont */
1217 break; /* another garbage check */
1219 if (request
== LM_SLC
) { /* SLC is not preceeded by WILL or WONT */
1221 * Process suboption buffer of slc's
1224 do_opt_slc(subpointer
, subend
- subpointer
);
1227 } else if (request
== LM_MODE
) {
1230 useeditmode
= SB_GET(); /* get mode flag */
1231 clientstat(LM_MODE
, 0, 0);
1237 switch (SB_GET()) { /* what suboption? */
1238 case LM_FORWARDMASK
:
1240 * According to spec, only server can send request for
1241 * forwardmask, and client can only return a positive response.
1242 * So don't worry about it.
1249 } /* end of case TELOPT_LINEMODE */
1251 case TELOPT_STATUS
: {
1259 if (my_state_is_will(TELOPT_STATUS
))
1270 } /* end of case TELOPT_STATUS */
1272 case TELOPT_XDISPLOC
: {
1273 if (SB_EOF() || SB_GET() != TELQUAL_IS
)
1275 settimer(xdisplocsubopt
);
1276 subpointer
[SB_LEN()] = '\0';
1277 (void)setenv("DISPLAY", (char *)subpointer
, 1);
1279 } /* end of case TELOPT_XDISPLOC */
1281 #ifdef TELOPT_NEW_ENVIRON
1282 case TELOPT_NEW_ENVIRON
:
1284 case TELOPT_OLD_ENVIRON
: {
1286 register char *cp
, *varp
, *valp
;
1291 if (c
== TELQUAL_IS
) {
1292 if (subchar
== TELOPT_OLD_ENVIRON
)
1293 settimer(oenvironsubopt
);
1295 settimer(environsubopt
);
1296 } else if (c
!= TELQUAL_INFO
) {
1300 #ifdef TELOPT_NEW_ENVIRON
1301 if (subchar
== TELOPT_NEW_ENVIRON
) {
1304 if ((c
== NEW_ENV_VAR
) || (c
== ENV_USERVAR
))
1312 * We only want to do this if we haven't already decided
1313 * whether or not the other side has its VALUE and VAR
1317 register int last
= -1; /* invalid value */
1319 int got_var
= 0, got_value
= 0, got_uservar
= 0;
1322 * The other side might have its VALUE and VAR values
1323 * reversed. To be interoperable, we need to determine
1324 * which way it is. If the first recognized character
1325 * is a VAR or VALUE, then that will tell us what
1326 * type of client it is. If the fist recognized
1327 * character is a USERVAR, then we continue scanning
1328 * the suboption looking for two consecutive
1329 * VAR or VALUE fields. We should not get two
1330 * consecutive VALUE fields, so finding two
1331 * consecutive VALUE or VAR fields will tell us
1332 * what the client is.
1339 if (last
< 0 || last
== OLD_ENV_VAR
1340 || (empty
&& (last
== OLD_ENV_VALUE
)))
1346 if (last
< 0 || last
== OLD_ENV_VALUE
1347 || (empty
&& (last
== OLD_ENV_VAR
)))
1348 goto env_ovar_wrong
;
1350 last
= OLD_ENV_VALUE
;
1353 /* count strings of USERVAR as one */
1354 if (last
!= ENV_USERVAR
)
1357 if (last
== OLD_ENV_VALUE
)
1359 if (last
== OLD_ENV_VAR
)
1360 goto env_ovar_wrong
;
1375 if (last
== OLD_ENV_VALUE
)
1377 if (last
== OLD_ENV_VAR
)
1378 goto env_ovar_wrong
;
1381 * Ok, the first thing was a USERVAR, and there
1382 * are not two consecutive VAR or VALUE commands,
1383 * and none of the VAR or VALUE commands are empty.
1384 * If the client has sent us a well-formed option,
1385 * then the number of VALUEs received should always
1386 * be less than or equal to the number of VARs and
1387 * USERVARs received.
1389 * If we got exactly as many VALUEs as VARs and
1390 * USERVARs, the client has the same definitions.
1392 * If we got exactly as many VARs as VALUEs and
1393 * USERVARS, the client has reversed definitions.
1395 if (got_uservar
+ got_var
== got_value
) {
1397 env_ovar
= OLD_ENV_VAR
;
1398 env_ovalue
= OLD_ENV_VALUE
;
1399 } else if (got_uservar
+ got_value
== got_var
) {
1401 env_ovar
= OLD_ENV_VALUE
;
1402 env_ovalue
= OLD_ENV_VAR
;
1403 DIAG(TD_OPTIONS
, {sprintf(nfrontp
,
1404 "ENVIRON VALUE and VAR are reversed!\r\n");
1405 nfrontp
+= strlen(nfrontp
);});
1414 if ((c
== env_ovar
) || (c
== ENV_USERVAR
))
1422 cp
= varp
= (char *)subpointer
;
1427 if (subchar
== TELOPT_OLD_ENVIRON
) {
1430 else if (c
== env_ovalue
)
1437 cp
= valp
= (char *)subpointer
;
1444 (void)setenv(varp
, valp
, 1);
1447 cp
= varp
= (char *)subpointer
;
1463 (void)setenv(varp
, valp
, 1);
1467 } /* end of case TELOPT_NEW_ENVIRON */
1468 #if defined(AUTHENTICATION)
1469 case TELOPT_AUTHENTICATION
:
1476 * These are sent by us and cannot be sent by
1481 auth_is(subpointer
, SB_LEN());
1484 auth_name(subpointer
, SB_LEN());
1490 case TELOPT_ENCRYPT
:
1494 case ENCRYPT_SUPPORT
:
1495 encrypt_support(subpointer
, SB_LEN());
1498 encrypt_is(subpointer
, SB_LEN());
1501 encrypt_reply(subpointer
, SB_LEN());
1504 encrypt_start(subpointer
, SB_LEN());
1509 case ENCRYPT_REQSTART
:
1510 encrypt_request_start(subpointer
, SB_LEN());
1512 case ENCRYPT_REQEND
:
1514 * We can always send an REQEND so that we cannot
1515 * get stuck encrypting. We should only get this
1516 * if we have been able to get in the correct mode
1519 encrypt_request_end();
1521 case ENCRYPT_ENC_KEYID
:
1522 encrypt_enc_keyid(subpointer
, SB_LEN());
1524 case ENCRYPT_DEC_KEYID
:
1525 encrypt_dec_keyid(subpointer
, SB_LEN());
1531 #endif /* ENCRYPTION */
1535 } /* end of switch */
1537 } /* end of suboption */
1542 clientstat(TELOPT_LINEMODE
, WILL
, 0);
1545 #define ADD(c) *ncp++ = c
1546 #define ADD_DATA(c) { *ncp++ = c; if (c == SE || c == IAC) *ncp++ = c; }
1550 unsigned char statusbuf
[256];
1551 register unsigned char *ncp
;
1552 register unsigned char i
;
1556 netflush(); /* get rid of anything waiting to go out */
1564 * We check the want_state rather than the current state,
1565 * because if we received a DO/WILL for an option that we
1566 * don't support, and the other side didn't send a DONT/WONT
1567 * in response to our WONT/DONT, then the "state" will be
1568 * WILL/DO, and the "want_state" will be WONT/DONT. We
1569 * need to go by the latter.
1571 for (i
= 0; i
< (unsigned char)NTELOPTS
; i
++) {
1572 if (my_want_state_is_will(i
)) {
1576 if (his_want_state_is_will(i
)) {
1582 if (his_want_state_is_will(TELOPT_LFLOW
)) {
1592 if (restartany
>= 0) {
1596 ADD(LFLOW_RESTART_ANY
);
1598 ADD(LFLOW_RESTART_XON
);
1605 if (his_want_state_is_will(TELOPT_LINEMODE
)) {
1606 unsigned char *cp
, *cpe
;
1610 ADD(TELOPT_LINEMODE
);
1616 ADD(TELOPT_LINEMODE
);
1621 for (cpe
= cp
+ len
; cp
< cpe
; cp
++)
1625 #endif /* LINEMODE */
1630 writenet(statusbuf
, ncp
- statusbuf
);
1631 netflush(); /* Send it on its way */
1634 {printsub('>', statusbuf
, ncp
- statusbuf
); netflush();});