/[inetutils]/inetutils/telnetd/state.c
ViewVC logotype

Diff of /inetutils/telnetd/state.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.1.7  
changed lines
  Added in v.1.8

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26