]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - crypto/telnet/telnetd/state.c
unfinished sblive driver, playback/mixer only for now - not enabled in
[FreeBSD/FreeBSD.git] / crypto / telnet / telnetd / state.c
1 /*
2  * Copyright (c) 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
20  *
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
31  * SUCH DAMAGE.
32  */
33
34 #ifndef lint
35 #if 0
36 static const char sccsid[] = "@(#)state.c       8.5 (Berkeley) 5/30/95";
37 #endif
38 static const char rcsid[] =
39   "$FreeBSD$";
40 #endif /* not lint */
41
42 #include "telnetd.h"
43 #if     defined(AUTHENTICATION)
44 #include <libtelnet/auth.h>
45 #endif
46 #if     defined(ENCRYPTION)
47 #include <libtelnet/encrypt.h>
48 #endif
49
50 unsigned char   doopt[] = { IAC, DO, '%', 'c', 0 };
51 unsigned char   dont[] = { IAC, DONT, '%', 'c', 0 };
52 unsigned char   will[] = { IAC, WILL, '%', 'c', 0 };
53 unsigned char   wont[] = { IAC, WONT, '%', 'c', 0 };
54 int     not42 = 1;
55
56 /*
57  * Buffer for sub-options, and macros
58  * for suboptions buffer manipulations
59  */
60 unsigned char subbuffer[512], *subpointer= subbuffer, *subend= subbuffer;
61
62 #define SB_CLEAR()      subpointer = subbuffer
63 #define SB_TERM()       { subend = subpointer; SB_CLEAR(); }
64 #define SB_ACCUM(c)     if (subpointer < (subbuffer+sizeof subbuffer)) { \
65                                 *subpointer++ = (c); \
66                         }
67 #define SB_GET()        ((*subpointer++)&0xff)
68 #define SB_EOF()        (subpointer >= subend)
69 #define SB_LEN()        (subend - subpointer)
70
71 #ifdef  ENV_HACK
72 unsigned char *subsave;
73 #define SB_SAVE()       subsave = subpointer;
74 #define SB_RESTORE()    subpointer = subsave;
75 #endif
76
77
78 /*
79  * State for recv fsm
80  */
81 #define TS_DATA         0       /* base state */
82 #define TS_IAC          1       /* look for double IAC's */
83 #define TS_CR           2       /* CR-LF ->'s CR */
84 #define TS_SB           3       /* throw away begin's... */
85 #define TS_SE           4       /* ...end's (suboption negotiation) */
86 #define TS_WILL         5       /* will option negotiation */
87 #define TS_WONT         6       /* wont " */
88 #define TS_DO           7       /* do " */
89 #define TS_DONT         8       /* dont " */
90
91         void
92 telrcv()
93 {
94         register int c;
95         static int state = TS_DATA;
96 #if     defined(CRAY2) && defined(UNICOS5)
97         char *opfrontp = pfrontp;
98 #endif
99
100         while (ncc > 0) {
101                 if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
102                         break;
103                 c = *netip++ & 0377, ncc--;
104 #ifdef  ENCRYPTION
105                 if (decrypt_input)
106                         c = (*decrypt_input)(c);
107 #endif  /* ENCRYPTION */
108                 switch (state) {
109
110                 case TS_CR:
111                         state = TS_DATA;
112                         /* Strip off \n or \0 after a \r */
113                         if ((c == 0) || (c == '\n')) {
114                                 break;
115                         }
116                         /* FALL THROUGH */
117
118                 case TS_DATA:
119                         if (c == IAC) {
120                                 state = TS_IAC;
121                                 break;
122                         }
123                         /*
124                          * We now map \r\n ==> \r for pragmatic reasons.
125                          * Many client implementations send \r\n when
126                          * the user hits the CarriageReturn key.
127                          *
128                          * We USED to map \r\n ==> \n, since \r\n says
129                          * that we want to be in column 1 of the next
130                          * printable line, and \n is the standard
131                          * unix way of saying that (\r is only good
132                          * if CRMOD is set, which it normally is).
133                          */
134                         if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) {
135                                 int nc = *netip;
136 #ifdef  ENCRYPTION
137                                 if (decrypt_input)
138                                         nc = (*decrypt_input)(nc & 0xff);
139 #endif  /* ENCRYPTION */
140 #ifdef  LINEMODE
141                                 /*
142                                  * If we are operating in linemode,
143                                  * convert to local end-of-line.
144                                  */
145                                 if (linemode && (ncc > 0) && (('\n' == nc) ||
146                                          ((0 == nc) && tty_iscrnl())) ) {
147                                         netip++; ncc--;
148                                         c = '\n';
149                                 } else
150 #endif
151                                 {
152 #ifdef  ENCRYPTION
153                                         if (decrypt_input)
154                                                 (void)(*decrypt_input)(-1);
155 #endif  /* ENCRYPTION */
156                                         state = TS_CR;
157                                 }
158                         }
159                         *pfrontp++ = c;
160                         break;
161
162                 case TS_IAC:
163 gotiac:                 switch (c) {
164
165                         /*
166                          * Send the process on the pty side an
167                          * interrupt.  Do this with a NULL or
168                          * interrupt char; depending on the tty mode.
169                          */
170                         case IP:
171                                 DIAG(TD_OPTIONS,
172                                         printoption("td: recv IAC", c));
173                                 interrupt();
174                                 break;
175
176                         case BREAK:
177                                 DIAG(TD_OPTIONS,
178                                         printoption("td: recv IAC", c));
179                                 sendbrk();
180                                 break;
181
182                         /*
183                          * Are You There?
184                          */
185                         case AYT:
186                                 DIAG(TD_OPTIONS,
187                                         printoption("td: recv IAC", c));
188                                 recv_ayt();
189                                 break;
190
191                         /*
192                          * Abort Output
193                          */
194                         case AO:
195                             {
196                                 DIAG(TD_OPTIONS,
197                                         printoption("td: recv IAC", c));
198                                 ptyflush();     /* half-hearted */
199                                 init_termbuf();
200
201                                 if (slctab[SLC_AO].sptr &&
202                                     *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) {
203                                     *pfrontp++ =
204                                         (unsigned char)*slctab[SLC_AO].sptr;
205                                 }
206
207                                 netclear();     /* clear buffer back */
208                                 *nfrontp++ = IAC;
209                                 *nfrontp++ = DM;
210                                 neturg = nfrontp-1; /* off by one XXX */
211                                 DIAG(TD_OPTIONS,
212                                         printoption("td: send IAC", DM));
213                                 break;
214                             }
215
216                         /*
217                          * Erase Character and
218                          * Erase Line
219                          */
220                         case EC:
221                         case EL:
222                             {
223                                 cc_t ch;
224
225                                 DIAG(TD_OPTIONS,
226                                         printoption("td: recv IAC", c));
227                                 ptyflush();     /* half-hearted */
228                                 init_termbuf();
229                                 if (c == EC)
230                                         ch = *slctab[SLC_EC].sptr;
231                                 else
232                                         ch = *slctab[SLC_EL].sptr;
233                                 if (ch != (cc_t)(_POSIX_VDISABLE))
234                                         *pfrontp++ = (unsigned char)ch;
235                                 break;
236                             }
237
238                         /*
239                          * Check for urgent data...
240                          */
241                         case DM:
242                                 DIAG(TD_OPTIONS,
243                                         printoption("td: recv IAC", c));
244                                 SYNCHing = stilloob(net);
245                                 settimer(gotDM);
246                                 break;
247
248
249                         /*
250                          * Begin option subnegotiation...
251                          */
252                         case SB:
253                                 state = TS_SB;
254                                 SB_CLEAR();
255                                 continue;
256
257                         case WILL:
258                                 state = TS_WILL;
259                                 continue;
260
261                         case WONT:
262                                 state = TS_WONT;
263                                 continue;
264
265                         case DO:
266                                 state = TS_DO;
267                                 continue;
268
269                         case DONT:
270                                 state = TS_DONT;
271                                 continue;
272                         case EOR:
273                                 if (his_state_is_will(TELOPT_EOR))
274                                         doeof();
275                                 break;
276
277                         /*
278                          * Handle RFC 10xx Telnet linemode option additions
279                          * to command stream (EOF, SUSP, ABORT).
280                          */
281                         case xEOF:
282                                 doeof();
283                                 break;
284
285                         case SUSP:
286                                 sendsusp();
287                                 break;
288
289                         case ABORT:
290                                 sendbrk();
291                                 break;
292
293                         case IAC:
294                                 *pfrontp++ = c;
295                                 break;
296                         }
297                         state = TS_DATA;
298                         break;
299
300                 case TS_SB:
301                         if (c == IAC) {
302                                 state = TS_SE;
303                         } else {
304                                 SB_ACCUM(c);
305                         }
306                         break;
307
308                 case TS_SE:
309                         if (c != SE) {
310                                 if (c != IAC) {
311                                         /*
312                                          * bad form of suboption negotiation.
313                                          * handle it in such a way as to avoid
314                                          * damage to local state.  Parse
315                                          * suboption buffer found so far,
316                                          * then treat remaining stream as
317                                          * another command sequence.
318                                          */
319
320                                         /* for DIAGNOSTICS */
321                                         SB_ACCUM(IAC);
322                                         SB_ACCUM(c);
323                                         subpointer -= 2;
324
325                                         SB_TERM();
326                                         suboption();
327                                         state = TS_IAC;
328                                         goto gotiac;
329                                 }
330                                 SB_ACCUM(c);
331                                 state = TS_SB;
332                         } else {
333                                 /* for DIAGNOSTICS */
334                                 SB_ACCUM(IAC);
335                                 SB_ACCUM(SE);
336                                 subpointer -= 2;
337
338                                 SB_TERM();
339                                 suboption();    /* handle sub-option */
340                                 state = TS_DATA;
341                         }
342                         break;
343
344                 case TS_WILL:
345                         willoption(c);
346                         state = TS_DATA;
347                         continue;
348
349                 case TS_WONT:
350                         wontoption(c);
351                         state = TS_DATA;
352                         continue;
353
354                 case TS_DO:
355                         dooption(c);
356                         state = TS_DATA;
357                         continue;
358
359                 case TS_DONT:
360                         dontoption(c);
361                         state = TS_DATA;
362                         continue;
363
364                 default:
365                         syslog(LOG_ERR, "panic state=%d", state);
366                         printf("telnetd: panic state=%d\n", state);
367                         exit(1);
368                 }
369         }
370 #if     defined(CRAY2) && defined(UNICOS5)
371         if (!linemode) {
372                 char    xptyobuf[BUFSIZ+NETSLOP];
373                 char    xbuf2[BUFSIZ];
374                 register char *cp;
375                 int n = pfrontp - opfrontp, oc;
376                 memmove(xptyobuf, opfrontp, n);
377                 pfrontp = opfrontp;
378                 pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP,
379                                         xbuf2, &oc, BUFSIZ);
380                 for (cp = xbuf2; oc > 0; --oc)
381                         if ((*nfrontp++ = *cp++) == IAC)
382                                 *nfrontp++ = IAC;
383         }
384 #endif  /* defined(CRAY2) && defined(UNICOS5) */
385 }  /* end of telrcv */
386
387 /*
388  * The will/wont/do/dont state machines are based on Dave Borman's
389  * Telnet option processing state machine.
390  *
391  * These correspond to the following states:
392  *      my_state = the last negotiated state
393  *      want_state = what I want the state to go to
394  *      want_resp = how many requests I have sent
395  * All state defaults are negative, and resp defaults to 0.
396  *
397  * When initiating a request to change state to new_state:
398  *
399  * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) {
400  *      do nothing;
401  * } else {
402  *      want_state = new_state;
403  *      send new_state;
404  *      want_resp++;
405  * }
406  *
407  * When receiving new_state:
408  *
409  * if (want_resp) {
410  *      want_resp--;
411  *      if (want_resp && (new_state == my_state))
412  *              want_resp--;
413  * }
414  * if ((want_resp == 0) && (new_state != want_state)) {
415  *      if (ok_to_switch_to new_state)
416  *              want_state = new_state;
417  *      else
418  *              want_resp++;
419  *      send want_state;
420  * }
421  * my_state = new_state;
422  *
423  * Note that new_state is implied in these functions by the function itself.
424  * will and do imply positive new_state, wont and dont imply negative.
425  *
426  * Finally, there is one catch.  If we send a negative response to a
427  * positive request, my_state will be the positive while want_state will
428  * remain negative.  my_state will revert to negative when the negative
429  * acknowlegment arrives from the peer.  Thus, my_state generally tells
430  * us not only the last negotiated state, but also tells us what the peer
431  * wants to be doing as well.  It is important to understand this difference
432  * as we may wish to be processing data streams based on our desired state
433  * (want_state) or based on what the peer thinks the state is (my_state).
434  *
435  * This all works fine because if the peer sends a positive request, the data
436  * that we receive prior to negative acknowlegment will probably be affected
437  * by the positive state, and we can process it as such (if we can; if we
438  * can't then it really doesn't matter).  If it is that important, then the
439  * peer probably should be buffering until this option state negotiation
440  * is complete.
441  *
442  */
443         void
444 send_do(option, init)
445         int option, init;
446 {
447         if (init) {
448                 if ((do_dont_resp[option] == 0 && his_state_is_will(option)) ||
449                     his_want_state_is_will(option))
450                         return;
451                 /*
452                  * Special case for TELOPT_TM:  We send a DO, but pretend
453                  * that we sent a DONT, so that we can send more DOs if
454                  * we want to.
455                  */
456                 if (option == TELOPT_TM)
457                         set_his_want_state_wont(option);
458                 else
459                         set_his_want_state_will(option);
460                 do_dont_resp[option]++;
461         }
462         (void) sprintf(nfrontp, (char *)doopt, option);
463         nfrontp += sizeof (dont) - 2;
464
465         DIAG(TD_OPTIONS, printoption("td: send do", option));
466 }
467
468 #ifdef  AUTHENTICATION
469 extern void auth_request();
470 #endif
471 #ifdef  LINEMODE
472 extern void doclientstat();
473 #endif
474 #ifdef  ENCRYPTION
475 extern void encrypt_send_support();
476 #endif  /* ENCRYPTION */
477
478         void
479 willoption(option)
480         int option;
481 {
482         int changeok = 0;
483         void (*func)() = 0;
484
485         /*
486          * process input from peer.
487          */
488
489         DIAG(TD_OPTIONS, printoption("td: recv will", option));
490
491         if (do_dont_resp[option]) {
492                 do_dont_resp[option]--;
493                 if (do_dont_resp[option] && his_state_is_will(option))
494                         do_dont_resp[option]--;
495         }
496         if (do_dont_resp[option] == 0) {
497             if (his_want_state_is_wont(option)) {
498                 switch (option) {
499
500                 case TELOPT_BINARY:
501                         init_termbuf();
502                         tty_binaryin(1);
503                         set_termbuf();
504                         changeok++;
505                         break;
506
507                 case TELOPT_ECHO:
508                         /*
509                          * See comments below for more info.
510                          */
511                         not42 = 0;      /* looks like a 4.2 system */
512                         break;
513
514                 case TELOPT_TM:
515 #if     defined(LINEMODE) && defined(KLUDGELINEMODE)
516                         /*
517                          * This telnetd implementation does not really
518                          * support timing marks, it just uses them to
519                          * support the kludge linemode stuff.  If we
520                          * receive a will or wont TM in response to our
521                          * do TM request that may have been sent to
522                          * determine kludge linemode support, process
523                          * it, otherwise TM should get a negative
524                          * response back.
525                          */
526                         /*
527                          * Handle the linemode kludge stuff.
528                          * If we are not currently supporting any
529                          * linemode at all, then we assume that this
530                          * is the client telling us to use kludge
531                          * linemode in response to our query.  Set the
532                          * linemode type that is to be supported, note
533                          * that the client wishes to use linemode, and
534                          * eat the will TM as though it never arrived.
535                          */
536                         if (lmodetype < KLUDGE_LINEMODE) {
537                                 lmodetype = KLUDGE_LINEMODE;
538                                 clientstat(TELOPT_LINEMODE, WILL, 0);
539                                 send_wont(TELOPT_SGA, 1);
540                         } else if (lmodetype == NO_AUTOKLUDGE) {
541                                 lmodetype = KLUDGE_OK;
542                         }
543 #endif  /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
544                         /*
545                          * We never respond to a WILL TM, and
546                          * we leave the state WONT.
547                          */
548                         return;
549
550                 case TELOPT_LFLOW:
551                         /*
552                          * If we are going to support flow control
553                          * option, then don't worry peer that we can't
554                          * change the flow control characters.
555                          */
556                         slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
557                         slctab[SLC_XON].defset.flag |= SLC_DEFAULT;
558                         slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
559                         slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT;
560                 case TELOPT_TTYPE:
561                 case TELOPT_SGA:
562                 case TELOPT_NAWS:
563                 case TELOPT_TSPEED:
564                 case TELOPT_XDISPLOC:
565                 case TELOPT_NEW_ENVIRON:
566                 case TELOPT_OLD_ENVIRON:
567                         changeok++;
568                         break;
569
570 #ifdef  LINEMODE
571                 case TELOPT_LINEMODE:
572 # ifdef KLUDGELINEMODE
573                         /*
574                          * Note client's desire to use linemode.
575                          */
576                         lmodetype = REAL_LINEMODE;
577 # endif /* KLUDGELINEMODE */
578                         func = doclientstat;
579                         changeok++;
580                         break;
581 #endif  /* LINEMODE */
582
583 #ifdef  AUTHENTICATION
584                 case TELOPT_AUTHENTICATION:
585                         func = auth_request;
586                         changeok++;
587                         break;
588 #endif
589
590 #ifdef  ENCRYPTION
591                 case TELOPT_ENCRYPT:
592                         func = encrypt_send_support;
593                         changeok++;
594                         break;
595 #endif  /* ENCRYPTION */
596
597                 default:
598                         break;
599                 }
600                 if (changeok) {
601                         set_his_want_state_will(option);
602                         send_do(option, 0);
603                 } else {
604                         do_dont_resp[option]++;
605                         send_dont(option, 0);
606                 }
607             } else {
608                 /*
609                  * Option processing that should happen when
610                  * we receive conformation of a change in
611                  * state that we had requested.
612                  */
613                 switch (option) {
614                 case TELOPT_ECHO:
615                         not42 = 0;      /* looks like a 4.2 system */
616                         /*
617                          * Egads, he responded "WILL ECHO".  Turn
618                          * it off right now!
619                          */
620                         send_dont(option, 1);
621                         /*
622                          * "WILL ECHO".  Kludge upon kludge!
623                          * A 4.2 client is now echoing user input at
624                          * the tty.  This is probably undesireable and
625                          * it should be stopped.  The client will
626                          * respond WONT TM to the DO TM that we send to
627                          * check for kludge linemode.  When the WONT TM
628                          * arrives, linemode will be turned off and a
629                          * change propogated to the pty.  This change
630                          * will cause us to process the new pty state
631                          * in localstat(), which will notice that
632                          * linemode is off and send a WILL ECHO
633                          * so that we are properly in character mode and
634                          * all is well.
635                          */
636                         break;
637 #ifdef  LINEMODE
638                 case TELOPT_LINEMODE:
639 # ifdef KLUDGELINEMODE
640                         /*
641                          * Note client's desire to use linemode.
642                          */
643                         lmodetype = REAL_LINEMODE;
644 # endif /* KLUDGELINEMODE */
645                         func = doclientstat;
646                         break;
647 #endif  /* LINEMODE */
648
649 #ifdef  AUTHENTICATION
650                 case TELOPT_AUTHENTICATION:
651                         func = auth_request;
652                         break;
653 #endif
654
655 #ifdef  ENCRYPTION
656                 case TELOPT_ENCRYPT:
657                         func = encrypt_send_support;
658                         break;
659 #endif  /* ENCRYPTION */
660                 case TELOPT_LFLOW:
661                         func = flowstat;
662                         break;
663                 }
664             }
665         }
666         set_his_state_will(option);
667         if (func)
668                 (*func)();
669 }  /* end of willoption */
670
671         void
672 send_dont(option, init)
673         int option, init;
674 {
675         if (init) {
676                 if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) ||
677                     his_want_state_is_wont(option))
678                         return;
679                 set_his_want_state_wont(option);
680                 do_dont_resp[option]++;
681         }
682         (void) sprintf(nfrontp, (char *)dont, option);
683         nfrontp += sizeof (doopt) - 2;
684
685         DIAG(TD_OPTIONS, printoption("td: send dont", option));
686 }
687
688         void
689 wontoption(option)
690         int option;
691 {
692         /*
693          * Process client input.
694          */
695
696         DIAG(TD_OPTIONS, printoption("td: recv wont", option));
697
698         if (do_dont_resp[option]) {
699                 do_dont_resp[option]--;
700                 if (do_dont_resp[option] && his_state_is_wont(option))
701                         do_dont_resp[option]--;
702         }
703         if (do_dont_resp[option] == 0) {
704             if (his_want_state_is_will(option)) {
705                 /* it is always ok to change to negative state */
706                 switch (option) {
707                 case TELOPT_ECHO:
708                         not42 = 1; /* doesn't seem to be a 4.2 system */
709                         break;
710
711                 case TELOPT_BINARY:
712                         init_termbuf();
713                         tty_binaryin(0);
714                         set_termbuf();
715                         break;
716
717 #ifdef  LINEMODE
718                 case TELOPT_LINEMODE:
719 # ifdef KLUDGELINEMODE
720                         /*
721                          * If real linemode is supported, then client is
722                          * asking to turn linemode off.
723                          */
724                         if (lmodetype != REAL_LINEMODE)
725                                 break;
726 # endif /* KLUDGELINEMODE */
727                         clientstat(TELOPT_LINEMODE, WONT, 0);
728                         break;
729 #endif  /* LINEMODE */
730
731                 case TELOPT_TM:
732                         /*
733                          * If we get a WONT TM, and had sent a DO TM,
734                          * don't respond with a DONT TM, just leave it
735                          * as is.  Short circut the state machine to
736                          * achive this.
737                          */
738                         set_his_want_state_wont(TELOPT_TM);
739                         return;
740
741                 case TELOPT_LFLOW:
742                         /*
743                          * If we are not going to support flow control
744                          * option, then let peer know that we can't
745                          * change the flow control characters.
746                          */
747                         slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
748                         slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE;
749                         slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
750                         slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE;
751                         break;
752
753 #if     defined(AUTHENTICATION)
754                 case TELOPT_AUTHENTICATION:
755                         auth_finished(0, AUTH_REJECT);
756                         break;
757 #endif
758
759                 /*
760                  * For options that we might spin waiting for
761                  * sub-negotiation, if the client turns off the
762                  * option rather than responding to the request,
763                  * we have to treat it here as if we got a response
764                  * to the sub-negotiation, (by updating the timers)
765                  * so that we'll break out of the loop.
766                  */
767                 case TELOPT_TTYPE:
768                         settimer(ttypesubopt);
769                         break;
770
771                 case TELOPT_TSPEED:
772                         settimer(tspeedsubopt);
773                         break;
774
775                 case TELOPT_XDISPLOC:
776                         settimer(xdisplocsubopt);
777                         break;
778
779                 case TELOPT_OLD_ENVIRON:
780                         settimer(oenvironsubopt);
781                         break;
782
783                 case TELOPT_NEW_ENVIRON:
784                         settimer(environsubopt);
785                         break;
786
787                 default:
788                         break;
789                 }
790                 set_his_want_state_wont(option);
791                 if (his_state_is_will(option))
792                         send_dont(option, 0);
793             } else {
794                 switch (option) {
795                 case TELOPT_TM:
796 #if     defined(LINEMODE) && defined(KLUDGELINEMODE)
797                         if (lmodetype < NO_AUTOKLUDGE) {
798                                 lmodetype = NO_LINEMODE;
799                                 clientstat(TELOPT_LINEMODE, WONT, 0);
800                                 send_will(TELOPT_SGA, 1);
801                                 send_will(TELOPT_ECHO, 1);
802                         }
803 #endif  /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
804                         break;
805
806 #if     defined(AUTHENTICATION)
807                 case TELOPT_AUTHENTICATION:
808                         auth_finished(0, AUTH_REJECT);
809                         break;
810 #endif
811                 default:
812                         break;
813                 }
814             }
815         }
816         set_his_state_wont(option);
817
818 }  /* end of wontoption */
819
820         void
821 send_will(option, init)
822         int option, init;
823 {
824         if (init) {
825                 if ((will_wont_resp[option] == 0 && my_state_is_will(option))||
826                     my_want_state_is_will(option))
827                         return;
828                 set_my_want_state_will(option);
829                 will_wont_resp[option]++;
830         }
831         (void) sprintf(nfrontp, (char *)will, option);
832         nfrontp += sizeof (doopt) - 2;
833
834         DIAG(TD_OPTIONS, printoption("td: send will", option));
835 }
836
837 #if     !defined(LINEMODE) || !defined(KLUDGELINEMODE)
838 /*
839  * When we get a DONT SGA, we will try once to turn it
840  * back on.  If the other side responds DONT SGA, we
841  * leave it at that.  This is so that when we talk to
842  * clients that understand KLUDGELINEMODE but not LINEMODE,
843  * we'll keep them in char-at-a-time mode.
844  */
845 int turn_on_sga = 0;
846 #endif
847
848         void
849 dooption(option)
850         int option;
851 {
852         int changeok = 0;
853
854         /*
855          * Process client input.
856          */
857
858         DIAG(TD_OPTIONS, printoption("td: recv do", option));
859
860         if (will_wont_resp[option]) {
861                 will_wont_resp[option]--;
862                 if (will_wont_resp[option] && my_state_is_will(option))
863                         will_wont_resp[option]--;
864         }
865         if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) {
866                 switch (option) {
867                 case TELOPT_ECHO:
868 #ifdef  LINEMODE
869 # ifdef KLUDGELINEMODE
870                         if (lmodetype == NO_LINEMODE)
871 # else
872                         if (his_state_is_wont(TELOPT_LINEMODE))
873 # endif
874 #endif
875                         {
876                                 init_termbuf();
877                                 tty_setecho(1);
878                                 set_termbuf();
879                         }
880                         changeok++;
881                         break;
882
883                 case TELOPT_BINARY:
884                         init_termbuf();
885                         tty_binaryout(1);
886                         set_termbuf();
887                         changeok++;
888                         break;
889
890                 case TELOPT_SGA:
891 #if     defined(LINEMODE) && defined(KLUDGELINEMODE)
892                         /*
893                          * If kludge linemode is in use, then we must
894                          * process an incoming do SGA for linemode
895                          * purposes.
896                          */
897                         if (lmodetype == KLUDGE_LINEMODE) {
898                                 /*
899                                  * Receipt of "do SGA" in kludge
900                                  * linemode is the peer asking us to
901                                  * turn off linemode.  Make note of
902                                  * the request.
903                                  */
904                                 clientstat(TELOPT_LINEMODE, WONT, 0);
905                                 /*
906                                  * If linemode did not get turned off
907                                  * then don't tell peer that we did.
908                                  * Breaking here forces a wont SGA to
909                                  * be returned.
910                                  */
911                                 if (linemode)
912                                         break;
913                         }
914 #else
915                         turn_on_sga = 0;
916 #endif  /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
917                         changeok++;
918                         break;
919
920                 case TELOPT_STATUS:
921                         changeok++;
922                         break;
923
924                 case TELOPT_TM:
925                         /*
926                          * Special case for TM.  We send a WILL, but
927                          * pretend we sent a WONT.
928                          */
929                         send_will(option, 0);
930                         set_my_want_state_wont(option);
931                         set_my_state_wont(option);
932                         return;
933
934                 case TELOPT_LOGOUT:
935                         /*
936                          * When we get a LOGOUT option, respond
937                          * with a WILL LOGOUT, make sure that
938                          * it gets written out to the network,
939                          * and then just go away...
940                          */
941                         set_my_want_state_will(TELOPT_LOGOUT);
942                         send_will(TELOPT_LOGOUT, 0);
943                         set_my_state_will(TELOPT_LOGOUT);
944                         (void)netflush();
945                         cleanup(0);
946                         /* NOT REACHED */
947                         break;
948
949 #ifdef  ENCRYPTION
950                 case TELOPT_ENCRYPT:
951                         changeok++;
952                         break;
953 #endif  /* ENCRYPTION */
954                 case TELOPT_LINEMODE:
955                 case TELOPT_TTYPE:
956                 case TELOPT_NAWS:
957                 case TELOPT_TSPEED:
958                 case TELOPT_LFLOW:
959                 case TELOPT_XDISPLOC:
960 #ifdef  TELOPT_ENVIRON
961                 case TELOPT_NEW_ENVIRON:
962 #endif
963                 case TELOPT_OLD_ENVIRON:
964                 default:
965                         break;
966                 }
967                 if (changeok) {
968                         set_my_want_state_will(option);
969                         send_will(option, 0);
970                 } else {
971                         will_wont_resp[option]++;
972                         send_wont(option, 0);
973                 }
974         }
975         set_my_state_will(option);
976
977 }  /* end of dooption */
978
979         void
980 send_wont(option, init)
981         int option, init;
982 {
983         if (init) {
984                 if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) ||
985                     my_want_state_is_wont(option))
986                         return;
987                 set_my_want_state_wont(option);
988                 will_wont_resp[option]++;
989         }
990         (void) sprintf(nfrontp, (char *)wont, option);
991         nfrontp += sizeof (wont) - 2;
992
993         DIAG(TD_OPTIONS, printoption("td: send wont", option));
994 }
995
996         void
997 dontoption(option)
998         int option;
999 {
1000         /*
1001          * Process client input.
1002          */
1003
1004
1005         DIAG(TD_OPTIONS, printoption("td: recv dont", option));
1006
1007         if (will_wont_resp[option]) {
1008                 will_wont_resp[option]--;
1009                 if (will_wont_resp[option] && my_state_is_wont(option))
1010                         will_wont_resp[option]--;
1011         }
1012         if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) {
1013                 switch (option) {
1014                 case TELOPT_BINARY:
1015                         init_termbuf();
1016                         tty_binaryout(0);
1017                         set_termbuf();
1018                         break;
1019
1020                 case TELOPT_ECHO:       /* we should stop echoing */
1021 #ifdef  LINEMODE
1022 # ifdef KLUDGELINEMODE
1023                         if ((lmodetype != REAL_LINEMODE) &&
1024                             (lmodetype != KLUDGE_LINEMODE))
1025 # else
1026                         if (his_state_is_wont(TELOPT_LINEMODE))
1027 # endif
1028 #endif
1029                         {
1030                                 init_termbuf();
1031                                 tty_setecho(0);
1032                                 set_termbuf();
1033                         }
1034                         break;
1035
1036                 case TELOPT_SGA:
1037 #if     defined(LINEMODE) && defined(KLUDGELINEMODE)
1038                         /*
1039                          * If kludge linemode is in use, then we
1040                          * must process an incoming do SGA for
1041                          * linemode purposes.
1042                          */
1043                         if ((lmodetype == KLUDGE_LINEMODE) ||
1044                             (lmodetype == KLUDGE_OK)) {
1045                                 /*
1046                                  * The client is asking us to turn
1047                                  * linemode on.
1048                                  */
1049                                 lmodetype = KLUDGE_LINEMODE;
1050                                 clientstat(TELOPT_LINEMODE, WILL, 0);
1051                                 /*
1052                                  * If we did not turn line mode on,
1053                                  * then what do we say?  Will SGA?
1054                                  * This violates design of telnet.
1055                                  * Gross.  Very Gross.
1056                                  */
1057                         }
1058                         break;
1059 #else
1060                         set_my_want_state_wont(option);
1061                         if (my_state_is_will(option))
1062                                 send_wont(option, 0);
1063                         set_my_state_wont(option);
1064                         if (turn_on_sga ^= 1)
1065                                 send_will(option, 1);
1066                         return;
1067 #endif  /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
1068
1069                 default:
1070                         break;
1071                 }
1072
1073                 set_my_want_state_wont(option);
1074                 if (my_state_is_will(option))
1075                         send_wont(option, 0);
1076         }
1077         set_my_state_wont(option);
1078
1079 }  /* end of dontoption */
1080
1081 #ifdef  ENV_HACK
1082 int env_ovar = -1;
1083 int env_ovalue = -1;
1084 #else   /* ENV_HACK */
1085 # define env_ovar OLD_ENV_VAR
1086 # define env_ovalue OLD_ENV_VALUE
1087 #endif  /* ENV_HACK */
1088
1089 /*
1090  * suboption()
1091  *
1092  *      Look at the sub-option buffer, and try to be helpful to the other
1093  * side.
1094  *
1095  *      Currently we recognize:
1096  *
1097  *      Terminal type is
1098  *      Linemode
1099  *      Window size
1100  *      Terminal speed
1101  */
1102         void
1103 suboption()
1104 {
1105     register int subchar;
1106
1107     DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);});
1108
1109     subchar = SB_GET();
1110     switch (subchar) {
1111     case TELOPT_TSPEED: {
1112         register int xspeed, rspeed;
1113
1114         if (his_state_is_wont(TELOPT_TSPEED))   /* Ignore if option disabled */
1115                 break;
1116
1117         settimer(tspeedsubopt);
1118
1119         if (SB_EOF() || SB_GET() != TELQUAL_IS)
1120                 return;
1121
1122         xspeed = atoi((char *)subpointer);
1123
1124         while (SB_GET() != ',' && !SB_EOF());
1125         if (SB_EOF())
1126                 return;
1127
1128         rspeed = atoi((char *)subpointer);
1129         clientstat(TELOPT_TSPEED, xspeed, rspeed);
1130
1131         break;
1132
1133     }  /* end of case TELOPT_TSPEED */
1134
1135     case TELOPT_TTYPE: {                /* Yaaaay! */
1136         static char terminalname[41];
1137
1138         if (his_state_is_wont(TELOPT_TTYPE))    /* Ignore if option disabled */
1139                 break;
1140         settimer(ttypesubopt);
1141
1142         if (SB_EOF() || SB_GET() != TELQUAL_IS) {
1143             return;             /* ??? XXX but, this is the most robust */
1144         }
1145
1146         terminaltype = terminalname;
1147
1148         while ((terminaltype < (terminalname + sizeof terminalname-1)) &&
1149                                                                     !SB_EOF()) {
1150             register int c;
1151
1152             c = SB_GET();
1153             if (isupper(c)) {
1154                 c = tolower(c);
1155             }
1156             *terminaltype++ = c;    /* accumulate name */
1157         }
1158         *terminaltype = 0;
1159         terminaltype = terminalname;
1160         break;
1161     }  /* end of case TELOPT_TTYPE */
1162
1163     case TELOPT_NAWS: {
1164         register int xwinsize, ywinsize;
1165
1166         if (his_state_is_wont(TELOPT_NAWS))     /* Ignore if option disabled */
1167                 break;
1168
1169         if (SB_EOF())
1170                 return;
1171         xwinsize = SB_GET() << 8;
1172         if (SB_EOF())
1173                 return;
1174         xwinsize |= SB_GET();
1175         if (SB_EOF())
1176                 return;
1177         ywinsize = SB_GET() << 8;
1178         if (SB_EOF())
1179                 return;
1180         ywinsize |= SB_GET();
1181         clientstat(TELOPT_NAWS, xwinsize, ywinsize);
1182
1183         break;
1184
1185     }  /* end of case TELOPT_NAWS */
1186
1187 #ifdef  LINEMODE
1188     case TELOPT_LINEMODE: {
1189         register int request;
1190
1191         if (his_state_is_wont(TELOPT_LINEMODE)) /* Ignore if option disabled */
1192                 break;
1193         /*
1194          * Process linemode suboptions.
1195          */
1196         if (SB_EOF())
1197             break;              /* garbage was sent */
1198         request = SB_GET();     /* get will/wont */
1199
1200         if (SB_EOF())
1201             break;              /* another garbage check */
1202
1203         if (request == LM_SLC) {  /* SLC is not preceeded by WILL or WONT */
1204                 /*
1205                  * Process suboption buffer of slc's
1206                  */
1207                 start_slc(1);
1208                 do_opt_slc(subpointer, subend - subpointer);
1209                 (void) end_slc(0);
1210                 break;
1211         } else if (request == LM_MODE) {
1212                 if (SB_EOF())
1213                     return;
1214                 useeditmode = SB_GET();  /* get mode flag */
1215                 clientstat(LM_MODE, 0, 0);
1216                 break;
1217         }
1218
1219         if (SB_EOF())
1220             break;
1221         switch (SB_GET()) {  /* what suboption? */
1222         case LM_FORWARDMASK:
1223                 /*
1224                  * According to spec, only server can send request for
1225                  * forwardmask, and client can only return a positive response.
1226                  * So don't worry about it.
1227                  */
1228
1229         default:
1230                 break;
1231         }
1232         break;
1233     }  /* end of case TELOPT_LINEMODE */
1234 #endif
1235     case TELOPT_STATUS: {
1236         int mode;
1237
1238         if (SB_EOF())
1239             break;
1240         mode = SB_GET();
1241         switch (mode) {
1242         case TELQUAL_SEND:
1243             if (my_state_is_will(TELOPT_STATUS))
1244                 send_status();
1245             break;
1246
1247         case TELQUAL_IS:
1248             break;
1249
1250         default:
1251             break;
1252         }
1253         break;
1254     }  /* end of case TELOPT_STATUS */
1255
1256     case TELOPT_XDISPLOC: {
1257         if (SB_EOF() || SB_GET() != TELQUAL_IS)
1258                 return;
1259         settimer(xdisplocsubopt);
1260         subpointer[SB_LEN()] = '\0';
1261         (void)setenv("DISPLAY", (char *)subpointer, 1);
1262         break;
1263     }  /* end of case TELOPT_XDISPLOC */
1264
1265 #ifdef  TELOPT_NEW_ENVIRON
1266     case TELOPT_NEW_ENVIRON:
1267 #endif
1268     case TELOPT_OLD_ENVIRON: {
1269         register int c;
1270         register char *cp, *varp, *valp;
1271
1272         if (SB_EOF())
1273                 return;
1274         c = SB_GET();
1275         if (c == TELQUAL_IS) {
1276                 if (subchar == TELOPT_OLD_ENVIRON)
1277                         settimer(oenvironsubopt);
1278                 else
1279                         settimer(environsubopt);
1280         } else if (c != TELQUAL_INFO) {
1281                 return;
1282         }
1283
1284 #ifdef  TELOPT_NEW_ENVIRON
1285         if (subchar == TELOPT_NEW_ENVIRON) {
1286             while (!SB_EOF()) {
1287                 c = SB_GET();
1288                 if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR))
1289                         break;
1290             }
1291         } else
1292 #endif
1293         {
1294 #ifdef  ENV_HACK
1295             /*
1296              * We only want to do this if we haven't already decided
1297              * whether or not the other side has its VALUE and VAR
1298              * reversed.
1299              */
1300             if (env_ovar < 0) {
1301                 register int last = -1;         /* invalid value */
1302                 int empty = 0;
1303                 int got_var = 0, got_value = 0, got_uservar = 0;
1304
1305                 /*
1306                  * The other side might have its VALUE and VAR values
1307                  * reversed.  To be interoperable, we need to determine
1308                  * which way it is.  If the first recognized character
1309                  * is a VAR or VALUE, then that will tell us what
1310                  * type of client it is.  If the fist recognized
1311                  * character is a USERVAR, then we continue scanning
1312                  * the suboption looking for two consecutive
1313                  * VAR or VALUE fields.  We should not get two
1314                  * consecutive VALUE fields, so finding two
1315                  * consecutive VALUE or VAR fields will tell us
1316                  * what the client is.
1317                  */
1318                 SB_SAVE();
1319                 while (!SB_EOF()) {
1320                         c = SB_GET();
1321                         switch(c) {
1322                         case OLD_ENV_VAR:
1323                                 if (last < 0 || last == OLD_ENV_VAR
1324                                     || (empty && (last == OLD_ENV_VALUE)))
1325                                         goto env_ovar_ok;
1326                                 got_var++;
1327                                 last = OLD_ENV_VAR;
1328                                 break;
1329                         case OLD_ENV_VALUE:
1330                                 if (last < 0 || last == OLD_ENV_VALUE
1331                                     || (empty && (last == OLD_ENV_VAR)))
1332                                         goto env_ovar_wrong;
1333                                 got_value++;
1334                                 last = OLD_ENV_VALUE;
1335                                 break;
1336                         case ENV_USERVAR:
1337                                 /* count strings of USERVAR as one */
1338                                 if (last != ENV_USERVAR)
1339                                         got_uservar++;
1340                                 if (empty) {
1341                                         if (last == OLD_ENV_VALUE)
1342                                                 goto env_ovar_ok;
1343                                         if (last == OLD_ENV_VAR)
1344                                                 goto env_ovar_wrong;
1345                                 }
1346                                 last = ENV_USERVAR;
1347                                 break;
1348                         case ENV_ESC:
1349                                 if (!SB_EOF())
1350                                         c = SB_GET();
1351                                 /* FALL THROUGH */
1352                         default:
1353                                 empty = 0;
1354                                 continue;
1355                         }
1356                         empty = 1;
1357                 }
1358                 if (empty) {
1359                         if (last == OLD_ENV_VALUE)
1360                                 goto env_ovar_ok;
1361                         if (last == OLD_ENV_VAR)
1362                                 goto env_ovar_wrong;
1363                 }
1364                 /*
1365                  * Ok, the first thing was a USERVAR, and there
1366                  * are not two consecutive VAR or VALUE commands,
1367                  * and none of the VAR or VALUE commands are empty.
1368                  * If the client has sent us a well-formed option,
1369                  * then the number of VALUEs received should always
1370                  * be less than or equal to the number of VARs and
1371                  * USERVARs received.
1372                  *
1373                  * If we got exactly as many VALUEs as VARs and
1374                  * USERVARs, the client has the same definitions.
1375                  *
1376                  * If we got exactly as many VARs as VALUEs and
1377                  * USERVARS, the client has reversed definitions.
1378                  */
1379                 if (got_uservar + got_var == got_value) {
1380             env_ovar_ok:
1381                         env_ovar = OLD_ENV_VAR;
1382                         env_ovalue = OLD_ENV_VALUE;
1383                 } else if (got_uservar + got_value == got_var) {
1384             env_ovar_wrong:
1385                         env_ovar = OLD_ENV_VALUE;
1386                         env_ovalue = OLD_ENV_VAR;
1387                         DIAG(TD_OPTIONS, {sprintf(nfrontp,
1388                                 "ENVIRON VALUE and VAR are reversed!\r\n");
1389                                 nfrontp += strlen(nfrontp);});
1390
1391                 }
1392             }
1393             SB_RESTORE();
1394 #endif
1395
1396             while (!SB_EOF()) {
1397                 c = SB_GET();
1398                 if ((c == env_ovar) || (c == ENV_USERVAR))
1399                         break;
1400             }
1401         }
1402
1403         if (SB_EOF())
1404                 return;
1405
1406         cp = varp = (char *)subpointer;
1407         valp = 0;
1408
1409         while (!SB_EOF()) {
1410                 c = SB_GET();
1411                 if (subchar == TELOPT_OLD_ENVIRON) {
1412                         if (c == env_ovar)
1413                                 c = NEW_ENV_VAR;
1414                         else if (c == env_ovalue)
1415                                 c = NEW_ENV_VALUE;
1416                 }
1417                 switch (c) {
1418
1419                 case NEW_ENV_VALUE:
1420                         *cp = '\0';
1421                         cp = valp = (char *)subpointer;
1422                         break;
1423
1424                 case NEW_ENV_VAR:
1425                 case ENV_USERVAR:
1426                         *cp = '\0';
1427                         if (valp)
1428                                 (void)setenv(varp, valp, 1);
1429                         else
1430                                 unsetenv(varp);
1431                         cp = varp = (char *)subpointer;
1432                         valp = 0;
1433                         break;
1434
1435                 case ENV_ESC:
1436                         if (SB_EOF())
1437                                 break;
1438                         c = SB_GET();
1439                         /* FALL THROUGH */
1440                 default:
1441                         *cp++ = c;
1442                         break;
1443                 }
1444         }
1445         *cp = '\0';
1446         if (valp)
1447                 (void)setenv(varp, valp, 1);
1448         else
1449                 unsetenv(varp);
1450         break;
1451     }  /* end of case TELOPT_NEW_ENVIRON */
1452 #if     defined(AUTHENTICATION)
1453     case TELOPT_AUTHENTICATION:
1454         if (SB_EOF())
1455                 break;
1456         switch(SB_GET()) {
1457         case TELQUAL_SEND:
1458         case TELQUAL_REPLY:
1459                 /*
1460                  * These are sent by us and cannot be sent by
1461                  * the client.
1462                  */
1463                 break;
1464         case TELQUAL_IS:
1465                 auth_is(subpointer, SB_LEN());
1466                 break;
1467         case TELQUAL_NAME:
1468                 auth_name(subpointer, SB_LEN());
1469                 break;
1470         }
1471         break;
1472 #endif
1473 #ifdef  ENCRYPTION
1474     case TELOPT_ENCRYPT:
1475         if (SB_EOF())
1476                 break;
1477         switch(SB_GET()) {
1478         case ENCRYPT_SUPPORT:
1479                 encrypt_support(subpointer, SB_LEN());
1480                 break;
1481         case ENCRYPT_IS:
1482                 encrypt_is(subpointer, SB_LEN());
1483                 break;
1484         case ENCRYPT_REPLY:
1485                 encrypt_reply(subpointer, SB_LEN());
1486                 break;
1487         case ENCRYPT_START:
1488                 encrypt_start(subpointer, SB_LEN());
1489                 break;
1490         case ENCRYPT_END:
1491                 encrypt_end();
1492                 break;
1493         case ENCRYPT_REQSTART:
1494                 encrypt_request_start(subpointer, SB_LEN());
1495                 break;
1496         case ENCRYPT_REQEND:
1497                 /*
1498                  * We can always send an REQEND so that we cannot
1499                  * get stuck encrypting.  We should only get this
1500                  * if we have been able to get in the correct mode
1501                  * anyhow.
1502                  */
1503                 encrypt_request_end();
1504                 break;
1505         case ENCRYPT_ENC_KEYID:
1506                 encrypt_enc_keyid(subpointer, SB_LEN());
1507                 break;
1508         case ENCRYPT_DEC_KEYID:
1509                 encrypt_dec_keyid(subpointer, SB_LEN());
1510                 break;
1511         default:
1512                 break;
1513         }
1514         break;
1515 #endif  /* ENCRYPTION */
1516
1517     default:
1518         break;
1519     }  /* end of switch */
1520
1521 }  /* end of suboption */
1522
1523         void
1524 doclientstat()
1525 {
1526         clientstat(TELOPT_LINEMODE, WILL, 0);
1527 }
1528
1529 #define ADD(c)   *ncp++ = c
1530 #define ADD_DATA(c) { *ncp++ = c; if (c == SE || c == IAC) *ncp++ = c; }
1531         void
1532 send_status()
1533 {
1534         unsigned char statusbuf[256];
1535         register unsigned char *ncp;
1536         register unsigned char i;
1537
1538         ncp = statusbuf;
1539
1540         netflush();     /* get rid of anything waiting to go out */
1541
1542         ADD(IAC);
1543         ADD(SB);
1544         ADD(TELOPT_STATUS);
1545         ADD(TELQUAL_IS);
1546
1547         /*
1548          * We check the want_state rather than the current state,
1549          * because if we received a DO/WILL for an option that we
1550          * don't support, and the other side didn't send a DONT/WONT
1551          * in response to our WONT/DONT, then the "state" will be
1552          * WILL/DO, and the "want_state" will be WONT/DONT.  We
1553          * need to go by the latter.
1554          */
1555         for (i = 0; i < (unsigned char)NTELOPTS; i++) {
1556                 if (my_want_state_is_will(i)) {
1557                         ADD(WILL);
1558                         ADD_DATA(i);
1559                 }
1560                 if (his_want_state_is_will(i)) {
1561                         ADD(DO);
1562                         ADD_DATA(i);
1563                 }
1564         }
1565
1566         if (his_want_state_is_will(TELOPT_LFLOW)) {
1567                 ADD(SB);
1568                 ADD(TELOPT_LFLOW);
1569                 if (flowmode) {
1570                         ADD(LFLOW_ON);
1571                 } else {
1572                         ADD(LFLOW_OFF);
1573                 }
1574                 ADD(SE);
1575
1576                 if (restartany >= 0) {
1577                         ADD(SB);
1578                         ADD(TELOPT_LFLOW);
1579                         if (restartany) {
1580                                 ADD(LFLOW_RESTART_ANY);
1581                         } else {
1582                                 ADD(LFLOW_RESTART_XON);
1583                         }
1584                         ADD(SE);
1585                 }
1586         }
1587
1588 #ifdef  LINEMODE
1589         if (his_want_state_is_will(TELOPT_LINEMODE)) {
1590                 unsigned char *cp, *cpe;
1591                 int len;
1592
1593                 ADD(SB);
1594                 ADD(TELOPT_LINEMODE);
1595                 ADD(LM_MODE);
1596                 ADD_DATA(editmode);
1597                 ADD(SE);
1598
1599                 ADD(SB);
1600                 ADD(TELOPT_LINEMODE);
1601                 ADD(LM_SLC);
1602                 start_slc(0);
1603                 send_slc();
1604                 len = end_slc(&cp);
1605                 for (cpe = cp + len; cp < cpe; cp++)
1606                         ADD_DATA(*cp);
1607                 ADD(SE);
1608         }
1609 #endif  /* LINEMODE */
1610
1611         ADD(IAC);
1612         ADD(SE);
1613
1614         writenet(statusbuf, ncp - statusbuf);
1615         netflush();     /* Send it on its way */
1616
1617         DIAG(TD_OPTIONS,
1618                 {printsub('>', statusbuf, ncp - statusbuf); netflush();});
1619 }