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