Merge branch 'vendor/OPENSSL'
[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.4 2005/03/31 16:11:13 corecode 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 const * const slc_reply_eom = &slc_reply[sizeof(slc_reply)];
1193 unsigned char *slc_replyp;
1194
1195 void
1196 slc_start_reply(void)
1197 {
1198         slc_replyp = slc_reply;
1199         *slc_replyp++ = IAC;
1200         *slc_replyp++ = SB;
1201         *slc_replyp++ = TELOPT_LINEMODE;
1202         *slc_replyp++ = LM_SLC;
1203 }
1204
1205 void
1206 slc_add_reply(unsigned char func, unsigned char flags, cc_t value)
1207 {
1208         /* A sequence of up to 6 bytes my be written for this member of the SLC
1209          * suboption list by this function.  The end of negotiation command,
1210          * which is written by slc_end_reply(), will require 2 additional
1211          * bytes.  Do not proceed unless there is sufficient space for these
1212          * items.
1213          */
1214         if (&slc_replyp[6+2] > slc_reply_eom)
1215                 return;
1216         if ((*slc_replyp++ = func) == IAC)
1217                 *slc_replyp++ = IAC;
1218         if ((*slc_replyp++ = flags) == IAC)
1219                 *slc_replyp++ = IAC;
1220         if ((*slc_replyp++ = (unsigned char)value) == IAC)
1221                 *slc_replyp++ = IAC;
1222 }
1223
1224 void
1225 slc_end_reply(void)
1226 {
1227     int len;
1228
1229     /* The end of negotiation command requires 2 bytes. */
1230     if (&slc_replyp[2] > slc_reply_eom)
1231         return;
1232     *slc_replyp++ = IAC;
1233     *slc_replyp++ = SE;
1234     len = slc_replyp - slc_reply;
1235     if (len <= 6)
1236         return;
1237     if (NETROOM() > len) {
1238         ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
1239         printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
1240     }
1241 /*@*/else printf("slc_end_reply: not enough room\n");
1242 }
1243
1244 int
1245 slc_update(void)
1246 {
1247         struct spc *spcp;
1248         int need_update = 0;
1249
1250         for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1251                 if (!(spcp->flags&SLC_ACK))
1252                         continue;
1253                 spcp->flags &= ~SLC_ACK;
1254                 if (spcp->valp && (*spcp->valp != spcp->val)) {
1255                         *spcp->valp = spcp->val;
1256                         need_update = 1;
1257                 }
1258         }
1259         return(need_update);
1260 }
1261
1262 #ifdef  OLD_ENVIRON
1263 # ifdef ENV_HACK
1264 /*
1265  * Earlier version of telnet/telnetd from the BSD code had
1266  * the definitions of VALUE and VAR reversed.  To ensure
1267  * maximum interoperability, we assume that the server is
1268  * an older BSD server, until proven otherwise.  The newer
1269  * BSD servers should be able to handle either definition,
1270  * so it is better to use the wrong values if we don't
1271  * know what type of server it is.
1272  */
1273 int env_auto = 1;
1274 int old_env_var = OLD_ENV_VAR;
1275 int old_env_value = OLD_ENV_VALUE;
1276 # else
1277 #  define old_env_var OLD_ENV_VAR
1278 #  define old_env_value OLD_ENV_VALUE
1279 # endif
1280 #endif
1281
1282 void
1283 env_opt(unsigned char *buf, int len)
1284 {
1285         unsigned char *ep = 0, *epc = 0;
1286         int i;
1287
1288         switch(buf[0]&0xff) {
1289         case TELQUAL_SEND:
1290                 env_opt_start();
1291                 if (len == 1) {
1292                         env_opt_add(NULL);
1293                 } else for (i = 1; i < len; i++) {
1294                         switch (buf[i]&0xff) {
1295 #ifdef  OLD_ENVIRON
1296                         case OLD_ENV_VAR:
1297 # ifdef ENV_HACK
1298                                 if (telopt_environ == TELOPT_OLD_ENVIRON
1299                                     && env_auto) {
1300                                         /* Server has the same definitions */
1301                                         old_env_var = OLD_ENV_VAR;
1302                                         old_env_value = OLD_ENV_VALUE;
1303                                 }
1304                                 /* FALL THROUGH */
1305 # endif
1306                         case OLD_ENV_VALUE:
1307                                 /*
1308                                  * Although OLD_ENV_VALUE is not legal, we will
1309                                  * still recognize it, just in case it is an
1310                                  * old server that has VAR & VALUE mixed up...
1311                                  */
1312                                 /* FALL THROUGH */
1313 #else
1314                         case NEW_ENV_VAR:
1315 #endif
1316                         case ENV_USERVAR:
1317                                 if (ep) {
1318                                         *epc = 0;
1319                                         env_opt_add(ep);
1320                                 }
1321                                 ep = epc = &buf[i+1];
1322                                 break;
1323                         case ENV_ESC:
1324                                 i++;
1325                                 /*FALL THROUGH*/
1326                         default:
1327                                 if (epc)
1328                                         *epc++ = buf[i];
1329                                 break;
1330                         }
1331                 }
1332                 if (ep) {
1333                         *epc = 0;
1334                         env_opt_add(ep);
1335                 }
1336                 env_opt_end(1);
1337                 break;
1338
1339         case TELQUAL_IS:
1340         case TELQUAL_INFO:
1341                 /* Ignore for now.  We shouldn't get it anyway. */
1342                 break;
1343
1344         default:
1345                 break;
1346         }
1347 }
1348
1349 #define OPT_REPLY_SIZE  (2 * SUBBUFSIZE)
1350 unsigned char *opt_reply = NULL;
1351 unsigned char *opt_replyp;
1352 unsigned char *opt_replyend;
1353
1354 void
1355 env_opt_start(void)
1356 {
1357         if (opt_reply)
1358                 opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE);
1359         else
1360                 opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE);
1361         if (opt_reply == NULL) {
1362 /*@*/           printf("env_opt_start: malloc()/realloc() failed!!!\n");
1363                 opt_reply = opt_replyp = opt_replyend = NULL;
1364                 return;
1365         }
1366         opt_replyp = opt_reply;
1367         opt_replyend = opt_reply + OPT_REPLY_SIZE;
1368         *opt_replyp++ = IAC;
1369         *opt_replyp++ = SB;
1370         *opt_replyp++ = telopt_environ;
1371         *opt_replyp++ = TELQUAL_IS;
1372 }
1373
1374 void
1375 env_opt_start_info(void)
1376 {
1377         env_opt_start();
1378         if (opt_replyp)
1379             opt_replyp[-1] = TELQUAL_INFO;
1380 }
1381
1382 void
1383 env_opt_add(unsigned char *ep)
1384 {
1385         unsigned char *vp, c;
1386
1387         if (opt_reply == NULL)          /*XXX*/
1388                 return;                 /*XXX*/
1389
1390         if (ep == NULL || *ep == '\0') {
1391                 /* Send user defined variables first. */
1392                 env_default(1, 0);
1393                 while ((ep = env_default(0, 0)))
1394                         env_opt_add(ep);
1395
1396                 /* Now add the list of well know variables.  */
1397                 env_default(1, 1);
1398                 while ((ep = env_default(0, 1)))
1399                         env_opt_add(ep);
1400                 return;
1401         }
1402         vp = env_getvalue(ep);
1403         if (opt_replyp + (vp ? 2 * strlen((char *)vp) : 0) +
1404                                 2 * strlen((char *)ep) + 6 > opt_replyend)
1405         {
1406
1407                 int len;
1408                 opt_replyend += OPT_REPLY_SIZE;
1409                 len = opt_replyend - opt_reply;
1410                 opt_reply = (unsigned char *)realloc(opt_reply, len);
1411                 if (opt_reply == NULL) {
1412 /*@*/                   printf("env_opt_add: realloc() failed!!!\n");
1413                         opt_reply = opt_replyp = opt_replyend = NULL;
1414                         return;
1415                 }
1416                 opt_replyp = opt_reply + len - (opt_replyend - opt_replyp);
1417                 opt_replyend = opt_reply + len;
1418         }
1419         if (opt_welldefined(ep))
1420 #ifdef  OLD_ENVIRON
1421                 if (telopt_environ == TELOPT_OLD_ENVIRON)
1422                         *opt_replyp++ = old_env_var;
1423                 else
1424 #endif
1425                         *opt_replyp++ = NEW_ENV_VAR;
1426         else
1427                 *opt_replyp++ = ENV_USERVAR;
1428         for (;;) {
1429                 while ((c = *ep++)) {
1430                         if (opt_replyp + (2 + 2) > opt_replyend)
1431                                 return;
1432                         switch(c&0xff) {
1433                         case IAC:
1434                                 *opt_replyp++ = IAC;
1435                                 break;
1436                         case NEW_ENV_VAR:
1437                         case NEW_ENV_VALUE:
1438                         case ENV_ESC:
1439                         case ENV_USERVAR:
1440                                 *opt_replyp++ = ENV_ESC;
1441                                 break;
1442                         }
1443                         *opt_replyp++ = c;
1444                 }
1445                 if ((ep = vp)) {
1446                         if (opt_replyp + (1 + 2 + 2) > opt_replyend)
1447                                 return;
1448 #ifdef  OLD_ENVIRON
1449                         if (telopt_environ == TELOPT_OLD_ENVIRON)
1450                                 *opt_replyp++ = old_env_value;
1451                         else
1452 #endif
1453                                 *opt_replyp++ = NEW_ENV_VALUE;
1454                         vp = NULL;
1455                 } else
1456                         break;
1457         }
1458 }
1459
1460 int
1461 opt_welldefined(const char *ep)
1462 {
1463         if ((strcmp(ep, "USER") == 0) ||
1464             (strcmp(ep, "DISPLAY") == 0) ||
1465             (strcmp(ep, "PRINTER") == 0) ||
1466             (strcmp(ep, "SYSTEMTYPE") == 0) ||
1467             (strcmp(ep, "JOB") == 0) ||
1468             (strcmp(ep, "ACCT") == 0))
1469                 return(1);
1470         return(0);
1471 }
1472
1473 void
1474 env_opt_end(int emptyok)
1475 {
1476         int len;
1477
1478         if (opt_replyp + 2 > opt_replyend)
1479                 return;
1480         len = opt_replyp + 2 - opt_reply;
1481         if (emptyok || len > 6) {
1482                 *opt_replyp++ = IAC;
1483                 *opt_replyp++ = SE;
1484                 if (NETROOM() > len) {
1485                         ring_supply_data(&netoring, opt_reply, len);
1486                         printsub('>', &opt_reply[2], len - 2);
1487                 }
1488 /*@*/           else printf("slc_end_reply: not enough room\n");
1489         }
1490         if (opt_reply) {
1491                 free(opt_reply);
1492                 opt_reply = opt_replyp = opt_replyend = NULL;
1493         }
1494 }
1495
1496 \f
1497
1498 int
1499 telrcv(void)
1500 {
1501     int c;
1502     int scc;
1503     unsigned char *sbp;
1504     int count;
1505     int returnValue = 0;
1506
1507     scc = 0;
1508     count = 0;
1509     while (TTYROOM() > 2) {
1510         if (scc == 0) {
1511             if (count) {
1512                 ring_consumed(&netiring, count);
1513                 returnValue = 1;
1514                 count = 0;
1515             }
1516             sbp = netiring.consume;
1517             scc = ring_full_consecutive(&netiring);
1518             if (scc == 0) {
1519                 /* No more data coming in */
1520                 break;
1521             }
1522         }
1523
1524         c = *sbp++ & 0xff, scc--; count++;
1525
1526         switch (telrcv_state) {
1527
1528         case TS_CR:
1529             telrcv_state = TS_DATA;
1530             if (c == '\0') {
1531                 break;  /* Ignore \0 after CR */
1532             }
1533             else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
1534                 TTYADD(c);
1535                 break;
1536             }
1537             /* Else, fall through */
1538
1539         case TS_DATA:
1540             if (c == IAC) {
1541                 telrcv_state = TS_IAC;
1542                 break;
1543             }
1544                     /*
1545                      * The 'crmod' hack (see following) is needed
1546                      * since we can't * set CRMOD on output only.
1547                      * Machines like MULTICS like to send \r without
1548                      * \n; since we must turn off CRMOD to get proper
1549                      * input, the mapping is done here (sigh).
1550                      */
1551             if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
1552                 if (scc > 0) {
1553                     c = *sbp&0xff;
1554                     if (c == 0) {
1555                         sbp++, scc--; count++;
1556                         /* a "true" CR */
1557                         TTYADD('\r');
1558                     } else if (my_want_state_is_dont(TELOPT_ECHO) &&
1559                                         (c == '\n')) {
1560                         sbp++, scc--; count++;
1561                         TTYADD('\n');
1562                     } else {
1563
1564                         TTYADD('\r');
1565                         if (crmod) {
1566                                 TTYADD('\n');
1567                         }
1568                     }
1569                 } else {
1570                     telrcv_state = TS_CR;
1571                     TTYADD('\r');
1572                     if (crmod) {
1573                             TTYADD('\n');
1574                     }
1575                 }
1576             } else {
1577                 TTYADD(c);
1578             }
1579             continue;
1580
1581         case TS_IAC:
1582 process_iac:
1583             switch (c) {
1584
1585             case WILL:
1586                 telrcv_state = TS_WILL;
1587                 continue;
1588
1589             case WONT:
1590                 telrcv_state = TS_WONT;
1591                 continue;
1592
1593             case DO:
1594                 telrcv_state = TS_DO;
1595                 continue;
1596
1597             case DONT:
1598                 telrcv_state = TS_DONT;
1599                 continue;
1600
1601             case DM:
1602                     /*
1603                      * We may have missed an urgent notification,
1604                      * so make sure we flush whatever is in the
1605                      * buffer currently.
1606                      */
1607                 printoption("RCVD", IAC, DM);
1608                 SYNCHing = 1;
1609                 (void) ttyflush(1);
1610                 SYNCHing = stilloob();
1611                 settimer(gotDM);
1612                 break;
1613
1614             case SB:
1615                 SB_CLEAR();
1616                 telrcv_state = TS_SB;
1617                 continue;
1618
1619             case IAC:
1620                 TTYADD(IAC);
1621                 break;
1622
1623             case NOP:
1624             case GA:
1625             default:
1626                 printoption("RCVD", IAC, c);
1627                 break;
1628             }
1629             telrcv_state = TS_DATA;
1630             continue;
1631
1632         case TS_WILL:
1633             printoption("RCVD", WILL, c);
1634             willoption(c);
1635             telrcv_state = TS_DATA;
1636             continue;
1637
1638         case TS_WONT:
1639             printoption("RCVD", WONT, c);
1640             wontoption(c);
1641             telrcv_state = TS_DATA;
1642             continue;
1643
1644         case TS_DO:
1645             printoption("RCVD", DO, c);
1646             dooption(c);
1647             if (c == TELOPT_NAWS) {
1648                 sendnaws();
1649             } else if (c == TELOPT_LFLOW) {
1650                 localflow = 1;
1651                 setcommandmode();
1652                 setconnmode(0);
1653             }
1654             telrcv_state = TS_DATA;
1655             continue;
1656
1657         case TS_DONT:
1658             printoption("RCVD", DONT, c);
1659             dontoption(c);
1660             flushline = 1;
1661             setconnmode(0);     /* set new tty mode (maybe) */
1662             telrcv_state = TS_DATA;
1663             continue;
1664
1665         case TS_SB:
1666             if (c == IAC) {
1667                 telrcv_state = TS_SE;
1668             } else {
1669                 SB_ACCUM(c);
1670             }
1671             continue;
1672
1673         case TS_SE:
1674             if (c != SE) {
1675                 if (c != IAC) {
1676                     /*
1677                      * This is an error.  We only expect to get
1678                      * "IAC IAC" or "IAC SE".  Several things may
1679                      * have happend.  An IAC was not doubled, the
1680                      * IAC SE was left off, or another option got
1681                      * inserted into the suboption are all possibilities.
1682                      * If we assume that the IAC was not doubled,
1683                      * and really the IAC SE was left off, we could
1684                      * get into an infinate loop here.  So, instead,
1685                      * we terminate the suboption, and process the
1686                      * partial suboption if we can.
1687                      */
1688                     SB_ACCUM(IAC);
1689                     SB_ACCUM(c);
1690                     subpointer -= 2;
1691                     SB_TERM();
1692
1693                     printoption("In SUBOPTION processing, RCVD", IAC, c);
1694                     suboption();        /* handle sub-option */
1695                     telrcv_state = TS_IAC;
1696                     goto process_iac;
1697                 }
1698                 SB_ACCUM(c);
1699                 telrcv_state = TS_SB;
1700             } else {
1701                 SB_ACCUM(IAC);
1702                 SB_ACCUM(SE);
1703                 subpointer -= 2;
1704                 SB_TERM();
1705                 suboption();    /* handle sub-option */
1706                 telrcv_state = TS_DATA;
1707             }
1708         }
1709     }
1710     if (count)
1711         ring_consumed(&netiring, count);
1712     return returnValue||count;
1713 }
1714
1715 static int bol = 1, local = 0;
1716
1717 int
1718 rlogin_susp(void)
1719 {
1720     if (local) {
1721         local = 0;
1722         bol = 1;
1723         command(0, "z\n", 2);
1724         return(1);
1725     }
1726     return(0);
1727 }
1728
1729 static int
1730 telsnd(void)
1731 {
1732     int tcc;
1733     int count;
1734     int returnValue = 0;
1735     unsigned char *tbp;
1736
1737     tcc = 0;
1738     count = 0;
1739     while (NETROOM() > 2) {
1740         int sc;
1741         int c;
1742
1743         if (tcc == 0) {
1744             if (count) {
1745                 ring_consumed(&ttyiring, count);
1746                 returnValue = 1;
1747                 count = 0;
1748             }
1749             tbp = ttyiring.consume;
1750             tcc = ring_full_consecutive(&ttyiring);
1751             if (tcc == 0) {
1752                 break;
1753             }
1754         }
1755         c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
1756         if (rlogin != _POSIX_VDISABLE) {
1757                 if (bol) {
1758                         bol = 0;
1759                         if (sc == rlogin) {
1760                                 local = 1;
1761                                 continue;
1762                         }
1763                 } else if (local) {
1764                         local = 0;
1765                         if (sc == '.' || c == termEofChar) {
1766                                 bol = 1;
1767                                 command(0, "close\n", 6);
1768                                 continue;
1769                         }
1770                         if (sc == termSuspChar) {
1771                                 bol = 1;
1772                                 command(0, "z\n", 2);
1773                                 continue;
1774                         }
1775                         if (sc == escape) {
1776                                 command(0, tbp, tcc);
1777                                 bol = 1;
1778                                 count += tcc;
1779                                 tcc = 0;
1780                                 flushline = 1;
1781                                 break;
1782                         }
1783                         if (sc != rlogin) {
1784                                 ++tcc;
1785                                 --tbp;
1786                                 --count;
1787                                 c = sc = rlogin;
1788                         }
1789                 }
1790                 if ((sc == '\n') || (sc == '\r'))
1791                         bol = 1;
1792         } else if (escape != _POSIX_VDISABLE && sc == escape) {
1793             /*
1794              * Double escape is a pass through of a single escape character.
1795              */
1796             if (tcc && strip(*tbp) == escape) {
1797                 tbp++;
1798                 tcc--;
1799                 count++;
1800                 bol = 0;
1801             } else {
1802                 command(0, (char *)tbp, tcc);
1803                 bol = 1;
1804                 count += tcc;
1805                 tcc = 0;
1806                 flushline = 1;
1807                 break;
1808             }
1809         } else
1810             bol = 0;
1811 #ifdef  KLUDGELINEMODE
1812         if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
1813             if (tcc > 0 && strip(*tbp) == echoc) {
1814                 tcc--; tbp++; count++;
1815             } else {
1816                 dontlecho = !dontlecho;
1817                 settimer(echotoggle);
1818                 setconnmode(0);
1819                 flushline = 1;
1820                 break;
1821             }
1822         }
1823 #endif
1824         if (MODE_LOCAL_CHARS(globalmode)) {
1825             if (TerminalSpecialChars(sc) == 0) {
1826                 bol = 1;
1827                 break;
1828             }
1829         }
1830         if (my_want_state_is_wont(TELOPT_BINARY)) {
1831             switch (c) {
1832             case '\n':
1833                     /*
1834                      * If we are in CRMOD mode (\r ==> \n)
1835                      * on our local machine, then probably
1836                      * a newline (unix) is CRLF (TELNET).
1837                      */
1838                 if (MODE_LOCAL_CHARS(globalmode)) {
1839                     NETADD('\r');
1840                 }
1841                 NETADD('\n');
1842                 bol = flushline = 1;
1843                 break;
1844             case '\r':
1845                 if (!crlf) {
1846                     NET2ADD('\r', '\0');
1847                 } else {
1848                     NET2ADD('\r', '\n');
1849                 }
1850                 bol = flushline = 1;
1851                 break;
1852             case IAC:
1853                 NET2ADD(IAC, IAC);
1854                 break;
1855             default:
1856                 NETADD(c);
1857                 break;
1858             }
1859         } else if (c == IAC) {
1860             NET2ADD(IAC, IAC);
1861         } else {
1862             NETADD(c);
1863         }
1864     }
1865     if (count)
1866         ring_consumed(&ttyiring, count);
1867     return returnValue||count;          /* Non-zero if we did anything */
1868 }
1869 \f
1870 /*
1871  * Scheduler()
1872  *
1873  * Try to do something.
1874  *
1875  * If we do something useful, return 1; else return 0.
1876  *
1877  */
1878
1879 static int
1880 Scheduler(int block)
1881 {
1882                 /* One wants to be a bit careful about setting returnValue
1883                  * to one, since a one implies we did some useful work,
1884                  * and therefore probably won't be called to block next
1885                  */
1886     int returnValue;
1887     int netin, netout, netex, ttyin, ttyout;
1888
1889     /* Decide which rings should be processed */
1890
1891     netout = ring_full_count(&netoring) &&
1892             (flushline ||
1893                 (my_want_state_is_wont(TELOPT_LINEMODE)
1894 #ifdef  KLUDGELINEMODE
1895                         && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
1896 #endif
1897                 ) ||
1898                         my_want_state_is_will(TELOPT_BINARY));
1899     ttyout = ring_full_count(&ttyoring);
1900
1901     ttyin = ring_empty_count(&ttyiring) && (clienteof == 0);
1902
1903     netin = !ISend && ring_empty_count(&netiring);
1904
1905     netex = !SYNCHing;
1906
1907     /* Call to system code to process rings */
1908
1909     returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
1910
1911     /* Now, look at the input rings, looking for work to do. */
1912
1913     if (ring_full_count(&ttyiring)) {
1914             returnValue |= telsnd();
1915     }
1916
1917     if (ring_full_count(&netiring)) {
1918         returnValue |= telrcv();
1919     }
1920     return returnValue;
1921 }
1922 \f
1923 #define __unusedhere __unused
1924 /*
1925  * Select from tty and network...
1926  */
1927 void
1928 telnet(char *user __unusedhere)
1929 {
1930     sys_telnet_init();
1931
1932     if (telnetport) {
1933         send_do(TELOPT_SGA, 1);
1934         send_will(TELOPT_TTYPE, 1);
1935         send_will(TELOPT_NAWS, 1);
1936         send_will(TELOPT_TSPEED, 1);
1937         send_will(TELOPT_LFLOW, 1);
1938         send_will(TELOPT_LINEMODE, 1);
1939         send_will(TELOPT_NEW_ENVIRON, 1);
1940         send_do(TELOPT_STATUS, 1);
1941         if (env_getvalue("DISPLAY"))
1942             send_will(TELOPT_XDISPLOC, 1);
1943         if (eight)
1944             tel_enter_binary(eight);
1945     }
1946
1947     for (;;) {
1948         int schedValue;
1949
1950         while ((schedValue = Scheduler(0)) != 0) {
1951             if (schedValue == -1) {
1952                 setcommandmode();
1953                 return;
1954             }
1955         }
1956
1957         if (Scheduler(1) == -1) {
1958             setcommandmode();
1959             return;
1960         }
1961     }
1962 }
1963 \f
1964 #if     0       /* XXX - this not being in is a bug */
1965 /*
1966  * nextitem()
1967  *
1968  *      Return the address of the next "item" in the TELNET data
1969  * stream.  This will be the address of the next character if
1970  * the current address is a user data character, or it will
1971  * be the address of the character following the TELNET command
1972  * if the current address is a TELNET IAC ("I Am a Command")
1973  * character.
1974  */
1975
1976 static char *
1977 nextitem(char *current)
1978 {
1979     if ((*current&0xff) != IAC) {
1980         return current+1;
1981     }
1982     switch (*(current+1)&0xff) {
1983     case DO:
1984     case DONT:
1985     case WILL:
1986     case WONT:
1987         return current+3;
1988     case SB:            /* loop forever looking for the SE */
1989         {
1990             char *look = current+2;
1991
1992             for (;;) {
1993                 if ((*look++&0xff) == IAC) {
1994                     if ((*look++&0xff) == SE) {
1995                         return look;
1996                     }
1997                 }
1998             }
1999         }
2000     default:
2001         return current+2;
2002     }
2003 }
2004 #endif  /* 0 */
2005
2006 /*
2007  * netclear()
2008  *
2009  *      We are about to do a TELNET SYNCH operation.  Clear
2010  * the path to the network.
2011  *
2012  *      Things are a bit tricky since we may have sent the first
2013  * byte or so of a previous TELNET command into the network.
2014  * So, we have to scan the network buffer from the beginning
2015  * until we are up to where we want to be.
2016  *
2017  *      A side effect of what we do, just to keep things
2018  * simple, is to clear the urgent data pointer.  The principal
2019  * caller should be setting the urgent data pointer AFTER calling
2020  * us in any case.
2021  */
2022
2023 static void
2024 netclear(void)
2025 {
2026         /* Deleted */
2027 }
2028 \f
2029 /*
2030  * These routines add various telnet commands to the data stream.
2031  */
2032
2033 static void
2034 doflush(void)
2035 {
2036     NET2ADD(IAC, DO);
2037     NETADD(TELOPT_TM);
2038     flushline = 1;
2039     flushout = 1;
2040     (void) ttyflush(1);                 /* Flush/drop output */
2041     /* do printoption AFTER flush, otherwise the output gets tossed... */
2042     printoption("SENT", DO, TELOPT_TM);
2043 }
2044
2045 void
2046 xmitAO(void)
2047 {
2048     NET2ADD(IAC, AO);
2049     printoption("SENT", IAC, AO);
2050     if (autoflush) {
2051         doflush();
2052     }
2053 }
2054
2055 void
2056 xmitEL(void)
2057 {
2058     NET2ADD(IAC, EL);
2059     printoption("SENT", IAC, EL);
2060 }
2061
2062 void
2063 xmitEC(void)
2064 {
2065     NET2ADD(IAC, EC);
2066     printoption("SENT", IAC, EC);
2067 }
2068
2069 int
2070 dosynch(char *ch __unused)
2071 {
2072     netclear();                 /* clear the path to the network */
2073     NETADD(IAC);
2074     setneturg();
2075     NETADD(DM);
2076     printoption("SENT", IAC, DM);
2077     return 1;
2078 }
2079
2080 int want_status_response = 0;
2081
2082 int
2083 get_status(char *ch __unused)
2084 {
2085     unsigned char tmp[16];
2086     unsigned char *cp;
2087
2088     if (my_want_state_is_dont(TELOPT_STATUS)) {
2089         printf("Remote side does not support STATUS option\n");
2090         return 0;
2091     }
2092     cp = tmp;
2093
2094     *cp++ = IAC;
2095     *cp++ = SB;
2096     *cp++ = TELOPT_STATUS;
2097     *cp++ = TELQUAL_SEND;
2098     *cp++ = IAC;
2099     *cp++ = SE;
2100     if (NETROOM() >= cp - tmp) {
2101         ring_supply_data(&netoring, tmp, cp-tmp);
2102         printsub('>', tmp+2, cp - tmp - 2);
2103     }
2104     ++want_status_response;
2105     return 1;
2106 }
2107
2108 void
2109 intp(void)
2110 {
2111     NET2ADD(IAC, IP);
2112     printoption("SENT", IAC, IP);
2113     flushline = 1;
2114     if (autoflush) {
2115         doflush();
2116     }
2117     if (autosynch) {
2118         dosynch(NULL);
2119     }
2120 }
2121
2122 void
2123 sendbrk(void)
2124 {
2125     NET2ADD(IAC, BREAK);
2126     printoption("SENT", IAC, BREAK);
2127     flushline = 1;
2128     if (autoflush) {
2129         doflush();
2130     }
2131     if (autosynch) {
2132         dosynch(NULL);
2133     }
2134 }
2135
2136 void
2137 sendabort(void)
2138 {
2139     NET2ADD(IAC, ABORT);
2140     printoption("SENT", IAC, ABORT);
2141     flushline = 1;
2142     if (autoflush) {
2143         doflush();
2144     }
2145     if (autosynch) {
2146         dosynch(NULL);
2147     }
2148 }
2149
2150 void
2151 sendsusp(void)
2152 {
2153     NET2ADD(IAC, SUSP);
2154     printoption("SENT", IAC, SUSP);
2155     flushline = 1;
2156     if (autoflush) {
2157         doflush();
2158     }
2159     if (autosynch) {
2160         dosynch(NULL);
2161     }
2162 }
2163
2164 void
2165 sendeof(void)
2166 {
2167     NET2ADD(IAC, xEOF);
2168     printoption("SENT", IAC, xEOF);
2169 }
2170
2171 void
2172 sendayt(void)
2173 {
2174     NET2ADD(IAC, AYT);
2175     printoption("SENT", IAC, AYT);
2176 }
2177
2178 /*
2179  * Send a window size update to the remote system.
2180  */
2181
2182 void
2183 sendnaws(void)
2184 {
2185     long rows, cols;
2186     unsigned char tmp[16];
2187     unsigned char *cp;
2188
2189     if (my_state_is_wont(TELOPT_NAWS))
2190         return;
2191
2192 #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
2193                             if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
2194
2195     if (TerminalWindowSize(&rows, &cols) == 0) {        /* Failed */
2196         return;
2197     }
2198
2199     cp = tmp;
2200
2201     *cp++ = IAC;
2202     *cp++ = SB;
2203     *cp++ = TELOPT_NAWS;
2204     PUTSHORT(cp, cols);
2205     PUTSHORT(cp, rows);
2206     *cp++ = IAC;
2207     *cp++ = SE;
2208     if (NETROOM() >= cp - tmp) {
2209         ring_supply_data(&netoring, tmp, cp-tmp);
2210         printsub('>', tmp+2, cp - tmp - 2);
2211     }
2212 }
2213
2214 void
2215 tel_enter_binary(int rw)
2216 {
2217     if (rw&1)
2218         send_do(TELOPT_BINARY, 1);
2219     if (rw&2)
2220         send_will(TELOPT_BINARY, 1);
2221 }
2222
2223 void
2224 tel_leave_binary(int rw)
2225 {
2226     if (rw&1)
2227         send_dont(TELOPT_BINARY, 1);
2228     if (rw&2)
2229         send_wont(TELOPT_BINARY, 1);
2230 }