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