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