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