]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - crypto/heimdal/appl/telnet/telnet/telnet.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / crypto / heimdal / appl / telnet / telnet / telnet.c
1 /*
2  * Copyright (c) 1988, 1990, 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 "telnet_locl.h"
35
36 RCSID("$Id: telnet.c 16285 2005-11-03 18:38:57Z lha $");
37
38 #define strip(x) (eight ? (x) : ((x) & 0x7f))
39
40 static unsigned char    subbuffer[SUBBUFSIZE],
41                         *subpointer, *subend;    /* buffer for sub-options */
42 #define SB_CLEAR()      subpointer = subbuffer;
43 #define SB_TERM()       { subend = subpointer; SB_CLEAR(); }
44 #define SB_ACCUM(c)     if (subpointer < (subbuffer+sizeof subbuffer)) { \
45                                 *subpointer++ = (c); \
46                         }
47
48 #define SB_GET()        ((*subpointer++)&0xff)
49 #define SB_PEEK()       ((*subpointer)&0xff)
50 #define SB_EOF()        (subpointer >= subend)
51 #define SB_LEN()        (subend - subpointer)
52
53 char    options[256];           /* The combined options */
54 char    do_dont_resp[256];
55 char    will_wont_resp[256];
56
57 int
58         eight = 3,
59         binary = 0,
60         autologin = 0,  /* Autologin anyone? */
61         skiprc = 0,
62         connected,
63         showoptions,
64         ISend,          /* trying to send network data in */
65         debug = 0,
66         crmod,
67         netdata,        /* Print out network data flow */
68         crlf,           /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
69         telnetport,
70         wantencryption = 0,
71         SYNCHing,       /* we are in TELNET SYNCH mode */
72         flushout,       /* flush output */
73         autoflush = 0,  /* flush output when interrupting? */
74         autosynch,      /* send interrupt characters with SYNCH? */
75         localflow,      /* we handle flow control locally */
76         restartany,     /* if flow control enabled, restart on any character */
77         localchars,     /* we recognize interrupt/quit */
78         donelclchars,   /* the user has set "localchars" */
79         donebinarytoggle,       /* the user has put us in binary */
80         dontlecho,      /* do we suppress local echoing right now? */
81         globalmode;
82
83 char *prompt = 0;
84
85 int scheduler_lockout_tty = 0;
86
87 cc_t escape;
88 cc_t rlogin;
89 #ifdef  KLUDGELINEMODE
90 cc_t echoc;
91 #endif
92
93 /*
94  * Telnet receiver states for fsm
95  */
96 #define TS_DATA         0
97 #define TS_IAC          1
98 #define TS_WILL         2
99 #define TS_WONT         3
100 #define TS_DO           4
101 #define TS_DONT         5
102 #define TS_CR           6
103 #define TS_SB           7               /* sub-option collection */
104 #define TS_SE           8               /* looking for sub-option end */
105
106 static int      telrcv_state;
107 #ifdef  OLD_ENVIRON
108 unsigned char telopt_environ = TELOPT_NEW_ENVIRON;
109 #else
110 # define telopt_environ TELOPT_NEW_ENVIRON
111 #endif
112
113 jmp_buf toplevel;
114 jmp_buf peerdied;
115
116 int     flushline;
117 int     linemode;
118
119 #ifdef  KLUDGELINEMODE
120 int     kludgelinemode = 1;
121 #endif
122
123 /*
124  * The following are some clocks used to decide how to interpret
125  * the relationship between various variables.
126  */
127
128 Clocks clocks;
129
130 static int is_unique(char *name, char **as, char **ae);
131
132
133 /*
134  * Initialize telnet environment.
135  */
136
137 void
138 init_telnet(void)
139 {
140     env_init();
141
142     SB_CLEAR();
143     memset(options, 0, sizeof options);
144
145     connected = ISend = localflow = donebinarytoggle = 0;
146 #if     defined(AUTHENTICATION) || defined(ENCRYPTION)
147     auth_encrypt_connect(connected);
148 #endif  /* defined(AUTHENTICATION) || defined(ENCRYPTION)  */
149     restartany = -1;
150
151     SYNCHing = 0;
152
153     /* Don't change NetTrace */
154
155     escape = CONTROL(']');
156     rlogin = _POSIX_VDISABLE;
157 #ifdef  KLUDGELINEMODE
158     echoc = CONTROL('E');
159 #endif
160
161     flushline = 1;
162     telrcv_state = TS_DATA;
163 }
164
165
166 /*
167  * These routines are in charge of sending option negotiations
168  * to the other side.
169  *
170  * The basic idea is that we send the negotiation if either side
171  * is in disagreement as to what the current state should be.
172  */
173
174 void
175 send_do(int c, int init)
176 {
177     if (init) {
178         if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
179                                 my_want_state_is_do(c))
180             return;
181         set_my_want_state_do(c);
182         do_dont_resp[c]++;
183     }
184     NET2ADD(IAC, DO);
185     NETADD(c);
186     printoption("SENT", DO, c);
187 }
188
189 void
190 send_dont(int c, int init)
191 {
192     if (init) {
193         if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
194                                 my_want_state_is_dont(c))
195             return;
196         set_my_want_state_dont(c);
197         do_dont_resp[c]++;
198     }
199     NET2ADD(IAC, DONT);
200     NETADD(c);
201     printoption("SENT", DONT, c);
202 }
203
204 void
205 send_will(int c, int init)
206 {
207     if (init) {
208         if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
209                                 my_want_state_is_will(c))
210             return;
211         set_my_want_state_will(c);
212         will_wont_resp[c]++;
213     }
214     NET2ADD(IAC, WILL);
215     NETADD(c);
216     printoption("SENT", WILL, c);
217 }
218
219 void
220 send_wont(int c, int init)
221 {
222     if (init) {
223         if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
224                                 my_want_state_is_wont(c))
225             return;
226         set_my_want_state_wont(c);
227         will_wont_resp[c]++;
228     }
229     NET2ADD(IAC, WONT);
230     NETADD(c);
231     printoption("SENT", WONT, c);
232 }
233
234
235 void
236 willoption(int option)
237 {
238         int new_state_ok = 0;
239
240         if (do_dont_resp[option]) {
241             --do_dont_resp[option];
242             if (do_dont_resp[option] && my_state_is_do(option))
243                 --do_dont_resp[option];
244         }
245
246         if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
247
248             switch (option) {
249
250             case TELOPT_ECHO:
251             case TELOPT_BINARY:
252             case TELOPT_SGA:
253                 settimer(modenegotiated);
254                 /* FALL THROUGH */
255             case TELOPT_STATUS:
256 #if     defined(AUTHENTICATION)
257             case TELOPT_AUTHENTICATION:
258 #endif
259 #if     defined(ENCRYPTION)
260             case TELOPT_ENCRYPT:
261 #endif
262                 new_state_ok = 1;
263                 break;
264
265             case TELOPT_TM:
266                 if (flushout)
267                     flushout = 0;
268                 /*
269                  * Special case for TM.  If we get back a WILL,
270                  * pretend we got back a WONT.
271                  */
272                 set_my_want_state_dont(option);
273                 set_my_state_dont(option);
274                 return;                 /* Never reply to TM will's/wont's */
275
276             case TELOPT_LINEMODE:
277             default:
278                 break;
279             }
280
281             if (new_state_ok) {
282                 set_my_want_state_do(option);
283                 send_do(option, 0);
284                 setconnmode(0);         /* possibly set new tty mode */
285             } else {
286                 do_dont_resp[option]++;
287                 send_dont(option, 0);
288             }
289         }
290         set_my_state_do(option);
291 #if     defined(ENCRYPTION)
292         if (option == TELOPT_ENCRYPT)
293                 encrypt_send_support();
294 #endif
295 }
296
297 void
298 wontoption(int option)
299 {
300         if (do_dont_resp[option]) {
301             --do_dont_resp[option];
302             if (do_dont_resp[option] && my_state_is_dont(option))
303                 --do_dont_resp[option];
304         }
305
306         if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
307
308             switch (option) {
309
310 #ifdef  KLUDGELINEMODE
311             case TELOPT_SGA:
312                 if (!kludgelinemode)
313                     break;
314                 /* FALL THROUGH */
315 #endif
316             case TELOPT_ECHO:
317                 settimer(modenegotiated);
318                 break;
319
320             case TELOPT_TM:
321                 if (flushout)
322                     flushout = 0;
323                 set_my_want_state_dont(option);
324                 set_my_state_dont(option);
325                 return;         /* Never reply to TM will's/wont's */
326
327 #ifdef ENCRYPTION
328             case TELOPT_ENCRYPT:
329               encrypt_not();
330               break;
331 #endif
332             default:
333                 break;
334             }
335             set_my_want_state_dont(option);
336             if (my_state_is_do(option))
337                 send_dont(option, 0);
338             setconnmode(0);                     /* Set new tty mode */
339         } else if (option == TELOPT_TM) {
340             /*
341              * Special case for TM.
342              */
343             if (flushout)
344                 flushout = 0;
345             set_my_want_state_dont(option);
346         }
347         set_my_state_dont(option);
348 }
349
350 static void
351 dooption(int option)
352 {
353         int new_state_ok = 0;
354
355         if (will_wont_resp[option]) {
356             --will_wont_resp[option];
357             if (will_wont_resp[option] && my_state_is_will(option))
358                 --will_wont_resp[option];
359         }
360
361         if (will_wont_resp[option] == 0) {
362           if (my_want_state_is_wont(option)) {
363
364             switch (option) {
365
366             case TELOPT_TM:
367                 /*
368                  * Special case for TM.  We send a WILL, but pretend
369                  * we sent WONT.
370                  */
371                 send_will(option, 0);
372                 set_my_want_state_wont(TELOPT_TM);
373                 set_my_state_wont(TELOPT_TM);
374                 return;
375
376             case TELOPT_BINARY:         /* binary mode */
377             case TELOPT_NAWS:           /* window size */
378             case TELOPT_TSPEED:         /* terminal speed */
379             case TELOPT_LFLOW:          /* local flow control */
380             case TELOPT_TTYPE:          /* terminal type option */
381             case TELOPT_SGA:            /* no big deal */
382 #if     defined(ENCRYPTION)
383             case TELOPT_ENCRYPT:        /* encryption variable option */
384 #endif
385                 new_state_ok = 1;
386                 break;
387
388             case TELOPT_NEW_ENVIRON:    /* New environment variable option */
389 #ifdef  OLD_ENVIRON
390                 if (my_state_is_will(TELOPT_OLD_ENVIRON))
391                         send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */
392                 goto env_common;
393             case TELOPT_OLD_ENVIRON:    /* Old environment variable option */
394                 if (my_state_is_will(TELOPT_NEW_ENVIRON))
395                         break;          /* Don't enable if new one is in use! */
396             env_common:
397                 telopt_environ = option;
398 #endif
399                 new_state_ok = 1;
400                 break;
401
402 #if     defined(AUTHENTICATION)
403             case TELOPT_AUTHENTICATION:
404                 if (autologin)
405                         new_state_ok = 1;
406                 break;
407 #endif
408
409             case TELOPT_XDISPLOC:       /* X Display location */
410                 if (env_getvalue((unsigned char *)"DISPLAY"))
411                     new_state_ok = 1;
412                 break;
413
414             case TELOPT_LINEMODE:
415 #ifdef  KLUDGELINEMODE
416                 kludgelinemode = 0;
417                 send_do(TELOPT_SGA, 1);
418 #endif
419                 set_my_want_state_will(TELOPT_LINEMODE);
420                 send_will(option, 0);
421                 set_my_state_will(TELOPT_LINEMODE);
422                 slc_init();
423                 return;
424
425             case TELOPT_ECHO:           /* We're never going to echo... */
426             default:
427                 break;
428             }
429
430             if (new_state_ok) {
431                 set_my_want_state_will(option);
432                 send_will(option, 0);
433                 setconnmode(0);                 /* Set new tty mode */
434             } else {
435                 will_wont_resp[option]++;
436                 send_wont(option, 0);
437             }
438           } else {
439             /*
440              * Handle options that need more things done after the
441              * other side has acknowledged the option.
442              */
443             switch (option) {
444             case TELOPT_LINEMODE:
445 #ifdef  KLUDGELINEMODE
446                 kludgelinemode = 0;
447                 send_do(TELOPT_SGA, 1);
448 #endif
449                 set_my_state_will(option);
450                 slc_init();
451                 send_do(TELOPT_SGA, 0);
452                 return;
453             }
454           }
455         }
456         set_my_state_will(option);
457 }
458
459 static void
460 dontoption(int option)
461 {
462
463         if (will_wont_resp[option]) {
464             --will_wont_resp[option];
465             if (will_wont_resp[option] && my_state_is_wont(option))
466                 --will_wont_resp[option];
467         }
468
469         if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
470             switch (option) {
471             case TELOPT_LINEMODE:
472                 linemode = 0;   /* put us back to the default state */
473                 break;
474 #ifdef  OLD_ENVIRON
475             case TELOPT_NEW_ENVIRON:
476                 /*
477                  * The new environ option wasn't recognized, try
478                  * the old one.
479                  */
480                 send_will(TELOPT_OLD_ENVIRON, 1);
481                 telopt_environ = TELOPT_OLD_ENVIRON;
482                 break;
483 #endif
484 #if 0
485 #ifdef ENCRYPTION
486             case TELOPT_ENCRYPT:
487               encrypt_not();
488               break;
489 #endif
490 #endif
491             }
492             /* we always accept a DONT */
493             set_my_want_state_wont(option);
494             if (my_state_is_will(option))
495                 send_wont(option, 0);
496             setconnmode(0);                     /* Set new tty mode */
497         }
498         set_my_state_wont(option);
499 }
500
501 /*
502  * Given a buffer returned by tgetent(), this routine will turn
503  * the pipe separated list of names in the buffer into an array
504  * of pointers to null terminated names.  We toss out any bad,
505  * duplicate, or verbose names (names with spaces).
506  */
507
508 static char *name_unknown = "UNKNOWN";
509 static char *unknown[] = { 0, 0 };
510
511 static char **
512 mklist(char *buf, char *name)
513 {
514         int n;
515         char c, *cp, **argvp, *cp2, **argv, **avt;
516
517         if (name) {
518                 if ((int)strlen(name) > 40) {
519                         name = 0;
520                         unknown[0] = name_unknown;
521                 } else {
522                         unknown[0] = name;
523                         strupr(name);
524                 }
525         } else
526                 unknown[0] = name_unknown;
527         /*
528          * Count up the number of names.
529          */
530         for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
531                 if (*cp == '|')
532                         n++;
533         }
534         /*
535          * Allocate an array to put the name pointers into
536          */
537         argv = (char **)malloc((n+3)*sizeof(char *));
538         if (argv == 0)
539                 return(unknown);
540
541         /*
542          * Fill up the array of pointers to names.
543          */
544         *argv = 0;
545         argvp = argv+1;
546         n = 0;
547         for (cp = cp2 = buf; (c = *cp);  cp++) {
548                 if (c == '|' || c == ':') {
549                         *cp++ = '\0';
550                         /*
551                          * Skip entries that have spaces or are over 40
552                          * characters long.  If this is our environment
553                          * name, then put it up front.  Otherwise, as
554                          * long as this is not a duplicate name (case
555                          * insensitive) add it to the list.
556                          */
557                         if (n || (cp - cp2 > 41))
558                                 ;
559                         else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
560                                 *argv = cp2;
561                         else if (is_unique(cp2, argv+1, argvp))
562                                 *argvp++ = cp2;
563                         if (c == ':')
564                                 break;
565                         /*
566                          * Skip multiple delimiters. Reset cp2 to
567                          * the beginning of the next name. Reset n,
568                          * the flag for names with spaces.
569                          */
570                         while ((c = *cp) == '|')
571                                 cp++;
572                         cp2 = cp;
573                         n = 0;
574                 }
575                 /*
576                  * Skip entries with spaces or non-ascii values.
577                  * Convert lower case letters to upper case.
578                  */
579 #undef ISASCII
580 #define ISASCII(c) (!((c)&0x80))
581                 if ((c == ' ') || !ISASCII(c))
582                         n = 1;
583                 else if (islower((unsigned char)c))
584                         *cp = toupper((unsigned char)c);
585         }
586
587         /*
588          * Check for an old V6 2 character name.  If the second
589          * name points to the beginning of the buffer, and is
590          * only 2 characters long, move it to the end of the array.
591          */
592         if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
593                 --argvp;
594                 for (avt = &argv[1]; avt < argvp; avt++)
595                         *avt = *(avt+1);
596                 *argvp++ = buf;
597         }
598
599         /*
600          * Duplicate last name, for TTYPE option, and null
601          * terminate the array.  If we didn't find a match on
602          * our terminal name, put that name at the beginning.
603          */
604         cp = *(argvp-1);
605         *argvp++ = cp;
606         *argvp = 0;
607
608         if (*argv == 0) {
609                 if (name)
610                         *argv = name;
611                 else {
612                         --argvp;
613                         for (avt = argv; avt < argvp; avt++)
614                                 *avt = *(avt+1);
615                 }
616         }
617         if (*argv)
618                 return(argv);
619         else
620                 return(unknown);
621 }
622
623 static int
624 is_unique(char *name, char **as, char **ae)
625 {
626         char **ap;
627         int n;
628
629         n = strlen(name) + 1;
630         for (ap = as; ap < ae; ap++)
631                 if (strncasecmp(*ap, name, n) == 0)
632                         return(0);
633         return (1);
634 }
635
636 static char termbuf[1024];
637
638 static int
639 telnet_setupterm(const char *tname, int fd, int *errp)
640 {
641 #ifdef HAVE_TGETENT
642     if (tgetent(termbuf, tname) == 1) {
643         termbuf[1023] = '\0';
644         if (errp)
645             *errp = 1;
646         return(0);
647     }
648     if (errp)
649         *errp = 0;
650     return(-1);
651 #else
652     strlcpy(termbuf, tname, sizeof(termbuf));
653     if(errp) *errp = 1;
654     return 0;
655 #endif
656 }
657
658 int resettermname = 1;
659
660 static char *
661 gettermname()
662 {
663         char *tname;
664         static char **tnamep = 0;
665         static char **next;
666         int err;
667
668         if (resettermname) {
669                 resettermname = 0;
670                 if (tnamep && tnamep != unknown)
671                         free(tnamep);
672                 if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) &&
673                                 telnet_setupterm(tname, 1, &err) == 0) {
674                         tnamep = mklist(termbuf, tname);
675                 } else {
676                         if (tname && ((int)strlen(tname) <= 40)) {
677                                 unknown[0] = tname;
678                                 strupr(tname);
679                         } else
680                                 unknown[0] = name_unknown;
681                         tnamep = unknown;
682                 }
683                 next = tnamep;
684         }
685         if (*next == 0)
686                 next = tnamep;
687         return(*next++);
688 }
689 /*
690  * suboption()
691  *
692  *      Look at the sub-option buffer, and try to be helpful to the other
693  * side.
694  *
695  *      Currently we recognize:
696  *
697  *              Terminal type, send request.
698  *              Terminal speed (send request).
699  *              Local flow control (is request).
700  *              Linemode
701  */
702
703 static void
704 suboption()
705 {
706     unsigned char subchar;
707
708     printsub('<', subbuffer, SB_LEN()+2);
709     switch (subchar = SB_GET()) {
710     case TELOPT_TTYPE:
711         if (my_want_state_is_wont(TELOPT_TTYPE))
712             return;
713         if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
714             return;
715         } else {
716             char *name;
717             unsigned char temp[50];
718             int len;
719
720             name = gettermname();
721             len = strlen(name) + 4 + 2;
722             if (len < NETROOM()) {
723                 snprintf((char *)temp, sizeof(temp),
724                          "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
725                          TELQUAL_IS, name, IAC, SE);
726                 ring_supply_data(&netoring, temp, len);
727                 printsub('>', &temp[2], len-2);
728             } else {
729                 ExitString("No room in buffer for terminal type.\n", 1);
730                 /*NOTREACHED*/
731             }
732         }
733         break;
734     case TELOPT_TSPEED:
735         if (my_want_state_is_wont(TELOPT_TSPEED))
736             return;
737         if (SB_EOF())
738             return;
739         if (SB_GET() == TELQUAL_SEND) {
740             long output_speed, input_speed;
741             unsigned char temp[50];
742             int len;
743
744             TerminalSpeeds(&input_speed, &output_speed);
745
746             snprintf((char *)temp, sizeof(temp),
747                      "%c%c%c%c%u,%u%c%c", IAC, SB, TELOPT_TSPEED,
748                      TELQUAL_IS,
749                      (unsigned)output_speed,
750                      (unsigned)input_speed, IAC, SE);
751             len = strlen((char *)temp+4) + 4;   /* temp[3] is 0 ... */
752
753             if (len < NETROOM()) {
754                 ring_supply_data(&netoring, temp, len);
755                 printsub('>', temp+2, len - 2);
756             }
757 /*@*/       else printf("lm_will: not enough room in buffer\n");
758         }
759         break;
760     case TELOPT_LFLOW:
761         if (my_want_state_is_wont(TELOPT_LFLOW))
762             return;
763         if (SB_EOF())
764             return;
765         switch(SB_GET()) {
766         case LFLOW_RESTART_ANY:
767             restartany = 1;
768             break;
769         case LFLOW_RESTART_XON:
770             restartany = 0;
771             break;
772         case LFLOW_ON:
773             localflow = 1;
774             break;
775         case LFLOW_OFF:
776             localflow = 0;
777             break;
778         default:
779             return;
780         }
781         setcommandmode();
782         setconnmode(0);
783         break;
784
785     case TELOPT_LINEMODE:
786         if (my_want_state_is_wont(TELOPT_LINEMODE))
787             return;
788         if (SB_EOF())
789             return;
790         switch (SB_GET()) {
791         case WILL:
792             lm_will(subpointer, SB_LEN());
793             break;
794         case WONT:
795             lm_wont(subpointer, SB_LEN());
796             break;
797         case DO:
798             lm_do(subpointer, SB_LEN());
799             break;
800         case DONT:
801             lm_dont(subpointer, SB_LEN());
802             break;
803         case LM_SLC:
804             slc(subpointer, SB_LEN());
805             break;
806         case LM_MODE:
807             lm_mode(subpointer, SB_LEN(), 0);
808             break;
809         default:
810             break;
811         }
812         break;
813
814 #ifdef  OLD_ENVIRON
815     case TELOPT_OLD_ENVIRON:
816 #endif
817     case TELOPT_NEW_ENVIRON:
818         if (SB_EOF())
819             return;
820         switch(SB_PEEK()) {
821         case TELQUAL_IS:
822         case TELQUAL_INFO:
823             if (my_want_state_is_dont(subchar))
824                 return;
825             break;
826         case TELQUAL_SEND:
827             if (my_want_state_is_wont(subchar)) {
828                 return;
829             }
830             break;
831         default:
832             return;
833         }
834         env_opt(subpointer, SB_LEN());
835         break;
836
837     case TELOPT_XDISPLOC:
838         if (my_want_state_is_wont(TELOPT_XDISPLOC))
839             return;
840         if (SB_EOF())
841             return;
842         if (SB_GET() == TELQUAL_SEND) {
843             unsigned char temp[50], *dp;
844             int len;
845
846             if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) {
847                 /*
848                  * Something happened, we no longer have a DISPLAY
849                  * variable.  So, turn off the option.
850                  */
851                 send_wont(TELOPT_XDISPLOC, 1);
852                 break;
853             }
854             snprintf((char *)temp, sizeof(temp),
855                      "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
856                      TELQUAL_IS, dp, IAC, SE);
857             len = strlen((char *)temp+4) + 4;   /* temp[3] is 0 ... */
858
859             if (len < NETROOM()) {
860                 ring_supply_data(&netoring, temp, len);
861                 printsub('>', temp+2, len - 2);
862             }
863 /*@*/       else printf("lm_will: not enough room in buffer\n");
864         }
865         break;
866
867 #if     defined(AUTHENTICATION)
868         case TELOPT_AUTHENTICATION: {
869                 if (!autologin)
870                         break;
871                 if (SB_EOF())
872                         return;
873                 switch(SB_GET()) {
874                 case TELQUAL_IS:
875                         if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
876                                 return;
877                         auth_is(subpointer, SB_LEN());
878                         break;
879                 case TELQUAL_SEND:
880                         if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
881                                 return;
882                         auth_send(subpointer, SB_LEN());
883                         break;
884                 case TELQUAL_REPLY:
885                         if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
886                                 return;
887                         auth_reply(subpointer, SB_LEN());
888                         break;
889                 case TELQUAL_NAME:
890                         if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
891                                 return;
892                         auth_name(subpointer, SB_LEN());
893                         break;
894                 }
895         }
896         break;
897 #endif
898 #if     defined(ENCRYPTION)
899         case TELOPT_ENCRYPT:
900                 if (SB_EOF())
901                         return;
902                 switch(SB_GET()) {
903                 case ENCRYPT_START:
904                         if (my_want_state_is_dont(TELOPT_ENCRYPT))
905                                 return;
906                         encrypt_start(subpointer, SB_LEN());
907                         break;
908                 case ENCRYPT_END:
909                         if (my_want_state_is_dont(TELOPT_ENCRYPT))
910                                 return;
911                         encrypt_end();
912                         break;
913                 case ENCRYPT_SUPPORT:
914                         if (my_want_state_is_wont(TELOPT_ENCRYPT))
915                                 return;
916                         encrypt_support(subpointer, SB_LEN());
917                         break;
918                 case ENCRYPT_REQSTART:
919                         if (my_want_state_is_wont(TELOPT_ENCRYPT))
920                                 return;
921                         encrypt_request_start(subpointer, SB_LEN());
922                         break;
923                 case ENCRYPT_REQEND:
924                         if (my_want_state_is_wont(TELOPT_ENCRYPT))
925                                 return;
926                         /*
927                          * We can always send an REQEND so that we cannot
928                          * get stuck encrypting.  We should only get this
929                          * if we have been able to get in the correct mode
930                          * anyhow.
931                          */
932                         encrypt_request_end();
933                         break;
934                 case ENCRYPT_IS:
935                         if (my_want_state_is_dont(TELOPT_ENCRYPT))
936                                 return;
937                         encrypt_is(subpointer, SB_LEN());
938                         break;
939                 case ENCRYPT_REPLY:
940                         if (my_want_state_is_wont(TELOPT_ENCRYPT))
941                                 return;
942                         encrypt_reply(subpointer, SB_LEN());
943                         break;
944                 case ENCRYPT_ENC_KEYID:
945                         if (my_want_state_is_dont(TELOPT_ENCRYPT))
946                                 return;
947                         encrypt_enc_keyid(subpointer, SB_LEN());
948                         break;
949                 case ENCRYPT_DEC_KEYID:
950                         if (my_want_state_is_wont(TELOPT_ENCRYPT))
951                                 return;
952                         encrypt_dec_keyid(subpointer, SB_LEN());
953                         break;
954                 default:
955                         break;
956                 }
957                 break;
958 #endif
959     default:
960         break;
961     }
962 }
963
964 static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
965
966 void
967 lm_will(unsigned char *cmd, int len)
968 {
969     if (len < 1) {
970 /*@*/   printf("lm_will: no command!!!\n");     /* Should not happen... */
971         return;
972     }
973     switch(cmd[0]) {
974     case LM_FORWARDMASK:        /* We shouldn't ever get this... */
975     default:
976         str_lm[3] = DONT;
977         str_lm[4] = cmd[0];
978         if (NETROOM() > sizeof(str_lm)) {
979             ring_supply_data(&netoring, str_lm, sizeof(str_lm));
980             printsub('>', &str_lm[2], sizeof(str_lm)-2);
981         }
982 /*@*/   else printf("lm_will: not enough room in buffer\n");
983         break;
984     }
985 }
986
987 void
988 lm_wont(unsigned char *cmd, int len)
989 {
990     if (len < 1) {
991 /*@*/   printf("lm_wont: no command!!!\n");     /* Should not happen... */
992         return;
993     }
994     switch(cmd[0]) {
995     case LM_FORWARDMASK:        /* We shouldn't ever get this... */
996     default:
997         /* We are always DONT, so don't respond */
998         return;
999     }
1000 }
1001
1002 void
1003 lm_do(unsigned char *cmd, int len)
1004 {
1005     if (len < 1) {
1006 /*@*/   printf("lm_do: no command!!!\n");       /* Should not happen... */
1007         return;
1008     }
1009     switch(cmd[0]) {
1010     case LM_FORWARDMASK:
1011     default:
1012         str_lm[3] = WONT;
1013         str_lm[4] = cmd[0];
1014         if (NETROOM() > sizeof(str_lm)) {
1015             ring_supply_data(&netoring, str_lm, sizeof(str_lm));
1016             printsub('>', &str_lm[2], sizeof(str_lm)-2);
1017         }
1018 /*@*/   else printf("lm_do: not enough room in buffer\n");
1019         break;
1020     }
1021 }
1022
1023 void
1024 lm_dont(unsigned char *cmd, int len)
1025 {
1026     if (len < 1) {
1027 /*@*/   printf("lm_dont: no command!!!\n");     /* Should not happen... */
1028         return;
1029     }
1030     switch(cmd[0]) {
1031     case LM_FORWARDMASK:
1032     default:
1033         /* we are always WONT, so don't respond */
1034         break;
1035     }
1036 }
1037
1038 static unsigned char str_lm_mode[] = {
1039         IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
1040 };
1041
1042 void
1043 lm_mode(unsigned char *cmd, int len, int init)
1044 {
1045         if (len != 1)
1046                 return;
1047         if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
1048                 return;
1049         if (*cmd&MODE_ACK)
1050                 return;
1051         linemode = *cmd&(MODE_MASK&~MODE_ACK);
1052         str_lm_mode[4] = linemode;
1053         if (!init)
1054             str_lm_mode[4] |= MODE_ACK;
1055         if (NETROOM() > sizeof(str_lm_mode)) {
1056             ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
1057             printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
1058         }
1059 /*@*/   else printf("lm_mode: not enough room in buffer\n");
1060         setconnmode(0); /* set changed mode */
1061 }
1062
1063
1064
1065 /*
1066  * slc()
1067  * Handle special character suboption of LINEMODE.
1068  */
1069
1070 struct spc {
1071         cc_t val;
1072         cc_t *valp;
1073         char flags;     /* Current flags & level */
1074         char mylevel;   /* Maximum level & flags */
1075 } spc_data[NSLC+1];
1076
1077 #define SLC_IMPORT      0
1078 #define SLC_EXPORT      1
1079 #define SLC_RVALUE      2
1080 static int slc_mode = SLC_EXPORT;
1081
1082 void
1083 slc_init()
1084 {
1085         struct spc *spcp;
1086
1087         localchars = 1;
1088         for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
1089                 spcp->val = 0;
1090                 spcp->valp = 0;
1091                 spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
1092         }
1093
1094 #define initfunc(func, flags) { \
1095                                         spcp = &spc_data[func]; \
1096                                         if ((spcp->valp = tcval(func))) { \
1097                                             spcp->val = *spcp->valp; \
1098                                             spcp->mylevel = SLC_VARIABLE|flags; \
1099                                         } else { \
1100                                             spcp->val = 0; \
1101                                             spcp->mylevel = SLC_DEFAULT; \
1102                                         } \
1103                                     }
1104
1105         initfunc(SLC_SYNCH, 0);
1106         /* No BRK */
1107         initfunc(SLC_AO, 0);
1108         initfunc(SLC_AYT, 0);
1109         /* No EOR */
1110         initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
1111         initfunc(SLC_EOF, 0);
1112         initfunc(SLC_SUSP, SLC_FLUSHIN);
1113         initfunc(SLC_EC, 0);
1114         initfunc(SLC_EL, 0);
1115         initfunc(SLC_EW, 0);
1116         initfunc(SLC_RP, 0);
1117         initfunc(SLC_LNEXT, 0);
1118         initfunc(SLC_XON, 0);
1119         initfunc(SLC_XOFF, 0);
1120         initfunc(SLC_FORW1, 0);
1121         initfunc(SLC_FORW2, 0);
1122         /* No FORW2 */
1123
1124         initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
1125 #undef  initfunc
1126
1127         if (slc_mode == SLC_EXPORT)
1128                 slc_export();
1129         else
1130                 slc_import(1);
1131
1132 }
1133
1134 void
1135 slcstate()
1136 {
1137     printf("Special characters are %s values\n",
1138                 slc_mode == SLC_IMPORT ? "remote default" :
1139                 slc_mode == SLC_EXPORT ? "local" :
1140                                          "remote");
1141 }
1142
1143 void
1144 slc_mode_export()
1145 {
1146     slc_mode = SLC_EXPORT;
1147     if (my_state_is_will(TELOPT_LINEMODE))
1148         slc_export();
1149 }
1150
1151 void
1152 slc_mode_import(int def)
1153 {
1154     slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
1155     if (my_state_is_will(TELOPT_LINEMODE))
1156         slc_import(def);
1157 }
1158
1159 unsigned char slc_import_val[] = {
1160         IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
1161 };
1162 unsigned char slc_import_def[] = {
1163         IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
1164 };
1165
1166 void
1167 slc_import(int def)
1168 {
1169     if (NETROOM() > sizeof(slc_import_val)) {
1170         if (def) {
1171             ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
1172             printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
1173         } else {
1174             ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
1175             printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
1176         }
1177     }
1178 /*@*/ else printf("slc_import: not enough room\n");
1179 }
1180
1181 void
1182 slc_export()
1183 {
1184     struct spc *spcp;
1185
1186     TerminalDefaultChars();
1187
1188     slc_start_reply();
1189     for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1190         if (spcp->mylevel != SLC_NOSUPPORT) {
1191             if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1192                 spcp->flags = SLC_NOSUPPORT;
1193             else
1194                 spcp->flags = spcp->mylevel;
1195             if (spcp->valp)
1196                 spcp->val = *spcp->valp;
1197             slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1198         }
1199     }
1200     slc_end_reply();
1201     slc_update();
1202     setconnmode(1);     /* Make sure the character values are set */
1203 }
1204
1205 void
1206 slc(unsigned char *cp, int len)
1207 {
1208         struct spc *spcp;
1209         int func,level;
1210
1211         slc_start_reply();
1212
1213         for (; len >= 3; len -=3, cp +=3) {
1214
1215                 func = cp[SLC_FUNC];
1216
1217                 if (func == 0) {
1218                         /*
1219                          * Client side: always ignore 0 function.
1220                          */
1221                         continue;
1222                 }
1223                 if (func > NSLC) {
1224                         if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
1225                                 slc_add_reply(func, SLC_NOSUPPORT, 0);
1226                         continue;
1227                 }
1228
1229                 spcp = &spc_data[func];
1230
1231                 level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
1232
1233                 if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
1234                     ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
1235                         continue;
1236                 }
1237
1238                 if (level == (SLC_DEFAULT|SLC_ACK)) {
1239                         /*
1240                          * This is an error condition, the SLC_ACK
1241                          * bit should never be set for the SLC_DEFAULT
1242                          * level.  Our best guess to recover is to
1243                          * ignore the SLC_ACK bit.
1244                          */
1245                         cp[SLC_FLAGS] &= ~SLC_ACK;
1246                 }
1247
1248                 if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
1249                         spcp->val = (cc_t)cp[SLC_VALUE];
1250                         spcp->flags = cp[SLC_FLAGS];    /* include SLC_ACK */
1251                         continue;
1252                 }
1253
1254                 level &= ~SLC_ACK;
1255
1256                 if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
1257                         spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
1258                         spcp->val = (cc_t)cp[SLC_VALUE];
1259                 }
1260                 if (level == SLC_DEFAULT) {
1261                         if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
1262                                 spcp->flags = spcp->mylevel;
1263                         else
1264                                 spcp->flags = SLC_NOSUPPORT;
1265                 }
1266                 slc_add_reply(func, spcp->flags, spcp->val);
1267         }
1268         slc_end_reply();
1269         if (slc_update())
1270                 setconnmode(1); /* set the  new character values */
1271 }
1272
1273 void
1274 slc_check()
1275 {
1276     struct spc *spcp;
1277
1278     slc_start_reply();
1279     for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1280         if (spcp->valp && spcp->val != *spcp->valp) {
1281             spcp->val = *spcp->valp;
1282             if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1283                 spcp->flags = SLC_NOSUPPORT;
1284             else
1285                 spcp->flags = spcp->mylevel;
1286             slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1287         }
1288     }
1289     slc_end_reply();
1290     setconnmode(1);
1291 }
1292
1293
1294 unsigned char slc_reply[128];
1295 unsigned char const * const slc_reply_eom = &slc_reply[sizeof(slc_reply)];
1296 unsigned char *slc_replyp;
1297
1298 void
1299 slc_start_reply()
1300 {
1301         slc_replyp = slc_reply;
1302         *slc_replyp++ = IAC;
1303         *slc_replyp++ = SB;
1304         *slc_replyp++ = TELOPT_LINEMODE;
1305         *slc_replyp++ = LM_SLC;
1306 }
1307
1308 void
1309 slc_add_reply(unsigned char func, unsigned char flags, cc_t value)
1310 {
1311         /* A sequence of up to 6 bytes my be written for this member of the SLC
1312          * suboption list by this function.  The end of negotiation command,
1313          * which is written by slc_end_reply(), will require 2 additional
1314          * bytes.  Do not proceed unless there is sufficient space for these
1315          * items.
1316          */
1317         if (&slc_replyp[6+2] > slc_reply_eom)
1318                 return;
1319         if ((*slc_replyp++ = func) == IAC)
1320                 *slc_replyp++ = IAC;
1321         if ((*slc_replyp++ = flags) == IAC)
1322                 *slc_replyp++ = IAC;
1323         if ((*slc_replyp++ = (unsigned char)value) == IAC)
1324                 *slc_replyp++ = IAC;
1325 }
1326
1327 void
1328 slc_end_reply()
1329 {
1330     int len;
1331
1332     /* The end of negotiation command requires 2 bytes. */
1333     if (&slc_replyp[2] > slc_reply_eom)
1334             return;
1335     *slc_replyp++ = IAC;
1336     *slc_replyp++ = SE;
1337     len = slc_replyp - slc_reply;
1338     if (len <= 6)
1339         return;
1340     if (NETROOM() > len) {
1341         ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
1342         printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
1343     }
1344 /*@*/else printf("slc_end_reply: not enough room\n");
1345 }
1346
1347 int
1348 slc_update()
1349 {
1350         struct spc *spcp;
1351         int need_update = 0;
1352
1353         for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1354                 if (!(spcp->flags&SLC_ACK))
1355                         continue;
1356                 spcp->flags &= ~SLC_ACK;
1357                 if (spcp->valp && (*spcp->valp != spcp->val)) {
1358                         *spcp->valp = spcp->val;
1359                         need_update = 1;
1360                 }
1361         }
1362         return(need_update);
1363 }
1364
1365 #ifdef  OLD_ENVIRON
1366 #  define old_env_var OLD_ENV_VAR
1367 #  define old_env_value OLD_ENV_VALUE
1368 #endif
1369
1370 void
1371 env_opt(unsigned char *buf, int len)
1372 {
1373         unsigned char *ep = 0, *epc = 0;
1374         int i;
1375
1376         switch(buf[0]&0xff) {
1377         case TELQUAL_SEND:
1378                 env_opt_start();
1379                 if (len == 1) {
1380                         env_opt_add(NULL);
1381                 } else for (i = 1; i < len; i++) {
1382                         switch (buf[i]&0xff) {
1383 #ifdef  OLD_ENVIRON
1384                         case OLD_ENV_VAR:
1385                         case OLD_ENV_VALUE:
1386                                 /*
1387                                  * Although OLD_ENV_VALUE is not legal, we will
1388                                  * still recognize it, just in case it is an
1389                                  * old server that has VAR & VALUE mixed up...
1390                                  */
1391                                 /* FALL THROUGH */
1392 #else
1393                         case NEW_ENV_VAR:
1394 #endif
1395                         case ENV_USERVAR:
1396                                 if (ep) {
1397                                         *epc = 0;
1398                                         env_opt_add(ep);
1399                                 }
1400                                 ep = epc = &buf[i+1];
1401                                 break;
1402                         case ENV_ESC:
1403                                 i++;
1404                                 /*FALL THROUGH*/
1405                         default:
1406                                 if (epc)
1407                                         *epc++ = buf[i];
1408                                 break;
1409                         }
1410                 }
1411                 if (ep) {
1412                         *epc = 0;
1413                         env_opt_add(ep);
1414                 }
1415                 env_opt_end(1);
1416                 break;
1417
1418         case TELQUAL_IS:
1419         case TELQUAL_INFO:
1420                 /* Ignore for now.  We shouldn't get it anyway. */
1421                 break;
1422
1423         default:
1424                 break;
1425         }
1426 }
1427
1428 #define OPT_REPLY_SIZE  (2 * SUBBUFSIZE)
1429 unsigned char *opt_reply;
1430 unsigned char *opt_replyp;
1431 unsigned char *opt_replyend;
1432
1433 void
1434 env_opt_start()
1435 {
1436         if (opt_reply) {
1437                 void *tmp = realloc (opt_reply, OPT_REPLY_SIZE);
1438                 if (tmp != NULL) {
1439                         opt_reply = tmp;
1440                 } else {
1441                         free (opt_reply);
1442                         opt_reply = NULL;
1443                 }
1444         } else
1445                 opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE);
1446         if (opt_reply == NULL) {
1447 /*@*/           printf("env_opt_start: malloc()/realloc() failed!!!\n");
1448                 opt_reply = opt_replyp = opt_replyend = NULL;
1449                 return;
1450         }
1451         opt_replyp = opt_reply;
1452         opt_replyend = opt_reply + OPT_REPLY_SIZE;
1453         *opt_replyp++ = IAC;
1454         *opt_replyp++ = SB;
1455         *opt_replyp++ = telopt_environ;
1456         *opt_replyp++ = TELQUAL_IS;
1457 }
1458
1459 void
1460 env_opt_start_info()
1461 {
1462         env_opt_start();
1463         if (opt_replyp)
1464             opt_replyp[-1] = TELQUAL_INFO;
1465 }
1466
1467 void
1468 env_opt_add(unsigned char *ep)
1469 {
1470         unsigned char *vp, c;
1471
1472         if (opt_reply == NULL)          /*XXX*/
1473                 return;                 /*XXX*/
1474
1475         if (ep == NULL || *ep == '\0') {
1476                 /* Send user defined variables first. */
1477                 env_default(1, 0);
1478                 while ((ep = env_default(0, 0)))
1479                         env_opt_add(ep);
1480
1481                 /* Now add the list of well know variables.  */
1482                 env_default(1, 1);
1483                 while ((ep = env_default(0, 1)))
1484                         env_opt_add(ep);
1485                 return;
1486         }
1487         vp = env_getvalue(ep);
1488         if (opt_replyp + (vp ? 2 * strlen((char *)vp) : 0) +
1489                                 2 * strlen((char *)ep) + 6 > opt_replyend)
1490         {
1491                 int len;
1492                 void *tmp;
1493                 opt_replyend += OPT_REPLY_SIZE;
1494                 len = opt_replyend - opt_reply;
1495                 tmp = realloc(opt_reply, len);
1496                 if (tmp == NULL) {
1497 /*@*/                   printf("env_opt_add: realloc() failed!!!\n");
1498                         opt_reply = opt_replyp = opt_replyend = NULL;
1499                         return;
1500                 }
1501                 opt_reply = tmp;
1502                 opt_replyp = opt_reply + len - (opt_replyend - opt_replyp);
1503                 opt_replyend = opt_reply + len;
1504         }
1505         if (opt_welldefined((char *)ep)) {
1506 #ifdef  OLD_ENVIRON
1507                 if (telopt_environ == TELOPT_OLD_ENVIRON)
1508                         *opt_replyp++ = old_env_var;
1509                 else
1510 #endif
1511                         *opt_replyp++ = NEW_ENV_VAR;
1512         } else
1513                 *opt_replyp++ = ENV_USERVAR;
1514         for (;;) {
1515                 while ((c = *ep++)) {
1516                         if (opt_replyp + (2 + 2) > opt_replyend)
1517                                 return;
1518                         switch(c&0xff) {
1519                         case IAC:
1520                                 *opt_replyp++ = IAC;
1521                                 break;
1522                         case NEW_ENV_VAR:
1523                         case NEW_ENV_VALUE:
1524                         case ENV_ESC:
1525                         case ENV_USERVAR:
1526                                 *opt_replyp++ = ENV_ESC;
1527                                 break;
1528                         }
1529                         *opt_replyp++ = c;
1530                 }
1531                 if ((ep = vp)) {
1532                         if (opt_replyp + (1 + 2 + 2) > opt_replyend)
1533                                 return;
1534 #ifdef  OLD_ENVIRON
1535                         if (telopt_environ == TELOPT_OLD_ENVIRON)
1536                                 *opt_replyp++ = old_env_value;
1537                         else
1538 #endif
1539                                 *opt_replyp++ = NEW_ENV_VALUE;
1540                         vp = NULL;
1541                 } else
1542                         break;
1543         }
1544 }
1545
1546 int
1547 opt_welldefined(char *ep)
1548 {
1549         if ((strcmp(ep, "USER") == 0) ||
1550             (strcmp(ep, "DISPLAY") == 0) ||
1551             (strcmp(ep, "PRINTER") == 0) ||
1552             (strcmp(ep, "SYSTEMTYPE") == 0) ||
1553             (strcmp(ep, "JOB") == 0) ||
1554             (strcmp(ep, "ACCT") == 0))
1555                 return(1);
1556         return(0);
1557 }
1558
1559 void
1560 env_opt_end(int emptyok)
1561 {
1562         int len;
1563
1564         if (opt_replyp + 2 > opt_replyend)
1565                 return;
1566         len = opt_replyp + 2 - opt_reply;
1567         if (emptyok || len > 6) {
1568                 *opt_replyp++ = IAC;
1569                 *opt_replyp++ = SE;
1570                 if (NETROOM() > len) {
1571                         ring_supply_data(&netoring, opt_reply, len);
1572                         printsub('>', &opt_reply[2], len - 2);
1573                 }
1574 /*@*/           else printf("slc_end_reply: not enough room\n");
1575         }
1576         if (opt_reply) {
1577                 free(opt_reply);
1578                 opt_reply = opt_replyp = opt_replyend = NULL;
1579         }
1580 }
1581
1582
1583
1584 int
1585 telrcv(void)
1586 {
1587     int c;
1588     int scc;
1589     unsigned char *sbp = NULL;
1590     int count;
1591     int returnValue = 0;
1592
1593     scc = 0;
1594     count = 0;
1595     while (TTYROOM() > 2) {
1596         if (scc == 0) {
1597             if (count) {
1598                 ring_consumed(&netiring, count);
1599                 returnValue = 1;
1600                 count = 0;
1601             }
1602             sbp = netiring.consume;
1603             scc = ring_full_consecutive(&netiring);
1604             if (scc == 0) {
1605                 /* No more data coming in */
1606                 break;
1607             }
1608         }
1609
1610         c = *sbp++ & 0xff, scc--; count++;
1611 #if     defined(ENCRYPTION)
1612         if (decrypt_input)
1613                 c = (*decrypt_input)(c);
1614 #endif
1615
1616         switch (telrcv_state) {
1617
1618         case TS_CR:
1619             telrcv_state = TS_DATA;
1620             if (c == '\0') {
1621                 break;  /* Ignore \0 after CR */
1622             }
1623             else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
1624                 TTYADD(c);
1625                 break;
1626             }
1627             /* Else, fall through */
1628
1629         case TS_DATA:
1630             if (c == IAC) {
1631                 telrcv_state = TS_IAC;
1632                 break;
1633             }
1634                     /* 
1635                      * The 'crmod' hack (see following) is needed
1636                      * since we can't set CRMOD on output only.
1637                      * Machines like MULTICS like to send \r without
1638                      * \n; since we must turn off CRMOD to get proper
1639                      * input, the mapping is done here (sigh).
1640                      */
1641             if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
1642                 if (scc > 0) {
1643                     c = *sbp&0xff;
1644 #if     defined(ENCRYPTION)
1645                     if (decrypt_input)
1646                         c = (*decrypt_input)(c);
1647 #endif
1648                     if (c == 0) {
1649                         sbp++, scc--; count++;
1650                         /* a "true" CR */
1651                         TTYADD('\r');
1652                     } else if (my_want_state_is_dont(TELOPT_ECHO) &&
1653                                         (c == '\n')) {
1654                         sbp++, scc--; count++;
1655                         TTYADD('\n');
1656                     } else {
1657 #if     defined(ENCRYPTION)
1658                         if (decrypt_input)
1659                             (*decrypt_input)(-1);
1660 #endif
1661
1662                         TTYADD('\r');
1663                         if (crmod) {
1664                                 TTYADD('\n');
1665                         }
1666                     }
1667                 } else {
1668                     telrcv_state = TS_CR;
1669                     TTYADD('\r');
1670                     if (crmod) {
1671                             TTYADD('\n');
1672                     }
1673                 }
1674             } else {
1675                 TTYADD(c);
1676             }
1677             continue;
1678
1679         case TS_IAC:
1680 process_iac:
1681             switch (c) {
1682
1683             case WILL:
1684                 telrcv_state = TS_WILL;
1685                 continue;
1686
1687             case WONT:
1688                 telrcv_state = TS_WONT;
1689                 continue;
1690
1691             case DO:
1692                 telrcv_state = TS_DO;
1693                 continue;
1694
1695             case DONT:
1696                 telrcv_state = TS_DONT;
1697                 continue;
1698
1699             case DM:
1700                     /*
1701                      * We may have missed an urgent notification,
1702                      * so make sure we flush whatever is in the
1703                      * buffer currently.
1704                      */
1705                 printoption("RCVD", IAC, DM);
1706                 SYNCHing = 1;
1707                 ttyflush(1);
1708                 SYNCHing = stilloob();
1709                 settimer(gotDM);
1710                 break;
1711
1712             case SB:
1713                 SB_CLEAR();
1714                 telrcv_state = TS_SB;
1715                 continue;
1716
1717
1718             case IAC:
1719                 TTYADD(IAC);
1720                 break;
1721
1722             case NOP:
1723             case GA:
1724             default:
1725                 printoption("RCVD", IAC, c);
1726                 break;
1727             }
1728             telrcv_state = TS_DATA;
1729             continue;
1730
1731         case TS_WILL:
1732             printoption("RCVD", WILL, c);
1733             willoption(c);
1734             telrcv_state = TS_DATA;
1735             continue;
1736
1737         case TS_WONT:
1738             printoption("RCVD", WONT, c);
1739             wontoption(c);
1740             telrcv_state = TS_DATA;
1741             continue;
1742
1743         case TS_DO:
1744             printoption("RCVD", DO, c);
1745             dooption(c);
1746             if (c == TELOPT_NAWS) {
1747                 sendnaws();
1748             } else if (c == TELOPT_LFLOW) {
1749                 localflow = 1;
1750                 setcommandmode();
1751                 setconnmode(0);
1752             }
1753             telrcv_state = TS_DATA;
1754             continue;
1755
1756         case TS_DONT:
1757             printoption("RCVD", DONT, c);
1758             dontoption(c);
1759             flushline = 1;
1760             setconnmode(0);     /* set new tty mode (maybe) */
1761             telrcv_state = TS_DATA;
1762             continue;
1763
1764         case TS_SB:
1765             if (c == IAC) {
1766                 telrcv_state = TS_SE;
1767             } else {
1768                 SB_ACCUM(c);
1769             }
1770             continue;
1771
1772         case TS_SE:
1773             if (c != SE) {
1774                 if (c != IAC) {
1775                     /*
1776                      * This is an error.  We only expect to get
1777                      * "IAC IAC" or "IAC SE".  Several things may
1778                      * have happened.  An IAC was not doubled, the
1779                      * IAC SE was left off, or another option got
1780                      * inserted into the suboption are all possibilities.
1781                      * If we assume that the IAC was not doubled,
1782                      * and really the IAC SE was left off, we could
1783                      * get into an infinite loop here.  So, instead,
1784                      * we terminate the suboption, and process the
1785                      * partial suboption if we can.
1786                      */
1787                     SB_ACCUM(IAC);
1788                     SB_ACCUM(c);
1789                     subpointer -= 2;
1790                     SB_TERM();
1791
1792                     printoption("In SUBOPTION processing, RCVD", IAC, c);
1793                     suboption();        /* handle sub-option */
1794                     telrcv_state = TS_IAC;
1795                     goto process_iac;
1796                 }
1797                 SB_ACCUM(c);
1798                 telrcv_state = TS_SB;
1799             } else {
1800                 SB_ACCUM(IAC);
1801                 SB_ACCUM(SE);
1802                 subpointer -= 2;
1803                 SB_TERM();
1804                 suboption();    /* handle sub-option */
1805                 telrcv_state = TS_DATA;
1806             }
1807         }
1808     }
1809     if (count)
1810         ring_consumed(&netiring, count);
1811     return returnValue||count;
1812 }
1813
1814 static int bol = 1, local = 0;
1815
1816 int
1817 rlogin_susp(void)
1818 {
1819     if (local) {
1820         local = 0;
1821         bol = 1;
1822         command(0, "z\n", 2);
1823         return(1);
1824     }
1825     return(0);
1826 }
1827
1828 static int
1829 telsnd()
1830 {
1831     int tcc;
1832     int count;
1833     int returnValue = 0;
1834     unsigned char *tbp = NULL;
1835
1836     tcc = 0;
1837     count = 0;
1838     while (NETROOM() > 2) {
1839         int sc;
1840         int c;
1841
1842         if (tcc == 0) {
1843             if (count) {
1844                 ring_consumed(&ttyiring, count);
1845                 returnValue = 1;
1846                 count = 0;
1847             }
1848             tbp = ttyiring.consume;
1849             tcc = ring_full_consecutive(&ttyiring);
1850             if (tcc == 0) {
1851                 break;
1852             }
1853         }
1854         c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
1855         if (rlogin != _POSIX_VDISABLE) {
1856                 if (bol) {
1857                         bol = 0;
1858                         if (sc == rlogin) {
1859                                 local = 1;
1860                                 continue;
1861                         }
1862                 } else if (local) {
1863                         local = 0;
1864                         if (sc == '.' || c == termEofChar) {
1865                                 bol = 1;
1866                                 command(0, "close\n", 6);
1867                                 continue;
1868                         }
1869                         if (sc == termSuspChar) {
1870                                 bol = 1;
1871                                 command(0, "z\n", 2);
1872                                 continue;
1873                         }
1874                         if (sc == escape) {
1875                                 command(0, (char *)tbp, tcc);
1876                                 bol = 1;
1877                                 count += tcc;
1878                                 tcc = 0;
1879                                 flushline = 1;
1880                                 break;
1881                         }
1882                         if (sc != rlogin) {
1883                                 ++tcc;
1884                                 --tbp;
1885                                 --count;
1886                                 c = sc = rlogin;
1887                         }
1888                 }
1889                 if ((sc == '\n') || (sc == '\r'))
1890                         bol = 1;
1891         } else if (sc == escape) {
1892             /*
1893              * Double escape is a pass through of a single escape character.
1894              */
1895             if (tcc && strip(*tbp) == escape) {
1896                 tbp++;
1897                 tcc--;
1898                 count++;
1899                 bol = 0;
1900             } else {
1901                 command(0, (char *)tbp, tcc);
1902                 bol = 1;
1903                 count += tcc;
1904                 tcc = 0;
1905                 flushline = 1;
1906                 break;
1907             }
1908         } else
1909             bol = 0;
1910 #ifdef  KLUDGELINEMODE
1911         if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
1912             if (tcc > 0 && strip(*tbp) == echoc) {
1913                 tcc--; tbp++; count++;
1914             } else {
1915                 dontlecho = !dontlecho;
1916                 settimer(echotoggle);
1917                 setconnmode(0);
1918                 flushline = 1;
1919                 break;
1920             }
1921         }
1922 #endif
1923         if (MODE_LOCAL_CHARS(globalmode)) {
1924             if (TerminalSpecialChars(sc) == 0) {
1925                 bol = 1;
1926                 break;
1927             }
1928         }
1929         if (my_want_state_is_wont(TELOPT_BINARY)) {
1930             switch (c) {
1931             case '\n':
1932                     /*
1933                      * If we are in CRMOD mode (\r ==> \n)
1934                      * on our local machine, then probably
1935                      * a newline (unix) is CRLF (TELNET).
1936                      */
1937                 if (MODE_LOCAL_CHARS(globalmode)) {
1938                     NETADD('\r');
1939                 }
1940                 NETADD('\n');
1941                 bol = flushline = 1;
1942                 break;
1943             case '\r':
1944                 if (!crlf) {
1945                     NET2ADD('\r', '\0');
1946                 } else {
1947                     NET2ADD('\r', '\n');
1948                 }
1949                 bol = flushline = 1;
1950                 break;
1951             case IAC:
1952                 NET2ADD(IAC, IAC);
1953                 break;
1954             default:
1955                 NETADD(c);
1956                 break;
1957             }
1958         } else if (c == IAC) {
1959             NET2ADD(IAC, IAC);
1960         } else {
1961             NETADD(c);
1962         }
1963     }
1964     if (count)
1965         ring_consumed(&ttyiring, count);
1966     return returnValue||count;          /* Non-zero if we did anything */
1967 }
1968
1969 /*
1970  * Scheduler()
1971  *
1972  * Try to do something.
1973  *
1974  * If we do something useful, return 1; else return 0.
1975  *
1976  */
1977
1978
1979     int
1980 Scheduler(int block) /* should we block in the select ? */
1981 {
1982                 /* One wants to be a bit careful about setting returnValue
1983                  * to one, since a one implies we did some useful work,
1984                  * and therefore probably won't be called to block next
1985                  * time (TN3270 mode only).
1986                  */
1987     int returnValue;
1988     int netin, netout, netex, ttyin, ttyout;
1989
1990     /* Decide which rings should be processed */
1991
1992     netout = ring_full_count(&netoring) &&
1993             (flushline ||
1994                 (my_want_state_is_wont(TELOPT_LINEMODE)
1995 #ifdef  KLUDGELINEMODE
1996                         && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
1997 #endif
1998                 ) ||
1999                         my_want_state_is_will(TELOPT_BINARY));
2000     ttyout = ring_full_count(&ttyoring);
2001
2002     ttyin = ring_empty_count(&ttyiring);
2003
2004     netin = !ISend && ring_empty_count(&netiring);
2005
2006     netex = !SYNCHing;
2007
2008     /* If we have seen a signal recently, reset things */
2009
2010     if (scheduler_lockout_tty) {
2011         ttyin = ttyout = 0;
2012     }
2013
2014     /* Call to system code to process rings */
2015
2016     returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
2017
2018     /* Now, look at the input rings, looking for work to do. */
2019
2020     if (ring_full_count(&ttyiring)) {
2021             returnValue |= telsnd();
2022     }
2023
2024     if (ring_full_count(&netiring)) {
2025         returnValue |= telrcv();
2026     }
2027     return returnValue;
2028 }
2029
2030 extern int auth_has_failed; /* XXX should be somewhere else */
2031
2032 /*
2033  * Select from tty and network...
2034  */
2035 void
2036 my_telnet(char *user)
2037 {
2038     int printed_encrypt = 0;
2039     
2040     sys_telnet_init();
2041
2042 #if     defined(AUTHENTICATION) || defined(ENCRYPTION)
2043     {
2044         static char local_host[256] = { 0 };
2045
2046         if (!local_host[0]) {
2047                 /* XXX - should be k_gethostname? */
2048                 gethostname(local_host, sizeof(local_host));
2049                 local_host[sizeof(local_host)-1] = 0;
2050         }
2051         auth_encrypt_init(local_host, hostname, "TELNET", 0);
2052         auth_encrypt_user(user);
2053     }
2054 #endif
2055     if (telnetport) {
2056 #if     defined(AUTHENTICATION)
2057         if (autologin)
2058                 send_will(TELOPT_AUTHENTICATION, 1);
2059 #endif
2060 #if     defined(ENCRYPTION)
2061         send_do(TELOPT_ENCRYPT, 1);
2062         send_will(TELOPT_ENCRYPT, 1);
2063 #endif
2064         send_do(TELOPT_SGA, 1);
2065         send_will(TELOPT_TTYPE, 1);
2066         send_will(TELOPT_NAWS, 1);
2067         send_will(TELOPT_TSPEED, 1);
2068         send_will(TELOPT_LFLOW, 1);
2069         send_will(TELOPT_LINEMODE, 1);
2070         send_will(TELOPT_NEW_ENVIRON, 1);
2071         send_do(TELOPT_STATUS, 1);
2072         if (env_getvalue((unsigned char *)"DISPLAY"))
2073             send_will(TELOPT_XDISPLOC, 1);
2074         if (binary)
2075             tel_enter_binary(binary);
2076     }
2077
2078 #ifdef ENCRYPTION
2079     /*
2080      * Note: we assume a tie to the authentication option here.  This
2081      * is necessary so that authentication fails, we don't spin
2082      * forever. 
2083      */
2084     if (telnetport && wantencryption) {
2085         time_t timeout = time(0) + 60;
2086
2087         send_do(TELOPT_ENCRYPT, 1);
2088         send_will(TELOPT_ENCRYPT, 1);
2089         while (1) {
2090             if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) {
2091                 if (wantencryption == -1) {
2092                     break;
2093                 } else {
2094                     printf("\nServer refused to negotiate authentication,\n");
2095                     printf("which is required for encryption.\n");
2096                     Exit(1);
2097                 }
2098             }
2099             if (auth_has_failed) {
2100                 printf("\nAuthentication negotiation has failed,\n");
2101                 printf("which is required for encryption.\n");
2102                 Exit(1);
2103             }
2104             if (my_want_state_is_dont(TELOPT_ENCRYPT) ||
2105                 my_want_state_is_wont(TELOPT_ENCRYPT)) {
2106                 printf("\nServer refused to negotiate encryption.\n");
2107                 Exit(1);
2108             }
2109             if (encrypt_is_encrypting())
2110                 break;
2111             if (time(0) > timeout) {
2112                 printf("\nEncryption could not be enabled.\n");
2113                 Exit(1);
2114             }
2115             if (printed_encrypt == 0) {
2116                     printed_encrypt = 1;
2117                     printf("Waiting for encryption to be negotiated...\n");
2118                     /*
2119                      * Turn on MODE_TRAPSIG and then turn off localchars 
2120                      * so that ^C will cause telnet to exit.
2121                      */
2122                     TerminalNewMode(getconnmode()|MODE_TRAPSIG);
2123                     intr_waiting = 1;
2124             }
2125             if (intr_happened) {
2126                     printf("\nUser interrupt.\n");
2127                     Exit(1);
2128             }
2129             if (telnet_spin()) {
2130                     printf("\nServer disconnected.\n");
2131                     Exit(1);
2132             }
2133                 
2134         }
2135         if (printed_encrypt) {
2136                 printf("Encryption negotiated.\n");
2137                 intr_waiting = 0;
2138                 setconnmode(0);
2139         }
2140     }
2141 #endif
2142
2143     for (;;) {
2144         int schedValue;
2145
2146         while ((schedValue = Scheduler(0)) != 0) {
2147             if (schedValue == -1) {
2148                 setcommandmode();
2149                 return;
2150             }
2151         }
2152
2153         if (Scheduler(1) == -1) {
2154             setcommandmode();
2155             return;
2156         }
2157     }
2158 }
2159
2160 /*
2161  * netclear()
2162  *
2163  *      We are about to do a TELNET SYNCH operation.  Clear
2164  * the path to the network.
2165  *
2166  *      Things are a bit tricky since we may have sent the first
2167  * byte or so of a previous TELNET command into the network.
2168  * So, we have to scan the network buffer from the beginning
2169  * until we are up to where we want to be.
2170  *
2171  *      A side effect of what we do, just to keep things
2172  * simple, is to clear the urgent data pointer.  The principal
2173  * caller should be setting the urgent data pointer AFTER calling
2174  * us in any case.
2175  */
2176
2177 static void
2178 netclear()
2179 {
2180 #if     0       /* XXX */
2181     char *thisitem, *next;
2182     char *good;
2183 #define wewant(p)       ((nfrontp > p) && ((*p&0xff) == IAC) && \
2184                                 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
2185
2186     thisitem = netobuf;
2187
2188     while ((next = nextitem(thisitem)) <= netobuf.send) {
2189         thisitem = next;
2190     }
2191
2192     /* Now, thisitem is first before/at boundary. */
2193
2194     good = netobuf;     /* where the good bytes go */
2195
2196     while (netoring.add > thisitem) {
2197         if (wewant(thisitem)) {
2198             int length;
2199
2200             next = thisitem;
2201             do {
2202                 next = nextitem(next);
2203             } while (wewant(next) && (nfrontp > next));
2204             length = next-thisitem;
2205             memmove(good, thisitem, length);
2206             good += length;
2207             thisitem = next;
2208         } else {
2209             thisitem = nextitem(thisitem);
2210         }
2211     }
2212
2213 #endif  /* 0 */
2214 }
2215
2216 /*
2217  * These routines add various telnet commands to the data stream.
2218  */
2219
2220 static void
2221 doflush()
2222 {
2223     NET2ADD(IAC, DO);
2224     NETADD(TELOPT_TM);
2225     flushline = 1;
2226     flushout = 1;
2227     ttyflush(1);                        /* Flush/drop output */
2228     /* do printoption AFTER flush, otherwise the output gets tossed... */
2229     printoption("SENT", DO, TELOPT_TM);
2230 }
2231
2232 void
2233 xmitAO(void)
2234 {
2235     NET2ADD(IAC, AO);
2236     printoption("SENT", IAC, AO);
2237     if (autoflush) {
2238         doflush();
2239     }
2240 }
2241
2242
2243 void
2244 xmitEL(void)
2245 {
2246     NET2ADD(IAC, EL);
2247     printoption("SENT", IAC, EL);
2248 }
2249
2250 void
2251 xmitEC(void)
2252 {
2253     NET2ADD(IAC, EC);
2254     printoption("SENT", IAC, EC);
2255 }
2256
2257
2258 int
2259 dosynch()
2260 {
2261     netclear();                 /* clear the path to the network */
2262     NETADD(IAC);
2263     setneturg();
2264     NETADD(DM);
2265     printoption("SENT", IAC, DM);
2266     return 1;
2267 }
2268
2269 int want_status_response = 0;
2270
2271 int
2272 get_status()
2273 {
2274     unsigned char tmp[16];
2275     unsigned char *cp;
2276
2277     if (my_want_state_is_dont(TELOPT_STATUS)) {
2278         printf("Remote side does not support STATUS option\n");
2279         return 0;
2280     }
2281     cp = tmp;
2282
2283     *cp++ = IAC;
2284     *cp++ = SB;
2285     *cp++ = TELOPT_STATUS;
2286     *cp++ = TELQUAL_SEND;
2287     *cp++ = IAC;
2288     *cp++ = SE;
2289     if (NETROOM() >= cp - tmp) {
2290         ring_supply_data(&netoring, tmp, cp-tmp);
2291         printsub('>', tmp+2, cp - tmp - 2);
2292     }
2293     ++want_status_response;
2294     return 1;
2295 }
2296
2297 void
2298 intp(void)
2299 {
2300     NET2ADD(IAC, IP);
2301     printoption("SENT", IAC, IP);
2302     flushline = 1;
2303     if (autoflush) {
2304         doflush();
2305     }
2306     if (autosynch) {
2307         dosynch();
2308     }
2309 }
2310
2311 void
2312 sendbrk(void)
2313 {
2314     NET2ADD(IAC, BREAK);
2315     printoption("SENT", IAC, BREAK);
2316     flushline = 1;
2317     if (autoflush) {
2318         doflush();
2319     }
2320     if (autosynch) {
2321         dosynch();
2322     }
2323 }
2324
2325 void
2326 sendabort(void)
2327 {
2328     NET2ADD(IAC, ABORT);
2329     printoption("SENT", IAC, ABORT);
2330     flushline = 1;
2331     if (autoflush) {
2332         doflush();
2333     }
2334     if (autosynch) {
2335         dosynch();
2336     }
2337 }
2338
2339 void
2340 sendsusp(void)
2341 {
2342     NET2ADD(IAC, SUSP);
2343     printoption("SENT", IAC, SUSP);
2344     flushline = 1;
2345     if (autoflush) {
2346         doflush();
2347     }
2348     if (autosynch) {
2349         dosynch();
2350     }
2351 }
2352
2353 void
2354 sendeof(void)
2355 {
2356     NET2ADD(IAC, xEOF);
2357     printoption("SENT", IAC, xEOF);
2358 }
2359
2360 void
2361 sendayt(void)
2362 {
2363     NET2ADD(IAC, AYT);
2364     printoption("SENT", IAC, AYT);
2365 }
2366
2367 /*
2368  * Send a window size update to the remote system.
2369  */
2370
2371 void
2372 sendnaws()
2373 {
2374     long rows, cols;
2375     unsigned char tmp[16];
2376     unsigned char *cp;
2377
2378     if (my_state_is_wont(TELOPT_NAWS))
2379         return;
2380
2381 #undef PUTSHORT
2382 #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
2383                             if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
2384
2385     if (TerminalWindowSize(&rows, &cols) == 0) {        /* Failed */
2386         return;
2387     }
2388
2389     cp = tmp;
2390
2391     *cp++ = IAC;
2392     *cp++ = SB;
2393     *cp++ = TELOPT_NAWS;
2394     PUTSHORT(cp, cols);
2395     PUTSHORT(cp, rows);
2396     *cp++ = IAC;
2397     *cp++ = SE;
2398     if (NETROOM() >= cp - tmp) {
2399         ring_supply_data(&netoring, tmp, cp-tmp);
2400         printsub('>', tmp+2, cp - tmp - 2);
2401     }
2402 }
2403
2404 void
2405 tel_enter_binary(int rw)
2406 {
2407     if (rw&1)
2408         send_do(TELOPT_BINARY, 1);
2409     if (rw&2)
2410         send_will(TELOPT_BINARY, 1);
2411 }
2412
2413 void
2414 tel_leave_binary(int rw)
2415 {
2416     if (rw&1)
2417         send_dont(TELOPT_BINARY, 1);
2418     if (rw&2)
2419         send_wont(TELOPT_BINARY, 1);
2420 }