applied 050_ck_patch.patch
[ckermit.git] / ckctel.c
1 char *cktelv = "Telnet support, 8.0.269, 4 Mar 2004";
2 #define CKCTEL_C
3
4 int sstelnet = 0;                       /* Do server-side Telnet negotiation */
5
6 /*  C K C T E L  --  Telnet support  */
7
8 /*
9   Authors:
10     Telnet protocol by Frank da Cruz and Jeffrey Altman.
11     Telnet Forward X by Jeffrey Altman
12     Telnet START_TLS support by Jeffrey Altman
13     Telnet AUTH and ENCRYPT support by Jeffrey Altman
14     Telnet COMPORT support by Jeffrey Altman
15     Telnet NEW-ENVIRONMENT support by Jeffrey Altman
16     Telnet NAWS support by Frank da Cruz and Jeffrey Altman
17     Telnet TERMTYPE support by Jeffrey Altman
18     Telnet KERMIT support by Jeffrey Altman
19     Other contributions as indicated in the code.
20
21   Copyright (C) 1985, 2004,
22     Trustees of Columbia University in the City of New York.
23     All rights reserved.  See the C-Kermit COPYING.TXT file or the
24     copyright text in the ckcmai.c module for disclaimer and permissions.
25 */
26
27 /*
28   NOTE TO CONTRIBUTORS: This file, and all the other shared (ckc and cku)
29   C-Kermit source files, must be compatible with C preprocessors that support
30   only #ifdef, #else, #endif, #define, and #undef.  Please do not use #if,
31   logical operators, or other preprocessor features in this module.  Also,
32   don't use any ANSI C constructs except within #ifdef CK_ANSIC..#endif.
33 */
34
35 #include "ckcsym.h"
36 #include "ckcdeb.h"
37
38 #ifdef TNCODE
39 #include "ckcker.h"
40 #define TELCMDS                         /* to define name array */
41 #define TELOPTS                         /* to define name array */
42 #define SLC_NAMES                       /* to define name array */
43 #define ENCRYPT_NAMES
44 #define AUTH_NAMES
45 #define TELOPT_STATES
46 #define TELOPT_MODES
47 #define TNC_NAMES
48 #include "ckcnet.h"
49 #include "ckctel.h"
50 #ifdef CK_AUTHENTICATION
51 #include "ckuath.h"
52 #endif /* CK_AUTHENTICATION */
53 #ifdef CK_SSL
54 #include "ck_ssl.h"
55 #endif /* CK_SSL */
56
57 #ifndef NOTERM
58 #ifdef OS2                              /* For terminal type name string */
59 #include "ckuusr.h"
60 #ifndef NT
61 #include <os2.h>
62 #undef COMMENT
63 #else
64 #define isascii __isascii
65 #endif /* NT */
66 #include "ckocon.h"
67 extern int tt_type, max_tt;
68 extern struct tt_info_rec tt_info[];
69 #endif /* OS2 */
70 #endif /* NOTERM */
71
72 #ifdef OS2
73 #include <assert.h>
74 #ifdef NT
75 #include <setjmpex.h>
76 #else /* NT */
77 #include <setjmp.h>
78 #endif /* NT */
79 #include <signal.h>
80 #include "ckcsig.h"
81 #include "ckosyn.h"
82 #endif /* OS2 */
83
84 #ifdef CK_NAWS                          /* Negotiate About Window Size */
85 #ifdef RLOGCODE
86 _PROTOTYP( int rlog_naws, (void) );
87 #endif /* RLOGCODE */
88 #endif /* CK_NAWS */
89
90 int tn_init = 0;                        /* Telnet protocol initialized flag */
91 int tn_begun = 0;                       /* Telnet protocol started flag */
92 static int tn_first = 1;                /* First time init flag */
93 extern int tn_exit;                     /* Exit on disconnect */
94 extern int inserver;                    /* Running as IKSD */
95 char *tn_term = NULL;                   /* Terminal type override */
96
97 #ifdef CK_SNDLOC
98 char *tn_loc = NULL;                    /* Location override */
99 #endif /* CK_SNDLOC */
100 int tn_nlm = TNL_CRLF;                  /* Telnet CR -> CR LF mode */
101 int tn_b_nlm = TNL_CR;                  /* Telnet Binary CR RAW mode */
102 int tn_b_meu = 0;                       /* Telnet Binary ME means U too */
103 int tn_b_ume = 0;                       /* Telnet Binary U means ME too */
104 int tn_wait_flg = 1;                    /* Telnet Wait for Negotiations */
105 int tn_infinite = 0;                    /* Telnet Bug Infinite-Loop-Check */
106 int tn_rem_echo = 1;                    /* We will echo if WILL ECHO */
107 int tn_b_xfer = 0;                      /* Telnet Binary for Xfers? */
108 int tn_sb_bug = 1;                      /* Telnet BUG - SB w/o WILL or DO */
109 int tn_auth_krb5_des_bug = 1;           /* Telnet BUG - AUTH KRB5 DES */
110                                         /*              truncates long keys */
111 int tn_no_encrypt_xfer = 0;             /* Turn off Telnet Encrypt? */
112 int tn_delay_sb = 1;                    /* Delay SBs until safe */
113 int tn_auth_how = TN_AUTH_HOW_ANY;
114 int tn_auth_enc = TN_AUTH_ENC_ANY;
115 int tn_deb = 0;                         /* Telnet Debug mode */
116 int tn_sfu = 0;                         /* Microsoft SFU compatibility */
117 #ifdef CK_FORWARD_X
118 char * tn_fwdx_xauthority = NULL;       /* Xauthority File */
119 int    fwdx_no_encrypt = 0;             /* Forward-X requires encryption */
120 #endif /* CK_FORWARD_X */
121
122 #ifdef OS2
123 int ttnum = -1;                         /* Last Telnet Terminal Type sent */
124 int ttnumend = 0;                       /* Has end of list been found */
125 #endif /* OS2 */
126
127 char tn_msg[TN_MSG_LEN];                /* Telnet data can be rather long */
128 char hexbuf[TN_MSG_LEN];
129 char tn_msg_out[TN_MSG_LEN];
130 #ifdef CK_FORWARD_X
131 CHAR fwdx_msg_out[TN_MSG_LEN];
132 #endif /* CK_FORWARD_X */
133
134 /*
135   In order to prevent an infinite telnet negotiation loop we maintain a
136   count of the number of times the same telnet negotiation message is
137   sent. When this count hits MAXTNCNT, we do not send any more of the
138   message. The count is stored in the tncnts[][] array.
139
140   The tncnts[][] array is indexed by negotiation option (SUPPRESS GO AHEAD,
141   TERMINAL TYPE, NAWS, etc. - see the tnopts[] array) and the four
142   negotiation message types (WILL, WONT, DO, DONT).  All telnet negotiations
143   are kept track of in this way.
144
145   The count for a message is zeroed when the "opposite" message is sent.
146   WILL is the opposite of WONT, and DO is the opposite of DONT.
147   For example sending "WILL SGA" increments tncnts[TELOPT_SGA][0]
148   and zeroes tncnts[TELOPT_SGA][1].
149
150   The code that does this is in tn_sopt().
151
152   rogersh@fsj.co.jp, 18/3/1995
153
154   8/16/1998 - with the recent rewrite of the telnet state machine I don't
155   think this code is necessary anymore.  However, it can't do any harm so
156   I am leaving it in.    - Jeff
157
158   12/28/1998 - all references to tncnts[] must be done with TELOPT_INDEX(opt)
159   because the Telnet option list is no longer contiguous.  We also must
160   allocate NTELOPTS + 1 because the TELOPT_INDEX() macro returns NTELOPTS
161   for an invalid option number.
162 */
163
164 #define MAXTNCNT 4      /* Permits 4 intermediate telnet firewalls/gateways */
165
166 char tncnts[NTELOPTS+1][4];             /* Counts */
167 char tnopps[4] = { 1,0,3,2 };           /* Opposites */
168
169 #ifdef CK_ENVIRONMENT
170 #ifdef CK_FORWARD_X
171 #define TSBUFSIZ 2056
172 #else /* CK_FORWARD_X */
173 #define TSBUFSIZ 1024
174 #endif /* CK_FORWARD_X */
175 char tn_env_acct[64];
176 char tn_env_disp[64];
177 char tn_env_job[64];
178 char tn_env_prnt[64];
179 char tn_env_sys[64];
180 char * tn_env_uservar[8][2];
181 int tn_env_flg = 1;
182 #else /* CK_ENVIRONMENT */
183 #define TSBUFSIZ 41
184 int tn_env_flg = 0;
185 #endif /* CK_ENVIRONMENT */
186
187 #ifdef COMMENT
188 /* SIGWINCH handler moved to ckuusx.c */
189 #ifndef NOSIGWINCH
190 #ifdef CK_NAWS                          /* Window size business */
191 #ifdef UNIX
192 #include <signal.h>
193 #endif /* UNIX */
194 #endif /* CK_NAWS */
195 #endif /* NOSIGWINCH */
196 #endif /* COMMENT */
197
198 CHAR sb[TSBUFSIZ];                      /* Buffer - incoming subnegotiations */
199 CHAR sb_out[TSBUFSIZ];                  /* Buffer - outgoing subnegotiations */
200
201 int tn_duplex = 1;                      /* Local echo */
202
203 extern char uidbuf[];                   /* User ID buffer */
204 extern int quiet, ttnet, ttnproto, debses, what, duplex, oldplex, local;
205 extern int seslog, sessft, whyclosed;
206 #ifdef OS2
207 #ifndef NOTERM
208 extern int tt_rows[], tt_cols[];
209 extern int tt_status[VNUM];
210 extern int scrninitialized[];
211 #endif /* NOTERM */
212 #else /* OS2 */
213 extern int tt_rows, tt_cols;            /* Everybody has this */
214 #endif /* OS2 */
215 extern int cmd_cols, cmd_rows;
216 extern char namecopy[];
217 extern char myipaddr[];             /* Global copy of my IP address */
218
219 #ifndef TELOPT_MACRO
220 int
221 telopt_index(opt) int opt; {
222     if (opt >= 0 && opt <= TELOPT_STDERR)
223       return(opt);
224     else if (opt >= TELOPT_PRAGMA_LOGON && opt <= TELOPT_PRAGMA_HEARTBEAT)
225       return(opt-88);
226     else if (opt == TELOPT_IBM_SAK)
227       return(opt-147);
228     else
229       return(NTELOPTS);
230 }
231
232 int
233 telopt_ok(opt) int opt; {
234     return((opt >= TELOPT_BINARY && opt <= TELOPT_STDERR) ||
235            (opt >= TELOPT_PRAGMA_LOGON && opt <= TELOPT_PRAGMA_HEARTBEAT) ||
236            (opt == TELOPT_IBM_SAK));
237 }
238
239 CHAR *
240 telopt(opt) int opt; {
241     if (telopt_ok(opt))
242       return((CHAR *)telopts[telopt_index(opt)]);
243     else
244       return((CHAR *)"UNKNOWN");
245 }
246
247 int
248 telopt_mode_ok(opt) int opt; {
249     return((unsigned int)(opt) <= TN_NG_MU);
250 }
251
252 CHAR *
253 telopt_mode(opt) int opt; {
254     if (telopt_mode_ok(opt))
255       return((CHAR *)telopt_modes[opt-TN_NG_RF]);
256     else
257       return((CHAR *)"UNKNOWN");
258 }
259 #endif /* TELOPT_MACRO */
260
261 static int
262 tn_outst(notquiet) int notquiet; {
263     int outstanding = 0;
264     int x = 0;
265 #ifdef CK_ENCRYPTION
266     int e = 0;
267     int d = 0;
268 #endif /* CK_ENCRYPTION */
269
270     if (tn_wait_flg) {
271         for (x = TELOPT_FIRST; x <= TELOPT_LAST; x++) {
272             if (TELOPT_OK(x)) {
273                 if (TELOPT_UNANSWERED_WILL(x)) {
274                     if ( notquiet )
275                       printf("?Telnet waiting for response to WILL %s\r\n",
276                              TELOPT(x));
277                     debug(F111,"tn_outst","unanswered WILL",x);
278                     outstanding = 1;
279                     if ( !notquiet )
280                       break;
281                 }
282                 if (TELOPT_UNANSWERED_DO(x)) {
283                     if ( notquiet )
284                       printf("?Telnet waiting for response to DO %s\r\n",
285                              TELOPT(x));
286                     debug(F111,"tn_outst","unanswered DO",x);
287                     outstanding = 1;
288                     if ( !notquiet )
289                       break;
290                 }
291                 if (TELOPT_UNANSWERED_WONT(x)) {
292                     if ( notquiet )
293                       printf("?Telnet waiting for response to WONT %s\r\n",
294                              TELOPT(x));
295                     debug(F111,"tn_outst","unanswered WONT",x);
296                     outstanding = 1;
297                     if ( !notquiet )
298                       break;
299                 }
300                 if (TELOPT_UNANSWERED_DONT(x)) {
301                     if ( notquiet )
302                       printf("?Telnet waiting for response to DONT %s\r\n",
303                              TELOPT(x));
304                     debug(F111,"tn_outst","unanswered DONT",x);
305                     outstanding = 1;
306                     if ( !notquiet )
307                       break;
308                 }
309                 if (TELOPT_UNANSWERED_SB(x)) {
310                     if ( notquiet )
311                       printf("?Telnet waiting for response to SB %s\r\n",
312                              TELOPT(x));
313                     debug(F111,"tn_outst","unanswered SB",x);
314                     outstanding = 1;
315                     if ( !notquiet )
316                       break;
317                 }
318             }
319         }
320 #ifdef CK_AUTHENTICATION
321         if (ck_tn_auth_in_progress()) {
322             if (TELOPT_ME(TELOPT_AUTHENTICATION)) {
323                 if (notquiet)
324                   printf("?Telnet waiting for WILL %s subnegotiation\r\n",
325                          TELOPT(TELOPT_AUTHENTICATION));
326                 debug(F111,
327                       "tn_outst",
328                       "ME authentication in progress",
329                       TELOPT_AUTHENTICATION
330                       );
331                 outstanding = 1;
332             } else if (TELOPT_U(TELOPT_AUTHENTICATION)) {
333                 if (notquiet)
334                   printf("?Telnet waiting for DO %s subnegotiation\r\n",
335                          TELOPT(TELOPT_AUTHENTICATION));
336                 debug(F111,
337                       "tn_outst",
338                       "U authentication in progress",
339                       TELOPT_AUTHENTICATION
340                       );
341                 outstanding = 1;
342             }
343         }
344 #endif /* CK_AUTHENTICATION */
345 #ifdef CK_ENCRYPTION
346         if (!outstanding) {
347             e = ck_tn_encrypting();
348             d = ck_tn_decrypting();
349             if (TELOPT_ME(TELOPT_ENCRYPTION)) {
350                 if (TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop && e ||
351                     !TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop && !e
352                     ) {
353                     if ( notquiet )
354                       printf("?Telnet waiting for WILL %s subnegotiation\r\n",
355                              TELOPT(TELOPT_ENCRYPTION));
356                     debug(F111,
357                           "tn_outst",
358                           "encryption mode switch",
359                           TELOPT_ENCRYPTION
360                           );
361                     outstanding = 1;
362                 }
363             }
364             if (TELOPT_U(TELOPT_ENCRYPTION)) {
365                 if (TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop && d ||
366                     !TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop && !d
367                     ) {
368                     if ( notquiet )
369                       printf("?Telnet waiting for DO %s subnegotiation\r\n",
370                              TELOPT(TELOPT_ENCRYPTION));
371                     debug(F111,
372                           "tn_outst",
373                           "decryption mode switch",
374                            TELOPT_ENCRYPTION
375                           );
376                     outstanding = 1;
377                 }
378             }
379         }
380 #endif /* CK_ENCRYPTION */
381     } /* if (tn_wait_flg) */
382
383 #ifdef IKS_OPTION
384     /* Even if we are not waiting for Telnet options we must wait for */
385     /* Kermit Telnet Subnegotiations if we have sent a request to the */
386     /* other guy.  Otherwise we will get out of sync.                 */
387     if (!outstanding) {
388         if (TELOPT_U(TELOPT_KERMIT) &&
389             (TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start ||
390              TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop ||
391              !TELOPT_SB(TELOPT_KERMIT).kermit.sop)
392             ) {
393             if ( notquiet )
394               printf("?Telnet waiting for SB %s negotiation\r\n",
395                      TELOPT(TELOPT_KERMIT));
396             debug(F111,"tn_outst","U kermit in progress",TELOPT_KERMIT);
397             outstanding = 1;
398         }
399     }
400 #endif /* IKS_OPTION */
401
402 #ifdef TN_COMPORT
403     if (!outstanding) {
404         if (TELOPT_ME(TELOPT_COMPORT)) {
405             if (TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb) {
406                 if (notquiet)
407                     printf("?Telnet waiting for SB %s negotiation\r\n",
408                             TELOPT(TELOPT_COMPORT));
409                debug(F111,"tn_outst","ComPort SB in progress",TELOPT_COMPORT);
410                outstanding = 1;
411             }
412             if (TELOPT_SB(TELOPT_COMPORT).comport.wait_for_ms) {
413                 if (notquiet)
414               printf("?Telnet waiting for SB %s MODEM_STATUS negotiation\r\n",
415                             TELOPT(TELOPT_COMPORT));
416             debug(F111,"tn_outst","ComPort SB MS in progress",TELOPT_COMPORT);
417                outstanding = 1;
418             }
419         }
420     }
421 #endif /* TN_COMPORT */
422     return(outstanding);
423 }
424
425 int
426 istncomport() {
427 #ifdef TN_COMPORT
428     if (!local) return(0);
429     if (ttnet != NET_TCPB) return(0);
430     if (ttnproto != NP_TELNET) return(0);
431     if (TELOPT_ME(TELOPT_COMPORT))
432       return(1);
433     else
434 #endif /* TN_COMPORT */
435       return(0);
436 }
437
438 /* tn_wait() -- Wait for response to Telnet negotiation. */
439 /*
440   Wait for up to <timeout> seconds for the response to arrive.
441   Place all non-telnet data into Telnet Wait Buffer.
442   If response does arrive return 1, else return 0.
443 */
444 #ifndef TN_WAIT_BUF_SZ
445 #define TN_WAIT_BUF_SZ 4096
446 #endif /* TN_WAIT_BUF_SZ */
447 static char tn_wait_buf[TN_WAIT_BUF_SZ];
448 static int  tn_wait_idx = 0;
449 #ifndef TN_TIMEOUT
450 #define TN_TIMEOUT 120
451 #endif /* TN_TIMEOUT */
452 static int tn_wait_tmo = TN_TIMEOUT;
453
454 #ifdef CKSPINNER
455 VOID
456 prtwait(state) int state; {
457     switch (state % 4) {
458       case 0:
459         printf("/");
460         break;
461       case 1:
462         printf("-");
463         break;
464       case 2:
465         printf("\\");
466         break;
467       case 3:
468         printf("|");
469         break;
470     }
471 }
472 #endif /* CKSPINNER */
473
474 static int nflag = 0;
475
476 int
477 #ifdef CK_ANSIC
478 tn_wait(char * where)
479 #else
480 tn_wait(where) char * where;
481 #endif /* CK_ANSIC */
482 /* tn_wait */ {
483     extern int ckxech, local;
484     int ch = 0, count = 0;
485 #ifndef NOHINTS
486     int nohintgiven = 1;
487     extern int hints;
488 #endif /* NOHINTS */
489     int outstanding;
490 #ifdef TN_COMPORT
491     int savcarr;
492     extern int ttcarr;
493 #endif /* TN_COMPORT */
494
495     rtimer();
496
497     debug(F110,"tn_wait waiting for",where,0);
498     tn_wait_tmo = TN_TIMEOUT;
499     debug(F111,"tn_wait","timeout",tn_wait_tmo);
500     outstanding = tn_outst(0);
501     debug(F111,"tn_wait","outstanding",outstanding);
502     debug(F111,"tn_wait","tn_wait_flg",tn_wait_flg);
503
504     /* The following is meant to be !(||).  We only want to return */
505     /* immediately if both the tn_wait_flg && tn_outst() are false */
506     if (!(outstanding || tn_wait_flg))  /* If no need to wait */
507       return(1);                        /* Don't. */
508
509     if (tn_deb || debses) tn_debug("<wait for outstanding negotiations>");
510
511 #ifdef CKSPINNER
512     if (!sstelnet && !quiet)
513         prtwait(0);
514 #endif /* CKSPINNER */
515
516     /* Wait up to TN_TIMEOUT sec for responses to outstanding telnet negs */
517     do {
518 #ifdef NTSIG
519         ck_ih();
520 #endif /* NTSIG */
521         ch = ttinc(1);
522         if (ch == -1) {                 /* Timed out */
523             if (!sstelnet && !quiet) {  /* Let user know... */
524 #ifdef CKSPINNER
525                 printf("\b");
526                 prtwait(gtimer());
527 #else
528                 if (nflag == 0) {
529                     printf(" Negotiations.");
530                     nflag++;
531                 }
532                 if (nflag > 0) {
533                     printf(".");
534                     nflag++;
535                     fflush(stdout);
536                 }
537 #endif /* CKSPINNER */
538             }
539         } else if (ch < -1) {
540             printf("\r\n?Connection closed by peer.\r\n");
541             if (tn_deb || debses) tn_debug("<connection closed by peer>");
542             return(-1);
543         } else
544         switch (ch) {
545           case IAC:
546 #ifdef CKSPINNER
547             if (!sstelnet && !quiet)
548               printf("\b");
549 #endif /* CKSPINNER */
550             ch = tn_doop((CHAR)(ch & 0xff),inserver?ckxech:duplex,ttinc);
551 #ifdef CKSPINNER
552             if (!sstelnet && !quiet) {
553                 prtwait(gtimer());
554             }
555 #endif /* CKSPINNER */
556             debug(F101,"tn_wait tn_doop","",ch);
557             switch (ch) {
558               case 1:
559                 duplex = 1;             /* Turn on echoing */
560                 if (inserver)
561                   ckxech = 1;
562                 break;
563               case 2:
564                 duplex = 0;             /* Turn off echoing */
565                 if (inserver)
566                   ckxech = 0;
567                 break;
568               case 3:
569                 tn_wait_buf[tn_wait_idx++] = IAC;
570                 break;
571               case 4:                   /* IKS event */
572               case 6:                   /* Logout */
573                 break;
574               case -1:
575                 if (!quiet)
576                 printf("?Telnet Option negotiation error.\n");
577                 if (tn_deb || debses)
578                   tn_debug("<Telnet Option negotiation error>");
579                 return(-1);
580               case -2:
581                 printf("?Connection closed by peer.\n");
582                 if (tn_deb || debses) tn_debug("<Connection closed by peer>");
583                 ttclos(0);
584                 return(-2);
585               default:
586                 if (ch < 0) {
587                   if (tn_deb || debses) tn_debug("<Unknown connection error>");
588                   return(ch);
589                 }
590             } /* switch */
591             break;
592           default:
593 #ifdef CKSPINNER
594             if (!sstelnet && !quiet) {
595                 printf("\b");
596                 prtwait(gtimer());
597             }
598 #endif /* CKSPINNER */
599             tn_wait_buf[tn_wait_idx++] = (CHAR)(ch & 0xff);
600         } /* switch */
601
602         outstanding = tn_outst(0);
603
604         if ( outstanding && ch != IAC ) {
605             int timer = gtimer();
606             if ( timer > tn_wait_tmo ) {
607                 if (!sstelnet) {
608                     printf(
609                     "\r\n?Telnet Protocol Timeout - connection closed\r\n");
610                     if (tn_deb || debses)
611                         tn_debug(
612                         "<telnet protocol timeout - connection closed>");
613                     tn_outst(1);
614                 }
615                 /* if we do not close the connection, then we will block */
616                 /* the next time we hit a wait.  and if we don't we will */
617                 /* do the wrong thing if the host sends 0xFF and does    */
618                 /* not intend it to be an IAC.                           */
619                 ttclos(0);
620                 whyclosed = WC_TELOPT;
621                 return(-1);
622             }
623 #ifndef NOHINTS
624             else if ( hints && timer > 30 && nohintgiven && !inserver ) {
625 #ifdef CKSPINNER
626                                 printf("\b");
627 #else /* CKSPINNER */
628                                 printf("\r\n");
629 #endif /* CKSPINNER */
630       printf("*************************\r\n");
631         printf("The Telnet %s is not sending required responses.\r\n\r\n",
632                 sstelnet?"client":"server");
633       tn_outst(1);
634       printf("\nYou can continue to wait or you can cancel with Ctrl-C.\r\n");
635       printf("In case the Telnet server never responds as required,\r\n");
636       printf("you can try connecting to this host with TELNET /NOWAIT.\r\n");
637       printf("Use SET HINTS OFF to suppress further hints.\r\n");
638       printf("*************************\r\n");
639       nohintgiven = 0;
640             }
641 #endif /* NOHINTS */
642         }
643
644 #ifdef TN_COMPORT
645         /* Must disable carrier detect check if we are using Telnet Comport */
646         savcarr = ttcarr;
647         ttscarr(CAR_OFF);
648         count = ttchk();
649         ttscarr(savcarr);
650 #else /* TN_COMPORT */
651         count = ttchk();
652 #endif /* TN_COMPORT */
653     } while ((tn_wait_idx < TN_WAIT_BUF_SZ) &&
654              (outstanding && count >= 0));
655
656     if (tn_wait_idx == TN_WAIT_BUF_SZ) {
657       if (tn_deb || debses) tn_debug("<Telnet Wait Buffer filled>");
658       return(0);
659     }
660
661     if (!sstelnet && !quiet) {
662 #ifdef CKSPINNER
663         printf("\b \b");
664 #else
665         if (nflag > 0) {
666             printf(" (OK)\n");
667             nflag = -1;
668         }
669 #endif /* CKSPINNER */
670     }
671     if (tn_deb || debses) tn_debug("<no outstanding negotiations>");
672     return(0);
673 }
674
675 /* Push data from the Telnet Wait Buffer into the I/O Queue */
676 /* Return 1 on success                                      */
677
678 int
679 tn_push() {
680 #ifdef NETLEBUF
681     extern int tt_push_inited;
682 #endif /* NETLEBUF */
683     if (tn_wait_idx) {
684         hexdump((CHAR *)"tn_push",tn_wait_buf,tn_wait_idx);
685 #ifdef NETLEBUF
686         if (!tt_push_inited)            /* Local handling */
687           le_init();
688         le_puts((CHAR *)tn_wait_buf,tn_wait_idx);
689 #else                                   /* External handling... */
690 #ifdef OS2                              /* K95 has its own way */
691         le_puts((CHAR *)tn_wait_buf,tn_wait_idx);
692 #else
693 #ifdef TTLEBUF                          /* UNIX, etc */
694         le_puts((CHAR *)tn_wait_buf,tn_wait_idx);
695 #else
696 /*
697   If you see this message in AOS/VS, OS-9, VOS, etc, you need to copy
698   the #ifdef TTLEBUF..#endif code from ckutio.c to the corresponding
699   places in your ck?tio.c module.
700 */
701         printf("tn_push called but not implemented - data lost.\n");
702 #endif /* TTLEBUF */
703 #endif /* OS2 */
704 #endif /* NETLEBUF */
705         tn_wait_idx = 0;
706     }
707     tn_wait_tmo = TN_TIMEOUT;           /* Reset wait timer stats */
708     return(1);
709 }
710
711 /*  T N _ S O P T  */
712 /*
713    Sends a telnet option, avoids loops.
714    Returns 1 if command was sent, 0 if not, -1 on error.
715 */
716 int
717 tn_sopt(cmd,opt) int cmd, opt; {        /* TELNET SEND OPTION */
718     CHAR buf[5];
719     char msg[128];
720     int rc;
721
722     if (ttnet != NET_TCPB) return(-1);  /* Must be TCP/IP */
723     if (ttnproto != NP_TELNET) return(-1); /* Must be telnet protocol */
724     if (!TELCMD_OK(cmd)) return(-1);
725     if (TELOPT_OK(opt)) {
726         if (cmd == DO && TELOPT_UNANSWERED_DO(opt)) return(0);
727         if (cmd == WILL && TELOPT_UNANSWERED_WILL(opt)) return(0);
728         if (cmd == DONT && TELOPT_UNANSWERED_DONT(opt)) return(0);
729         if (cmd == WONT && TELOPT_UNANSWERED_WONT(opt)) return(0);
730     }
731 #ifdef CK_SSL
732     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
733         return(0);
734     }
735 #endif /* CK_SSL */
736
737     if (cmd == DO && opt == TELOPT_AUTHENTICATION)
738       buf[0] = 0;
739
740     if (tn_infinite && TELOPT_OK(opt)) { /* See comment above about   */
741         int index = TELOPT_INDEX(opt);   /* preventing infinite loops */
742         int m = cmd - WILL;
743
744         if (tncnts[index][m] > MAXTNCNT) {
745 #ifdef DEBUG
746             if (tn_deb || debses || deblog) {
747                 ckmakmsg(msg,sizeof(msg),
748                            "TELNET negotiation loop ",
749                            TELCMD(cmd), " ",
750                            TELOPT(opt));
751                 debug(F101,msg,"",opt);
752                 if (tn_deb || debses) tn_debug(msg);
753             }
754 #endif /* DEBUG */
755             return(0);
756         }
757         tncnts[index][m]++;
758         tncnts[index][tnopps[m]] = 0;
759     }
760     buf[0] = (CHAR) IAC;
761     buf[1] = (CHAR) (cmd & 0xff);
762     buf[2] = (CHAR) (opt & 0xff);
763     buf[3] = (CHAR) 0;
764 #ifdef DEBUG
765     if ((tn_deb || debses || deblog) && cmd != SB)
766         ckmakmsg(msg,sizeof(msg),"TELNET SENT ",TELCMD(cmd)," ",
767                   TELOPT(opt));
768 #endif /* DEBUG */
769 #ifdef OS2
770     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
771 #endif
772     debug(F101,msg,"",opt);
773     if ((tn_deb || debses) && cmd != SB)
774       tn_debug(msg);
775     rc = (ttol(buf,3) < 3);
776 #ifdef OS2
777     ReleaseTelnetMutex();
778 #endif
779     if (rc)
780         return(-1);
781
782
783     if (TELOPT_OK(opt)) {
784         if (cmd == DONT && TELOPT_UNANSWERED_DO(opt))
785           TELOPT_UNANSWERED_DO(opt) = 0;
786         if (cmd == WONT && TELOPT_UNANSWERED_WILL(opt))
787           TELOPT_UNANSWERED_WILL(opt) = 0;
788         if (cmd == DO && TELOPT_UNANSWERED_DONT(opt))
789           TELOPT_UNANSWERED_DONT(opt) = 0;
790         if (cmd == WILL && TELOPT_UNANSWERED_WONT(opt))
791           TELOPT_UNANSWERED_WONT(opt) = 0;
792     }
793     return(1);
794 }
795
796 /* Send a telnet sub-option */
797 /* Returns 1 if command was sent, 0 if not, -1 on error */
798
799 int
800 tn_ssbopt(opt,sub,data,len) int opt, sub; CHAR * data; int len; {
801     CHAR buf[256];
802     int n,m,rc;
803
804     if (ttnet != NET_TCPB) return(0);   /* Must be TCP/IP */
805     if (ttnproto != NP_TELNET) return(0); /* Must be telnet protocol */
806     if (!TELOPT_OK(opt)) return(-1);
807     if (len < 0 || len > 250) {
808         debug(F111,"Unable to Send TELNET SB - data too long","len",len);
809         return(-1);                     /* Data too long */
810     }
811 #ifdef CK_SSL
812     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
813         if (ttchk() < 0)
814           return(-1);
815         else
816           return(1);
817     }
818 #endif /* CK_SSL */
819
820     if (!data) len = 0;
821
822     buf[0] = (CHAR) IAC;
823     buf[1] = (CHAR) (SB & 0xff);
824     buf[2] = (CHAR) (opt & 0xff);
825     buf[3] = (CHAR) (sub & 0xff);
826     if (data && len > 0) {
827         memcpy(&buf[4],data,len);
828     }
829     buf[4+len] = (CHAR) IAC;
830     buf[5+len] = (CHAR) SE;
831
832 #ifdef DEBUG
833     if (tn_deb || debses || deblog) {
834         if (opt == TELOPT_START_TLS && sub == 1)
835           ckmakmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB ",
836                     TELOPT(opt)," FOLLOWS IAC SE",NULL);
837         else if (opt == TELOPT_TTYPE && sub == 1)
838           ckmakmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB ", TELOPT(opt),
839                     " SEND IAC SE",NULL);
840         else if (opt == TELOPT_TTYPE && sub == 0)
841           ckmakxmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB ",TELOPT(opt)," IS ",
842                     (char *)data," IAC SE",NULL,NULL,NULL,NULL,NULL,NULL,NULL);
843         else if (opt == TELOPT_NEWENVIRON) {
844             int i, quote;
845             ckmakmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB ",
846                      TELOPT(TELOPT_NEWENVIRON)," ",
847                      sub == TELQUAL_SEND ? "SEND" :
848                      sub == TELQUAL_IS ? "IS" :
849                      sub == TELQUAL_INFO ?"INFO" : "UNKNOWN" );
850             for (i = 0, quote = 0; i < len; i++) {
851                 if (quote) {
852                     sprintf(hexbuf,"%02x",data[i]); /* safe but ugly */
853                     ckstrncat(tn_msg_out,hexbuf,TN_MSG_LEN);
854                     quote = 0;
855                 } else {
856                     switch (data[i]) {
857                       case TEL_ENV_USERVAR:
858                         ckstrncat(tn_msg_out," USERVAR ",TN_MSG_LEN);
859                         break;
860                       case TEL_ENV_VAR:
861                         ckstrncat(tn_msg_out," VAR ",TN_MSG_LEN);
862                         break;
863                       case TEL_ENV_VALUE:
864                         ckstrncat(tn_msg_out," VALUE ",TN_MSG_LEN);
865                         break;
866                       case TEL_ENV_ESC:
867                         ckstrncat(tn_msg_out," ESC ",TN_MSG_LEN);
868                         quote = 1;
869                         break;
870                       case IAC:
871                         ckstrncat(tn_msg_out," IAC ",TN_MSG_LEN);
872                         break;
873                       default:
874                         sprintf(hexbuf,"%c",data[i]); /* safe but ugly */
875                         ckstrncat(tn_msg_out,hexbuf,TN_MSG_LEN);
876                     }
877                 }
878             }
879             ckstrncat(tn_msg_out," IAC SE",TN_MSG_LEN);
880         } else {
881             sprintf(hexbuf,"%02x",sub);             /* safe but ugly */
882             ckmakxmsg(tn_msg_out,TN_MSG_LEN,
883                       "TELNET SENT SB ",TELOPT(opt),
884                       " ",
885                       hexbuf,
886                       " <data> IAC SE",
887                        NULL,NULL,NULL,NULL,NULL,NULL,NULL
888                       );
889         }
890     }
891 #endif /* DEBUG */
892 #ifdef OS2
893     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
894 #endif /* OS2 */
895 #ifdef DEBUG
896     debug(F101,tn_msg_out,"",opt);
897     if (tn_deb || debses)
898       tn_debug(tn_msg_out);
899 #endif /* DEBUG */
900     rc = (ttol(buf,6+len) < 6+len);
901 #ifdef OS2
902     ReleaseTelnetMutex();
903 #endif
904
905     if (rc)
906       return(-1);
907     return(1);
908 }
909
910 /*
911   tn_flui() -- Processes all waiting data for Telnet commands.
912   All non-Telnet data is to be stored into the Telnet Wait Buffer.
913   Returns 1 on success.
914 */
915 int
916 tn_flui() {
917     extern int ckxech;
918     int x = 0;
919
920     /* Wait up to 5 sec for responses to outstanding telnet negotiations */
921     while (x >= 0 && ttchk() > 0  && tn_wait_idx < TN_WAIT_BUF_SZ) {
922         x = ttinc(1);
923         switch (x) {
924           case IAC:
925             x = tn_doop((CHAR)(x & 0xff),inserver?ckxech:duplex,ttinc);
926             debug(F101,"tn_flui tn_doop","",x);
927             switch (x) {
928               case 1:                   /* Turn on echoing */
929                 duplex = 1;
930                 if (inserver)
931                   ckxech = 1;
932                 break;
933               case 2:                   /* Turn off echoing */
934                 duplex = 0;
935                 if (inserver)
936                   ckxech = 0;
937                 break;
938               case 3:
939                 tn_wait_buf[tn_wait_idx++] = IAC;
940                 break;
941               case 4:                   /* IKS event */
942               case 6:                   /* Logout */
943                 break;
944             }
945             break;
946           default:
947             if (x >= 0)
948               tn_wait_buf[tn_wait_idx++] = x;
949         }
950     }
951     return(1);
952 }
953
954 unsigned char *
955 tn_get_display()
956 {
957     char * disp = NULL;
958     static char tmploc[256];
959
960     /* Must compute the DISPLAY string we are going to send to the host */
961     /* If one is not assigned, do not send a string unless the user has */
962     /* explicitedly requested we try to send one via X-Display Location */
963     /* But do not send a string at all if FORWARD_X is in use.          */
964
965     debug(F110,"tn_get_display() myipaddr",myipaddr,0);
966 #ifdef CK_ENVIRONMENT
967     debug(F110,"tn_get_display() tn_env_disp",tn_env_disp,0);
968     if (tn_env_disp[0]) {
969         int colon = ckindex(":",tn_env_disp,0,0,1);
970         if ( !colon ) {
971             ckmakmsg(tmploc,256,myipaddr,":",tn_env_disp,NULL);
972             disp = tmploc;
973         } else if ( ckindex("localhost:",tn_env_disp,0,0,0) ||
974                     ckindex("unix:",tn_env_disp,0,0,0) ||
975                     ckindex("127.0.0.1:",tn_env_disp,0,0,0) ||
976                     !ckstrcmp("0:",tn_env_disp,2,1) ||
977                     tn_env_disp[0] == ':' ) {
978             ckmakmsg(tmploc,256,myipaddr,":",&tn_env_disp[colon],NULL);
979             disp = tmploc;
980         } else
981             disp = tn_env_disp;
982     }
983     else
984 #endif /* CK_ENVIRONMENT */
985         if (TELOPT_ME(TELOPT_XDISPLOC) ||
986               TELOPT_U(TELOPT_FORWARD_X)) {
987         ckmakmsg(tmploc,256,myipaddr,":0.0",NULL,NULL);
988         disp = tmploc;
989     }
990     debug(F110,"tn_get_display() returns",disp,0);
991     return((CHAR *)disp);
992 }
993
994 #ifdef CK_FORWARD_X
995 static Xauth fake_xauth = {0,0,NULL,0,NULL,0,NULL,0,NULL};
996 static Xauth *real_xauth=NULL;
997
998 /*
999  * Author:  Jim Fulton, MIT X Consortium
1000  *
1001  * fwdx_parse_displayname -
1002  * display a display string up into its component parts
1003  */
1004 #ifdef UNIX
1005 #define UNIX_CONNECTION "unix"
1006 #define UNIX_CONNECTION_LENGTH 4
1007 #endif
1008
1009 /*
1010  * private utility routines
1011  */
1012
1013 static int
1014 #ifdef CK_ANSIC
1015 XmuGetHostname (char *buf, int maxlen)
1016 #else
1017 XmuGetHostname (buf, maxlen)
1018     char *buf;
1019     int maxlen;
1020 #endif /* CK_ANSIC */
1021 {
1022     int len;
1023
1024 #ifdef NEED_UTSNAME
1025     /*
1026      * same host name crock as in server and xinit.
1027      */
1028     struct utsname name;
1029
1030     uname (&name);
1031     len = strlen (name.nodename);
1032     if (len >= maxlen) len = maxlen - 1;
1033     strncpy (buf, name.nodename, len);
1034     buf[len] = '\0';
1035 #else
1036     buf[0] = '\0';
1037     (void) gethostname (buf, maxlen);
1038     buf [maxlen - 1] = '\0';
1039     len = strlen(buf);
1040 #endif /* hpux */
1041     return len;
1042 }
1043
1044 static char *
1045 #ifdef CK_ANSIC
1046 copystring (char *src, int len)
1047 #else
1048 copystring (src, len)
1049     char *src;
1050     int len;
1051 #endif /* CK_ANSIC */
1052 {
1053     char *cp;
1054
1055     if (!src && len != 0) return NULL;
1056     cp = malloc (len + 1);
1057     if (cp) {
1058         if (src) strncpy (cp, src, len);
1059         cp[len] = '\0';
1060     }
1061     return cp;
1062 }
1063
1064 static char *
1065 #ifdef CK_ANSIC
1066 get_local_hostname (char *buf, int maxlen)
1067 #else
1068 get_local_hostname (buf, maxlen)
1069     char *buf;
1070     int maxlen;
1071 #endif
1072 {
1073     buf[0] = '\0';
1074     (void) XmuGetHostname (buf, maxlen);
1075     return (buf[0] ? buf : NULL);
1076 }
1077
1078 #ifndef UNIX
1079 static char *
1080 copyhostname ()
1081 {
1082     char buf[256];
1083
1084     return (get_local_hostname (buf, sizeof buf) ?
1085             copystring (buf, strlen (buf)) : NULL);
1086 }
1087 #endif
1088
1089
1090 int
1091 #ifdef CK_ANSIC
1092 fwdx_parse_displayname (char *displayname, int *familyp, char **hostp,
1093                         int *dpynump, int *scrnump, char **restp)
1094 #else
1095 fwdx_parse_displayname (displayname, familyp, hostp, dpynump, scrnump, restp)
1096     char *displayname;
1097     int *familyp;                       /* return */
1098     char **hostp;                       /* return */
1099     int *dpynump, *scrnump;             /* return */
1100     char **restp;                       /* return */
1101 #endif /* CK_ANSIC */
1102 {
1103     char *ptr;                          /* work variables */
1104     int len;                            /* work variable */
1105     int family = -1;                    /* value to be returned */
1106     char *host = NULL;                  /* must free if set and error return */
1107     int dpynum = -1;                    /* value to be returned */
1108     int scrnum = 0;                     /* value to be returned */
1109     char *rest = NULL;                  /* must free if set and error return */
1110     int dnet = 0;                       /* if 1 then using DECnet */
1111
1112                                         /* check the name */
1113     if (!displayname || !displayname[0])
1114         return 0;
1115                                         /* must have at least :number */
1116     ptr = (char *)strchr(displayname, ':');
1117     if (!ptr || !ptr[1]) return 0;
1118     if (ptr[1] == ':') {
1119         if (ptr[2] == '\0') return 0;
1120         dnet = 1;
1121     }
1122
1123     /*
1124      * get the host string; if none is given, use the most effiecient path
1125      */
1126
1127     len = (ptr - displayname);  /* length of host name */
1128     if (len == 0) {                     /* choose most efficient path */
1129 #ifdef UNIX
1130         host = copystring (UNIX_CONNECTION, UNIX_CONNECTION_LENGTH);
1131         family = FamilyLocal;
1132 #else
1133         if (dnet) {
1134             host = copystring ("0", 1);
1135             family = FamilyDECnet;
1136         } else {
1137             host = copyhostname ();
1138             family = FamilyInternet;
1139         }
1140 #endif
1141     } else {
1142         host = copystring (displayname, len);
1143         if (dnet) {
1144             family = dnet;
1145         } else {
1146 #ifdef UNIX
1147             if (host && strcmp (host, UNIX_CONNECTION) == 0)
1148               family = FamilyLocal;
1149             else
1150 #endif
1151               family = FamilyInternet;
1152         }
1153     }
1154
1155     if (!host) return 0;
1156
1157
1158     /*
1159      * get the display number; we know that there is something after the
1160      * colon (or colons) from above.  note that host is now set and must
1161      * be freed if there is an error.
1162      */
1163
1164     if (dnet) ptr++;                    /* skip the extra DECnet colon */
1165     ptr++;                              /* move to start of display num */
1166     {
1167         register char *cp;
1168
1169         for (cp = ptr; *cp && isascii(*cp) && isdigit(*cp); cp++) ;
1170         len = (cp - ptr);
1171                                         /* check present and valid follow */
1172         if (len == 0 || (*cp && *cp != '.')) {
1173             free (host);
1174             return 0;
1175         }
1176
1177         dpynum = atoi (ptr);            /* it will handle num. as well */
1178         ptr = cp;
1179     }
1180
1181     /*
1182      * now get screen number if given; ptr may point to nul at this point
1183      */
1184     if (ptr[0] == '.') {
1185         register char *cp;
1186
1187         ptr++;
1188         for (cp = ptr; *cp && isascii(*cp) && isdigit(*cp); cp++) ;
1189         len = (cp - ptr);
1190         if (len == 0 || (*cp && *cp != '.')) {  /* all prop name */
1191             free (host);
1192             return 0;
1193         }
1194
1195         scrnum = atoi (ptr);            /* it will handle num. as well */
1196         ptr = cp;
1197     }
1198
1199     /*
1200      * and finally, get any additional stuff that might be following the
1201      * the screen number; ptr must point to a period if there is anything
1202      */
1203
1204     if (ptr[0] == '.') {
1205         ptr++;
1206         len = strlen (ptr);
1207         if (len > 0) {
1208             rest = copystring (ptr, len);
1209             if (!rest) {
1210                 free (host);
1211                 return 1;
1212             }
1213         }
1214     }
1215
1216     /*
1217      * and we are done!
1218      */
1219
1220     if ( familyp )
1221         *familyp = family;
1222     if ( hostp )
1223         *hostp = host;
1224     else
1225         free(host);
1226     if ( dpynump )
1227         *dpynump = dpynum;
1228     if ( scrnump )
1229         *scrnump = scrnum;
1230     if ( restp )
1231         *restp = rest;
1232     else
1233         free(rest);
1234     return 1;
1235 }
1236
1237
1238 int
1239 #ifdef CK_ANSIC
1240 fwdx_tn_sb( unsigned char * sb, int n )
1241 #else
1242 fwdx_tn_sb( sb, n ) unsigned char * sb; int n;
1243 #endif /* CK_ANSIC */
1244 {
1245     unsigned short hchannel, nchannel;
1246     unsigned char * p;
1247     int i;
1248     int rc = -1;
1249
1250     /* check to ensure we have negotiated Forward X */
1251     if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) ||
1252          !sstelnet && !TELOPT_U(TELOPT_FORWARD_X) ) {
1253         debug(F100,"fwdx_tn_sb() not negotiated","",0);
1254         return(0);
1255     }
1256
1257 #ifdef CK_SSL
1258     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
1259         return(0);
1260     }
1261 #endif /* CK_SSL */
1262
1263     switch (sb[0]) {
1264     case FWDX_SCREEN:
1265         if (sstelnet && n == 4)
1266             rc = fwdx_create_listen_socket(sb[1]);
1267         break;
1268     case FWDX_OPEN:
1269         if ( !sstelnet && n >= 5 ) {
1270             p = (unsigned char *) &nchannel;
1271             i = 1;
1272             /* IAC quoting has been stripped in tn_sb() */
1273             p[0] = sb[i++];
1274             p[1] = sb[i++];
1275             hchannel = ntohs(nchannel);
1276             rc = fwdx_open_client_channel(hchannel);
1277             if ( rc < 0 ) {
1278                 /* Failed; Send CLOSE channel */
1279                 fwdx_send_close(hchannel);
1280                 rc = 0;         /* Do not consider this to be a telnet error */
1281             }
1282 #ifdef NT
1283             if ( !TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started ) {
1284                 ckThreadBegin( &fwdx_thread,32655, 0, FALSE, 0 ) ;
1285                 TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started = 1;
1286             }
1287 #endif /* NT */
1288         }
1289         break;
1290     case FWDX_CLOSE:
1291         p = (unsigned char *) &nchannel;
1292         i = 1;
1293         /* IAC quoting has been stripped in tn_sb() */
1294         p[0] = sb[i++];
1295         p[1] = sb[i++];
1296         hchannel = ntohs(nchannel);
1297         fwdx_close_channel(hchannel);
1298         rc = 0; /* no errors when closing */
1299         break;
1300     case FWDX_DATA:
1301         p = (unsigned char *) &nchannel;
1302         i = 1;
1303         /* IAC quoting has been stripped in tn_sb() */
1304         p[0] = sb[i++];
1305         p[1] = sb[i++];
1306         hchannel = ntohs(nchannel);
1307         rc = fwdx_send_xauth_to_xserver(hchannel,(char *)&sb[3],n-5);
1308         if ( rc >= 0 && n-5-rc > 0) {
1309             rc = fwdx_write_data_to_channel(hchannel,(char *)&sb[3+rc],n-5-rc);
1310             if ( rc < 0 ) {
1311                 /* Failed; Send CLOSE channel */
1312                 rc = fwdx_send_close(hchannel);
1313             }
1314         }
1315         break;
1316     case FWDX_OPTIONS:
1317         if ( sstelnet ) {
1318 #ifndef FWDX_SERVER
1319             rc = 0;
1320 #else
1321             rc = fwdx_server_accept_options((char*)&sb[2],n-3);
1322 #endif
1323         } else {
1324             rc = fwdx_client_reply_options((char *)&sb[2],n-3);
1325             if ( rc >= 0 ) {
1326                 rc = tn_sndfwdx();
1327             }
1328         }
1329         break;
1330     case FWDX_OPT_DATA:
1331         switch ( sb[1] ) {
1332         default:
1333             rc = 0;             /* we don't recognize, not an error */
1334         }
1335         break;
1336
1337     case FWDX_XOFF:
1338     case FWDX_XON:
1339         if ( !sstelnet ) {
1340             p = (unsigned char *) &nchannel;
1341             i = 1;
1342             /* IAC quoting has been stripped in tn_sb() */
1343             p[0] = sb[i++];
1344             p[1] = sb[i++];
1345             hchannel = ntohs(nchannel);
1346             TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[hchannel].suspend =
1347                 (sb[0] == FWDX_XOFF);
1348             rc = 0;
1349         }
1350         break;
1351     }
1352     return(rc < 0 ? -1 : 0);
1353 }
1354
1355 int
1356 #ifdef CK_ANSIC
1357 fwdx_send_xauth_to_xserver(int channel, unsigned char * data, int len)
1358 #else
1359 fwdx_send_xauth_to_xserver(channel, data, len)
1360     int channel; unsigned char * data; int len;
1361 #endif /* CK_ANSIC */
1362 {
1363     int name_len, data_len, i;
1364
1365     for (i = 0; i < MAXFWDX ; i++) {
1366         if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
1367             break;
1368     }
1369     if ( i == MAXFWDX )
1370         goto auth_err;
1371
1372     if (!TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth)
1373         return(0);
1374
1375     if (len < 12)
1376         goto auth_err;
1377
1378     /* Parse the lengths of variable-length fields. */
1379     if (data[0] == 0x42) {              /* byte order MSB first. */
1380         /* Xauth packets appear to always have this format */
1381         if ( data[1] != 0x00 ||
1382              data[2] != 0x00 ||
1383              data[3] != 0x0B ||
1384              data[4] != 0x00 ||
1385              data[5] != 0x00 )
1386             goto auth_err;
1387
1388         name_len = (data[6] << 8) + data[7];
1389         data_len = (data[8] << 8) + data[9];
1390     } else if (data[0] == 0x6c) {       /* Byte order LSB first. */
1391         /* Xauth packets appear to always have this format */
1392         if ( data[1] != 0x00 ||
1393              data[2] != 0x0B ||
1394              data[3] != 0x00 ||
1395              data[4] != 0x00 ||
1396              data[5] != 0x00 )
1397             goto auth_err;
1398
1399         name_len = data[6] + (data[7] << 8);
1400         data_len = data[8] + (data[9] << 8);
1401     } else {
1402         /* bad byte order byte */
1403         goto auth_err;
1404     }
1405
1406     /* Check if the whole packet is in buffer. */
1407     if (len < 12 + ((name_len + 3) & ~3) + ((data_len + 3) & ~3))
1408         goto auth_err;
1409     /* If the Telnet Server allows a real Xauth message to be sent */
1410     /* Then let the message be processed by the Xserver.           */
1411     if (name_len + data_len > 0) {
1412        TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0;
1413        return(0);
1414     }
1415     else
1416     /* If an empty Xauth message was received.  We are going to   */
1417     /* send our own Xauth message using the real Xauth data.  And */
1418     /* then send any other data in the buffer.                    */
1419     {
1420         int c, err, dpynum, scrnum, family, sb_len;
1421         char *display, *host = NULL, *rest = NULL;
1422         unsigned char *sb, *p;
1423
1424         /* parse the local DISPLAY env var */
1425         display = getenv("DISPLAY");
1426         if ( !display )
1427             display = "127.0.0.1:0.0";
1428
1429         if (fwdx_parse_displayname(display,
1430                                    &family, &host, &dpynum, &scrnum, &rest)) {
1431             char * disp_no = ckitoa(dpynum);    /* should be unsigned */
1432             if (family == FamilyLocal) {
1433                 /* call with address = "<local host name>" */
1434                 char address[300] = "localhost";
1435                 gethostname(address, sizeof(address) - 1);
1436                 real_xauth = XauGetAuthByAddr(family,
1437                                               strlen(address),
1438                                               address,
1439                                               strlen(disp_no),
1440                                               disp_no, 0, NULL);
1441             }
1442             else if (family == FamilyInternet) {
1443                 /* call with address = 4 bytes numeric ip addr (MSB) */
1444                 struct hostent *hi;
1445                 if (hi = gethostbyname(host))
1446                     real_xauth = XauGetAuthByAddr(family, 4,
1447                                                   hi->h_addr, strlen(disp_no),
1448                                                   disp_no, 0, NULL);
1449             }
1450         }
1451         if (host) free(host);
1452         if (rest) free(rest);
1453         if (!real_xauth) {
1454     TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0;
1455             return(0);
1456         }
1457
1458         if (!strncmp(real_xauth->name,
1459                      "MIT-MAGIC-COOKIE-1",
1460                      real_xauth->name_length)) {
1461             char msg[64];
1462
1463             name_len = real_xauth->name_length;
1464             data_len = 16;
1465
1466             if ( data[0] == 0x42 ) {
1467                 msg[0] = 0x42; /* MSB order */
1468                 msg[1] = msg[2] = 0;
1469                 msg[3] = 0x0B;
1470                 msg[4] = msg[5] = 0;
1471                 msg[6] = (name_len >> 8);
1472                 msg[7] = (name_len & 0xFF);
1473                 msg[8] = (data_len >> 8);
1474                 msg[9] = (data_len & 0xFF);
1475             } else {
1476                 msg[0] = 0x6c; /* LSB order */
1477                 msg[1] = 0;
1478                 msg[2] = 0x0B;
1479                 msg[3] = msg[4] = msg[5] = 0;
1480                 msg[6] = (name_len & 0xFF);
1481                 msg[7] = (name_len >> 8);
1482                 msg[8] = (data_len & 0xFF);
1483                 msg[9] = (data_len >> 8);
1484             }
1485             msg[10] = msg[11] = 0;
1486             memcpy(&msg[12],real_xauth->name,18);
1487             msg[30] = msg[31] = 0;
1488             memcpy(&msg[32],real_xauth->data,16);
1489
1490             if (fwdx_write_data_to_channel(channel,(char *)msg,48) < 0) {
1491   TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0;
1492                 return(-1);
1493             } else {
1494   TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0;
1495                 return(12);
1496             }
1497         } else {
1498   TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0;
1499             return(0);        /* we do not know how to handle this type yet */
1500         }
1501     }
1502
1503   auth_err:
1504         debug(F100,"fwdx_send_xauth_to_xserver error","",0);
1505     return(-1);
1506 }
1507
1508
1509 #ifdef COMMENT
1510 int
1511 #ifdef CK_ANSIC
1512 fwdx_authorize_channel(int channel, unsigned char * data, int len)
1513 #else
1514 fwdx_authorize_channel(channel, data, len)
1515     int channel; unsigned char * data; int len;
1516 #endif /* CK_ANSIC */
1517 {
1518     /* XXX maybe we should have some retry handling if not the whole first
1519     * authorization packet arrives complete
1520     */
1521     if ( !TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].authorized ) {
1522         int name_len, data_len;
1523
1524         if (len < 12)
1525             goto auth_err;
1526
1527         /* Parse the lengths of variable-length fields. */
1528         if (data[0] == 0x42) {          /* byte order MSB first. */
1529             /* Xauth packets appear to always have this format */
1530             if ( data[1] != 0x00 ||
1531                  data[2] != 0x00 ||
1532                  data[3] != 0x0B ||
1533                  data[4] != 0x00 ||
1534                  data[5] != 0x00 )
1535                 goto auth_err;
1536
1537             name_len = (data[6] << 8) + data[7];
1538             data_len = (data[8] << 8) + data[9];
1539         } else if (data[0] == 0x6c) {   /* Byte order LSB first. */
1540             /* Xauth packets appear to always have this format */
1541             if ( data[1] != 0x00 ||
1542                  data[2] != 0x0B ||
1543                  data[3] != 0x00 ||
1544                  data[4] != 0x00 ||
1545                  data[5] != 0x00 )
1546                 goto auth_err;
1547
1548             name_len = data[6] + (data[7] << 8);
1549             data_len = data[8] + (data[9] << 8);
1550         } else {
1551             /* bad byte order byte */
1552             goto auth_err;
1553         }
1554         /* Check if authentication protocol matches. */
1555         if (name_len != fake_xauth.name_length ||
1556              memcmp(data + 12, fake_xauth.name, name_len) != 0) {
1557             /* connection uses different authentication protocol */
1558             goto auth_err;
1559         }
1560         /* Check if authentication data matches our fake data. */
1561         if (data_len != fake_xauth.data_length ||
1562              memcmp(data + 12 + ((name_len + 3) & ~3),
1563                      fake_xauth.data, fake_xauth.data_length) != 0) {
1564             /* auth data does not match fake data */
1565             goto auth_err;
1566         }
1567         /* substitute the fake data with real data if we have any */
1568         if (real_xauth && real_xauth->data)
1569             memcpy(data + 12 + ((name_len + 3) & ~3),
1570                    real_xauth->data, data_len);
1571
1572         TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].authorized = 1;
1573     }
1574     return(0);
1575   auth_err:
1576     return(-1);
1577 }
1578 #endif /* COMMENT */
1579
1580 int
1581 #ifdef CK_ANSIC
1582 fwdx_send_close(int channel)
1583 #else
1584 fwdx_send_close(channel) int channel;
1585 #endif /* CK_ANSIC */
1586 {
1587     unsigned short nchannel;
1588     int i,rc;
1589     CHAR * p;
1590
1591 #ifdef CK_SSL
1592     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
1593         return(0);
1594     }
1595 #endif /* CK_SSL */
1596
1597     nchannel = htons(channel);
1598     p = (unsigned char *) &nchannel;
1599
1600     i = 0;
1601     sb_out[i++] = (CHAR) IAC;               /* I Am a Command */
1602     sb_out[i++] = (CHAR) SB;                /* Subnegotiation */
1603     sb_out[i++] = TELOPT_FORWARD_X;         /* Forward X */
1604     sb_out[i++] = FWDX_CLOSE;               /* Open */
1605     sb_out[i++] = p[0];                     /* First Byte of Channel */
1606     if ( p[0] == IAC )
1607         sb_out[i++] = IAC;
1608     sb_out[i++] = p[1];                     /* Second Byte of Channel */
1609     if ( p[1] == IAC )
1610         sb_out[i++] = IAC;
1611     sb_out[i++] = (CHAR) IAC;               /* End of Subnegotiation */
1612     sb_out[i++] = (CHAR) SE;                /* marked by IAC SE */
1613 #ifdef DEBUG
1614     if (deblog || tn_deb || debses) {
1615         ckmakxmsg(fwdx_msg_out,TN_MSG_LEN,"TELNET SENT SB ",
1616                   TELOPT(TELOPT_FORWARD_X),
1617                   " CLOSE CHANNEL=",ckitoa(channel)," IAC SE",
1618                   NULL,NULL,NULL,NULL,NULL,NULL,NULL
1619                   );
1620     }
1621 #endif /* DEBUG */
1622 #ifdef OS2
1623     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
1624 #endif
1625 #ifdef DEBUG
1626     debug(F100,fwdx_msg_out,"",0);
1627     if (tn_deb || debses) tn_debug(fwdx_msg_out);
1628 #endif /* DEBUG */
1629     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
1630 #ifdef OS2
1631     ReleaseTelnetMutex();
1632 #endif
1633     if (rc)
1634       return(-1);
1635     return(0);
1636 }
1637
1638 int
1639 #ifdef CK_ANSIC
1640 fwdx_send_open(int channel)
1641 #else /* CK_ANSIC */
1642 fwdx_send_open(channel) int channel;
1643 #endif /* CK_ANSIC */
1644 {
1645     unsigned short nchannel;
1646     int i, rc;
1647     CHAR * p;
1648
1649 #ifdef CK_SSL
1650     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
1651         return(0);
1652     }
1653 #endif /* CK_SSL */
1654
1655     nchannel = htons(channel);
1656     p = (unsigned char *) &nchannel;
1657
1658     i = 0;
1659     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
1660     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
1661     sb_out[i++] = TELOPT_FORWARD_X;           /* Forward X */
1662     sb_out[i++] = FWDX_OPEN;                  /* Open */
1663     sb_out[i++] = p[0];                       /* First Byte of Channel */
1664     if ( p[0] == IAC )
1665         sb_out[i++] = IAC;
1666     sb_out[i++] = p[1];                       /* Second Byte of Channel */
1667     if ( p[1] == IAC )
1668         sb_out[i++] = IAC;
1669     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
1670     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
1671 #ifdef DEBUG
1672     if (deblog || tn_deb || debses) {
1673         ckmakxmsg(fwdx_msg_out,TN_MSG_LEN,"TELNET SENT SB ",
1674                   TELOPT(TELOPT_FORWARD_X),
1675                   " OPEN CHANNEL=",ckitoa(channel)," IAC SE",
1676                   NULL,NULL,NULL,NULL,NULL,NULL,NULL);
1677     }
1678 #endif /* DEBUG */
1679 #ifdef OS2
1680     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
1681 #endif
1682 #ifdef DEBUG
1683     debug(F100,fwdx_msg_out,"",0);
1684     if (tn_deb || debses) tn_debug(fwdx_msg_out);
1685 #endif /* DEBUG */
1686     rc = (ttol((CHAR *)sb_out,i) < 0);        /* Send it. */
1687 #ifdef OS2
1688     ReleaseTelnetMutex();
1689 #endif
1690     if (rc)
1691       return(-1);
1692     return(0);
1693 }
1694
1695 int
1696 #ifdef CK_ANSIC
1697 fwdx_client_reply_options(char *opts, int n)
1698 #else
1699 fwdx_client_reply_options(opts, n) char *opts; int n;
1700 #endif /* CK_ANSIC */
1701 {
1702     int i,j,rc;
1703
1704 #ifdef CK_SSL
1705     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
1706         return(0);
1707     }
1708 #endif /* CK_SSL */
1709
1710     i = 0;
1711     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
1712     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
1713     sb_out[i++] = TELOPT_FORWARD_X;           /* Forward X */
1714     sb_out[i++] = FWDX_OPTIONS;               /* Options */
1715
1716     /* Look for the options we recognize and will support for this session */
1717     /* and reply with their bytes set                                      */
1718     for (j=0; j<n; j++,i++) {
1719         sb_out[i] = FWDX_OPT_NONE;          /* Add zero byte - no options */
1720 #ifdef COMMENT
1721         /* If we had any options to support, this is how we would do it */
1722         if ( j == 0 ) {
1723             if (opts[j] & FWDX_OPT_XXXX) {
1724                 /* set flag to remember option is in use */
1725                 flag = 1;
1726                 sb_out[i] |= FWDX_OPT_XXXX;
1727             }
1728         }
1729 #endif /* COMMENT */
1730     }
1731     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
1732     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
1733 #ifdef DEBUG
1734     if (deblog || tn_deb || debses) {
1735         ckmakxmsg(fwdx_msg_out,TN_MSG_LEN,"TELNET SENT SB ",
1736                   TELOPT(TELOPT_FORWARD_X),
1737                   " OPTIONS ",ckctox(sb_out[4],1)," IAC SE",
1738                   NULL,NULL,NULL,NULL,NULL,NULL,NULL);
1739     }
1740 #endif /* DEBUG */
1741 #ifdef OS2
1742     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
1743 #endif
1744 #ifdef DEBUG
1745     debug(F100,fwdx_msg_out,"",0);
1746     if (tn_deb || debses) tn_debug(fwdx_msg_out);
1747 #endif /* DEBUG */
1748     rc = (ttol((CHAR *)sb_out,i) < 0);        /* Send it. */
1749 #ifdef OS2
1750     ReleaseTelnetMutex();
1751 #endif
1752     if (rc)
1753       return(-1);
1754     return(0);
1755 }
1756
1757
1758 int
1759 fwdx_send_options() {
1760     int i, rc;
1761
1762 #ifdef CK_SSL
1763     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
1764         return(0);
1765     }
1766 #endif /* CK_SSL */
1767
1768     i = 0;
1769     sb_out[i++] = (CHAR) IAC;               /* I Am a Command */
1770     sb_out[i++] = (CHAR) SB;                /* Subnegotiation */
1771     sb_out[i++] = TELOPT_FORWARD_X;         /* Forward X */
1772     sb_out[i++] = FWDX_OPTIONS;             /* Options */
1773     sb_out[i]   = FWDX_OPT_NONE;
1774     /* activate options here */
1775     i++;
1776     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
1777     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
1778
1779 #ifdef DEBUG
1780     if (deblog || tn_deb || debses) {
1781         ckmakmsg(fwdx_msg_out,TN_MSG_LEN,"TELNET SENT SB ",
1782                  TELOPT(TELOPT_FORWARD_X),
1783                  " OPTIONS 00 IAC SE",NULL);
1784     }
1785 #endif /* DEBUG */
1786 #ifdef OS2
1787     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
1788 #endif
1789 #ifdef DEBUG
1790     debug(F100,fwdx_msg_out,"",0);
1791     if (tn_deb || debses) tn_debug(fwdx_msg_out);
1792 #endif /* DEBUG */
1793     rc = (ttol((CHAR *)sb_out,i) < 0);        /* Send it. */
1794 #ifdef OS2
1795     ReleaseTelnetMutex();
1796 #endif
1797     if (rc)
1798       return(-1);
1799     return(0);
1800 }
1801
1802 int
1803 #ifdef CK_ANSIC
1804 fwdx_send_data_from_channel(int channel, char * data, int len)
1805 #else
1806 fwdx_send_data_from_channel(channel, data, len)
1807     int channel; char * data; int len;
1808 #endif
1809 {
1810     unsigned short nchannel;
1811     /* static */ CHAR sb_priv[2048];
1812     CHAR * p;
1813     int i, j, j_sav, rc;
1814     unsigned int tmp;
1815
1816     debug(F111,"fwdx_send_data_from_channel()","channel",channel);
1817
1818 #ifdef CK_SSL
1819     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
1820         return(0);
1821     }
1822 #endif /* CK_SSL */
1823
1824     nchannel = htons(channel);
1825     p = (unsigned char *) &nchannel;
1826
1827     j = 0;
1828     sb_priv[j++] = (CHAR) IAC;                 /* I Am a Command */
1829     sb_priv[j++] = (CHAR) SB;                  /* Subnegotiation */
1830     sb_priv[j++] = TELOPT_FORWARD_X;           /* Forward X */
1831     sb_priv[j++] = FWDX_DATA;                  /* Data */
1832     sb_priv[j++] = p[0];                       /* First Byte of Channel */
1833     if ( p[0] == IAC )
1834         sb_priv[j++] = IAC;
1835     sb_priv[j++] = p[1];                       /* Second Byte of Channel */
1836     if ( p[1] == IAC )
1837         sb_priv[j++] = IAC;
1838     j_sav = j;
1839
1840     for (i = 0; i < len; i++) {
1841         tmp = (unsigned int)data[i];
1842         if ( tmp == IAC ) {
1843             sb_priv[j++] = IAC;
1844             sb_priv[j++] = IAC;
1845         } else {
1846             sb_priv[j++] = tmp;
1847         }
1848         if ( j >= 2045 && (i < len-1) ) {
1849             sb_priv[j++] = (CHAR) IAC;  /* End of Subnegotiation */
1850             sb_priv[j++] = (CHAR) SE;   /* marked by IAC SE */
1851
1852 #ifdef DEBUG
1853             if (deblog || tn_deb || debses) {
1854                 ckmakxmsg( fwdx_msg_out,TN_MSG_LEN,"TELNET SENT SB ",
1855                            TELOPT(TELOPT_FORWARD_X),
1856                            " DATA CHANNEL=",ckitoa(channel)," ",
1857                            NULL,NULL,NULL,NULL,NULL,NULL,NULL );
1858                 tn_hex(fwdx_msg_out,TN_MSG_LEN,&sb_priv[j_sav],j-(j_sav+2));
1859                 ckstrncat(fwdx_msg_out," IAC SE",TN_MSG_LEN);
1860             }
1861 #endif /* DEBUG */
1862 #ifdef OS2
1863             RequestTelnetMutex( SEM_INDEFINITE_WAIT );
1864 #endif
1865 #ifdef DEBUG
1866             debug(F100,fwdx_msg_out,"",0);
1867             if (tn_deb || debses) tn_debug(fwdx_msg_out);
1868 #endif /* DEBUG */
1869             rc = (ttol(sb_priv,j) < 0);                /* Send it. */
1870 #ifdef OS2
1871             ReleaseTelnetMutex();
1872 #endif
1873             if (rc) {
1874                 debug(F110,"fwdx_send_data_from_channel()","ttol() failed",0);
1875                 return(-1);
1876             }
1877
1878             j = 0;
1879             sb_priv[j++] = (CHAR) IAC;                 /* I Am a Command */
1880             sb_priv[j++] = (CHAR) SB;                  /* Subnegotiation */
1881             sb_priv[j++] = TELOPT_FORWARD_X;           /* Forward X */
1882             sb_priv[j++] = FWDX_DATA;                  /* Data */
1883             sb_priv[j++] = p[0];                       /* First Byte of Channel */
1884             if ( p[0] == IAC )
1885                 sb_priv[j++] = IAC;
1886             sb_priv[j++] = p[1];                       /* Second Byte of Channel */
1887             if ( p[1] == IAC )
1888                 sb_priv[j++] = IAC;
1889         }
1890     }
1891
1892     sb_priv[j++] = (CHAR) IAC;                 /* End of Subnegotiation */
1893     sb_priv[j++] = (CHAR) SE;                  /* marked by IAC SE */
1894
1895 #ifdef DEBUG
1896     if (deblog || tn_deb || debses) {
1897         ckmakxmsg( fwdx_msg_out,TN_MSG_LEN,
1898                    "TELNET SENT SB ",TELOPT(TELOPT_FORWARD_X),
1899                    " DATA ",ckctox(p[0],1)," ",ckctox(p[1],1)," ",
1900                    NULL,NULL,NULL,NULL,NULL);
1901         tn_hex(fwdx_msg_out,TN_MSG_LEN,&sb_priv[6],j-8);
1902         ckstrncat(fwdx_msg_out," IAC SE",TN_MSG_LEN);
1903     }
1904 #endif /* DEBUG */
1905 #ifdef OS2
1906     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
1907 #endif
1908 #ifdef DEBUG
1909     debug(F100,fwdx_msg_out,"",0);
1910     if (tn_deb || debses) tn_debug(fwdx_msg_out);
1911 #endif /* DEBUG */
1912     rc = (ttol(sb_priv,j) < 0);                /* Send it. */
1913 #ifdef OS2
1914     ReleaseTelnetMutex();
1915 #endif
1916     if ( rc ) {
1917         debug(F110,"fwdx_send_data_from_channel()","ttol() failed",0);
1918         return(-1);
1919     }
1920
1921
1922     return(0);
1923 }
1924
1925 static unsigned char *
1926 #ifdef CK_ANSIC
1927 fwdx_add_quoted_twobyte(unsigned char *p, unsigned short twobyte)
1928 #else
1929 fwdx_add_quoted_twobyte(p, twobyte)
1930     unsigned char *p; unsigned short twobyte;
1931 #endif /* CK_ANSIC */
1932 /* adds the IAC quoted (MSB) representation of 'channel' at buffer pointer 'p',
1933  * returning pointer to new buffer position. NO OVERFLOW CHECK!
1934  */
1935 {
1936     *p++ = (unsigned char)((twobyte >> 8) & 0xFF);
1937     if (*(p - 1) == 0xFF)
1938         *p++ = 0xFF;
1939     *p++ = (unsigned char)(twobyte & 0xFF);
1940     if (*(p - 1) == 0xFF)
1941         *p++ = 0xFF;
1942     return p;
1943 }
1944
1945 int
1946 #ifdef CK_ANSIC
1947 fwdx_create_fake_xauth(char *name, int name_len, int data_len)
1948 #else
1949 fwdx_create_fake_xauth(name, name_len, data_len)
1950     char *name; int name_len; int data_len;
1951 #endif /* CK_ANSIC */
1952 {
1953     char stackdata[256];
1954     unsigned int c, n;
1955
1956     if (!name_len || !data_len)
1957         return 1;
1958     fake_xauth.name = malloc(name_len);
1959     fake_xauth.data = malloc(data_len);
1960     if (!fake_xauth.name || !fake_xauth.data)
1961         return 2;
1962     fake_xauth.name_length = name_len;
1963     memcpy(fake_xauth.name, name, name_len);
1964     fake_xauth.data_length = data_len;
1965
1966     /* try to make a random unsigned int to feed srand() */
1967     c = time(NULL);
1968     c *= getpid();
1969     for (n = 0; n < sizeof(stackdata); n++)
1970         c += stackdata[n];
1971     srand((unsigned int)c);
1972     for (c = 0; c < data_len; c++)
1973         fake_xauth.data[c] = (unsigned char)rand();
1974     return 0;
1975 }
1976
1977 #ifdef COMMENT
1978 /* No longer used */
1979 int
1980 fwdx_send_xauth(void)
1981 {
1982     int c, err, dpynum, family, sb_len, rc;
1983     char *display, *host = NULL;
1984     unsigned char *sb_priv, *p;
1985
1986     /* parse the local DISPLAY env var */
1987     if (!(display = tn_get_display()))
1988         return (-1);
1989     if (fwdx_parse_displayname(display, &family, &host, &dpynum, NULL, NULL)) {
1990         char * disp_no = ckitoa(dpynum);
1991         if (family == FamilyLocal) {
1992             /* call with address = "<local host name>" */
1993             char address[300] = "localhost";
1994             gethostname(address, sizeof(address) - 1);
1995             real_xauth = XauGetAuthByAddr(family,
1996                                           strlen(address),
1997                                           address,
1998                                           strlen(disp_no),
1999                                           disp_no, 0, NULL
2000                                           );
2001         }
2002         else if (family == FamilyInternet) {
2003             /* call with address = 4 bytes numeric ip addr (MSB) */
2004             struct hostent *hi;
2005             if (hi = gethostbyname(host))
2006                 real_xauth = XauGetAuthByAddr(family, 4,
2007                                               hi->h_addr,
2008                                               strlen(disp_no),
2009                                               disp_no, 0, NULL
2010                                               );
2011         }
2012     }
2013     if (host) {
2014         free(host);
2015         host = NULL;
2016     }
2017     if (real_xauth)
2018         err = fwdx_create_fake_xauth(real_xauth->name,
2019                                      real_xauth->name_length,
2020                                      real_xauth->data_length
2021                                      );
2022     else
2023       err = fwdx_create_fake_xauth("MIT-MAGIC-COOKIE-1",
2024                                    strlen("MIT-MAGIC-COOKIE-1"), 16);
2025     if (err)
2026         return(-1);
2027
2028     /* allocate memory for the SB block, alloc for worst case              */
2029     /* the following sprintf() calls are safe due to length checking       */
2030     /* buffer is twice as big as the input just in case every byte was IAC */
2031     sb_len = 5 + 2 + 2 + fake_xauth.name_length + fake_xauth.data_length + 2;
2032     if (!(sb_priv = malloc(2 * sb_len)))
2033         return(-1);
2034     p = sb_priv;
2035     sprintf(p, "%c%c%c%c%c", IAC, SB, TELOPT_FORWARD_X,
2036             FWDX_OPT_DATA, FWDX_OPT_XAUTH);
2037     p += 5;
2038     p = fwdx_add_quoted_twobyte(p, fake_xauth.name_length);
2039     p = fwdx_add_quoted_twobyte(p, fake_xauth.data_length);
2040     for (c = 0; c < fake_xauth.name_length; c++) {
2041         *p++ = fake_xauth.name[c];
2042         if ((unsigned char)fake_xauth.name[c] == 0xFF)
2043             *p++ = 0xFF;
2044     }
2045     for (c = 0; c < fake_xauth.data_length; c++) {
2046         *p++ = fake_xauth.data[c];
2047         if ((unsigned char)fake_xauth.data[c] == 0xFF)
2048             *p++ = 0xFF;
2049     }
2050     sprintf(p, "%c%c", IAC, SE);
2051     p += 2;
2052
2053 #ifdef DEBUG
2054     if (deblog || tn_deb || debses) {
2055         sprintf(fwdx_msg_out,"TELNET SENT SB %s OPTION_DATA XAUTH ",
2056                  TELOPT(TELOPT_FORWARD_X));
2057         tn_hex(fwdx_msg_out,TN_MSG_LEN,&sb_priv[5],(p-sb_priv)-7);
2058         ckstrncat(fwdx_msg_out," IAC SE",TN_MSG_LEN);
2059     }
2060 #endif /* DEBUG */
2061
2062     /* Add Telnet Debug info here */
2063 #ifdef OS2
2064     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
2065 #endif
2066 #ifdef DEBUG
2067     debug(F100,fwdx_msg_out,"",0);
2068     if (tn_deb || debses) tn_debug(fwdx_msg_out);
2069 #endif /* DEBUG */
2070     rc = ( ttol(sb_priv,p-sb_priv) < 0 );                /* Send it. */
2071 #ifdef OS2
2072     ReleaseTelnetMutex();
2073 #endif
2074     if (rc) {
2075         debug(F110,"fwdx_send_xauth()","ttol() failed",0);
2076         return(-1);
2077     }
2078
2079
2080     free(sb_priv);
2081     return(0);
2082 }
2083 #endif /* COMMENT */
2084 #ifdef FWDX_SERVER
2085 /* Only if we ever become a server - not yet ported to Kermit   */
2086 /* And even so most of this code does not belong in this module */
2087
2088 int
2089 fwdx_write_xauthfile(void)
2090 {
2091     int dpynum, scrnum, family;
2092     char myhost[300], *host, *rest = NULL;
2093     FILE *file;
2094     struct sockaddr_in saddr;
2095     struct hostent *hi;
2096
2097     if (!fwdx_display && !fwdx_xauthfile)
2098         return 1;
2099     if (!parse_displayname(fwdx_display,
2100                            &family, &host, &dpynum, &scrnum, &rest))
2101         return 2;
2102     if (rest) free(rest);
2103     if (host) free(host);
2104     if (family != FamilyInternet)
2105         return 3; /* every thing but FamilyInternet is unexpected */
2106
2107     /* X connections to localhost:1 is actually treated as local unix sockets,
2108      * see the 'xauth' man page.
2109      */
2110     xauth.family = FamilyLocal;
2111     if (gethostname(myhost, sizeof(myhost) - 1))
2112         return 5;
2113     xauth.address_length = strlen(myhost);
2114     if (!(xauth.address = malloc(xauth.address_length)))
2115         return 5;
2116     memcpy(xauth.address, myhost, xauth.address_length);
2117
2118     /* the display number is written as a string, not numeric */
2119     if (!(xauth.number = malloc(6)))
2120         return 6;
2121     snprintf(xauth.number, 5, "%u", dpynum);
2122     xauth.number_length = strlen(xauth.number);
2123     if (!(file = fopen(fwdx_xauthfile, "wb")))
2124         return 7;
2125     if (!XauWriteAuth(file, &xauth))
2126         return 8;
2127     fclose(file);
2128     setenv("XAUTHORITY", fwdx_xauthfile, 1);
2129     return 0;
2130 }
2131
2132 int
2133 fwdx_setup_xauth(unsigned char *sp, int len)
2134 /* called with 'len' xauth bytes, starting at 'sp'
2135  * the data format is: <uint16 name_length> <uint16 data_length> <name> <data>
2136  */
2137 {
2138     int xauthfd;
2139
2140     if (!fwdx_options[FWDX_OPT_XAUTH])
2141         return 1;
2142     if (len < 4)
2143         return 2;
2144
2145     /* setup the xauth struct */
2146     xauth.name_length = (sp[0] << 8) + sp[1];
2147     xauth.data_length = (sp[2] << 8) + sp[3];
2148     if (len != 4 + xauth.name_length + xauth.data_length)
2149         return 3;
2150     xauth.name = malloc(xauth.name_length);
2151     xauth.data = malloc(xauth.data_length);
2152     if (!xauth.name || !xauth.data)
2153         return 4;
2154     memcpy(xauth.name, sp + 4, xauth.name_length);
2155     memcpy(xauth.data, sp + 4 + xauth.name_length, xauth.data_length);
2156
2157     /* Setup to always have a local .Xauthority. */
2158     fwdx_xauthfile = malloc(MAXPATHLEN+1);
2159     snprintf(fwdx_xauthfile, MAXPATHLEN, "/tmp/XauthXXXXXX");
2160     if ((xauthfd = mkstemp(fwdx_xauthfile)) != -1)
2161         /* we change file ownership later, when we know who is to be owner! */
2162         close(xauthfd);
2163     else {
2164         free(fwdx_xauthfile);
2165         fwdx_xauthfile = NULL;
2166         return 5;
2167     }
2168 /* Must have the subshell's new DISPLAY env var to write xauth to xauthfile */
2169     if (fwdx_display)
2170         if (fwdx_write_xauthfile())
2171             return 6;
2172
2173     return 0;
2174 }
2175
2176 void fwdx_set_xauthfile_owner(int uid)
2177 {
2178     struct passwd *pwd;
2179
2180     if (!fwdx_xauthfile || !(pwd = getpwuid(uid)))
2181         return;
2182     chown(fwdx_xauthfile, pwd->pw_uid, pwd->pw_gid);
2183 }
2184
2185 int
2186 fwdx_server_accept_options(unsigned char *sp, int len)
2187 /* called with 'len' option bytes, starting at 'sp' */
2188 {
2189     int c;
2190
2191     for (c = 0; c < len-2; c++) {
2192         if (c == 0) {
2193             if (sp[c] & FWDX_OPT_XAUTH)
2194                 flag = 1;
2195         }
2196     }
2197     return(0);
2198 }
2199 #endif /* FWDX_SERVER */
2200 #endif /* CK_FORWARD_X */
2201
2202 #ifdef IKS_OPTION
2203 /*
2204   iks_wait() -- Wait for an IKS subnegotiation response.
2205   sb - is either KERMIT_REQ_START or KERMIT_REQ_STOP depending on the desired
2206        state of the peer's Kermit server.
2207   flushok - specifies whether it is ok to throw away non-Telnet data
2208        if so, then we call ttflui() instead of tn_flui().
2209   Returns:
2210    1 if the desired state is achieved or if it is unknown.
2211    0 if the desired state is not achieved.
2212 */
2213 int
2214 #ifdef CK_ANSIC
2215 iks_wait(int sb, int flushok)
2216 #else /* CK_ANSIC */
2217 iks_wait(sb,flushok) int sb; int flushok;
2218 #endif /* CK_ANSIC */
2219 {
2220     int tn_wait_save = tn_wait_flg;
2221     int x;
2222
2223     if (TELOPT_U(TELOPT_KERMIT)) {
2224         switch (sb) {
2225           case KERMIT_REQ_START:
2226             debug(F111,
2227                   "iks_wait KERMIT_REQ_START",
2228                   "u_start",
2229                   TELOPT_SB(TELOPT_KERMIT).kermit.u_start
2230                   );
2231             tn_siks(KERMIT_REQ_START);
2232             tn_wait_flg = 1;            /* Kermit Option MUST wait */
2233             do {
2234                 if (flushok)
2235                   tn_wait_idx = 0;
2236                 x = tn_wait("iks_wait() me_iks_req_start");
2237             } while (x == 0 && flushok && tn_wait_idx == TN_WAIT_BUF_SZ);
2238             tn_wait_flg = tn_wait_save;
2239             if (flushok)
2240               tn_wait_idx = 0;
2241             if (tn_wait_idx == TN_WAIT_BUF_SZ) {
2242                 /*
2243                  * We are attempting to start a kermit server on the peer
2244                  * the most likely reason is because we want to perform a
2245                  * file transfer.  But there is a huge amount of non telnet
2246                  * negotiation data coming in and so we have not been able
2247                  * to find the response.  So we will lie and assume that
2248                  * response is 'yes'.  The worse that will happen is that
2249                  * a RESP_STOP is received after we enter protocol mode.
2250                  * And the protocol operation will be canceled.
2251                  */
2252                 tn_push();
2253                 return(1);
2254             } else {
2255                 tn_push();
2256                 return(TELOPT_SB(TELOPT_KERMIT).kermit.u_start);
2257             }
2258           case KERMIT_REQ_STOP:
2259             debug(F111,
2260                   "iks_wait KERMIT_REQ_STOP",
2261                   "u_start",
2262                   TELOPT_SB(TELOPT_KERMIT).kermit.u_start
2263                   );
2264             tn_siks(KERMIT_REQ_STOP);
2265             tn_wait_flg = 1;            /* Kermit Option MUST wait */
2266             do {
2267                 if (flushok)
2268                   tn_wait_idx = 0;
2269                 x = tn_wait("iks_wait() me_iks_req_stop");
2270             } while (x == 0 && flushok && tn_wait_idx == TN_WAIT_BUF_SZ);
2271             tn_wait_flg = tn_wait_save;
2272             if (flushok)
2273               tn_wait_idx = 0;
2274
2275             if (tn_wait_idx == TN_WAIT_BUF_SZ) {
2276                 /*
2277                  * We are attempting to stop a kermit server on the peer
2278                  * the most likely reason being that we want to enter
2279                  * CONNECT mode.  But there is a huge amount of non telnet
2280                  * negotiation data coming in and so we have not been able
2281                  * to find the response.  So we will lie and assume that
2282                  * the answer is 'yes' and allow the CONNECT command to
2283                  * succeed.  The worst that happens is that CONNECT mode
2284                  * swallows the incoming data displaying it to the user
2285                  * and then it resumes Kermit client mode.
2286                  */
2287                 tn_push();
2288                 return(1);
2289             } else {
2290                 tn_push();
2291                 return(!TELOPT_SB(TELOPT_KERMIT).kermit.u_start);
2292             }
2293         }
2294         tn_push();
2295     }
2296     return(1);
2297 }
2298
2299 int
2300 #ifdef CK_ANSIC
2301 iks_tn_sb(CHAR * sb, int n)
2302 #else
2303 iks_tn_sb(sb, n) CHAR * sb; int n;
2304 #endif /* CK_ANSIC */
2305 {
2306     extern int server;
2307     extern CHAR sstate;
2308 #ifdef NOICP
2309     extern int autodl;
2310     int inautodl = 0, cmdadl = 1;
2311 #else
2312 #ifdef CK_AUTODL
2313     extern int autodl, inautodl, cmdadl;
2314 #endif /* CK_AUTODL */
2315 #endif /* NOICP */
2316     switch (sb[0]) {
2317       case KERMIT_START:                /* START */
2318         TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 1;
2319         return(4);
2320
2321       case KERMIT_STOP:                 /* STOP */
2322         TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 0;
2323         return(4);
2324
2325       case KERMIT_REQ_START:            /* REQ-START */
2326 #ifndef NOXFER
2327         if (inserver) {
2328 #ifdef CK_AUTODL
2329             cmdadl = 1;                 /* Turn on packet detection */
2330 #endif /* CK_AUTODL */
2331             TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 1;
2332             tn_siks(KERMIT_RESP_START);
2333         } else if (TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
2334             tn_siks(KERMIT_RESP_START);
2335         } else {
2336 #ifndef IKSDONLY
2337 #ifdef CK_AUTODL
2338 #ifdef OS2
2339             if (local && (IsConnectMode() && autodl) ||
2340                 (!IsConnectMode() && 
2341                   (inautodl || sstate == 'x' || sstate == 'v'))
2342                 )
2343               tn_siks(KERMIT_RESP_START); /* START */
2344             else
2345
2346 #else /* OS2 */
2347             if ((local && what == W_CONNECT && autodl) ||
2348                 (local && what != W_CONNECT &&
2349                   (inautodl || sstate == 'x' || sstate == 'v')
2350                 ))
2351               tn_siks(KERMIT_RESP_START); /* START */
2352             else
2353 #endif /* OS2 */
2354 #endif /* CK_AUTODL */
2355 #endif /* IKSDONLY */
2356               tn_siks(KERMIT_RESP_STOP);
2357         }
2358 #else /* NOXFER */
2359           tn_siks(KERMIT_RESP_STOP);
2360 #endif /* NOXFER */
2361         return(4);
2362
2363       case KERMIT_REQ_STOP:             /* REQ-STOP */
2364         /* The protocol requires that the request be responded to */
2365         /* either by changing states or by reporting the current  */
2366         /* state.  */
2367
2368         /* We need to provide the user some way of dictating what */
2369         /* the policies should be.  For instance, if we are in    */
2370         /* CONNECT mode with autodownload ON and we get a REQ-STOP*/
2371         /* what should the proper response be?                    */
2372 #ifndef NOXFER
2373         if (inserver
2374 #ifdef CK_AUTODL
2375             || !local && cmdadl
2376 #endif /* CK_AUTODL */
2377             ) {
2378 #ifdef CK_AUTODL
2379             cmdadl = 0;                 /* Turn off packet detection */
2380 #endif /* CK_AUTODL */
2381             tn_siks(KERMIT_RESP_STOP);
2382         } else if (server) {
2383             extern int en_fin;
2384             if (en_fin) {               /* If the server is allowed to stop */
2385                 tn_siks(KERMIT_RESP_STOP);
2386             } else {                    /* We are not allowed to stop */
2387                 tn_siks(KERMIT_RESP_START);
2388             }
2389         }
2390 #ifndef IKSDONLY
2391 #ifdef CK_AUTODL
2392 #ifdef OS2
2393         else if (local && (IsConnectMode() && autodl) ||
2394                    (!IsConnectMode() && inautodl)
2395                    ) {
2396             /* If we are a pseudo-server and the other side requests */
2397             /* that we stop, tell then that we have even though we   */
2398             /* have not.  Otherwise, the other side might refuse to  */
2399             /* enter SERVER mode.                                    */
2400
2401             tn_siks(KERMIT_RESP_STOP);  /* STOP */
2402         }
2403 #else /* OS2 */
2404         else if ((local && what == W_CONNECT && autodl) ||
2405                    (local && what != W_CONNECT && inautodl)
2406                    ) {
2407             /* If we are a pseudo-server and the other side requests */
2408             /* that we stop, tell then that we have even though we   */
2409             /* have not.  Otherwise, the other side might refuse to  */
2410             /* enter SERVER mode.                                    */
2411
2412             tn_siks(KERMIT_RESP_STOP);  /* STOP */
2413         }
2414 #endif /* OS2 */
2415 #endif /* CK_AUTODL */
2416 #endif /* IKSDONLY */
2417         else
2418 #endif /* NOXFER */
2419         {
2420             /* If we are not currently in any mode that accepts */
2421             /* Kermit packets then of course report that we are */
2422             /* not being a Kermit server.                       */
2423
2424             tn_siks(KERMIT_RESP_STOP);  /* STOP */
2425         }
2426         return(4);
2427
2428       case KERMIT_SOP: {                /* SOP */
2429 #ifndef NOXFER
2430           extern CHAR stchr;            /* Incoming SOP character */
2431           stchr = sb[1];
2432 #endif /* NOXFER */
2433           TELOPT_SB(TELOPT_KERMIT).kermit.sop = 1;
2434           return(4);
2435       }
2436
2437       case KERMIT_RESP_START:           /* START */
2438         TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 1;
2439         if (TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start) {
2440             TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start = 0;
2441         } else if (TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop) {
2442             /* If we have issued a request to stop a Kermit Server */
2443             /* and the response is Start, then we must report this */
2444             /* to the caller.                                      */
2445             TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop = 0;
2446         }
2447         return(4);
2448
2449       case KERMIT_RESP_STOP:            /* STOP */
2450         TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 0;
2451         if (TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start) {
2452             TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start = 0;
2453             /* If we have issued a request to start a Kermit Server */
2454             /* and the response is Stop, then we must report this   */
2455             /* to the caller.                                       */
2456         } else if (TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop) {
2457             TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop = 0;
2458         }
2459         return(4);
2460
2461       default:
2462         return(0);
2463
2464     } /* switch (sb[0]) */
2465 }
2466 #endif /* IKS_OPTION */
2467
2468 /* Initialize telnet settings - set default values for ME and U modes */
2469 int
2470 tn_set_modes() {
2471     int opt,cmd;
2472 #ifdef CK_FORWARD_X
2473     int x;
2474 #endif /* CK_FORWARD_X */
2475 #ifdef CK_ENVIRONMENT
2476     {
2477         int i,j;
2478         for (i = 0; i < 8; i++) {
2479             tn_env_uservar[i][0] = NULL;
2480             tn_env_uservar[i][1] = NULL;
2481         }
2482     }
2483 #endif /* CK_ENVIRONMENT */
2484
2485     /* initialize all options to refuse in both directions */
2486     for (opt = 0; opt < NTELOPTS; opt++) {
2487         TELOPT_ME(opt) = 0;
2488         TELOPT_U(opt)  = 0;
2489         TELOPT_UNANSWERED_WILL(opt) = 0;
2490         TELOPT_UNANSWERED_DO(opt)   = 0;
2491         TELOPT_UNANSWERED_WONT(opt) = 0;
2492         TELOPT_UNANSWERED_DONT(opt)   = 0;
2493         TELOPT_UNANSWERED_SB(opt)   = 0;
2494         TELOPT_ME_MODE(opt) = TN_NG_RF;
2495         TELOPT_U_MODE(opt) = TN_NG_RF;
2496         TELOPT_DEF_S_ME_MODE(opt) = TN_NG_RF;
2497         TELOPT_DEF_S_U_MODE(opt) = TN_NG_RF;
2498         TELOPT_DEF_C_ME_MODE(opt) = TN_NG_RF;
2499         TELOPT_DEF_C_U_MODE(opt) = TN_NG_RF;
2500         for (cmd = 0; cmd < 4; cmd ++)
2501           tncnts[TELOPT_INDEX(opt)][cmd] = 0;
2502     }
2503 #ifdef IKS_OPTION
2504     TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
2505     TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 0;
2506     TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start = 0;
2507     TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop = 0;
2508     TELOPT_SB(TELOPT_KERMIT).kermit.sop = 0;
2509 #endif /* IKS_OPTION */
2510
2511 #ifdef CK_ENCRYPTION
2512     TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop = 0;
2513 #endif /* CK_ENCRYPTION */
2514
2515 #ifdef  CK_NAWS
2516     TELOPT_SB(TELOPT_NAWS).naws.x = 0;
2517     TELOPT_SB(TELOPT_NAWS).naws.y = 0;
2518 #endif /* CK_NAWS */
2519
2520 #ifdef CK_SSL
2521     TELOPT_SB(TELOPT_START_TLS).start_tls.u_follows = 0;
2522     TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows = 0;
2523     TELOPT_SB(TELOPT_START_TLS).start_tls.auth_request = 0;
2524 #endif /* CK_SSL */
2525
2526     /* Now set the ones we want to accept to the proper values */
2527     TELOPT_DEF_S_ME_MODE(TELOPT_SGA) = TN_NG_RQ;
2528     TELOPT_DEF_S_U_MODE(TELOPT_SGA) = TN_NG_RQ;
2529     TELOPT_DEF_C_ME_MODE(TELOPT_SGA) = TN_NG_AC;
2530     TELOPT_DEF_C_U_MODE(TELOPT_SGA) = TN_NG_AC;
2531
2532     TELOPT_DEF_S_ME_MODE(TELOPT_BINARY) = TN_NG_AC;
2533     TELOPT_DEF_S_U_MODE(TELOPT_BINARY) = TN_NG_AC;
2534     TELOPT_DEF_C_ME_MODE(TELOPT_BINARY) = TN_NG_AC;
2535     TELOPT_DEF_C_U_MODE(TELOPT_BINARY) = TN_NG_AC;
2536
2537     TELOPT_DEF_S_ME_MODE(TELOPT_LOGOUT) = TN_NG_AC;
2538     TELOPT_DEF_S_U_MODE(TELOPT_LOGOUT) = TN_NG_AC;
2539     TELOPT_DEF_C_ME_MODE(TELOPT_LOGOUT) = TN_NG_AC;
2540     TELOPT_DEF_C_U_MODE(TELOPT_LOGOUT) = TN_NG_AC;
2541
2542 #ifdef IKS_OPTION
2543     TELOPT_DEF_S_ME_MODE(TELOPT_KERMIT) = TN_NG_RQ;
2544     TELOPT_DEF_S_U_MODE(TELOPT_KERMIT) = TN_NG_RQ;
2545     TELOPT_DEF_C_ME_MODE(TELOPT_KERMIT) = TN_NG_RQ;
2546     TELOPT_DEF_C_U_MODE(TELOPT_KERMIT) = TN_NG_RQ;
2547 #endif /* IKS_OPTION */
2548
2549 #ifdef CK_ENCRYPTION
2550     TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ;
2551     TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ;
2552     TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ;
2553     TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ;
2554 #endif /* CK_ENCRYPTION */
2555
2556     TELOPT_DEF_S_ME_MODE(TELOPT_ECHO) = TN_NG_RQ;
2557 #ifdef IKSD
2558     if ( !inserver )
2559 #endif /* IKSD */
2560       TELOPT_DEF_S_U_MODE(TELOPT_TTYPE) = TN_NG_RQ;
2561
2562 #ifdef CK_ENVIRONMENT
2563     TELOPT_DEF_S_U_MODE(TELOPT_NEWENVIRON) = TN_NG_RQ;
2564 #endif /* CK_ENVIRONMENT */
2565
2566 #ifdef CK_AUTHENTICATION
2567     TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_RQ;
2568 #endif /* CK_AUTHENTICATION */
2569
2570 #ifdef CK_SSL
2571     if (ck_ssleay_is_installed()) {
2572         TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RQ;
2573         TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_AC;
2574     }
2575 #endif /* CK_SSL */
2576
2577 #ifdef CK_NAWS
2578     TELOPT_DEF_S_U_MODE(TELOPT_NAWS) = TN_NG_RQ;
2579 #endif /* CK_NAWS */
2580
2581     TELOPT_DEF_C_U_MODE(TELOPT_ECHO) = TN_NG_AC;
2582     TELOPT_DEF_C_ME_MODE(TELOPT_TTYPE) = TN_NG_RQ;
2583
2584 #ifdef CK_ENVIRONMENT
2585     TELOPT_DEF_C_ME_MODE(TELOPT_NEWENVIRON) = TN_NG_RQ;
2586 #endif /* CK_ENVIRONMENT */
2587
2588 #ifdef CK_AUTHENTICATION
2589     TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_RQ;
2590 #endif /* CK_AUTHENTICATION */
2591
2592 #ifdef CK_NAWS
2593     TELOPT_DEF_C_ME_MODE(TELOPT_NAWS) = TN_NG_RQ;
2594 #endif /* CK_NAWS */
2595
2596 #ifdef CK_SNDLOC
2597     TELOPT_DEF_C_ME_MODE(TELOPT_SNDLOC) = TN_NG_RQ;
2598 #endif /* CK_SNDLOC */
2599
2600 #ifdef CK_FORWARD_X
2601     TELOPT_DEF_C_U_MODE(TELOPT_FORWARD_X) = TN_NG_AC;
2602     TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = -1;
2603     for (x = 0; x < MAXFWDX; x++) {
2604        TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd = -1;
2605        TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id = -1;
2606        TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].need_to_send_xauth = 0;
2607        TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend = 0;
2608     }
2609 #endif /* CK_FORWARD_X */
2610
2611 #ifdef TN_COMPORT
2612     TELOPT_DEF_C_ME_MODE(TELOPT_COMPORT) = TN_NG_RQ;
2613 #endif /* TN_COMPORT */
2614
2615     /* Set the initial values for currently known mode */
2616     for (opt = TELOPT_FIRST; opt <= TELOPT_LAST; opt++) {
2617         if (TELOPT_OK(opt)) {
2618             TELOPT_ME_MODE(opt) = sstelnet ?
2619               TELOPT_DEF_S_ME_MODE(opt) :
2620                 TELOPT_DEF_C_ME_MODE(opt);
2621             TELOPT_U_MODE(opt) = sstelnet ?
2622               TELOPT_DEF_S_U_MODE(opt) :
2623                 TELOPT_DEF_C_U_MODE(opt);
2624         }
2625     }
2626     return(1);
2627 }
2628
2629
2630 /* Send Delayed Subnegotiations */
2631
2632 VOID
2633 tn_sdsb() {
2634     if (TELOPT_SB(TELOPT_TTYPE).term.need_to_send) {
2635         tn_sttyp();
2636         TELOPT_SB(TELOPT_TTYPE).term.need_to_send = 0;
2637     }
2638 #ifdef CK_ENVIRONMENT
2639     if (TELOPT_SB(TELOPT_NEWENVIRON).env.need_to_send &&
2640         TELOPT_SB(TELOPT_NEWENVIRON).env.str) {
2641         tn_snenv((CHAR *)TELOPT_SB(TELOPT_NEWENVIRON).env.str,
2642                  TELOPT_SB(TELOPT_NEWENVIRON).env.len);
2643         free(TELOPT_SB(TELOPT_NEWENVIRON).env.str);
2644         TELOPT_SB(TELOPT_NEWENVIRON).env.str=NULL;
2645         TELOPT_SB(TELOPT_NEWENVIRON).env.len=0;
2646         TELOPT_SB(TELOPT_NEWENVIRON).env.need_to_send = 0;
2647     }
2648 #ifdef CK_XDISPLOC
2649     if (TELOPT_SB(TELOPT_XDISPLOC).xdisp.need_to_send) {
2650         tn_sxdisploc();
2651         TELOPT_SB(TELOPT_XDISPLOC).xdisp.need_to_send = 0;
2652     }
2653 #endif /* CK_XDISPLOC */
2654 #endif /* CK_ENVIRONMENT */
2655 #ifdef CK_NAWS
2656     if (TELOPT_SB(TELOPT_NAWS).naws.need_to_send) {
2657         tn_snaws();
2658         TELOPT_SB(TELOPT_NAWS).naws.need_to_send = 0;
2659     }
2660 #endif /* CK_NAWS */
2661 #ifdef CK_SNDLOC
2662     if (TELOPT_SB(TELOPT_SNDLOC).sndloc.need_to_send) {
2663         tn_sndloc();
2664         TELOPT_SB(TELOPT_SNDLOC).sndloc.need_to_send = 0;
2665     }
2666 #endif /* CK_SNDLOC */
2667 #ifdef CK_FORWARD_X
2668     if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.need_to_send) {
2669         if ( sstelnet )
2670             fwdx_send_options();
2671         TELOPT_SB(TELOPT_FORWARD_X).forward_x.need_to_send = 0;
2672     }
2673 #endif /* CK_FORWARD_X */
2674 #ifdef TN_COMPORT
2675     if (TELOPT_SB(TELOPT_COMPORT).comport.need_to_send) {
2676         tn_sndcomport();
2677         TELOPT_SB(TELOPT_COMPORT).comport.need_to_send = 0;
2678     }
2679 #endif /* TN_COMPORT */
2680
2681 }
2682
2683 int
2684 tn_reset() {
2685     int x,opt,cmd;
2686
2687     tn_wait_idx = 0;                    /* Clear the tn_push() buffer */
2688     tn_wait_tmo = TN_TIMEOUT;           /* Reset wait timer stats */
2689
2690     nflag = 0;
2691
2692     /* Reset the TELNET OPTIONS counts */
2693     for (opt = TELOPT_FIRST; opt <= TELOPT_LAST; opt++) {
2694         if (TELOPT_OK(opt)) {
2695             TELOPT_ME(opt) = 0;
2696             TELOPT_U(opt)  = 0;
2697             TELOPT_UNANSWERED_WILL(opt) = 0;
2698             TELOPT_UNANSWERED_DO(opt)   = 0;
2699             TELOPT_UNANSWERED_WONT(opt) = 0;
2700             TELOPT_UNANSWERED_DONT(opt)   = 0;
2701             TELOPT_UNANSWERED_SB(opt)   = 0;
2702             TELOPT_ME_MODE(opt) = sstelnet ?
2703               TELOPT_DEF_S_ME_MODE(opt) :
2704                 TELOPT_DEF_C_ME_MODE(opt);
2705             TELOPT_U_MODE(opt) = sstelnet ?
2706               TELOPT_DEF_S_U_MODE(opt) :
2707                 TELOPT_DEF_C_U_MODE(opt);
2708
2709 #ifdef DEBUG
2710             if (deblog) {
2711                 switch (TELOPT_ME_MODE(opt)) {
2712                   case TN_NG_RF:
2713                     debug(F110,"tn_ini ME REFUSE ",TELOPT(opt),0);
2714                     break;
2715                   case TN_NG_AC:
2716                     debug(F110,"tn_ini ME ACCEPT ",TELOPT(opt),0);
2717                     break;
2718                   case TN_NG_RQ:
2719                     debug(F110,"tn_ini ME REQUEST",TELOPT(opt),0);
2720                     break;
2721                   case TN_NG_MU:
2722                     debug(F110,"tn_ini ME REQUIRE",TELOPT(opt),0);
2723                     break;
2724                 }
2725                 switch (TELOPT_U_MODE(opt)) {
2726                   case TN_NG_RF:
2727                     debug(F110,"tn_ini U  REFUSE ",TELOPT(opt),0);
2728                     break;
2729                   case TN_NG_AC:
2730                     debug(F110,"tn_ini U  ACCEPT ",TELOPT(opt),0);
2731                     break;
2732                   case TN_NG_RQ:
2733                     debug(F110,"tn_ini U  REQUEST",TELOPT(opt),0);
2734                     break;
2735                   case TN_NG_MU:
2736                     debug(F110,"tn_ini U  REQUIRE",TELOPT(opt),0);
2737                     break;
2738                 }
2739             }
2740 #endif /* DEBUG */
2741             for (cmd = 0; cmd < 4; cmd ++)
2742               tncnts[TELOPT_INDEX(opt)][cmd] = 0;
2743         }
2744     }
2745 #ifdef CK_ENVIRONMENT
2746     if (!tn_env_flg) {
2747         TELOPT_ME_MODE(TELOPT_NEWENVIRON) = TN_NG_RF;
2748         TELOPT_U_MODE(TELOPT_NEWENVIRON) = TN_NG_RF;
2749     }
2750 #endif /* CK_ENVIRONMENT */
2751 #ifdef CK_SNDLOC
2752     if (!tn_loc)
2753         TELOPT_DEF_C_ME_MODE(TELOPT_SNDLOC) = TN_NG_RF;
2754 #endif /* CK_SNDLOC */
2755 #ifdef IKS_OPTION
2756     TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
2757     TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 0;
2758     TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start = 0;
2759     TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop = 0;
2760     TELOPT_SB(TELOPT_KERMIT).kermit.sop = 0;
2761 #endif /* IKS_OPTION */
2762 #ifdef CK_ENCRYPTION
2763     TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop = 0;
2764     TELOPT_SB(TELOPT_ENCRYPTION).encrypt.need_to_send = 0;
2765 #endif /* CK_ENCRYPTION */
2766 #ifdef  CK_NAWS
2767     TELOPT_SB(TELOPT_NAWS).naws.need_to_send = 0;
2768     TELOPT_SB(TELOPT_NAWS).naws.x = 0;
2769     TELOPT_SB(TELOPT_NAWS).naws.y = 0;
2770 #endif /* CK_NAWS */
2771     TELOPT_SB(TELOPT_TTYPE).term.need_to_send = 0;
2772     TELOPT_SB(TELOPT_TTYPE).term.type[0] = '\0';
2773 #ifdef CK_ENVIRONMENT
2774     TELOPT_SB(TELOPT_NEWENVIRON).env.need_to_send = 0;
2775     if (tn_first)
2776         TELOPT_SB(TELOPT_NEWENVIRON).env.str=NULL;
2777     else if (TELOPT_SB(TELOPT_NEWENVIRON).env.str) {
2778         free(TELOPT_SB(TELOPT_NEWENVIRON).env.str);
2779         TELOPT_SB(TELOPT_NEWENVIRON).env.str=NULL;
2780     }
2781     TELOPT_SB(TELOPT_NEWENVIRON).env.len=0;
2782 #ifdef CK_XDISPLOC
2783     TELOPT_SB(TELOPT_XDISPLOC).xdisp.need_to_send = 0;
2784 #endif /* CK_XDISPLOC */
2785 #endif /* CK_ENVIRONMENT */
2786 #ifdef CK_SNDLOC
2787     TELOPT_SB(TELOPT_SNDLOC).sndloc.need_to_send = 0;
2788 #endif /* CK_SNDLOC */
2789 #ifdef CK_FORWARD_X
2790     TELOPT_SB(TELOPT_FORWARD_X).forward_x.need_to_send = 0;
2791     TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = -1;
2792     for (x = 0; x < MAXFWDX; x++) {
2793        TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd = -1;
2794        TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id = -1;
2795        TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].need_to_send_xauth = 0;
2796        TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend = 0;
2797     }
2798     /* Reset Xauth data */
2799     if ( real_xauth ) {
2800         XauDisposeAuth(real_xauth);
2801         real_xauth = NULL;
2802     }
2803     if ( fake_xauth.name )
2804         free(fake_xauth.name);
2805     if ( fake_xauth.data )
2806         free(fake_xauth.data);
2807     if ( fake_xauth.address )
2808         free(fake_xauth.address);
2809     if ( fake_xauth.number )
2810         free(fake_xauth.number);
2811     memset(&fake_xauth,0,sizeof(fake_xauth));
2812 #ifdef NT
2813     TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started = 0;
2814 #endif /* NT */
2815 #endif /* CK_FORWARD_X */
2816 #ifdef CK_SSL
2817     if (tls_only_flag || ssl_only_flag) {
2818         TELOPT_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
2819         TELOPT_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
2820     }
2821     TELOPT_SB(TELOPT_START_TLS).start_tls.u_follows = 0;
2822     TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows = 0;
2823     TELOPT_SB(TELOPT_START_TLS).start_tls.auth_request = 0;
2824 #endif /* CK_SSL */
2825
2826 #ifdef CK_ENCRYPTION
2827     if (!ck_crypt_is_installed()
2828 #ifdef CK_SSL
2829         || tls_only_flag || ssl_only_flag
2830 #endif /* CK_SSL */
2831         ) {
2832         TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2833         TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2834     }
2835 #endif /* CK_ENCRYPTION */
2836
2837 #ifdef TN_COMPORT
2838     TELOPT_SB(TELOPT_COMPORT).comport.need_to_send = 0;
2839     TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
2840     TELOPT_SB(TELOPT_COMPORT).comport.wait_for_ms = 0;
2841     tnc_init();
2842 #endif /* TN_COMPORT */
2843
2844     tn_first = 0;                       /* No longer the first time init */
2845
2846 #ifdef OS2
2847     ttnum = -1;                         /* Reset TermType negotiation */
2848     ttnumend = 0;
2849 #endif /* OS2 */
2850
2851     return(0);
2852 }
2853
2854 int
2855 tn_start() {
2856     int wait, x, opt;
2857
2858     if (tn_init && tn_begun)
2859         return(0);
2860     tn_begun = 1;
2861
2862     debug(F111,"tn_start","sstelnet",sstelnet);
2863     wait = 0;
2864     if (tn_duplex)  {
2865         oldplex = duplex;               /* save old duplex value */
2866         duplex = 1;                     /* and set to half duplex for telnet */
2867     }
2868 #ifdef CK_SSL
2869     if (!TELOPT_ME(TELOPT_START_TLS) &&
2870         TELOPT_ME_MODE(TELOPT_START_TLS) >= TN_NG_RQ) {
2871         if (tn_sopt(WILL, TELOPT_START_TLS) < 0)
2872           return(-1);
2873         TELOPT_UNANSWERED_WILL(TELOPT_START_TLS) = 1;
2874         wait = 1;
2875     }
2876     if (!TELOPT_U(TELOPT_START_TLS) &&
2877         TELOPT_U_MODE(TELOPT_START_TLS) >= TN_NG_RQ) {
2878         if (tn_sopt(DO, TELOPT_START_TLS) < 0)
2879           return(-1);
2880         TELOPT_UNANSWERED_DO(TELOPT_START_TLS) = 1;
2881         wait = 1;
2882     }
2883 #endif /* CK_SSL */
2884
2885 #ifdef CK_AUTHENTICATION
2886     debug(F110,"tn_ini() CK_AUTHENTICATION","",0);
2887     if (tn_init)                /* tn_ini() might be called recursively */
2888       return(0);
2889     if (!TELOPT_ME(TELOPT_AUTHENTICATION) &&
2890         TELOPT_ME_MODE(TELOPT_AUTHENTICATION) >= TN_NG_RQ) {
2891         if (tn_sopt(WILL, TELOPT_AUTHENTICATION) < 0)
2892           return(-1);
2893         TELOPT_UNANSWERED_WILL(TELOPT_AUTHENTICATION) = 1;
2894         wait = 1;
2895     }
2896     if (!TELOPT_U(TELOPT_AUTHENTICATION) &&
2897         TELOPT_U_MODE(TELOPT_AUTHENTICATION) >= TN_NG_RQ) {
2898         if (tn_sopt(DO, TELOPT_AUTHENTICATION) < 0)
2899           return(-1);
2900         TELOPT_UNANSWERED_DO(TELOPT_AUTHENTICATION) = 1;
2901         wait = 1;
2902     }
2903 #ifdef CK_ENCRYPTION
2904     if (TELOPT_U_MODE(TELOPT_AUTHENTICATION) == TN_NG_RF &&
2905          TELOPT_ME_MODE(TELOPT_AUTHENTICATION) == TN_NG_RF) {
2906         TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2907         TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
2908     }
2909 #endif /* CK_ENCRYPTION */
2910 #endif /* CK_AUTHENTICATION */
2911
2912 #ifdef CK_NAWS
2913 #ifndef NOLOCAL
2914     debug(F110,"tn_ini() CK_NAWS !NOLOCAL","",0);
2915     if (!sstelnet) {
2916         /* Console terminal screen rows and columns */
2917 #ifdef OS2
2918         debug(F101,
2919               "tn_ini tt_rows 1",
2920               "",
2921               VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0)
2922               );
2923         debug(F101,"tn_ini tt_cols 1","",VscrnGetWidth(VTERM));
2924         /* Not known yet */
2925         if (VscrnGetWidth(VTERM) < 0 ||
2926             VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) < 0) {
2927             ttgwsiz();                  /* Try to find out */
2928         }
2929         debug(F101,
2930               "tn_ini tt_rows 2",
2931               "",
2932               VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0)
2933               );
2934         debug(F101,"tn_ini tt_cols 2","",VscrnGetWidth(VTERM));
2935         /* Now do we know? */
2936         if (VscrnGetWidth(VTERM) > 0 &&
2937             VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) > 0) {
2938             if (!TELOPT_ME(TELOPT_NAWS) &&
2939                 TELOPT_ME_MODE(TELOPT_NAWS) >= TN_NG_RQ) {
2940                 if (tn_sopt(WILL, TELOPT_NAWS) < 0)
2941                   return(-1);
2942                 TELOPT_UNANSWERED_WILL(TELOPT_NAWS) = 1;
2943                 wait = 1;
2944             }
2945         }
2946 #else /* OS2 */
2947         debug(F101,"tn_ini tt_rows 1","",tt_rows);
2948         debug(F101,"tn_ini tt_cols 1","",tt_cols);
2949         if (tt_rows < 0 || tt_cols < 0) { /* Not known yet */
2950             ttgwsiz();                  /* Try to find out */
2951         }
2952         debug(F101,"tn_ini tt_rows 2","",tt_rows);
2953         debug(F101,"tn_ini tt_cols 2","",tt_cols);
2954         if (tt_rows > 0 && tt_cols > 0) { /* Now do we know? */
2955             if (!TELOPT_ME(TELOPT_NAWS) &&
2956                 TELOPT_ME_MODE(TELOPT_NAWS) >= TN_NG_RQ) {
2957                 if (tn_sopt(WILL, TELOPT_NAWS) < 0)
2958                   return(-1);
2959                 TELOPT_UNANSWERED_WILL(TELOPT_NAWS) = 1;
2960                 wait = 1;
2961             }
2962         }
2963 #endif /* OS2 */
2964     } else
2965 #endif /* NOLOCAL */
2966     {
2967         if (!TELOPT_U(TELOPT_NAWS) &&
2968             TELOPT_U_MODE(TELOPT_NAWS) >= TN_NG_RQ) {
2969             if (tn_sopt(DO, TELOPT_NAWS) < 0)
2970               return(-1);
2971             TELOPT_UNANSWERED_DO(TELOPT_NAWS) = 1;
2972             wait = 1;
2973         }
2974     }
2975 #endif /* CK_NAWS */
2976
2977     if (!TELOPT_ME(TELOPT_SGA) &&
2978         TELOPT_ME_MODE(TELOPT_SGA) >= TN_NG_RQ) {
2979         if (tn_sopt(WILL, TELOPT_SGA) < 0)
2980           return(-1);
2981         TELOPT_UNANSWERED_WILL(TELOPT_SGA) = 1;
2982         wait = 1;
2983     }
2984     if (!TELOPT_U(TELOPT_SGA) &&
2985         TELOPT_U_MODE(TELOPT_SGA) >= TN_NG_RQ) {
2986         if (tn_sopt(DO, TELOPT_SGA) < 0)
2987           return(-1);
2988         TELOPT_UNANSWERED_DO(TELOPT_SGA) = 1;
2989         wait = 1;
2990     }
2991     if (!tn_duplex) {
2992         if (!TELOPT_U(TELOPT_ECHO) &&
2993             TELOPT_U_MODE(TELOPT_ECHO) >= TN_NG_RQ) {
2994             if (tn_sopt(DO, TELOPT_ECHO) < 0)
2995               return(-1);
2996             TELOPT_UNANSWERED_DO(TELOPT_ECHO) = 1;
2997             wait = 1;
2998         }
2999     }
3000     if (!TELOPT_ME(TELOPT_ECHO) &&
3001         TELOPT_ME_MODE(TELOPT_ECHO) >= TN_NG_RQ) {
3002         if (tn_sopt(WILL, TELOPT_ECHO) < 0)
3003           return(-1);
3004         TELOPT_UNANSWERED_WILL(TELOPT_ECHO) = 1;
3005         wait = 1;
3006     }
3007
3008     debug(F100,"tn_ini about to send WILL TTYPE if requested","",0);
3009 /*
3010   Talking to TELNET port, so send WILL TERMINAL TYPE and DO SGA.
3011   Also send WILL NAWS if we know our screen dimensions.
3012 */
3013     if (!TELOPT_ME(TELOPT_TTYPE) &&
3014         TELOPT_ME_MODE(TELOPT_TTYPE) >= TN_NG_RQ) {
3015         if ((x = tn_sopt(WILL,TELOPT_TTYPE)) < 0) {
3016             debug(F101,"tn_ini tn_sopt WILL TTYPE failed","",x);
3017             return(-1);
3018         }
3019         TELOPT_UNANSWERED_WILL(TELOPT_TTYPE) = 1;
3020         wait = 1;
3021         debug(F100,"tn_ini sent WILL TTYPE ok","",0);
3022     }
3023     if (!TELOPT_U(TELOPT_TTYPE) &&
3024         TELOPT_U_MODE(TELOPT_TTYPE) >= TN_NG_RQ) {
3025         if ((x = tn_sopt(DO,TELOPT_TTYPE)) < 0) {
3026             debug(F101,"tn_ini tn_sopt DO TTYPE failed","",x);
3027             return(-1);
3028         }
3029         TELOPT_UNANSWERED_DO(TELOPT_TTYPE) = 1;
3030         wait = 1;
3031         debug(F100,"tn_ini sent DO TTYPE ok","",0);
3032     }
3033     if (!TELOPT_ME(TELOPT_BINARY) &&
3034         TELOPT_ME_MODE(TELOPT_BINARY) >= TN_NG_RQ) {
3035         if (tn_sopt(WILL, TELOPT_BINARY) < 0)
3036           return(-1);
3037         TELOPT_UNANSWERED_WILL(TELOPT_BINARY) = 1;
3038         wait = 1;
3039     }
3040     if (!TELOPT_U(TELOPT_BINARY) &&
3041         TELOPT_U_MODE(TELOPT_BINARY) >= TN_NG_RQ) {
3042         if (tn_sopt(DO, TELOPT_BINARY) < 0)
3043           return(-1);
3044         TELOPT_UNANSWERED_DO(TELOPT_BINARY) = 1;
3045         wait = 1;
3046     }
3047 #ifdef CK_SNDLOC
3048     if (tn_loc) {
3049         if (!TELOPT_ME(TELOPT_SNDLOC) &&
3050             TELOPT_ME_MODE(TELOPT_SNDLOC) >= TN_NG_RQ) {
3051             if (tn_sopt(WILL, TELOPT_SNDLOC) < 0)
3052               return(-1);
3053             TELOPT_UNANSWERED_WILL(TELOPT_SNDLOC) = 1;
3054             wait = 1;
3055         }
3056     }
3057 #endif /* CK_SNDLOC */
3058 #ifdef CK_ENVIRONMENT
3059 #ifdef CK_FORWARD_X
3060     if (!TELOPT_U(TELOPT_FORWARD_X) &&
3061          TELOPT_U_MODE(TELOPT_FORWARD_X) >= TN_NG_RQ) {
3062         if (tn_sopt(WILL, TELOPT_FORWARD_X) < 0)
3063             return(-1);
3064         TELOPT_UNANSWERED_WILL(TELOPT_FORWARD_X) = 1;
3065         wait = 1;
3066     }
3067 #endif /* FORWARD_X */
3068 #ifdef CK_XDISPLOC
3069     if (!TELOPT_ME(TELOPT_XDISPLOC) &&
3070          TELOPT_ME_MODE(TELOPT_XDISPLOC) >= TN_NG_RQ) {
3071         if (tn_sopt(WILL, TELOPT_XDISPLOC) < 0)
3072             return(-1);
3073         TELOPT_UNANSWERED_WILL(TELOPT_XDISPLOC) = 1;
3074         wait = 1;
3075     }
3076 #endif /* CK_XDISPLOC */
3077     /* Will send terminal environment. */
3078     if (!TELOPT_ME(TELOPT_NEWENVIRON) &&
3079         TELOPT_ME_MODE(TELOPT_NEWENVIRON) >= TN_NG_RQ) {
3080         if (tn_sopt(WILL, TELOPT_NEWENVIRON) < 0)
3081           return(-1);
3082         TELOPT_UNANSWERED_WILL(TELOPT_NEWENVIRON) = 1;
3083         wait = 1;
3084     }
3085     if (!TELOPT_U(TELOPT_NEWENVIRON) &&
3086         TELOPT_U_MODE(TELOPT_NEWENVIRON) >= TN_NG_RQ) {
3087         if (tn_sopt(DO, TELOPT_NEWENVIRON) < 0)
3088           return(-1);
3089         TELOPT_UNANSWERED_DO(TELOPT_NEWENVIRON) = 1;
3090         wait = 1;
3091     }
3092 #endif /* CK_ENVIRONMENT */
3093
3094     /* Take care of any other telnet options that require handling. */
3095
3096     for (opt = TELOPT_FIRST; opt <= TELOPT_LAST; opt++) {
3097         switch (opt) {
3098           case TELOPT_AUTHENTICATION:
3099           case TELOPT_ENCRYPTION:
3100           case TELOPT_TTYPE:
3101           case TELOPT_NAWS:
3102           case TELOPT_BINARY:
3103           case TELOPT_NEWENVIRON:
3104           case TELOPT_SNDLOC:
3105           case TELOPT_XDISPLOC:
3106           case TELOPT_SGA:
3107           case TELOPT_ECHO:
3108           case TELOPT_KERMIT:
3109           case TELOPT_START_TLS:
3110           case TELOPT_FORWARD_X:
3111                 break;
3112             break;
3113           default:
3114             if (TELOPT_OK(opt)) {
3115                 if (!TELOPT_ME(opt) &&
3116                     TELOPT_ME_MODE(opt) >= TN_NG_RQ) {
3117                     if (tn_sopt(WILL, opt) < 0)
3118                       return(-1);
3119                     TELOPT_UNANSWERED_WILL(opt) = 1;
3120                     wait = 1;
3121                 }
3122                 if (!TELOPT_U(opt) &&
3123                     TELOPT_U_MODE(opt) >= TN_NG_RQ) {
3124                     if (tn_sopt(DO, opt) < 0)
3125                       return(-1);
3126                     TELOPT_UNANSWERED_DO(opt) = 1;
3127                     wait = 1;
3128                 }
3129             }
3130         }
3131     }
3132     if (wait) {
3133         if (tn_wait("pre-encrypt") < 0) {
3134             tn_push();
3135             return(-1);
3136         }
3137         wait = 0;
3138     }
3139
3140 #ifdef CK_ENCRYPTION
3141     if (tn_init)                /* tn_ini() may be called recursively */
3142       return(0);
3143
3144     if (!TELOPT_ME(TELOPT_ENCRYPTION) &&
3145         TELOPT_ME_MODE(TELOPT_ENCRYPTION) >= TN_NG_RQ) {
3146         if (tn_sopt(WILL, TELOPT_ENCRYPTION) < 0)
3147           return(-1);
3148         TELOPT_UNANSWERED_WILL(TELOPT_ENCRYPTION) = 1;
3149         wait = 1;
3150     }
3151     if (!TELOPT_U(TELOPT_ENCRYPTION) &&
3152         TELOPT_U_MODE(TELOPT_ENCRYPTION) >= TN_NG_RQ) {
3153         if (tn_sopt(DO, TELOPT_ENCRYPTION) < 0)
3154           return(-1);
3155         TELOPT_UNANSWERED_DO(TELOPT_ENCRYPTION) = 1;
3156         wait = 1;
3157     }
3158
3159     /* If we are going to encrypt, we want to do it before we send any more */
3160     /* data, especially the terminal type and environment variables.        */
3161     if (wait) {
3162         if (tn_wait("post-encrypt") < 0) {
3163             tn_push();
3164             return(-1);
3165         }
3166         wait = 0;
3167     }
3168 #endif /* CK_ENCRYPTION */
3169
3170     tn_sdsb();
3171
3172     if (tn_init)                   /* tn_ini() may be called recursively */
3173         return(0);
3174
3175 #ifdef IKS_OPTION
3176     /* Kermit Server negotiation must go last */
3177     /* Send U before ME */
3178
3179     if (!TELOPT_U(TELOPT_KERMIT) &&
3180         TELOPT_U_MODE(TELOPT_KERMIT) >= TN_NG_RQ) {
3181         if (tn_sopt(DO, TELOPT_KERMIT) < 0)
3182           return(-1);
3183         TELOPT_UNANSWERED_DO(TELOPT_KERMIT) = 1;
3184         wait = 1;
3185     }
3186     if (!TELOPT_ME(TELOPT_KERMIT) &&
3187         TELOPT_ME_MODE(TELOPT_KERMIT) >= TN_NG_RQ) {
3188         if (tn_sopt(WILL, TELOPT_KERMIT) < 0)
3189           return(-1);
3190         TELOPT_UNANSWERED_WILL(TELOPT_KERMIT) = 1;
3191         wait = 1;
3192     }
3193 #endif /* IKS_OPTION */
3194
3195     if (wait) {
3196         if (tn_wait("end of telnet negotiations") < 0) {
3197             tn_push();
3198             return(-1);
3199         }
3200         wait = 0;
3201     }
3202
3203     tn_sdsb();                          /* Send delayed subnegotiations */
3204     tn_push();
3205     return(0);
3206 }
3207
3208 /* Start a telnet connection. */
3209 /* Returns -1 on error, 0 if nothing happens, 1 if init msgs sent ok */
3210
3211 int
3212 tn_ini() {
3213     int x;
3214
3215     debug(F101,"tn_ini ttnproto","",ttnproto);
3216     debug(F101,"tn_ini tn_init","",tn_init);
3217
3218     if (ttnet != NET_TCPB)              /* Make sure connection is TCP/IP */
3219       return(0);
3220     if (tn_init)                        /* Have we done this already? */
3221       return(0);                        /* Don't do it again. */
3222
3223     tn_reset();                         /* Reset telnet parameters */
3224     tn_begun = 0;                       /* Reset; will be set by tn_start() */
3225
3226     switch ( ttnproto ) {
3227       case NP_RLOGIN:
3228       case NP_K4LOGIN:
3229       case NP_EK4LOGIN:
3230       case NP_K5LOGIN:
3231       case NP_EK5LOGIN:
3232       case NP_K5U2U:
3233         tn_init = 1;
3234         debug(F100,"tn_ini telnet negotiations ignored","tn_init",tn_init);
3235         return(0);
3236       case NP_NONE:
3237       case NP_SSL:
3238       case NP_TLS:                      /* If not talking to a telnet port, */
3239         ttnproto = NP_TELNET;           /* pretend it's telnet anyway, */
3240         oldplex = duplex;               /* save old duplex value */
3241         duplex = 1;                     /* and set to half duplex for telnet */
3242         if (inserver)
3243           debug(F100,"tn_ini skipping telnet negotiations","",0);
3244           else
3245         tn_wait("tn_ini - waiting to see if telnet negotiations were sent");
3246         tn_push();
3247         return(0);
3248       case NP_TCPRAW:                   /* Raw socket requested. */
3249         debug(F100,"tn_ini telnet negotiations ignored","tn_init",tn_init);
3250         return(0);
3251       case NP_KERMIT:                   /* switching to Telnet protocol */
3252       case NP_SSL_TELNET:
3253       case NP_TLS_TELNET:
3254         debug(F101,"tn_ini switching from XXX to Telnet","",ttnproto);
3255         ttnproto = NP_TELNET;
3256         /* fall through */
3257       default:
3258         /* We are already using a variation on Telnet protocol */
3259         ;
3260     }
3261
3262     x = tn_start();
3263     tn_init = 1;                        /* Remember successful completion. */
3264
3265     /* Don't send anything else! */
3266     debug(F101,"tn_ini duplex","",duplex);
3267     debug(F101,"tn_ini done, tn_init","",tn_init);
3268     return(x);
3269 }
3270
3271 int
3272 #ifdef CK_ANSIC
3273 tn_hex(CHAR * buf, int buflen, CHAR * data, int datalen)
3274 #else /* CK_ANSIC */
3275 tn_hex(buf, buflen, data, datalen)
3276     CHAR * buf;
3277     int buflen;
3278     CHAR * data;
3279     int datalen;
3280 #endif /* CK_ANSIC */
3281 {
3282     int i = 0, j = 0, k = 0;
3283     CHAR tmp[16];               /* in case value is treated as negative */
3284 #ifdef COMMENT
3285     int was_hex = 1;
3286
3287     for (k=0; k < datalen; k++) {
3288         if (data[k] < 32 || data[k] >= 127) {
3289             sprintf(tmp,"%s%02X ",was_hex?"":"\" ",data[k]);
3290             was_hex = 1;
3291         } else {
3292             sprintf(tmp,"%s%c",was_hex?"\"":"",data[k]);
3293             was_hex = 0;
3294         }
3295         ckstrncat((char *)buf,tmp,buflen);
3296     }
3297     if (!was_hex)
3298         ckstrncat((char *)buf,"\" ",buflen);
3299 #else /* COMMENT */
3300     if (datalen <= 0 || data == NULL || buf == NULL || buflen <= 0)
3301         return(0);
3302
3303     for (i = 0; i < datalen; i++) {
3304         ckstrncat((char *)buf,"\r\n  ",buflen);
3305         for (j = 0 ; (j < 16); j++) {
3306             if ((i + j) < datalen)
3307               sprintf((char *)tmp,
3308                       "%s%02x ",
3309                       (j == 8 ? "| " : ""),
3310                       (unsigned int) data[i + j]
3311                       );
3312             else
3313               sprintf((char *)tmp,
3314                       "%s   ",
3315                       (j == 8 ? "| " : "")
3316                       );
3317             ckstrncat((char *)buf,(char *)tmp,buflen);
3318         }
3319         ckstrncat((char *)buf," ",buflen);
3320         for (k = 0; (k < 16) && ((i + k) < datalen); k++) {
3321             sprintf((char *)tmp,
3322                      "%s%c",
3323                      (k == 8 ? " " : ""),
3324                      isprint((char)(data[i+k])) ? data[i+k] : '.'
3325                      );
3326             ckstrncat((char *)buf,(char *)tmp,buflen);
3327         }
3328         i += j - 1;
3329     } /* end for */
3330     ckstrncat((char *)buf,"\r\n  ",buflen);
3331 #endif /* COMMENT */
3332     return(strlen((char *)buf));
3333 }
3334
3335 VOID
3336 tn_debug(s) char *s; {
3337 #ifdef NOLOCAL
3338     return;
3339 #else /* NOLOCAL */
3340 #ifdef OS2
3341     void cwrite(unsigned short);
3342     char *p = s;
3343     _PROTOTYP (void os2bold, (void));
3344     extern int tt_type_mode;
3345 #endif /* OS2 */
3346
3347     if (!(tn_deb || debses))
3348       return;
3349     debug(F111,"tn_debug",s,what);
3350 #ifdef OS2
3351     if (1) {
3352         extern unsigned char colorcmd;
3353         colorcmd ^= 0x8 ;
3354         printf("%s\r\n",s);
3355         colorcmd ^= 0x8 ;
3356     }
3357     if (!scrninitialized[VTERM]) {
3358         USHORT x,y;
3359         checkscreenmode();
3360         GetCurPos(&y, &x);
3361         SaveCmdMode(x+1,y+1);
3362         scrninit();
3363         RestoreCmdMode();
3364     }
3365
3366     if ( ISVTNT(tt_type_mode) && ttnum != -1 && !debses )
3367         return;
3368
3369     RequestVscrnMutex( VTERM, SEM_INDEFINITE_WAIT ) ;
3370
3371     os2bold();                          /* Toggle boldness */
3372     while (*p)
3373       cwrite((CHAR) *p++);              /* Go boldly ... */
3374     os2bold();                          /* Toggle boldness back */
3375     if (debses) {
3376         debses = 0;
3377         cwrite((CHAR) '\015');
3378         cwrite((CHAR) '\012');
3379         debses = 1;
3380     } else {
3381         cwrite((CHAR) '\015');
3382         cwrite((CHAR) '\012');
3383     }
3384     ReleaseVscrnMutex(VTERM) ;
3385 #else
3386     if (what != W_CONNECT && what != W_DIALING && 
3387         what != W_COMMAND && what != W_NOTHING)
3388       return;                           /* CONNECT/command must be active */
3389     conoll(s);
3390 #endif /* OS2 */
3391 #endif /* NOLOCAL */
3392 }
3393
3394 /*
3395   Process in-band Telnet negotiation characters from the remote host.
3396   Call with the telnet IAC character and the current duplex setting
3397   (0 = remote echo, 1 = local echo), and a pointer to a function to call
3398   to read more characters.  Returns:
3399     6 if DO LOGOUT was received and accepted
3400     5 if the Kermit start of packet character has changed
3401     4 if state of remote Internet Kermit Service has changed
3402     3 if a quoted IAC was received
3403     2 if local echo must be changed to remote
3404     1 if remote echo must be changed to local
3405     0 if nothing happens or no action necessary
3406    -1 on failure (= internal or i/o error)
3407 */
3408 #ifdef IKS_OPTION
3409 int
3410 tn_siks(cmd) int cmd; {         /* TELNET SEND IKS SUB */
3411     CHAR buf[8];
3412 #ifndef NOXFER
3413     extern CHAR mystch;                 /* Outgoing Start of Packet Char */
3414 #else
3415     CHAR mystch = '\1';
3416 #endif /* NOXFER */
3417     int n,m,rc;
3418
3419     if (ttnet != NET_TCPB) return(0);   /* Must be TCP/IP */
3420     if (ttnproto != NP_TELNET) return(0); /* Must be telnet protocol */
3421     if (cmd < KERMIT_START || cmd > KERMIT_RESP_STOP) /* Illegal subcommand */
3422       return(-1);
3423
3424 #ifdef CK_SSL
3425     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
3426         return(0);
3427     }
3428 #endif /* CK_SSL */
3429     if (cmd == KERMIT_START || cmd == KERMIT_RESP_START) {
3430         TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 1;
3431     } else if (cmd == KERMIT_STOP || cmd == KERMIT_RESP_STOP) {
3432         TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0;
3433     } else if (cmd == KERMIT_REQ_STOP)
3434       TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop = 1;
3435     else if (cmd == KERMIT_REQ_START)
3436       TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start = 1;
3437
3438     if (cmd == KERMIT_SOP) {
3439         buf[0] = (CHAR) IAC;
3440         buf[1] = (CHAR) SB;
3441         buf[2] = (CHAR) TELOPT_KERMIT;
3442         buf[3] = (CHAR) (cmd & 0xff);
3443         buf[4] = (CHAR) mystch;
3444         buf[5] = (CHAR) IAC;
3445         buf[6] = (CHAR) SE;
3446         buf[7] = (CHAR) 0;
3447 #ifdef DEBUG
3448         if (tn_deb || debses || deblog)
3449             ckmakmsg( tn_msg_out,TN_MSG_LEN,"TELNET SENT SB KERMIT SOP ",
3450                       ckctox(mystch,1)," IAC SE",NULL);
3451 #endif /* DEBUG */
3452 #ifdef OS2
3453         RequestTelnetMutex( SEM_INDEFINITE_WAIT );
3454 #endif
3455 #ifdef DEBUG
3456         debug(F101,tn_msg_out,"",cmd);
3457         if (tn_deb || debses) tn_debug(tn_msg_out);
3458 #endif /* DEBUG */
3459         rc = ( ttol(buf,7) < 7 );                /* Send it. */
3460 #ifdef OS2
3461         ReleaseTelnetMutex();
3462 #endif
3463     if (rc)
3464         return(-1);
3465     } else {
3466         buf[0] = (CHAR) IAC;
3467         buf[1] = (CHAR) SB;
3468         buf[2] = (CHAR) TELOPT_KERMIT;
3469         buf[3] = (CHAR) (cmd & 0xff);
3470         buf[4] = (CHAR) IAC;
3471         buf[5] = (CHAR) SE;
3472         buf[6] = (CHAR) 0;
3473
3474 #ifdef DEBUG
3475         if (tn_deb || debses || deblog) {
3476             char * s = 0;
3477             switch (cmd) {
3478               case KERMIT_START: s = "START"; break;
3479               case KERMIT_STOP: s = "STOP"; break;
3480               case KERMIT_REQ_START: s = "REQ-START"; break;
3481               case KERMIT_REQ_STOP: s = "REQ-STOP"; break;
3482               case KERMIT_RESP_START: s = "RESP-START"; break;
3483               case KERMIT_RESP_STOP:  s = "RESP-STOP"; break;
3484             }
3485             ckmakmsg( tn_msg_out,TN_MSG_LEN,
3486                       "TELNET SENT SB kermit ",s," IAC SE",NULL);
3487         }
3488 #endif /* DEBUG */
3489 #ifdef OS2
3490         RequestTelnetMutex( SEM_INDEFINITE_WAIT );
3491 #endif
3492 #ifdef DEBUG
3493         debug(F101,tn_msg_out,"",cmd);
3494         if (tn_deb || debses) tn_debug(tn_msg_out);
3495 #endif /* DEBUG */
3496         rc = ( ttol(buf,6) < 6 );                /* Send it. */
3497 #ifdef OS2
3498         ReleaseTelnetMutex();
3499 #endif
3500         if (rc)
3501             return(-1);
3502     }
3503     return(1);
3504 }
3505 #endif /* IKS_OPTION */
3506
3507 /* tn_sb() performs Telnet Subnegotiation Parsing and Debugging */
3508 /* returns <= 0 on error, 1 on success */
3509 /* the length returned includes the IAC SE bytes */
3510
3511 int
3512 #ifdef CK_ANSIC                         /* TELNET SB */
3513 tn_sb( int opt, int * len, int (*fn)(int) )
3514 #else
3515 tn_sb( opt, len, fn ) int opt; int * len; int (*fn)();
3516 #endif /* CK_ANSIC */
3517 /* tn_sb */ {
3518     int c, x, y, n, m, flag;
3519     debug(F100,"Entering tn_sb()","",0);
3520     *len = 0;                   /* Initialize Len to 0 */
3521     n = flag = 0;               /* Flag for when done reading SB */
3522     while (n < TSBUFSIZ) {      /* Loop looking for IAC SE */
3523         if ((y = (*fn)(0)) < 0) /* Read a byte */
3524           return(y);
3525         y &= 0xff;              /* Make sure it's just 8 bits. */
3526         sb[n++] = (char) y;     /* Deposit in buffer. */
3527         if (seslog && sessft == XYFT_D) { /* Take care of session log */
3528             logchar((char) y);
3529         }
3530         if (y == IAC) {         /* If this is an IAC                */
3531             if (flag) {         /* If previous char was IAC         */
3532                 n--;            /* it's quoted, keep one IAC        */
3533                 flag = 0;       /* and turn off the flag.           */
3534             } else flag = 1;    /* Otherwise set the flag.          */
3535         } else if (flag) {      /* Something else following IAC     */
3536             if (y == SE)        /* If not SE, it's a protocol error */
3537               break;
3538             else if (y == DONT) { /* Used DONT instead of SE */
3539                 debug(F100,
3540                       "TELNET Subnegotiation error - used DONT instead of SE!",
3541                       ""
3542                       ,0
3543                       );
3544                 if (tn_deb || debses)
3545                   tn_debug(
3546                      "TELNET Subnegotiation error - used DONT instead of SE!");
3547                 flag = 3;
3548                 break;
3549             } else {            /* Other protocol error */
3550                 flag = 0;
3551                 break;
3552             }
3553         }
3554
3555 #ifdef CK_FORWARD_X
3556         if ( opt == TELOPT_FORWARD_X && sb[0] == FWDX_DATA &&
3557              n >= (TSBUFSIZ-4) && !flag ) {
3558             /* do not let the buffer over flow */
3559             /* write the data to the channel and continue processing */
3560             /* the incoming data until IAC SE is reached. */
3561             sb[n++] = IAC;
3562             sb[n++] = SE;
3563
3564 #ifdef DEBUG
3565             if ( deblog || tn_deb || debses ) {
3566                 int i;
3567                 ckmakmsg( tn_msg,TN_MSG_LEN,
3568                           "TELNET RCVD SB ",TELOPT(opt),
3569                           " DATA(buffer-full) ",NULL);
3570                 tn_hex(tn_msg,TN_MSG_LEN,&sb[1],n-3);
3571                 if (flag == 2)
3572                     ckstrncat(tn_msg," SE",TN_MSG_LEN);
3573                 else if (flag == 3)
3574                     ckstrncat(tn_msg," IAC DONT",TN_MSG_LEN);
3575                 else
3576                     ckstrncat(tn_msg," IAC SE",TN_MSG_LEN);
3577                 debug(F100,tn_msg,"",0);
3578                 if (tn_deb || debses)
3579                     tn_debug(tn_msg);
3580             }
3581 #endif /* DEBUG */
3582
3583             if ( fwdx_tn_sb(sb,n) < 0 ) {
3584                 debug(F100,"fxdx_tn_sb() failed","",0);
3585                 /* We can't return though because that would leave  */
3586                 /* data to be forwarded in the queue to the be sent */
3587                 /* to the terminal emulator.                        */
3588             }
3589             /* reset leave the msg type and channel number in place */
3590             n = 3;
3591         }
3592 #endif /* CK_FORWARD_X */
3593     }
3594     debug(F111,"tn_sb end of while loop","flag",flag);
3595     if (!flag) {                        /* Make sure we got a valid SB */
3596         debug(F111, "TELNET Subnegotiation prematurely broken","opt",opt);
3597         if (tn_deb || debses) {
3598             ckmakmsg( tn_msg, TN_MSG_LEN,
3599                       "TELNET ", TELOPT(opt),
3600                       " Subnegotiation prematurely broken",NULL
3601                       );
3602
3603           tn_debug(tn_msg);
3604         }
3605         /* Was -1 but that would be an I/O error, so absorb it and go on. */
3606         return(0);
3607     }
3608 #ifdef DEBUG
3609     if (deblog || tn_deb || debses) {
3610         int i;
3611         char * s[16];
3612         for (i = 0; i < 16; i++)
3613           s[i] = "";
3614         if (opt == TELOPT_NAWS) {
3615             i = 0;
3616         } else {
3617             i = 1;
3618             s[0] = "UNKNOWN";
3619
3620             switch (sb[0]) {
3621               case 0:
3622                 if (opt == TELOPT_FORWARD_X)
3623                   s[0] = "SCREEN";
3624                 else if (opt == TELOPT_KERMIT)
3625                   s[0] = "START";
3626                 else if (opt == TELOPT_LFLOW)
3627                   s[0] = "OFF";
3628                 else if (opt == TELOPT_COMPORT)
3629                   s[0] = "SIGNATURE";
3630                 else
3631                   s[0] = "IS";
3632                 if (opt == TELOPT_ENCRYPTION) {
3633                     i++;
3634                     if (sb[1] < ENCTYPE_CNT) {
3635                         s[1] = enctype_names[sb[1]];
3636                         i++;
3637                         switch(sb[2]) {
3638                           case 1:
3639                             s[2] = "FB64_IV";
3640                             break;
3641                           case 2:
3642                             s[2] = "FB64_IV_OK";
3643                             break;
3644                           case 3:
3645                             s[2] = "FB64_IV_BAD";
3646                             break;
3647                           case 4:
3648                             s[2] = "FB64_CHALLENGE";
3649                             break;
3650                           case 5:
3651                             s[2] = "FB64_RESPONSE";
3652                             break;
3653                         }
3654                     } else {
3655                         s[1] = "UNKNOWN";
3656                     }
3657                 }
3658                 if (opt == TELOPT_AUTHENTICATION) {
3659                     i += 2;
3660                     s[1] = AUTHTYPE_NAME(sb[1]);
3661                     s[2] = AUTHMODE_NAME(sb[2]);
3662                     if (sb[1]) {
3663                         i++;
3664                         switch (sb[3]) {
3665                           case 0:
3666                             switch (sb[1]) {
3667                               case AUTHTYPE_NTLM:
3668                                 s[3] = "NTLM_AUTH";
3669                                 break;
3670                               default:
3671                                 s[3] = "AUTH";
3672                             }
3673                             break;
3674                           case 1:
3675                             switch (sb[1]) {
3676                               case AUTHTYPE_SSL:
3677                                 s[3] = "START";
3678                                 break;
3679                               case AUTHTYPE_NTLM:
3680                                 s[3] = "NTLM_CHALLENGE";
3681                                 break;
3682                               default:
3683                                 s[3] = "REJECT";
3684                             }
3685                             break;
3686                           case 2:
3687                             switch (sb[1]) {
3688                               case AUTHTYPE_NTLM:
3689                                 s[3] = "NTLM_RESPONSE";
3690                                 break;
3691                               default:
3692                                 s[3] = "ACCEPT";
3693                             }
3694                             break;
3695                           case 3:
3696                             switch (sb[1]) {
3697                               case AUTHTYPE_NTLM:
3698                                 s[3] = "NTLM_ACCEPT";
3699                                 break;
3700                               case 1:   /* KERBEROS_v4 */
3701                               case 5:   /* SRP */
3702                                 s[3] = "CHALLENGE";
3703                                 break;
3704                               case 2:   /* KERBEROS_v5 */
3705                                 s[3] = "RESPONSE";
3706                                 break;
3707                               case AUTHTYPE_SSL:
3708                                 s[3] = "REJECT";
3709                                 break;
3710                             }
3711                             break;
3712                           case 4:
3713                             switch (sb[1]) {
3714                               case AUTHTYPE_NTLM:
3715                                 s[3] = "NTLM_REJECT";
3716                                 break;
3717                               case 1:   /* KERBEROS_V4 */
3718                               case 5:   /* SRP */
3719                                 s[3] = "RESPONSE";
3720                                 break;
3721                               case 2:   /* KERBEROS_V5 */
3722                                 s[3] = "FORWARD";
3723                                 break;
3724                             }
3725                             break;
3726                           case 5:
3727                             switch (sb[1]) {
3728                               case 5:   /* SRP */
3729                                 s[3] = "FORWARD";
3730                                 break;
3731                               case 2:   /* KERBEROS_V5 */
3732                                 s[3] = "FORWARD_ACCEPT";
3733                                 break;
3734                             }
3735                             break;
3736                           case 6:
3737                             switch (sb[1]) {
3738                               case 5:   /* SRP */
3739                                 s[3] = "FORWARD_ACCEPT";
3740                                 break;
3741                               case 2: /* KERBEROS_V5 */
3742                                 s[3] = "FORWARD_REJECT";
3743                                 break;
3744                             }
3745                             break;
3746                           case 7:
3747                             switch (sb[1]) {
3748                               case 5:   /* SRP */
3749                                 s[3] = "FORWARD_REJECT";
3750                                 break;
3751                               case 2: /* KERBEROS_V5 */
3752                                 s[3] = "TLS_VERIFY";
3753                                 break;
3754                               }
3755                             break;
3756                           case 8:
3757                             switch (sb[1]) {
3758                               case 5: /* SRP */
3759                                 s[3] = "EXP";
3760                                 break;
3761                             }
3762                             break;
3763                           case 9:
3764                             switch (sb[1]) {
3765                               case 5: /* SRP */
3766                                 s[3] = "PARAMS";
3767                                 break;
3768                             }
3769                             break;
3770                         }
3771                     }
3772                 }
3773                 break;
3774               case 1:
3775                 switch (opt) {
3776                   case TELOPT_FORWARD_X:
3777                     s[0] = "OPEN";
3778                     break;
3779                   case TELOPT_LFLOW:
3780                     s[0] = "ON";
3781                     break;
3782                   case TELOPT_KERMIT:
3783                     s[0] = "STOP";
3784                     break;
3785                   case TELOPT_COMPORT:
3786                     s[0] = "SET-BAUDRATE";
3787                       break;
3788                   case TELOPT_AUTHENTICATION:
3789                     s[0] = "SEND";
3790                     hexbuf[0] = '\0';
3791                     for (; i < n-2; i += 2) {
3792                         if ( AUTHTYPE_NAME_OK(sb[i]) &&
3793                              AUTHMODE_NAME_OK(sb[i]))
3794                             ckmakmsg( tn_msg, TN_MSG_LEN,
3795                                       AUTHTYPE_NAME(sb[i])," ",
3796                                       AUTHMODE_NAME(sb[i+1])," "
3797                                       );
3798                         else
3799                           ckmakxmsg(tn_msg, TN_MSG_LEN,
3800                                     AUTHTYPE_NAME(sb[i]),
3801                                     "=",
3802                                     ckitoa(sb[i]),
3803                                     " ",
3804                                     AUTHMODE_NAME(sb[i+1]),
3805                                     "=",
3806                                     ckitoa(sb[i+1]),
3807                                     " ",
3808                                     NULL,NULL,NULL,NULL
3809                                     );
3810                         ckstrncat(hexbuf,tn_msg,sizeof(hexbuf));
3811                     }
3812                     s[1] = hexbuf;
3813                     break;
3814
3815                   case TELOPT_ENCRYPTION:
3816                     s[0] = "SUPPORT";
3817                     while (i < n-2) {
3818                         s[i] = enctype_names[sb[i]];
3819                         i++;
3820                     }
3821                     break;
3822
3823                   case TELOPT_START_TLS:
3824                     s[0] = "FOLLOWS";
3825                     break;
3826                   default:
3827                     s[0] = "SEND";
3828                 }
3829                 break;
3830
3831               case 2:
3832                 switch (opt) {
3833                 case TELOPT_FORWARD_X:
3834                     s[0] = "CLOSE";
3835                     break;
3836                   case TELOPT_LFLOW:
3837                     s[0] = "RESTART-ANY";
3838                     break;
3839                   case TELOPT_KERMIT:
3840                     s[0] = "REQ-START";
3841                     break;
3842                   case TELOPT_COMPORT:
3843                     s[0] = "SET-DATASIZE";
3844                     break;
3845                   case TELOPT_NEWENVIRON:
3846                     s[0] = "INFO";
3847                     break;
3848                   case TELOPT_AUTHENTICATION:
3849                     s[0] = "REPLY";
3850                     i=4;
3851                     s[1] = AUTHTYPE_NAME(sb[1]);
3852                     s[2] = AUTHMODE_NAME(sb[2]);
3853                     switch (sb[3]) {
3854                       case 0:
3855                         switch (sb[1]) {
3856                           case AUTHTYPE_NTLM:
3857                             s[3] = "NTLM_AUTH";
3858                             break;
3859                           default:
3860                             s[3] = "AUTH";
3861                         }
3862                         break;
3863                       case 1:
3864                         switch (sb[1]) {
3865                           case AUTHTYPE_NTLM:
3866                             s[3] = "NTLM_CHALLENGE";
3867                             break;
3868                           default:
3869                             s[3] = "REJECT";
3870                         }
3871                         break;
3872                       case 2:
3873                         switch (sb[1]) {
3874                           case AUTHTYPE_NTLM:
3875                             s[3] = "NTLM_RESPONSE";
3876                             break;
3877                           default:
3878                             s[3] = "ACCEPT";
3879                         }
3880                         break;
3881                       case 3:
3882                         switch (sb[1]) {
3883                           case AUTHTYPE_NTLM:
3884                             s[3] = "NTLM_ACCEPT";
3885                             break;
3886                           case AUTHTYPE_KERBEROS_V4:
3887                           case AUTHTYPE_SRP:
3888                             s[3] = "CHALLENGE";
3889                             break;
3890                           case AUTHTYPE_KERBEROS_V5:
3891                             s[3] = "RESPONSE";
3892                             break;
3893                         }
3894                         break;
3895                       case 4:
3896                         switch (sb[1]) {
3897                           case AUTHTYPE_NTLM:
3898                             s[3] = "NTLM_REJECT";
3899                             break;
3900                           case AUTHTYPE_KERBEROS_V4:
3901                           case AUTHTYPE_SRP:
3902                             s[3] = "RESPONSE";
3903                             break;
3904                           case AUTHTYPE_KERBEROS_V5:
3905                             s[3] = "FORWARD";
3906                             break;
3907                         }
3908                         break;
3909                       case 5:
3910                         switch (sb[1]) {
3911                           case AUTHTYPE_SRP:
3912                             s[3] = "FORWARD";
3913                             break;
3914                           case AUTHTYPE_KERBEROS_V5:
3915                             s[3] = "FORWARD_ACCEPT";
3916                             break;
3917                         }
3918                         break;
3919                       case 6:
3920                         switch (sb[1]) {
3921                           case AUTHTYPE_SRP:
3922                             s[3] = "FORWARD_ACCEPT";
3923                             break;
3924                           case AUTHTYPE_KERBEROS_V5:
3925                             s[3] = "FORWARD_REJECT";
3926                             break;
3927                         }
3928                         break;
3929                       case 7:
3930                         switch (sb[1]) {
3931                           case AUTHTYPE_SRP:
3932                             s[3] = "FORWARD_REJECT";
3933                             break;
3934                           case AUTHTYPE_KERBEROS_V5:
3935                             s[3] = "TLS_VERIFY";
3936                             break;
3937                         }
3938                         break;
3939                       case 8:
3940                         switch (sb[1]) {
3941                           case AUTHTYPE_SRP:
3942                             s[3] = "EXP";
3943                             break;
3944                         }
3945                         break;
3946                       case 9:
3947                         switch (sb[1]) {
3948                           case AUTHTYPE_SRP:
3949                             s[3] = "PARAMS";
3950                             break;
3951                         }
3952                         break;
3953                     }
3954                     break;
3955                   case TELOPT_ENCRYPTION:
3956                     s[0] = "REPLY";
3957                     s[1] = enctype_names[sb[1]];
3958                     i++;
3959                     switch (sb[2]) {
3960                       case 1:
3961                         i++;
3962                         s[2] = "FB64_IV";
3963                         break;
3964                       case 2:
3965                         i++;
3966                         s[2] = "FB64_IV_OK";
3967                         break;
3968                       case 3:
3969                         i++;
3970                         s[2] = "FB64_IV_BAD";
3971                         break;
3972                       case 4:
3973                         i++;
3974                         s[2] = "FB64_CHALLENGE";
3975                         break;
3976                       case 5:
3977                         i++;
3978                         s[2] = "FB64_RESPONSE";
3979                         break;
3980                     }
3981                     break;
3982                 }
3983                 break;
3984               case 3:
3985                 switch (opt) {
3986                   case TELOPT_FORWARD_X:
3987                     s[0] = "DATA";
3988                     break;
3989                   case TELOPT_LFLOW:
3990                     s[0] = "RESTART-XON";
3991                     break;
3992                   case TELOPT_KERMIT:
3993                     s[0] = "REQ-STOP";
3994                     break;
3995                   case TELOPT_COMPORT:
3996                       s[0] = "SET-PARITY";
3997                       break;
3998                   case TELOPT_AUTHENTICATION:
3999                     s[0] = "NAME";
4000                     break;
4001                   case TELOPT_ENCRYPTION:
4002                     s[0] = "START";
4003                     break;
4004                 }
4005                 break;
4006               case 4:
4007                 switch (opt) {
4008                   case TELOPT_FORWARD_X:
4009                     s[0] = "OPTIONS";
4010                     break;
4011                   case TELOPT_KERMIT:
4012                     s[0] = "SOP";
4013                     break;
4014                   case TELOPT_COMPORT:
4015                       s[0] = "SET-STOPSIZE";
4016                       break;
4017                   case TELOPT_ENCRYPTION:
4018                     s[0] = "END";
4019                     break;
4020                 }
4021                 break;
4022               case 5:
4023                 switch (opt) {
4024                 case TELOPT_FORWARD_X:
4025                     s[0] = "OPTION_DATA";
4026                     break;
4027                 case TELOPT_ENCRYPTION:
4028                     s[0] = "REQUEST-START";
4029                     break;
4030                 case TELOPT_COMPORT:
4031                     s[0] = "SET-CONTROL";
4032                     break;
4033                 }
4034                 break;
4035               case 6:
4036                 switch (opt) {
4037                   case TELOPT_FORWARD_X:
4038                     s[0] = "XOFF";
4039                     break;
4040                   case TELOPT_ENCRYPTION:
4041                     s[0] = "REQUEST-END";
4042                     break;
4043                   case TELOPT_COMPORT:
4044                       s[0] = "NOTIFY-LINESTATE";
4045                       break;
4046                   }
4047                 break;
4048               case 7:
4049                 switch (opt) {
4050                   case TELOPT_FORWARD_X:
4051                     s[0] = "XON";
4052                     break;
4053                   case TELOPT_ENCRYPTION:
4054                     s[0] = "ENC-KEYID";
4055                     break;
4056                   case TELOPT_COMPORT:
4057                       s[0] = "NOTIFY-MODEMSTATE";
4058                       break;
4059                   }
4060                 break;
4061               case 8:
4062                 switch (opt) {
4063                   case TELOPT_KERMIT:
4064                     s[0] = "RESP-START";
4065                     break;
4066                   case TELOPT_ENCRYPTION:
4067                     s[0] = "DEC-KEYID";
4068                     break;
4069                   case TELOPT_COMPORT:
4070                       s[0] = "FLOWCONTROL-SUSPEND";
4071                       break;
4072                   }
4073                 break;
4074               case 9:
4075                 switch (opt) {
4076                   case TELOPT_KERMIT:
4077                     s[0] = "RESP-STOP";
4078                     break;
4079                   case TELOPT_COMPORT:
4080                       s[0] = "FLOWCONTROL-RESUME";
4081                       break;
4082                   }
4083                 break;
4084               case 10:
4085                   switch (opt) {
4086                   case TELOPT_COMPORT:
4087                     s[0] = "SET-LINESTATE-MASK";
4088                     break;
4089                   }
4090                   break;
4091             case 11:
4092                   switch (opt) {
4093                   case TELOPT_COMPORT:
4094                       s[0] = "SET-MODEMSTATE-MASK";
4095                       break;
4096                   }
4097                   break;
4098             case 12:
4099                   switch (opt) {
4100                   case TELOPT_COMPORT:
4101                       s[0] = "PURGE-DATA";
4102                       break;
4103                   }
4104                   break;
4105
4106
4107             case 100:
4108                   switch (opt) {
4109                   case TELOPT_COMPORT:
4110                       s[0] = "S_SIGNATURE";
4111                       break;
4112                   }
4113                   break;
4114             case 101:
4115                   switch (opt) {
4116                   case TELOPT_COMPORT:
4117                       s[0] = "S_SET-BAUDRATE";
4118                       break;
4119                   }
4120                   break;
4121             case 102:
4122                   switch (opt) {
4123                   case TELOPT_COMPORT:
4124                       s[0] = "S_SET-DATASIZE";
4125                       break;
4126                   }
4127                   break;
4128             case 103:
4129                   switch (opt) {
4130                   case TELOPT_COMPORT:
4131                       s[0] = "S_SET-PARITY";
4132                       break;
4133                   }
4134                   break;
4135             case 104:
4136                   switch (opt) {
4137                   case TELOPT_COMPORT:
4138                       s[0] = "S_SET-STOPSIZE";
4139                       break;
4140                   }
4141                   break;
4142             case 105:
4143                   switch (opt) {
4144                   case TELOPT_COMPORT:
4145                       s[0] = "S_SET-CONTROL";
4146                       break;
4147                   }
4148                   break;
4149             case 106:
4150                   switch (opt) {
4151                   case TELOPT_COMPORT:
4152                       s[0] = "S_NOTIFY-LINESTATE";
4153                       break;
4154                   }
4155                   break;
4156             case 107:
4157                   switch (opt) {
4158                   case TELOPT_COMPORT:
4159                       s[0] = "S_NOTIFY-MODEMSTATE";
4160                       break;
4161                   }
4162                   break;
4163             case 108:
4164                   switch (opt) {
4165                   case TELOPT_COMPORT:
4166                       s[0] = "S_FLOWCONTROL-SUSPEND";
4167                       break;
4168                   }
4169                   break;
4170             case 109:
4171                   switch (opt) {
4172                   case TELOPT_COMPORT:
4173                       s[0] = "S_FLOWCONTROL-RESUME";
4174                       break;
4175                   }
4176                   break;
4177             case 110:
4178                   switch (opt) {
4179                   case TELOPT_COMPORT:
4180                       s[0] = "S_SET-LINESTATE-MASK";
4181                       break;
4182                   }
4183                   break;
4184             case 111:
4185                   switch (opt) {
4186                   case TELOPT_COMPORT:
4187                       s[0] = "S_SET-MODEMSTATE-MASK";
4188                       break;
4189                   }
4190                   break;
4191             case 112:
4192                   switch (opt) {
4193                   case TELOPT_COMPORT:
4194                       s[0] = "S_PURGE-DATA";
4195                       break;
4196                   }
4197                   break;
4198               }
4199         }
4200 #ifdef M_XENIX
4201         {
4202           int len, param, param_len;
4203           ckmakmsg( tn_msg, TN_MSG_LEN,
4204                     "TELNET RCVD SB ",
4205                     TELOPT(opt)," ",NULL);
4206           len = strlen(tn_msg);
4207           for (param = 0; param <= 15; param++) {
4208             param_len = strlen(s[param]);
4209             if (param_len > 0) {
4210               strcpy(&tn_msg[len], s[param]);
4211               len += param_len;
4212               tn_msg[len++] = ' ';
4213             }
4214           }
4215           tn_msg[len] = '\0';
4216         }
4217 #else /* M_XENIX */
4218         ckmakxmsg(tn_msg,TN_MSG_LEN,"TELNET RCVD SB ",TELOPT(opt)," ",
4219                   NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
4220         {
4221             int i;
4222             for (i = 0; i < 16; i++) {
4223                 if (s[i][0]) {
4224                     ckstrncat(tn_msg,s[i],TN_MSG_LEN);
4225                     ckstrncat(tn_msg," ",TN_MSG_LEN);
4226                 }
4227             }
4228         }
4229 #endif /* M_XENIX */
4230         tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&sb[i],n-2-i);
4231         if (flag == 2)
4232           ckstrncat(tn_msg," SE",TN_MSG_LEN);
4233         else if (flag == 3)
4234           ckstrncat(tn_msg," IAC DONT",TN_MSG_LEN);
4235         else
4236           ckstrncat(tn_msg," IAC SE",TN_MSG_LEN);
4237         debug(F100,tn_msg,"",0);
4238         if (tn_deb || debses)
4239           tn_debug(tn_msg);
4240     }
4241     debug(F111,"tn_sb","len",n);
4242 #endif /* DEBUG */
4243     *len = n;           /* return length */
4244     return(1);          /* success */
4245 }
4246
4247 static char rows_buf[16] = { 0, 0 }; /* LINES Environment variable */
4248 static char cols_buf[16] = { 0, 0 }; /* COLUMNS Enviornment variable */
4249 static char term_buf[64] = { 0, 0 }; /* TERM Environment variable */
4250
4251 #ifdef CK_CURSES
4252 #ifndef VMS
4253 #ifndef COHERENT
4254 _PROTOTYP(int tgetent,(char *, char *));
4255 #endif /* COHERENT */
4256 #else
4257 #ifdef __DECC
4258 _PROTOTYP(int tgetent,(char *, char *));
4259 #endif /* __DECC */
4260 #endif /* VMS */
4261 extern char * trmbuf;                   /* Real curses */
4262 #endif /* CK_CURSES */
4263
4264 #ifdef CK_ENCRYPTION
4265 static int
4266 tn_no_encrypt()
4267 {
4268     /* Prevent Encryption from being negotiated */
4269     TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
4270     TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
4271
4272     /* Cancel any negotiation that might have started */
4273     ck_tn_enc_stop();
4274
4275     if (TELOPT_ME(TELOPT_ENCRYPTION) ||
4276          TELOPT_UNANSWERED_WILL(TELOPT_ENCRYPTION)) {
4277         TELOPT_ME(TELOPT_ENCRYPTION) = 0;
4278         if (tn_sopt(WONT,TELOPT_ENCRYPTION) < 0)
4279             return(-1);
4280         TELOPT_UNANSWERED_WONT(TELOPT_ENCRYPTION) = 1;
4281     }
4282     if (TELOPT_U(TELOPT_ENCRYPTION) ||
4283          TELOPT_UNANSWERED_DO(TELOPT_ENCRYPTION)) {
4284         TELOPT_U(TELOPT_ENCRYPTION) = 0;
4285         if (tn_sopt(DONT,TELOPT_ENCRYPTION) < 0)
4286             return(-1);
4287         TELOPT_UNANSWERED_DONT(TELOPT_ENCRYPTION) = 1;
4288     }
4289     return(0);
4290 }
4291 #endif /* CK_ENCRYPTION */
4292
4293 /* The following note came from the old SGA negotiation code.  This should */
4294 /* no longer be necessary with the New Telnet negotiation state machine.   */
4295 /*
4296   Note: The following is proper behavior, and required for talking to the
4297   Apertus interface to the NOTIS library system, e.g. at Iowa State U:
4298   scholar.iastate.edu.  Without this reply, the server hangs forever.  This
4299   code should not be loop-inducing, since C-Kermit never sends WILL SGA as
4300   an initial bid, so if DO SGA comes, it is never an ACK.
4301 */
4302 /*
4303   Return values:
4304   -1 = Telnet Option negotiation error
4305   -2 = Connection closed by peer
4306   -3 = Connection closed by us
4307   0  = Success
4308   1  = Echoing on
4309   2  = Echoing off
4310   3  = Quoted IAC
4311   4  = IKS Event
4312   5  = (unassigned)
4313   6  = Logout
4314 */
4315
4316 static int
4317 #ifdef CK_ANSIC                         /* TELNET DO OPTION */
4318 tn_xdoop(CHAR z, int echo, int (*fn)(int))
4319 #else
4320 tn_xdoop(z, echo, fn) CHAR z; int echo; int (*fn)();
4321 #endif /* CK_ANSIC */
4322 /* tn_xdoop */ {
4323     int c, x, y, n, m;
4324 #ifdef IKS_OPTION
4325     extern int server;
4326 #ifdef NOICP
4327     extern int autodl;
4328     int inautodl = 0, cmdadl = 1;
4329 #else
4330 #ifdef CK_AUTODL
4331     extern int autodl, inautodl, cmdadl;
4332 #endif /* CK_AUTODL */
4333 #endif /* NOICP */
4334 #endif /* IKS_OPTION */
4335
4336
4337 /* Have IAC, read command character. */
4338
4339     while ((c = (*fn)(0)) == -1);       /* Read command character */
4340     if (c < 0)
4341       return(c);
4342     c &= 0xFF;                          /* Strip high bits */
4343
4344     if (!TELCMD_OK(c)) {
4345 #ifdef DEBUG
4346         if (tn_deb || debses || deblog) {
4347             ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET RCVD UNKNOWN (",
4348                      ckitoa(c),")",NULL);
4349             debug(F101,tn_msg,"",c);
4350             if (tn_deb || debses)
4351               tn_debug(tn_msg);
4352         }
4353 #endif /* DEBUG */
4354         return(0);
4355     }
4356     if (ttnproto == NP_NONE) {
4357         debug(F100,"tn_doop discovered a Telnet command",
4358               "ttnproto = NP_TELNET",0);
4359         ttnproto = NP_TELNET;
4360     }
4361     if (seslog && sessft == XYFT_D) {   /* Copy to session log, if any. */
4362         logchar((char)z);
4363         logchar((char)c);
4364     }
4365
4366     if (c == (CHAR) IAC)                /* Quoted IAC */
4367       return(3);
4368
4369     if (c < SB) {                       /* Other command with no arguments. */
4370 #ifdef DEBUG
4371         if (deblog || tn_deb || debses) {
4372             ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET RCVD ",TELCMD(c),NULL,NULL);
4373             debug(F101,tn_msg,"",c);
4374             if (tn_deb || debses) tn_debug(tn_msg);
4375         }
4376 #endif /* DEBUG */
4377         switch (c) {                    /* What we would like to do here    */
4378           case TN_GA:                   /* Is substitute ASCII characters   */
4379             break;                      /* for the Telnet Command so that   */
4380           case TN_EL:                   /* the command may be processed by  */
4381             break;                      /* either the internal emulator or  */
4382           case TN_EC:                   /* by the superior process or shell */
4383             break;
4384           case TN_AYT:
4385 #ifdef OS2
4386             RequestTelnetMutex( SEM_INDEFINITE_WAIT );
4387 #endif
4388             ttol((CHAR *)"[Yes]\015\012",7);
4389 #ifdef OS2
4390             ReleaseTelnetMutex();
4391 #endif
4392             break;
4393           case TN_AO:
4394 #ifdef BETADEBUG
4395             bleep(BP_NOTE);
4396 #endif /* BETADEBUG */
4397             break;
4398           case TN_IP:
4399             break;
4400           case BREAK:
4401             break;
4402           case TN_DM:
4403             break;
4404           case TN_NOP:
4405             break;
4406           case SE:
4407             break;
4408           case TN_EOR:
4409             break;
4410           case TN_ABORT:
4411             break;
4412           case TN_SUSP:
4413             break;
4414           case TN_EOF:
4415             break;
4416           case TN_SAK:
4417             break;
4418         }
4419         return(0);
4420     }
4421
4422 /* SB, WILL, WONT, DO, or DONT need more bytes... */
4423
4424     if ((x = (*fn)(0)) < 0)             /* Get the option. */
4425       return(x);
4426     x &= 0xff;                          /* Trim to 8 bits. */
4427
4428     if (seslog && sessft == XYFT_D) {   /* Session log */
4429         logchar((char) x);
4430     }
4431 #ifdef DEBUG
4432     if ((deblog || tn_deb || debses) && c != SB) {
4433         ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET RCVD ",TELCMD(c)," ",TELOPT(x));
4434         debug(F101,tn_msg,"",x);
4435         if (tn_deb || debses) tn_debug(tn_msg);
4436     }
4437 #endif /* DEBUG */
4438     /* Now handle the command */
4439     switch (c) {
4440       case WILL:
4441 #ifdef CK_SSL
4442         if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
4443             return(0);
4444 #endif /* CK_SSL */
4445 #ifdef CK_FORWARD_X
4446           if (x == TELOPT_FORWARD_X) {
4447               if (!fwdx_server_avail() || !(fwdx_no_encrypt ||
4448 #ifdef CK_SSL
4449                  (ssl_active_flag || tls_active_flag)
4450 #else /* CK_SSL */
4451                  0
4452 #endif /* CK_SSL */
4453                  ||
4454 #ifdef CK_ENCRYPTION
4455                  (ck_tn_encrypting() && ck_tn_decrypting())
4456 #else /* CK_ENCRYPTION */
4457                  0
4458 #endif /* CK_ENCRYPTION */
4459                  )) {
4460                   TELOPT_U_MODE(TELOPT_FORWARD_X) = TN_NG_RF;
4461                   TELOPT_ME_MODE(TELOPT_FORWARD_X) = TN_NG_RF;
4462               }
4463           }
4464 #endif /* CK_FORWARD_X */
4465         if (!TELOPT_OK(x) || TELOPT_U_MODE(x) == TN_NG_RF) {
4466             if (tn_sopt(DONT,x) < 0)
4467               return(-1);
4468             if (TELOPT_UNANSWERED_DO(x))
4469                 TELOPT_UNANSWERED_DO(x) = 0;
4470         } else if (!TELOPT_U(x)) {
4471             if (!TELOPT_UNANSWERED_DO(x)) {
4472                 if (tn_sopt(DO,x) < 0)
4473                   return -1;
4474             }
4475             if (TELOPT_UNANSWERED_DO(x))
4476                 TELOPT_UNANSWERED_DO(x) = 0;
4477             TELOPT_U(x) = 1;
4478
4479             switch (x) {
4480 #ifdef CK_SSL
4481               case TELOPT_START_TLS:
4482                 /*
4483                    If my proposal is accepted, at this point the Telnet
4484                    protocol is turned off and a TLS negotiation takes
4485                    place.
4486
4487                    Start by sending SB START_TLS FOLLOWS  to signal
4488                    we are ready.  Wait for the peer to send the same
4489                    and then start the TLS negotiation.
4490
4491                    If the TLS negotiation succeeds we call tn_ini()
4492                    again to reset the telnet state machine and restart
4493                    the negotiation process over the now secure link.
4494
4495                    If the TLS negotiation fails, we call ttclos()
4496                    to terminate the connection.
4497
4498                    Only the server should receive a WILL START_TLS
4499                  */
4500                 tn_ssbopt(TELOPT_START_TLS,1,NULL,0);
4501                 TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows = 1;
4502                 break;
4503 #endif /* CK_SSL */
4504
4505 #ifdef CK_AUTHENTICATION
4506               case TELOPT_AUTHENTICATION: {
4507                   /* We now have to perform a SB SEND to identify the  */
4508                   /* supported authentication types to the other side. */
4509                   extern int authentication_version;
4510
4511 #ifdef CK_SSL
4512                   /* if we have an outstanding DO START_TLS then we must 
4513                    * wait for the response before we determine what to do
4514                    */
4515                   if (TELOPT_UNANSWERED_DO(TELOPT_START_TLS)) {
4516                       TELOPT_SB(TELOPT_START_TLS).start_tls.auth_request = 1;
4517                       break;
4518                   }
4519 #endif /* CK_SSL */
4520                   authentication_version = AUTHTYPE_AUTO;
4521                   ck_tn_auth_request();
4522                   break;
4523               }
4524 #endif /* CK_AUTHENTICATION */
4525 #ifdef CK_ENCRYPTION
4526               case TELOPT_ENCRYPTION:
4527                 if (!(TELOPT_ME(TELOPT_AUTHENTICATION) ||
4528                       TELOPT_U(TELOPT_AUTHENTICATION))
4529                     ) {
4530                     if (tn_sopt(DONT,x) < 0)
4531                       return(-1);
4532                     TELOPT_U(x) = 0;
4533                 } else {
4534                     if (ck_tn_auth_in_progress()) {
4535                         TELOPT_SB(TELOPT_ENCRYPTION).encrypt.need_to_send = 1;
4536                     } else {
4537                         /* Perform subnegotiation */
4538                         ck_encrypt_send_support();
4539                     }
4540                     if (!(TELOPT_ME(x) || TELOPT_UNANSWERED_WILL(x))
4541                         && TELOPT_ME_MODE(x) != TN_NG_RF) {
4542                         if (tn_sopt(WILL, x) < 0)
4543                           return(-1);
4544                         TELOPT_UNANSWERED_WILL(x) = 1;
4545                     }
4546                 }
4547                 break;
4548 #endif /* CK_ENCRYPTION */
4549 #ifdef IKS_OPTION
4550               case TELOPT_KERMIT:
4551                 if (!TELOPT_ME(x)) {
4552                     /* Tell the other side what Start of Packet Character */
4553                     tn_siks(KERMIT_SOP); /* SOP */
4554
4555                     if (!TELOPT_UNANSWERED_WILL(x) &&
4556                         TELOPT_ME_MODE(x) != TN_NG_RF) {
4557                         if (tn_sopt(WILL, x) < 0)
4558                           return(-1);
4559                         TELOPT_UNANSWERED_WILL(x) = 1;
4560                     }
4561                 }
4562                 break;
4563 #endif /* IKS_OPTION */
4564               case TELOPT_BINARY:
4565                 if (!TELOPT_ME(x)) {
4566                     if (!TELOPT_UNANSWERED_WILL(x) &&
4567                         TELOPT_ME_MODE(x) >= TN_NG_RQ) {
4568                         if (tn_sopt(WILL, x) < 0)
4569                           return(-1);
4570                         TELOPT_UNANSWERED_WILL(x) = 1;
4571                     }
4572                 }
4573                 break;
4574               case TELOPT_ECHO:
4575                 if (echo) {
4576                     if (TELOPT_UNANSWERED_DO(x))
4577                       TELOPT_UNANSWERED_DO(x) = 0;
4578                     return(2);
4579                 }
4580                 break;
4581               case TELOPT_TTYPE:
4582                 /* SB TTYPE SEND */
4583                 tn_ssbopt(TELOPT_TTYPE,TELQUAL_SEND,NULL,0);
4584                 TELOPT_UNANSWERED_SB(TELOPT_TTYPE)=1;
4585                 break;
4586 #ifdef CK_ENVIRONMENT
4587               case TELOPT_NEWENVIRON:   /* SB NEW-ENVIRON SEND */
4588                 {
4589                   char request[6];      /* request it */
4590                   sprintf(request,"%cUSER",TEL_ENV_VAR);        /* safe */
4591                   tn_ssbopt(TELOPT_NEWENVIRON,TELQUAL_SEND,request,
4592                             strlen(request));
4593                   TELOPT_UNANSWERED_SB(TELOPT_NEWENVIRON)=1;
4594                 }
4595                 break;
4596 #endif /* CK_ENVIRONMENT */
4597             } /* switch */
4598         } else {
4599             if (TELOPT_UNANSWERED_DO(x))
4600                 TELOPT_UNANSWERED_DO(x) = 0;
4601         }
4602         break;
4603       case WONT:
4604 #ifdef CK_SSL
4605         if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
4606             return(0);
4607 #endif /* CK_SSL */
4608         if (TELOPT_U(x) || TELOPT_UNANSWERED_DO(x)) {
4609             /* David Borman says we should not respond DONT when
4610              * the WONT is a response to a DO that we sent.
4611              * Nor should we send one if the state is already WONT
4612              * such as when we do not recognize the option since
4613              * options are initialized in the WONT/DONT state.
4614              */
4615             if (!(TELOPT_UNANSWERED_DO(x) || TELOPT_UNANSWERED_DONT(x)))
4616               if (tn_sopt(DONT,x) < 0)
4617                 return(-1);
4618             if (TELOPT_UNANSWERED_DONT(x))
4619                 TELOPT_UNANSWERED_DONT(x) = 0;
4620             if (TELOPT_UNANSWERED_DO(x))
4621                 TELOPT_UNANSWERED_DO(x) = 0;
4622             if (TELOPT_U(x)) {
4623                 TELOPT_U(x) = 0;
4624             }
4625             switch(x) {
4626 #ifdef CK_SSL
4627             case TELOPT_START_TLS:
4628                 if (sstelnet) {
4629                     if (TELOPT_U_MODE(x) == TN_NG_MU) {
4630                         printf("Telnet Start-TLS refused.\n");
4631                         ttclos(0);
4632                         whyclosed = WC_TELOPT;
4633                         return(-3);
4634                     }
4635                     if (TELOPT_SB(x).start_tls.auth_request) {
4636                         extern int authentication_version;
4637                         TELOPT_SB(x).start_tls.auth_request = 0;
4638                         authentication_version = AUTHTYPE_AUTO;
4639                         ck_tn_auth_request();
4640                     }
4641                 }
4642                 break;
4643 #endif /* CK_SSL */
4644 #ifdef CK_AUTHENTICATION
4645               case TELOPT_AUTHENTICATION:
4646                 if (sstelnet && TELOPT_U_MODE(x) == TN_NG_MU) {
4647                     printf("Telnet authentication refused.\n");
4648                     ttclos(0);
4649                     whyclosed = WC_TELOPT;
4650                     return(-3);
4651                 } else if (TELOPT_U_MODE(x) == TN_NG_RQ) {
4652                     TELOPT_U_MODE(x) = TN_NG_AC;
4653                 }
4654                 if (ck_tn_auth_in_progress())
4655                   printf("Telnet authentication refused.\n");
4656 #ifdef CK_ENCRYPTION
4657                 if (sstelnet) {
4658                     if (tn_no_encrypt()<0)
4659                         return(-1);
4660                 }
4661 #endif /* CK_ENCRYPTION */
4662                 break;
4663 #endif /* CK_AUTHENTICATION */
4664 #ifdef CK_ENCRYPTION
4665               case TELOPT_ENCRYPTION:
4666                 ck_tn_enc_stop();
4667                 break;
4668 #endif /* CK_ENCRYPTION */
4669 #ifdef IKS_OPTION
4670               case TELOPT_KERMIT:
4671                 TELOPT_SB(x).kermit.u_start = 0;
4672                 TELOPT_SB(x).kermit.me_req_start = 0;
4673                 TELOPT_SB(x).kermit.me_req_stop = 0;
4674                 break;
4675 #endif /* IKS_OPTION */
4676               case TELOPT_NAWS: {
4677                   /* The client does not support NAWS. */
4678                   /* Assume a height of 24 and a width of 80 */
4679                   if (sstelnet
4680 #ifdef IKSD
4681                    || inserver
4682 #endif /* IKSD */
4683                    ) {
4684                       int w = 80, h = 24;
4685 #ifndef NOLOCAL
4686                       if (tcp_incoming) {
4687 #ifdef OS2
4688                           tt_cols[VTERM] = w;
4689                           tt_rows[VTERM] = h;
4690                           VscrnSetWidth(VTERM, w);
4691                           VscrnSetHeight(VTERM, h+(tt_status[VTERM]?1:0));
4692 #else /* OS2 */
4693                           tt_cols = w;
4694                           tt_rows = h;
4695 #endif /* OS2 */
4696                       } else {
4697 #ifdef OS2
4698                           tt_cols[VCMD] = w;
4699                           tt_rows[VCMD] = h;
4700                           VscrnSetWidth(VCMD, w);
4701                           VscrnSetHeight(VCMD, h);
4702 #endif /* OS2 */
4703                           cmd_cols = w;
4704                           cmd_rows = h;
4705                       }
4706 #else /* NOLOCAL */
4707                       cmd_cols = w;
4708                       cmd_rows = h;
4709 #endif /* NOLOCAL */
4710                       /* Add LINES and COLUMNS to the environment */
4711                       ckmakmsg((char *)rows_buf,16,"LINES=",ckitoa(h),
4712                                 NULL,NULL);
4713                       ckmakmsg((char *)cols_buf,16,"COLUMNS=",ckitoa(w),
4714                                 NULL,NULL);
4715 #ifdef OS2ORUNIX
4716 #ifndef NOPUTENV
4717                       putenv(rows_buf);
4718                       putenv(cols_buf);
4719 #endif /* NOPUTENV */
4720 #endif /* OS2ORUNIX */
4721                   }
4722                   break;
4723               }
4724               case TELOPT_ECHO:
4725                 if (!echo) {
4726                     if (TELOPT_UNANSWERED_DO(x))
4727                       TELOPT_UNANSWERED_DO(x) = 0;
4728                     return(1);
4729                 }
4730                 break;
4731             }
4732         } else {
4733             if (TELOPT_UNANSWERED_DONT(x))
4734                 TELOPT_UNANSWERED_DONT(x) = 0;
4735             if (TELOPT_UNANSWERED_DO(x))
4736                 TELOPT_UNANSWERED_DO(x) = 0;
4737         }
4738         if (TELOPT_U_MODE(x) == TN_NG_MU) {
4739             ckmakmsg( tn_msg,TN_MSG_LEN,
4740                       "Peer refuses TELNET DO ",TELOPT(x),
4741                       " negotiations - terminating connection",NULL
4742                     );
4743             debug(F100,tn_msg,"",0);
4744             if (tn_deb || debses) tn_debug(tn_msg);
4745             printf("%s\n",tn_msg);
4746             ttclos(0);
4747             whyclosed = WC_TELOPT;
4748             return(-3);
4749         }
4750 #ifdef COMMENT
4751         if (x == TELOPT_ECHO && !echo) /* Special handling for echo */
4752           return(1);                   /* because we allow 'duplex' */
4753 #endif /* COMMENT */
4754         break;
4755
4756       case DO:
4757 #ifdef CK_SSL
4758         if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
4759             return(0);
4760 #endif /* CK_SSL */
4761         if (!TELOPT_OK(x) || TELOPT_ME_MODE(x) == TN_NG_RF) {
4762             if (tn_sopt(WONT,x) < 0)
4763               return(-1);
4764             if (TELOPT_UNANSWERED_WILL(x))
4765                 TELOPT_UNANSWERED_WILL(x) = 0;
4766         } else if (!TELOPT_ME(x)) {
4767             if (!TELOPT_UNANSWERED_WILL(x)) {
4768                 if (tn_sopt(WILL,x) < 0)
4769                   return(-1);
4770             }
4771             if (TELOPT_UNANSWERED_WILL(x))
4772                 TELOPT_UNANSWERED_WILL(x) = 0;
4773             TELOPT_ME(x) = 1;
4774
4775             switch (x) {
4776 #ifdef CK_SSL
4777               case TELOPT_START_TLS:
4778                 /*
4779                    If my proposal is accepted at this point the Telnet
4780                    protocol is turned off and a TLS negotiation takes
4781                    place.
4782
4783                    Start by sending SB START_TLS FOLLOWS  to signal
4784                    we are ready.  Wait for the peer to send the same
4785                    and then start the TLS negotiation.
4786
4787                    If the TLS negotiation succeeds we call tn_ini()
4788                    again to reset the telnet state machine and restart
4789                    the negotiation process over the now secure link.
4790
4791                    If the TLS negotiation fails, we call ttclos()
4792                    to terminate the connection.  Then we set the
4793                    U_MODE and ME_MODE for TELOPT_START_TLS to REFUSE
4794                    and then call ttopen() to create a new connection
4795                    to the same host but this time do not attempt
4796                    TLS security.
4797
4798                    Only the client should receive DO START_TLS.
4799                 */
4800                 tn_ssbopt(TELOPT_START_TLS,1,NULL,0);
4801                 TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows = 1;
4802                 break;
4803 #endif /* CK_SSL */
4804
4805 #ifdef CK_AUTHENTICATION
4806               case TELOPT_AUTHENTICATION: {
4807                   /* We don't know what authentication we are using yet */
4808                   /* but it is not NULL until a failure is detected so */
4809                   /* use AUTO in the meantime. */
4810                   extern int authentication_version;
4811                   authentication_version = AUTHTYPE_AUTO;
4812                   break;
4813               }
4814 #endif /* CK_AUTHENTICATION */
4815 #ifdef CK_ENCRYPTION
4816               case TELOPT_ENCRYPTION:
4817                 if (!(TELOPT_ME(TELOPT_AUTHENTICATION) ||
4818                       TELOPT_U(TELOPT_AUTHENTICATION))
4819                     ) {
4820                     if (tn_sopt(WONT,x) < 0)
4821                       return(-1);
4822                     TELOPT_ME(x) = 0;
4823                 } else {
4824                     if (!(TELOPT_U(x) || TELOPT_UNANSWERED_DO(x))
4825                         && TELOPT_U_MODE(x) != TN_NG_RF) {
4826                         if (tn_sopt(DO, x) < 0)
4827                           return(-1);
4828                         TELOPT_UNANSWERED_DO(x) = 1;
4829                     }
4830                 }
4831                 break;
4832 #endif /* CK_ENCRYPTION */
4833 #ifdef IKS_OPTION
4834               case TELOPT_KERMIT:
4835 /* If currently processing Kermit server packets, must tell the other side */
4836
4837                 debug(F111,"tn_doop","what",what);
4838                 debug(F111,"tn_doop","server",server);
4839 #ifdef CK_AUTODL
4840                 debug(F111,"tn_doop","autodl",autodl);
4841                 debug(F111,"tn_doop","inautodl",inautodl);
4842                 debug(F111,"tn_doop","cmdadl",cmdadl);
4843 #endif /* CK_AUTODL */
4844
4845                 if (server
4846 #ifdef CK_AUTODL
4847                     || (local && ((what == W_CONNECT && autodl) ||
4848                                   (what != W_CONNECT && inautodl)))
4849                     || (!local && cmdadl)
4850 #endif /* CK_AUTODL */
4851                     ) {
4852                     tn_siks(KERMIT_START);      /* START */
4853                 }
4854                 if (!TELOPT_U(x)) {
4855                     /* Tell the other side what Start of Packet Character */
4856                     tn_siks(KERMIT_SOP);             /* SOP */
4857                     if (!TELOPT_UNANSWERED_DO(x) &&
4858                         TELOPT_U_MODE(x) != TN_NG_RF) {
4859                         if (tn_sopt(DO, x) < 0)
4860                           return(-1);
4861                         TELOPT_UNANSWERED_DO(x) = 1;
4862                     }
4863                 }
4864                 break;
4865 #endif /* IKS_OPTION */
4866
4867               case TELOPT_BINARY:
4868                 if (!TELOPT_U(x)) {
4869                     if (!TELOPT_UNANSWERED_DO(x) &&
4870                         TELOPT_U_MODE(x) >= TN_NG_RQ) {
4871                         if (tn_sopt(DO, x) < 0)
4872                           return(-1);
4873                         TELOPT_UNANSWERED_DO(x) = 1;
4874                     }
4875                 }
4876                 break;
4877               case TELOPT_NAWS:
4878 #ifdef CK_NAWS
4879                 if ( !tn_delay_sb || !tn_outst(0) || tn_init ) {
4880                     if (tn_snaws() < 0)
4881                         return(-1);
4882                 } else {
4883                     TELOPT_SB(TELOPT_NAWS).naws.need_to_send = 1;
4884                 }
4885 #endif /* CK_NAWS */
4886                 break;
4887               case TELOPT_LOGOUT:
4888                 ttclos(0);              /* And then hangup */
4889                 whyclosed = WC_TELOPT;
4890                 return(6);
4891 #ifdef CK_SNDLOC
4892                case TELOPT_SNDLOC:
4893                   if ( !tn_delay_sb || !tn_outst(0) || tn_init ) {
4894                       if (tn_sndloc() < 0)
4895                           return(-1);
4896                   } else {
4897                       TELOPT_SB(TELOPT_SNDLOC).sndloc.need_to_send = 1;
4898                   }
4899                   break;
4900 #endif /* CK_SNDLOC */
4901 #ifdef CK_FORWARD_X
4902                case TELOPT_FORWARD_X:
4903                   if ( !tn_delay_sb || !tn_outst(0) || tn_init ) {
4904                       if (fwdx_send_options() < 0) {
4905                           if (tn_sopt(DONT,x) < 0)
4906                               return(-1);
4907                           TELOPT_UNANSWERED_DONT(x) = 1;
4908                       }
4909                   } else {
4910                       TELOPT_SB(TELOPT_FORWARD_X).forward_x.need_to_send = 1;
4911                   }
4912                   break;
4913 #endif /* CK_FORWARD_X */
4914 #ifdef TN_COMPORT
4915               case TELOPT_COMPORT: {
4916                 extern int reliable;
4917                 if (!tn_delay_sb || !tn_outst(0) || tn_init) {
4918                     if (tn_sndcomport() < 0)
4919                       return(-1);
4920                 } else {
4921                     TELOPT_SB(TELOPT_COMPORT).comport.need_to_send = 1;
4922                 }
4923                 /* Telnet -> Serial -> ??? is not a reliable connection. */
4924                 reliable = SET_OFF;
4925                 break;
4926               }
4927 #endif /* TN_COMPORT */
4928             } /* switch */
4929         } else {
4930           if (TELOPT_UNANSWERED_WILL(x))
4931             TELOPT_UNANSWERED_WILL(x) = 0;
4932         }
4933         break;
4934
4935       case DONT:
4936 #ifdef CK_SSL
4937         if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
4938             return(0);
4939 #endif /* CK_SSL */
4940         if (TELOPT_ME(x) || TELOPT_UNANSWERED_WILL(x)) {
4941             /* David Borman says we should not respond WONT when
4942              * the DONT is a response to a WILL that we sent.
4943              * Nor should we send one if the state is already WONT
4944              * such as when we do not recognize the option since
4945              * options are initialized in the WONT/DONT state.
4946              */
4947             if (!(TELOPT_UNANSWERED_WILL(x) || TELOPT_UNANSWERED_WONT(x)))
4948               if (tn_sopt(WONT,x) < 0)
4949                 return(-1);
4950
4951             if (TELOPT_UNANSWERED_WILL(x))
4952                 TELOPT_UNANSWERED_WILL(x) = 0;
4953             if (TELOPT_UNANSWERED_WONT(x))
4954                 TELOPT_UNANSWERED_WONT(x) = 0;
4955             if (TELOPT_ME(x))
4956               TELOPT_ME(x) = 0;
4957
4958             switch (x) {
4959 #ifdef CK_SSL
4960             case TELOPT_START_TLS:
4961                 if (!sstelnet && TELOPT_ME_MODE(x) == TN_NG_MU) {
4962                     printf("Telnet Start-TLS refused.\n");
4963                     ttclos(0);
4964                     whyclosed = WC_TELOPT;
4965                     return(-3);
4966                 }
4967                 break;
4968 #endif /* CK_SSL */
4969 #ifdef CK_AUTHENTICATION
4970               case TELOPT_AUTHENTICATION:
4971                 if (!sstelnet && TELOPT_ME_MODE(x) == TN_NG_MU) {
4972 #ifdef CK_SSL
4973                     if (tls_active_flag) {
4974                         TELOPT_ME_MODE(x) = TN_NG_AC;
4975                         break;
4976                     } else
4977 #endif /* CK_SSL */
4978                     {
4979                         printf("Telnet authentication refused.\n");
4980                         ttclos(0);
4981                         whyclosed = WC_TELOPT;
4982                         return(-3);
4983                     }
4984                 } else if (TELOPT_ME_MODE(x) == TN_NG_RQ) {
4985                     TELOPT_ME_MODE(x) = TN_NG_AC;
4986                 }
4987                 if (ck_tn_auth_in_progress())
4988                   printf("Telnet authentication refused.\n");
4989 #ifdef CK_ENCRYPTION
4990                 if (!sstelnet) {
4991                     if (tn_no_encrypt()<0)
4992                         return(-1);
4993                 }
4994 #endif /* CK_ENCRYPTION */
4995                 break;
4996 #endif /* CK_AUTHENTICATION */
4997               case TELOPT_ENCRYPTION:
4998 #ifdef CK_ENCRYPTION
4999                 ck_tn_enc_stop();
5000 #endif /* CK_ENCRYPTION */
5001                 break;
5002               case TELOPT_KERMIT:
5003 #ifdef IKS_OPTION
5004                 TELOPT_SB(x).kermit.me_start = 0;
5005 #endif /* IKS_OPTION */
5006                 break;
5007               default:
5008                 break;
5009             } /* switch */
5010         } else {
5011           if (TELOPT_UNANSWERED_WILL(x))
5012               TELOPT_UNANSWERED_WILL(x) = 0;
5013           if (TELOPT_UNANSWERED_WONT(x))
5014               TELOPT_UNANSWERED_WONT(x) = 0;
5015         }
5016         if (TELOPT_ME_MODE(x) == TN_NG_MU) {
5017             ckmakmsg( tn_msg,TN_MSG_LEN,
5018                       "Peer refuses TELNET WILL ",TELOPT(x),
5019                       " negotiations - terminating connection",
5020                       NULL
5021                       );
5022             debug(F100,tn_msg,"",0);
5023             if (tn_deb || debses) tn_debug(tn_msg);
5024             printf("%s\n",tn_msg);
5025             ttclos(0);
5026             whyclosed = WC_TELOPT;
5027             return(-3);
5028         }
5029         break;
5030       case SB:
5031         if ((y = tn_sb(x,&n,fn)) <= 0)
5032           return(y);
5033
5034 #ifdef CK_SSL
5035         /* Do not process subnegotiations other than START_TLS after we */
5036         /* have agreed to begin the TLS negotiation sequence.           */
5037         if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows &&
5038              x != TELOPT_START_TLS)
5039             break;
5040 #endif /* CK_SSL */
5041
5042         if (!TELOPT_OK(x)) {
5043             hexdump("unknown telnet subnegotiation",sb,n);
5044             break;
5045         } else if ( !(TELOPT_ME(x) || TELOPT_U(x)) ) {
5046             hexdump("telnet option not negotiated",sb,n);
5047             if (!tn_sb_bug)
5048                 break;
5049             if (TELOPT_UNANSWERED_WILL(x)) {
5050                 TELOPT_UNANSWERED_WILL(x) = 0;
5051                 TELOPT_U(x) = 1;
5052                 ckmakmsg(tn_msg,TN_MSG_LEN,
5053                          "TELNET DO ",TELOPT(x),
5054                          "(implied by receipt of SB - protocol error ignored)",
5055                          NULL
5056                          );
5057                 debug(F100,tn_msg,"",0);
5058                 if (tn_deb || debses) tn_debug(tn_msg);
5059             }
5060             if (TELOPT_UNANSWERED_DO(x)) {
5061                 TELOPT_UNANSWERED_DO(x) = 0;
5062                 TELOPT_ME(x) = 1;
5063                 ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET WILL ",TELOPT(x),
5064                         " (implied by receipt of SB - protocol error ignored)",
5065                         NULL);
5066                 debug(F100,tn_msg,"",0);
5067                 if (tn_deb || debses) tn_debug(tn_msg);
5068              }
5069         }
5070
5071         TELOPT_UNANSWERED_SB(x)=0;
5072         switch (x) {
5073 #ifdef CK_FORWARD_X
5074           case TELOPT_FORWARD_X:
5075             return(fwdx_tn_sb(sb, n));
5076 #endif /* CK_FORWARD_X */
5077 #ifdef CK_SSL
5078           case TELOPT_START_TLS: {
5079               /*
5080                  the other side is saying SB START_TLS FOLLOWS
5081                  the incoming channel is now ready for starting the
5082                  TLS negotiation.
5083                  */
5084               int def_tls_u_mode, def_tls_me_mode;
5085               int def_enc_u_mode, def_enc_me_mode;
5086               int rc = 0;
5087
5088                           if (sb[0] != 1) {
5089                                   break;
5090                           }
5091
5092               TELOPT_SB(TELOPT_START_TLS).start_tls.u_follows = 1;
5093               /* Preserve the default modes and make sure we will */
5094               /* refuse START_TLS when we retry. */
5095               if (sstelnet) {
5096                   def_tls_u_mode = TELOPT_DEF_S_U_MODE(TELOPT_START_TLS);
5097                   def_tls_me_mode = TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS);
5098                   TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
5099                   TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS)= TN_NG_RF;
5100 #ifdef CK_ENCRYPTION
5101                   def_enc_u_mode = TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION);
5102                   def_enc_me_mode = TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION);
5103                   TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
5104                   TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION)= TN_NG_RF;
5105 #endif /* CK_ENCRYPTION */
5106               } else {
5107                   def_tls_u_mode = TELOPT_DEF_C_U_MODE(TELOPT_START_TLS);
5108                   def_tls_me_mode = TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS);
5109                   TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
5110                   TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS)= TN_NG_RF;
5111 #ifdef CK_ENCRYPTION
5112                   def_enc_u_mode = TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION);
5113                   def_enc_me_mode = TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION);
5114                   TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
5115                   TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION)= TN_NG_RF;
5116 #endif /* CK_ENCRYPTION */
5117               }
5118               /* Negotiate TLS */
5119               ttnproto = NP_TLS;
5120               tn_init = 0;
5121               tn_begun = 0;
5122               if (ck_tn_tls_negotiate()<0) {
5123                   /* we failed.  disconnect and if we are the client */
5124                   /* then reconnect and try without START_TLS.       */
5125                   extern char * line;
5126                   int x = -1;
5127                   extern int mdmtyp;
5128
5129                   if (sstelnet) {
5130                       printf("TLS failed:  Disconnecting.\n");
5131                       TELOPT_DEF_S_U_MODE(TELOPT_START_TLS)  = def_tls_u_mode;
5132                       TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = def_tls_me_mode;
5133 #ifdef CK_ENCRYPTION
5134                      TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION)  = def_enc_u_mode;
5135                      TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = def_enc_me_mode;
5136 #endif /* CK_ENCRYPTION */
5137                       ttclos(0);
5138                       whyclosed = WC_TELOPT;
5139                       ttnproto = NP_TELNET;
5140                       rc = -3;
5141                   } else {
5142 #ifndef NOLOCAL
5143                       extern tls_norestore;
5144 #endif /* NOLOCAL */
5145                       printf("TLS failed:  Disconnecting...\n");
5146 #ifdef CK_ENCRYPTION
5147                      TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION)  = def_enc_u_mode;
5148                      TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = def_enc_me_mode;
5149 #endif /* CK_ENCRYPTION */
5150                       /* if START_TLS is not REQUIRED, then retry without it */
5151                       if ( def_tls_me_mode != TN_NG_MU ) {
5152                           extern char ttname[];
5153 #ifndef NOLOCAL
5154                           tls_norestore = 1;
5155 #endif /* NOLOCAL */
5156                           ttclos(0);
5157                           whyclosed = WC_TELOPT;
5158 #ifndef NOLOCAL
5159                           tls_norestore = 0;
5160 #endif /* NOLOCAL */
5161                           ttnproto = NP_TELNET;
5162                           printf("Reconnecting without TLS.\n");
5163                           sleep(2);
5164                           if (ttopen(ttname,&x,mdmtyp,0)<0)
5165                               rc = -3;
5166                       } else {
5167                           TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) =
5168                             def_tls_u_mode;
5169                           TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) =
5170                             def_tls_me_mode;
5171                           ttclos(0);
5172                           whyclosed = WC_TELOPT;
5173                           ttnproto = NP_TELNET;
5174                           rc = -3;
5175                       }
5176                   }
5177               } else {
5178 #ifdef CK_AUTHENTICATION
5179                   /* we succeeded.  restart telnet negotiations from */
5180                   /* the beginning.  However, if we have received a  */
5181                   /* client certificate and we are a server, then do */
5182                   /* not offer TELOPT_AUTH.                          */
5183                   if ( ck_tn_auth_valid() == AUTH_VALID ) {
5184                       TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_AC;
5185                       TELOPT_DEF_S_ME_MODE(TELOPT_AUTHENTICATION)= TN_NG_AC;
5186                   }
5187 #endif /* CK_AUTHENTICATION */
5188                   ttnproto = NP_TELNET;
5189                   if (tn_ini() < 0)
5190                     if (ttchk() < 0)
5191                       rc = -1;
5192               }
5193               /* Restore the default modes */
5194               if (sstelnet) {
5195                   TELOPT_DEF_S_U_MODE(TELOPT_START_TLS)  = def_tls_u_mode;
5196                   TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = def_tls_me_mode;
5197 #ifdef CK_ENCRYPTION
5198                   TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION)  = def_enc_u_mode;
5199                   TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = def_enc_me_mode;
5200 #endif /* CK_ENCRYPTION */
5201               } else {
5202                   TELOPT_DEF_C_U_MODE(TELOPT_START_TLS)  = def_tls_u_mode;
5203                   TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = def_tls_me_mode;
5204 #ifdef CK_ENCRYPTION
5205                   TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION)  = def_enc_u_mode;
5206                   TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = def_enc_me_mode;
5207 #endif /* CK_ENCRYPTION */
5208               }
5209               return(rc);
5210           }
5211 #endif /* CK_SSL */
5212 #ifdef CK_AUTHENTICATION
5213           case TELOPT_AUTHENTICATION:
5214             if (ck_tn_sb_auth((char *)sb,n) < 0) {
5215                 if (sstelnet && TELOPT_U_MODE(x) == TN_NG_MU) {
5216                     ttclos(0);
5217                     whyclosed = WC_TELOPT;
5218                     return(-3);
5219                 } else if (!sstelnet && TELOPT_ME_MODE(x) == TN_NG_MU) {
5220                     ttclos(0);
5221                     whyclosed = WC_TELOPT;
5222                     return(-3);
5223                 } else {
5224                     if (TELOPT_ME_MODE(x) == TN_NG_RQ)
5225                       TELOPT_ME_MODE(x) = TN_NG_AC;
5226                     if (TELOPT_U_MODE(x) == TN_NG_RQ)
5227                       TELOPT_U_MODE(x) = TN_NG_AC;
5228                 }
5229                 if (TELOPT_ME(x)) {
5230                     TELOPT_ME(x) = 0;
5231                     if (tn_sopt(WONT,x) < 0)
5232                       return(-1);
5233                 }
5234                 if (TELOPT_U(x)) {
5235                     TELOPT_U(x) = 0;
5236                     if (tn_sopt(DONT,x) < 0)
5237                       return(-1);
5238                 }
5239 #ifdef CK_ENCRYPTION
5240                 if (tn_no_encrypt()<0)
5241                     return(-1);
5242 #endif /* CK_ENCRYPTION */
5243             } else {
5244 #ifdef CK_ENCRYPTION
5245                 if (!ck_tn_auth_in_progress()) { /* we are finished */
5246                     if (ck_tn_authenticated() == AUTHTYPE_SSL) {
5247                         /* TLS was successful.  Disable ENCRYPTION */
5248                         TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
5249                         TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
5250                     }
5251                     if (TELOPT_SB(TELOPT_ENCRYPTION).encrypt.need_to_send) {
5252                         ck_encrypt_send_support();
5253                         TELOPT_SB(TELOPT_ENCRYPTION).encrypt.need_to_send = 0;
5254                     }
5255                 }
5256 #endif /* CK_ENCRYPTION */
5257             }
5258             break;
5259 #endif /* CK_AUTHENTICATION */
5260 #ifdef CK_ENCRYPTION
5261           case TELOPT_ENCRYPTION:
5262             if (ck_tn_sb_encrypt(sb, n) < 0) {
5263                 if (TELOPT_U_MODE(x) == TN_NG_MU ||
5264                     TELOPT_ME_MODE(x) == TN_NG_MU)
5265                   {
5266                       ttclos(0);
5267                       whyclosed = WC_TELOPT;
5268                       return(-3);
5269                 } else {
5270                     if (TELOPT_ME_MODE(x) == TN_NG_RQ)
5271                       TELOPT_ME_MODE(x) = TN_NG_AC;
5272                     if (TELOPT_U_MODE(x) == TN_NG_RQ)
5273                       TELOPT_U_MODE(x) = TN_NG_AC;
5274                 }
5275                 if (TELOPT_ME(x)) {
5276                     TELOPT_ME(x) = 0;
5277                     if (tn_sopt(WONT,x) < 0)
5278                       return(-1);
5279                 }
5280                 if (TELOPT_U(x)) {
5281                     TELOPT_U(x) = 0;
5282                     if (tn_sopt(DONT,x) < 0)
5283                       return(-1);
5284                 }
5285             }
5286             break;
5287 #endif /* CK_ENCRYPTION */
5288 #ifdef IKS_OPTION
5289           case TELOPT_KERMIT:
5290             return(iks_tn_sb(sb, n-2));
5291 #endif /* IKS_OPTION */
5292 #ifdef TN_COMPORT
5293           case TELOPT_COMPORT:
5294             return(tnc_tn_sb(sb, n-2));
5295 #endif /* TN_COMPORT */
5296           case TELOPT_TTYPE:
5297             switch (sb[0]) {
5298               case TELQUAL_SEND:        /* SEND terminal type? */
5299                 if ( !tn_delay_sb || !tn_outst(0) || tn_init ) {
5300                     if (tn_sttyp() < 0) /* Yes, so send it. */
5301                         return(-1);
5302                 } else {
5303                     TELOPT_SB(TELOPT_TTYPE).term.need_to_send = 1;
5304                 }
5305                 break;
5306               case TELQUAL_IS: {        /* IS terminal type? */
5307                   /* IS terminal type -- remote gave us its current type */
5308                   int i = 0;
5309 #ifndef OS2
5310                   CHAR oldterm[64], *p;
5311 #endif /* OS2 */
5312                   /* Isolate the specified terminal type string */
5313                   while (sb[i++] != IAC) {
5314                       if (i == 40 ||    /* max len of term string - RFC */
5315                           sb[i] == IAC) {
5316                           sb[i] = '\0';
5317                           break;
5318                       }
5319                   }
5320 #ifdef OS2
5321 #ifndef NOTERM
5322                   strupr(&(sb[1]));     /* Upper case it */
5323                   for (i = 0; i <= max_tt; i++) { /* find it in our list */
5324                       if (!strcmp(&(sb[1]),tt_info[i].x_name)
5325                           && i != TT_VTNT) /* can't support VTNT as server */
5326                         {
5327                           /* Set terminal type to the one chosen */
5328                           if (i != tt_type)
5329                             settermtype(i,0);
5330                           break;
5331                       }
5332                   }
5333                   if (i > max_tt &&
5334                       strcmp(&(sb[1]),TELOPT_SB(TELOPT_TTYPE).term.type)) {
5335                       /* Couldn't find the specified term type */
5336                       sb[40] = '\0';
5337                       strcpy(TELOPT_SB(TELOPT_TTYPE).term.type,&(sb[1]));
5338                       /* SB TTYPE SEND */
5339                       tn_ssbopt(TELOPT_TTYPE,TELQUAL_SEND,NULL,0);
5340                       TELOPT_UNANSWERED_SB(TELOPT_TTYPE)=1;
5341                   }
5342 #endif /* NOTERM */
5343 #else /* OS2 */
5344                   p = (CHAR *) getenv("TERM");
5345                   if (p)
5346                     ckstrncpy((char *)oldterm,(char *)p,63);
5347                   else
5348                     oldterm[0] = '\0';
5349                   cklower((char *)&(sb[1])); /* Lower case new term */
5350                   ckmakmsg(term_buf,64,"TERM=",(char *)&(sb[1]),NULL,NULL);
5351 #ifdef OS2ORUNIX
5352 #ifndef NOPUTENV
5353                   putenv(term_buf);
5354 #endif /* NOPUTENV */
5355 #endif /* OS2ORUNIX */
5356 #ifdef CK_CURSES
5357 #ifndef MYCURSES
5358 #ifndef COHERENT
5359                   if (trmbuf) {
5360                       if (tgetent(trmbuf,(char *)&sb[1]) < 1) {
5361                           /* Unsupported terminal.  If new and old terminal */
5362                           /* types do not match, ask for another type. */
5363                           if (strcmp((char *)oldterm,(char *)&sb[1])) {
5364                               /* SB TTYPE SEND */
5365                               tn_ssbopt(TELOPT_TTYPE,TELQUAL_SEND,NULL,0);
5366                               TELOPT_UNANSWERED_SB(TELOPT_TTYPE)=1;
5367                           }
5368                       }
5369                   }
5370 #endif /* COHERENT */
5371 #endif /* MYCURSES */
5372 #endif /* CK_CURSES */
5373 #endif /* OS2 */
5374               }
5375             }
5376             break;
5377 #ifdef CK_ENVIRONMENT
5378 #ifdef CK_XDISPLOC
5379           case TELOPT_XDISPLOC:         /* Send X-Display Location */
5380             if (sb[0] == TELQUAL_SEND) {/* SEND X-Display Loc? */
5381                 if ( !tn_delay_sb || !tn_outst(0) || tn_init ) {
5382                     if (tn_sxdisploc() < 0)     /* Yes, so send it. */
5383                         return(-1);
5384                 } else {
5385                     TELOPT_SB(TELOPT_XDISPLOC).xdisp.need_to_send = 1;
5386                 }
5387             }
5388             /* IS -- X Display Location (not supported) */
5389             else if (sb[0] == TELQUAL_IS) {
5390                 int i = 0;
5391                 /* Isolate the specified X-display string */
5392                 while (sb[i++] != IAC) {
5393                     if (i >= TSBUFSIZ)
5394                       return (-1);
5395                     if (sb[i] == IAC) {
5396                         sb[i] = '\0';
5397                         break;
5398                     }
5399                 }
5400                 debug(F110,"TELNET SB XDISPLOC IS",&sb[1],0);
5401             }
5402             break;
5403 #endif /* CK_XDISPLOC */
5404 #endif /* CK_ENVIRONMENT */
5405           case TELOPT_NAWS:
5406               if (sstelnet
5407 #ifdef IKSD
5408                    || inserver
5409 #endif /* IKSD */
5410                    ) {
5411                   int w = 0, h = 0;
5412                   int i = 0;
5413                   /* At this point sb[] should contain width and height */
5414                   if (sb[i] == IAC) i++;
5415                   w = (sb[i++] << 8);   /* save upper height */
5416                   if (sb[i] == IAC) i++;
5417                   w += sb[i++];         /* save the width */
5418                   if (sb[i] == IAC) i++;
5419                   h = (sb[i++] << 8);   /* save upper height */
5420                   if (sb[i] == IAC) i++;
5421                   h += sb[i++];
5422                   debug(F111,"tn_doop NAWS SB","width",w);
5423                   debug(F111,"tn_doop NAWS SB","height",h);
5424
5425                   if (w == 0)
5426                     w = 80;
5427                   if (h == 0)
5428                     h = 24;
5429 #ifndef NOLOCAL
5430                   if (tcp_incoming || inserver) {
5431 #ifdef OS2
5432                       tt_cols[VTERM] = w;
5433                       tt_rows[VTERM] = h;
5434                       VscrnSetWidth(VTERM, w);
5435                       VscrnSetHeight(VTERM, h+(tt_status[VTERM]?1:0));
5436 #ifdef IKSD
5437                       if (inserver) {
5438                           cmd_cols = tt_cols[VCMD] = w;
5439                           cmd_rows = tt_rows[VCMD] = h;
5440                           VscrnSetWidth(VCMD, w);
5441                           VscrnSetHeight(VCMD, h);
5442                       }
5443 #endif /* IKSD */
5444 #else /* OS2 */
5445                       tt_cols = w;
5446                       tt_rows = h;
5447 #endif /* OS2 */
5448                   } else {
5449 #ifdef OS2
5450                       tt_cols[VCMD] = w;
5451                       tt_rows[VCMD] = h;
5452                       VscrnSetWidth(VCMD, w);
5453                       VscrnSetHeight(VCMD, h);
5454 #endif /* OS2 */
5455                       cmd_cols = w;
5456                       cmd_rows = h;
5457                   }
5458 #else /* NOLOCAL */
5459                   cmd_cols = w;
5460                   cmd_rows = h;
5461 #endif /* NOLOCAL */
5462
5463                   /* Add LINES and COLUMNS to the environment */
5464                   ckmakmsg((char *)rows_buf,16,"LINES=",ckitoa(h),NULL,NULL);
5465                   ckmakmsg((char *)cols_buf,16,"COLUMNS=",ckitoa(w),NULL,NULL);
5466 #ifdef OS2ORUNIX
5467 #ifndef NOPUTENV
5468                   putenv(rows_buf);
5469                   putenv(cols_buf);
5470 #endif /* NOPUTENV */
5471 #endif /* OS2ORUNIX */
5472               }
5473               break;
5474 #ifdef CK_ENVIRONMENT
5475           case TELOPT_NEWENVIRON:
5476             switch (sb[0]) {
5477               case TELQUAL_IS:                  /* IS */
5478               case TELQUAL_INFO:                /* INFO */
5479                 if (sb[0] == TELQUAL_IS)
5480                   debug(F101,"tn_doop NEW-ENV SB IS","",n-3);
5481                 else
5482                   debug(F101,"tn_doop NEW-ENV SB INFO","",n-3);
5483                 if (sstelnet || inserver) { /* Yes, receive it. */
5484                     if (tn_rnenv((CHAR *)&sb[1],n-3) < 0)
5485                       return(-1);
5486                 }
5487                 break;
5488               case TELQUAL_SEND:        /* SEND */
5489                 if ( sstelnet || inserver )         /* ignore if server */
5490                     break;
5491                 /* We need to take the sb[] and build a structure */
5492                 /* containing all of the variables and types that */
5493                 /* we are supposed to keep track of and send to   */
5494                 /* the host, then call tn_snenv().                  */
5495                 /* Or we can punt ...                               */
5496                 if ( !tn_delay_sb || !tn_outst(0) || tn_init ) {
5497                   if (tn_snenv((CHAR *)&sb[1],n-3) < 0) /* Yes, send it. */
5498                      return(-1);
5499                 } else {
5500 #ifndef VMS
5501                   CHAR * xxx;
5502                   xxx = (CHAR *) malloc(n-1);
5503 #else
5504                   unsigned char * xxx;
5505                   xxx = (unsigned char *) malloc(n-1);
5506 #endif /* VMS */
5507                   /* Postpone sending until end of tn_ini() */
5508                   TELOPT_SB(TELOPT_NEWENVIRON).env.str = xxx;
5509                   if (TELOPT_SB(TELOPT_NEWENVIRON).env.str) {
5510                   memcpy((char *)TELOPT_SB(TELOPT_NEWENVIRON).env.str,
5511                             (char *)&sb[1],n-3);
5512                   TELOPT_SB(TELOPT_NEWENVIRON).env.str[n-3] = IAC;
5513                   TELOPT_SB(TELOPT_NEWENVIRON).env.str[n-2] = '\0';
5514                   TELOPT_SB(TELOPT_NEWENVIRON).env.len = n-3;
5515                   TELOPT_SB(TELOPT_NEWENVIRON).env.need_to_send = 1;
5516                   }
5517                 }
5518                 break;
5519               }
5520               break;
5521 #endif /* CK_ENVIRONMENT */
5522 #ifdef CK_SNDLOC
5523           case TELOPT_SNDLOC: {
5524               if ( deblog ) {
5525                   sb[n-2] = '\0';
5526                   debug(F110,"TELNET Send-Location",sb,0);
5527               }
5528               break;
5529           }
5530 #endif /* CK_SNDLOC */
5531           } /* switch */
5532         break;
5533     }
5534     return(0);
5535 }
5536
5537 int
5538 #ifdef CK_ANSIC                         /* TELNET DO OPTION */
5539 tn_doop(CHAR z, int echo, int (*fn)(int))
5540 #else
5541 tn_doop(z, echo, fn) CHAR z; int echo; int (*fn)();
5542 #endif /* CK_ANSIC */
5543 /* tn_doop */ {
5544     int x=0, y=0;
5545
5546     if (z != (CHAR) IAC) {
5547         debug(F101,"tn_doop bad call","",z);
5548         return(-1);
5549     }
5550     if (ttnet != NET_TCPB)              /* Check network type */
5551       return(0);
5552     if (ttnproto != NP_TELNET &&
5553          ttnproto != NP_NONE)           /* Check protocol */
5554         return(0);
5555
5556     x = tn_xdoop(z,echo,fn);
5557     if (x >= 0 && !tn_begun) {
5558         y = tn_start();
5559     }
5560     return(y < 0 ? y : x);
5561 }
5562
5563 #ifdef CK_ENVIRONMENT
5564
5565 /* Telnet receive new environment */
5566 /* Returns -1 on error, 0 if nothing happens, 1 on success */
5567 /* In order for this code to work, sb[len] == IAC          */
5568 /* We currently only support the USER environment variable */
5569
5570 int
5571 #ifdef CK_ANSIC
5572 tn_rnenv(CHAR * sb, int len)
5573 #else
5574 tn_rnenv(sb, len) CHAR * sb; int len;
5575 #endif /* CK_ANSIC */
5576 /* tn_rnenv */ {                        /* Receive new environment */
5577     char varname[17];
5578     char value[65];
5579     char * reply = 0, * s = 0;
5580     int i,j,k,n;                                /* Worker. */
5581     int type = 0; /* 0 for NONE, 1 for VAR, 2 for USERVAR, */
5582                   /* 3 for VALUE in progress */
5583
5584     if (ttnet != NET_TCPB) return(0);
5585     if (ttnproto != NP_TELNET) return(0);
5586     if (sb == NULL) return(-1);
5587
5588     if (len == 0) return(1);
5589
5590     /*
5591     Pairs of <type> [VAR=0, VALUE=1, ESC=2, USERVAR=3] <value> "unterminated"
5592     follow here until done...
5593     */
5594     for (i = 0, j = 0, k = 0, type = 0, varname[0]= '\0'; i <= len; i++) {
5595         switch (sb[i]) {
5596         case TEL_ENV_VAR:               /* VAR */
5597         case TEL_ENV_USERVAR:           /* USERVAR */
5598         case IAC:                       /* End of the list */
5599             switch (type) {
5600               case 0:                   /* Nothing in progress */
5601                 /* If we get IAC only, then that means there were */
5602                 /* no environment variables to send.  we are done */
5603                 if (j == 0 && sb[i] == IAC)
5604                     return(1);
5605               case 1:                   /* VAR in progress */
5606               case 2:                   /* USERVAR in progress */
5607               case 3:                   /* VALUE in progress */
5608                 value[k] = '\0';
5609                 varname[j] = '\0';
5610                 debug(F111,"tn_rnenv varname",varname,type);
5611                 debug(F111,"tn_rnenv value",value,type);
5612                 if (!strcmp(varname,"USER")) {
5613 #ifdef CK_AUTHENTICATION
5614                     if (ck_tn_auth_valid() != AUTH_VALID) {
5615                         extern char szUserNameRequested[];
5616                         debug(F100,"tn_rnenv != AUTH_VALID","",0);
5617                         ckstrncpy(szUserNameRequested,value,UIDBUFLEN);
5618                         ckstrncpy(uidbuf,value,UIDBUFLEN);
5619 #ifdef CK_SSL
5620                         if (ssl_active_flag) {
5621                             if ( tls_is_user_valid(ssl_con, uidbuf) ) {
5622                                 extern char szUserNameAuthenticated[];
5623                                 ckstrncpy(szUserNameAuthenticated,uidbuf,
5624                                            UIDBUFLEN);
5625                                 auth_finished(AUTH_VALID);
5626                             }
5627                         } else if (tls_active_flag) {
5628                             if ( tls_is_user_valid(tls_con, uidbuf) ) {
5629                                 extern char szUserNameAuthenticated[];
5630                                 ckstrncpy(szUserNameAuthenticated,uidbuf,
5631                                            UIDBUFLEN);
5632                                 auth_finished(AUTH_VALID);
5633                             }
5634                         }
5635 #endif /* CK_SSL */
5636                     } else {    /* AUTH_VALID */
5637                         int x = 0;
5638                         debug(F110,"tn_rnenv AUTH_VALID uidbuf",uidbuf,0);
5639
5640 #ifdef OS2
5641                         x = ckstrcmp(value,uidbuf,-1,0); /* case insensitive */
5642 #ifdef NT
5643                         /* NTLM authentication returns names of the form */
5644                         /* DOMAIN\user.  We need to check to see of the  */
5645                         /* USER VAR contains a domain name or not.  If   */
5646                         /* not, then we do not want to change state if   */
5647                         /* the uidbuf matches the USER VAR when the      */
5648                         /* DOMAIN is ignored.                            */
5649                         if ( x && ck_tn_authenticated() == AUTHTYPE_NTLM ) {
5650                             char * s1=NULL, * s2=NULL;
5651                             int    len1, len2, i;
5652
5653                             len1 = strlen(value);
5654                             for ( i=len1-1 ; i>=0 ; i--) {
5655                                 if ( value[i] == '\\' ) {
5656                                     s1 = &value[i+1];   /* DOMAIN found */
5657                                     break;
5658                                 }
5659                             }
5660
5661                             if ( s1 == NULL ) {
5662                                 len2 = strlen(uidbuf);
5663                                 for ( i=len2-1 ; i>=0 ; i--) {
5664                                     if ( uidbuf[i] == '\\' ) {
5665                                         s2 = &uidbuf[i+1];   /* DOMAIN found */
5666                                         break;
5667                                     }
5668                                 }
5669
5670                                 if ( s2 )
5671                                     x = ckstrcmp(value,s2,-1,0);
5672                             }
5673                         }
5674 #endif /* NT */
5675 #else /* OS2 */
5676                         x = ckstrcmp(value,uidbuf,-1,1); /* case sensitive */
5677 #endif /* OS2 */
5678                         if ( x ) {
5679                             extern char szUserNameRequested[];
5680                             ckstrncpy(uidbuf,value,UIDBUFLEN);
5681                             ckstrncpy(szUserNameRequested,value,UIDBUFLEN);
5682                             auth_finished(AUTH_USER);
5683 #ifdef CK_SSL
5684                             if (ssl_active_flag || tls_active_flag) {
5685                                 if ( tls_is_user_valid(ssl_con, uidbuf) )
5686                                     auth_finished(AUTH_VALID);
5687                             }
5688 #endif /* CK_SSL */
5689                         }
5690                     }
5691 #else /* CK_AUTHENTICATION */
5692                     ckstrncpy(uidbuf,value,UIDBUFLEN);
5693 #endif /* CK_AUTHENTICATION */
5694                 }
5695                 break;
5696             }
5697             varname[0] = '\0';
5698             value[0] = '\0';
5699             j = 0;
5700             k = 0;
5701             type = (sb[i] == TEL_ENV_USERVAR ? 2 :      /* USERVAR */
5702                     sb[i] == TEL_ENV_VAR ? 1 :  /* VAR */
5703                      0
5704                      );
5705             break;
5706         case TEL_ENV_VALUE: /* VALUE */
5707             if ( type == 1 || type == 2 )
5708                 type = 3;
5709             break;
5710         case TEL_ENV_ESC:       /* ESC */
5711             /* Take next character literally */
5712             if ( ++i >= len )
5713                 break;
5714             /* otherwise, fallthrough so byte will be added to string. */
5715         default:
5716             switch (type) {
5717             case 1:     /* VAR in progress */
5718             case 2:     /* USERVAR in progress */
5719                 if ( j < 16 )
5720                     varname[j++] = sb[i];
5721                 break;
5722             case 3:
5723                 if ( k < 64 )
5724                     value[k++] = sb[i];
5725                 break;
5726             }
5727         }
5728     }
5729     return(0);
5730 }
5731
5732 /* These are for Microsoft SFU version 2 Telnet Server */
5733 #define SFUTLNTVER "SFUTLNTVER"
5734 #define SFUTLNTMODE "SFUTLNTMODE"
5735 #define SFUTLNTVER_VALUE  "2"
5736 #define SFUTLNTMODE_VALUE "console"     /* The other value is "stream" */
5737
5738 /* Telnet send new environment */
5739 /* Returns -1 on error, 0 if nothing happens, 1 on success */
5740 /* In order for this code to work, sb[len] == IAC          */
5741
5742 int
5743 #ifdef CK_ANSIC
5744 tn_snenv(CHAR * sb, int len)
5745 #else
5746 tn_snenv(sb, len) CHAR * sb; int len;
5747 #endif /* CK_ANSIC */
5748 /* tn_snenv */ {                        /* Send new environment */
5749     char varname[16];
5750     char * reply = 0, * s = 0;
5751     int i,j,n;                          /* Worker. */
5752     int type = 0;       /* 0 for NONE, 1 for VAR, 2 for USERVAR in progress */
5753     extern int ck_lcname;
5754     char localuidbuf[UIDBUFLEN];        /* (Initialized just below) */
5755     char * uu = uidbuf;
5756     char * disp = NULL;
5757
5758     localuidbuf[0] = '\0';
5759     if (ttnet != NET_TCPB) return(0);
5760     if (ttnproto != NP_TELNET) return(0);
5761     if (!sb) return(-1);
5762
5763 #ifdef CK_SSL
5764     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
5765         return(0);
5766     }
5767 #endif /* CK_SSL */
5768
5769 #ifdef CK_FORWARD_X
5770     if (TELOPT_U(TELOPT_FORWARD_X)) {
5771         disp = NULL;
5772     } else
5773 #endif /* CK_FORWARD_X */
5774         disp = (char *)tn_get_display();
5775
5776     if (ck_lcname) {
5777         ckstrncpy(localuidbuf,uidbuf,UIDBUFLEN);
5778         cklower(localuidbuf);
5779         uu = localuidbuf;
5780     }
5781
5782     hexdump((CHAR *)"tn_snenv sb[]",sb,len);
5783     debug(F110,"tn_snenv uidbuf",uidbuf,0);
5784     debug(F110,"tn_snenv localuidbuf",localuidbuf,0);
5785     debug(F110,"tn_snenv tn_env_sys",tn_env_sys,0);
5786     debug(F110,"tn_snenv tn_env_disp",tn_env_disp,0);
5787     debug(F110,"tn_snenv disp",disp,0);
5788
5789     /* First determine the size of the buffer we will need */
5790     for (i = 0, j = 0, n = 0, type = 0, varname[0]= '\0'; i <= len; i++) {
5791         switch (sb[i]) {
5792           case TEL_ENV_VAR:             /* VAR */
5793           case TEL_ENV_USERVAR:         /* USERVAR */
5794         case IAC:                     /* End of the list */
5795             switch (type) {
5796             case 0:                   /* Nothing in progress */
5797                 /* If we get IAC only, then that means send all */
5798                 /* VAR and USERVAR.                             */
5799                 if (!(j == 0 && sb[i] == IAC))
5800                   break;
5801             case 1:                   /* VAR in progress */
5802                 varname[j] = '\0' ;
5803                 if (!varname[0]) {      /* Send All */
5804                     if (uu[0])
5805                       n += strlen(uu) + 4 + 2;
5806                     if (tn_env_job[0])
5807                       n += strlen(tn_env_job) + 3 + 2;
5808                     if (tn_env_acct[0])
5809                       n += strlen(tn_env_acct) + 4 + 2;
5810                     if (tn_env_prnt[0])
5811                       n += strlen(tn_env_prnt) + 7 + 2;
5812                     if (tn_env_sys[0])
5813                       n += strlen(tn_env_sys) + 10 + 2;
5814                     if (disp)
5815                       n += strlen(disp) + 7 + 2;
5816                 } else if (!strcmp(varname,"USER") && uu[0])
5817                   n += strlen(uu) + 4 + 2;
5818                 else if (!strcmp(varname,"JOB") && tn_env_job[0])
5819                   n += strlen(tn_env_job) + 3 + 2;
5820                 else if (!strcmp(varname,"ACCT") && tn_env_acct[0])
5821                   n += strlen(tn_env_acct) + 4 + 2;
5822                 else if (!strcmp(varname,"PRINTER") && tn_env_prnt[0])
5823                   n += strlen(tn_env_prnt) + 7 + 2;
5824                 else if (!strcmp(varname,"SYSTEMTYPE") && tn_env_sys[0])
5825                   n += strlen(tn_env_sys) + 10 + 2;
5826                 else if (!strcmp(varname,"DISPLAY") && disp)
5827                   n += strlen(disp) + 7 + 2;
5828                 /* If we get IAC only, then that means send all */
5829                 /* VAR and USERVAR.                             */
5830                   if (!(j == 0 && sb[i] == IAC))
5831                       break;
5832             case 2:                   /* USERVAR in progress */
5833                 varname[j] = '\0' ;
5834                 if (!varname[0]) {      /* Send All */
5835                     int x;
5836                     for ( x=0 ; x<8 ; x++ ) {
5837                         if ( tn_env_uservar[x][0] &&
5838                              tn_env_uservar[x][1] )
5839                             n += strlen(tn_env_uservar[x][0])
5840                                 + strlen(tn_env_uservar[x][1]) + 2;
5841                     }
5842                     if ( tn_sfu ) {
5843                         /* For compatibility with Microsoft Telnet Server */
5844                         n += strlen(SFUTLNTVER) + strlen(SFUTLNTVER_VALUE) + 2;
5845                         n += strlen(SFUTLNTMODE) +
5846                           strlen(SFUTLNTMODE_VALUE) + 2;
5847                     }
5848 #ifdef CK_SNDLOC
5849                     if ( tn_loc && tn_loc[0] )
5850                         n += strlen("LOCATION") + strlen(tn_loc) + 2;
5851 #endif /* CK_SNDLOC */
5852                 }
5853                 else if (tn_sfu && !strcmp(varname,SFUTLNTVER))
5854                     n += strlen(SFUTLNTVER) + strlen(SFUTLNTVER_VALUE) + 2;
5855                 else if (tn_sfu && !strcmp(varname,SFUTLNTMODE))
5856                     n += strlen(SFUTLNTMODE) + strlen(SFUTLNTMODE_VALUE) + 2;
5857 #ifdef CK_SNDLOC
5858                 else if ( tn_loc && tn_loc[0] && !strcmp(varname,"LOCATION"))
5859                     n += strlen("LOCATION") + strlen(tn_loc) + 2;
5860 #endif /* CK_SNDLOC */
5861                 else {
5862                     int x;
5863                     for ( x=0 ; x<8 ; x++ ) {
5864                         if ( tn_env_uservar[x][0] &&
5865                              tn_env_uservar[x][1] &&
5866                              !strcmp(varname,tn_env_uservar[x][0]))
5867                             n += strlen(tn_env_uservar[x][0])
5868                                 + strlen(tn_env_uservar[x][1]) + 2;
5869                     }
5870                 }
5871                 break;
5872             }
5873             varname[0] = '\0';
5874             j = 0;
5875             type = (sb[i] == TEL_ENV_USERVAR ? 2 :      /* USERVAR */
5876                     sb[i] == TEL_ENV_VAR ? 1 :          /* VAR */
5877                     0
5878                    );
5879             break;
5880           case TEL_ENV_VALUE:           /* VALUE */
5881             /* Protocol Error */
5882             debug(F100, "TELNET Subnegotiation error - VALUE in SEND", "",0);
5883             if (tn_deb || debses)
5884               tn_debug("TELNET Subnegotiation error - VALUE in SEND");
5885             return(0);
5886           case TEL_ENV_ESC:     /* ESC */
5887             if (++i >= len)
5888               break;
5889           default:
5890             if (j < 16 )
5891               varname[j++] = sb[i];
5892         }
5893     }
5894     reply = malloc(n + 16);              /* Leave room for IAC stuff */
5895     if (!reply) {
5896         debug(F100, "TELNET Subnegotiation error - malloc failed", "",0);
5897         if (tn_deb || debses)
5898           tn_debug("TELNET Subnegotiation error - malloc failed");
5899
5900         /* Send a return packet with no variables so that the host */
5901         /* may continue with additional negotiations               */
5902         if (tn_ssbopt(TELOPT_NEWENVIRON,TELQUAL_IS,"",0) < 0)
5903           return(-1);
5904         return(0);
5905     }
5906
5907     /* Now construct the real reply */
5908
5909     n = 0;                              /* Start at beginning of buffer */
5910 /*
5911   Pairs of <type> [VAR=0, VALUE=1, ESC=2, USERVAR=3] <value> "unterminated"
5912   follow here until done...
5913 */
5914     for (i = 0, j = 0, type = 0, varname[0]= '\0'; i <= len; i++) {
5915         switch (sb[i]) {
5916           case TEL_ENV_VAR:             /* VAR */
5917           case TEL_ENV_USERVAR:         /* USERVAR */
5918           case IAC:                     /* End of the list */
5919             switch (type) {
5920               case 0:                   /* Nothing in progress */
5921                 /* If we get IAC only, then that means send all */
5922                 /* VAR and USERVAR.                             */
5923                 if (!(j == 0 && sb[i] == IAC))
5924                   break;
5925               case 1:                   /* VAR in progress */
5926                 varname[j] = '\0';
5927                 if (!varname[0]) {
5928                     /* Send All */
5929                     if (uu[0]) {
5930                         reply[n] = TEL_ENV_VAR; /* VAR */
5931                         strcpy(&reply[n+1],"USER");
5932                         reply[n+5] = TEL_ENV_VALUE;             /* VALUE */
5933                         strcpy(&reply[n+6],uu);
5934                         n += strlen(uu) + 4 + 2;
5935                     }
5936                     if (tn_env_job[0]) {
5937                         reply[n] = TEL_ENV_VAR; /* VAR */
5938                         strcpy(&reply[n+1],"JOB");
5939                         reply[n+4] = TEL_ENV_VALUE;     /* VALUE */
5940                         strcpy(&reply[n+5],tn_env_job);
5941                         n += strlen(tn_env_job) + 3 + 2;
5942                     }
5943                     if (tn_env_acct[0]) {
5944                         reply[n] = TEL_ENV_VAR; /* VAR */
5945                         strcpy(&reply[n+1],"ACCT");
5946                         reply[n+5] = TEL_ENV_VALUE;     /* VALUE */
5947                         strcpy(&reply[n+6],tn_env_acct);
5948                         n += strlen(tn_env_acct) + 4 + 2;
5949                     }
5950                     if (tn_env_prnt[0]) {
5951                         reply[n] = TEL_ENV_VAR; /* VAR */
5952                         strcpy(&reply[n+1],"PRINTER");
5953                         reply[n+8] = TEL_ENV_VALUE;     /* VALUE */
5954                         strcpy(&reply[n+9],tn_env_prnt);
5955                         n += strlen(tn_env_prnt) + 7 + 2;
5956                     }
5957                     if (tn_env_sys[0]) {
5958                         reply[n] = TEL_ENV_VAR; /* VAR */
5959                         strcpy(&reply[n+1],"SYSTEMTYPE");
5960                         reply[n+11] = TEL_ENV_VALUE; /* VALUE */
5961                         strcpy(&reply[n+12],tn_env_sys);
5962                         n += strlen(tn_env_sys) + 10 + 2;
5963                     }
5964                     if (disp) {
5965                         reply[n] = TEL_ENV_VAR; /* VAR */
5966                         strcpy(&reply[n+1],"DISPLAY");
5967                         reply[n+8] = TEL_ENV_VALUE;     /* VALUE */
5968                         strcpy(&reply[n+9],disp);
5969                         n += strlen(disp) + 7 + 2;
5970                     }
5971                 } else if (!strcmp(varname,"USER") && uu[0]) {
5972                     reply[n] = TEL_ENV_VAR;     /* VAR */
5973                     strcpy(&reply[n+1],"USER");
5974                     reply[n+5] = TEL_ENV_VALUE; /* VALUE */
5975                     strcpy(&reply[n+6],uu);
5976                     n += strlen(uu) + 4 + 2;
5977                 } else if (!strcmp(varname,"JOB") && tn_env_job[0]) {
5978                     reply[n] = TEL_ENV_VAR;     /* VAR */
5979                     strcpy(&reply[n+1],"JOB");
5980                     reply[n+4] = TEL_ENV_VALUE; /* VALUE */
5981                     strcpy(&reply[n+5],tn_env_job);
5982                     n += strlen(tn_env_job) + 3 + 2;
5983                 } else if (!strcmp(varname,"ACCT") && tn_env_acct[0]) {
5984                     reply[n] = TEL_ENV_VAR;     /* VAR */
5985                     strcpy(&reply[n+1],"ACCT");
5986                     reply[n+5] = TEL_ENV_VALUE; /* VALUE */
5987                     strcpy(&reply[n+6],tn_env_acct);
5988                     n += strlen(tn_env_acct) + 4 + 2;
5989                 } else if (!strcmp(varname,"PRINTER") && tn_env_prnt[0]) {
5990                     reply[n] = TEL_ENV_VAR;     /* VAR */
5991                     strcpy(&reply[n+1],"PRINTER");
5992                     reply[n+8] = TEL_ENV_VALUE; /* VALUE */
5993                     strcpy(&reply[n+9],tn_env_prnt);
5994                     n += strlen(tn_env_prnt) + 7 + 2;
5995                 } else if (!strcmp(varname,"SYSTEMTYPE") && tn_env_sys[0]) {
5996                     reply[n] = TEL_ENV_VAR;     /* VAR */
5997                     strcpy(&reply[n+1],"SYSTEMTYPE");
5998                     reply[n+11] = TEL_ENV_VALUE;        /* VALUE */
5999                     strcpy(&reply[n+12],tn_env_sys);
6000                     n += strlen(tn_env_sys) + 10 + 2;
6001                 } else if (!strcmp(varname,"DISPLAY") && disp) {
6002                     reply[n] = TEL_ENV_VAR;     /* VAR */
6003                     strcpy(&reply[n+1],"DISPLAY");
6004                     reply[n+8] = TEL_ENV_VALUE; /* VALUE */
6005                     strcpy(&reply[n+9],disp);
6006                     n += strlen(disp) + 7 + 2;
6007                 }
6008                   /* If we get IAC only, then that means send all */
6009                   /* VAR and USERVAR.                             */
6010                   if (!(j == 0 && sb[i] == IAC))
6011                       break;
6012             case 2:     /* USERVAR in progress */
6013                   varname[j] = '\0';
6014                   if (!varname[0]) {
6015                       /* Send All */
6016                       int x,y;
6017                       for ( x=0 ; x<8 ; x++ ) {
6018                           if ( tn_env_uservar[x][0] &&
6019                                tn_env_uservar[x][1] ) {
6020                               reply[n] = TEL_ENV_USERVAR;     /* VAR */
6021                               y = strlen(tn_env_uservar[x][0]);
6022                               strcpy(&reply[n+1],tn_env_uservar[x][0]);
6023                               reply[n+y+1] = TEL_ENV_VALUE; /* VALUE */
6024                               strcpy(&reply[n+y+2],tn_env_uservar[x][1]);
6025                               n += y+strlen(tn_env_uservar[x][1])+2;
6026                           }
6027                       }
6028                       if ( tn_sfu ) {
6029                           /* Compatibility with Microsoft Telnet Server */
6030                           reply[n] = TEL_ENV_USERVAR;     /* VAR */
6031                           strcpy(&reply[n+1],SFUTLNTVER);
6032                           reply[n+11] = TEL_ENV_VALUE; /* VALUE */
6033                           strcpy(&reply[n+12],SFUTLNTVER_VALUE);
6034                           n += strlen(SFUTLNTVER)+strlen(SFUTLNTVER_VALUE)+2;
6035
6036                           reply[n] = TEL_ENV_USERVAR;     /* VAR */
6037                           strcpy(&reply[n+1],SFUTLNTMODE);
6038                           reply[n+12] = TEL_ENV_VALUE; /* VALUE */
6039                           strcpy(&reply[n+13],SFUTLNTMODE_VALUE);
6040                           n += strlen(SFUTLNTMODE)+strlen(SFUTLNTMODE_VALUE)+2;
6041                       }
6042                       if (tn_loc && tn_loc[0]) {
6043                           reply[n] = TEL_ENV_USERVAR;     /* VAR */
6044                           strcpy(&reply[n+1],"LOCATION");
6045                           reply[n+9] = TEL_ENV_VALUE; /* VALUE */
6046                           strcpy(&reply[n+10],tn_loc);
6047                           n += strlen("LOCATION") + strlen(tn_loc) + 2;
6048                       }
6049                   }  else if (tn_sfu && !strcmp(varname,SFUTLNTVER)) {
6050                       reply[n] = TEL_ENV_USERVAR;     /* VAR */
6051                       strcpy(&reply[n+1],SFUTLNTVER);
6052                       reply[n+11] = TEL_ENV_VALUE; /* VALUE */
6053                       strcpy(&reply[n+12],SFUTLNTVER_VALUE);
6054                       n += strlen(SFUTLNTVER) + strlen(SFUTLNTVER_VALUE) + 2;
6055                   }  else if (tn_sfu && !strcmp(varname,SFUTLNTMODE)) {
6056                       reply[n] = TEL_ENV_USERVAR;     /* VAR */
6057                       strcpy(&reply[n+1],SFUTLNTMODE);
6058                       reply[n+12] = TEL_ENV_VALUE; /* VALUE */
6059                       strcpy(&reply[n+13],SFUTLNTMODE_VALUE);
6060                       n += strlen(SFUTLNTMODE) + strlen(SFUTLNTMODE_VALUE) + 2;
6061                   }
6062 #ifdef CK_SNDLOC
6063                   else if (tn_loc && tn_loc[0] && !strcmp(varname,"LOCATION")){
6064                       reply[n] = TEL_ENV_USERVAR;     /* VAR */
6065                       strcpy(&reply[n+1],"LOCATION");
6066                       reply[n+9] = TEL_ENV_VALUE; /* VALUE */
6067                       strcpy(&reply[n+10],tn_loc);
6068                       n += strlen("LOCATION") + strlen(tn_loc) + 2;
6069                   }
6070 #endif /* CK_SNDLOC */
6071                   else {
6072                       int x,y;
6073                       for ( x=0 ; x<8 ; x++ ) {
6074                           if ( tn_env_uservar[x][0] &&
6075                                tn_env_uservar[x][1] &&
6076                                !strcmp(varname,tn_env_uservar[x][0])) {
6077                               reply[n] = TEL_ENV_USERVAR;     /* VAR */
6078                               y = strlen(tn_env_uservar[x][0]);
6079                               strcpy(&reply[n+1],tn_env_uservar[x][0]);
6080                               reply[n+y+1] = TEL_ENV_VALUE; /* VALUE */
6081                               strcpy(&reply[n+y+2],tn_env_uservar[x][1]);
6082                               n += y+strlen(tn_env_uservar[x][1])+2;
6083                           }
6084                       }
6085                   }
6086                 break;
6087             }
6088             varname[0] = '\0';
6089             j = 0;
6090             type = (sb[i] == TEL_ENV_USERVAR ? 2 :      /* USERVAR */
6091                     sb[i] == TEL_ENV_VAR ? 1 :  /* VAR */
6092                     0
6093                    );
6094             break;
6095           case TEL_ENV_VALUE: /* VALUE */
6096             /* Protocol Error */
6097             debug(F100, "TELNET Subnegotiation error - VALUE in SEND", "",0);
6098             if (tn_deb || debses)
6099               tn_debug("TELNET Subnegotiation error - VALUE in SEND");
6100             return(0);  /* Was -1 but that would be taken as */
6101                         /* an I/O error, so absorb it and go on. */
6102           case TEL_ENV_ESC:     /* ESC */
6103             /* Not sure what this for.  Quote next character? */
6104             break;
6105           default:
6106             varname[j++] = sb[i];
6107         }
6108     }
6109     if (tn_ssbopt(TELOPT_NEWENVIRON,TELQUAL_IS,reply,n) < 0) {
6110         free(reply);
6111         return(-1);
6112     }
6113     free(reply);
6114     return(1);
6115 }
6116 #endif /* CK_ENVIRONMENT */
6117
6118 /* Telnet send terminal type */
6119 /* Returns -1 on error, 0 if nothing happens, 1 if type sent successfully */
6120
6121 int
6122 tn_sttyp() {                            /* Send telnet terminal type. */
6123     char *ttn;                          /* Name of terminal type. */
6124 #ifdef OS2
6125     static int alias = -1;              /* which alias are we using ? */
6126     int settype = 0;
6127 #endif /* OS2 */
6128     int i, rc;                          /* Worker. */
6129     int tntermflg = 0;
6130
6131     if (ttnet != NET_TCPB) return(0);
6132     if (ttnproto != NP_TELNET) return(0);
6133
6134     if (!TELOPT_ME(TELOPT_TTYPE)) return(0);
6135
6136 #ifdef CK_SSL
6137     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
6138         return(0);
6139     }
6140 #endif /* CK_SSL */
6141     ttn = NULL;
6142
6143 #ifndef NOTERM
6144 #ifdef OS2
6145     if (!tn_term) {
6146         if (ttnum == -1) {
6147             ttnum = tt_type;
6148             settype = 0;
6149             alias = -1;
6150         } else if (ttnumend) {
6151             ttnumend = 0;
6152             settype = 0;
6153         } else {
6154             if (tt_info[tt_type].x_aliases[++alias] == NULL)  {
6155                 if (--tt_type < 0)
6156                   tt_type = max_tt;
6157                 if (ttnum == tt_type)
6158                   ttnumend = 1;
6159                 settype = 1;
6160                 alias = -1;
6161             }
6162         }
6163         if (tt_type >= 0 && tt_type <= max_tt) {
6164             if (alias == -1)
6165               ttn = tt_info[tt_type].x_name;
6166             else
6167               ttn = tt_info[tt_type].x_aliases[alias];
6168         } else
6169           ttn = NULL;
6170     }
6171     else settype = 0;
6172 #endif /* OS2 */
6173 #endif /* NOTERM */
6174
6175     if (tn_term) {                      /* Terminal type override? */
6176         debug(F110,"tn_sttyp",tn_term,0);
6177         if (*tn_term) {
6178             ttn = tn_term;
6179             tntermflg = 1;
6180         }
6181     } else debug(F100,"tn_sttyp no term override","",0);
6182
6183 #ifndef datageneral
6184     if (!ttn) {                         /* If no override, */
6185         ttn = getenv("TERM");           /* get it from the environment. */
6186     }
6187 #endif /* datageneral */
6188     if ((ttn == ((char *)0)) || ((int)strlen(ttn) >= TSBUFSIZ))
6189       ttn = "UNKNOWN";
6190     sb_out[0] = (CHAR) IAC;                 /* I Am a Command */
6191     sb_out[1] = (CHAR) SB;                  /* Subnegotiation */
6192     sb_out[2] = TELOPT_TTYPE;               /* Terminal Type */
6193     sb_out[3] = (CHAR) 0;                   /* Is... */
6194     for (i = 4; *ttn; ttn++,i++) {      /* Copy and uppercase it */
6195 #ifdef VMS
6196         if (!tntermflg && *ttn == '-' &&
6197             (!strcmp(ttn,"-80") || !strcmp(ttn,"-132")))
6198           break;
6199         else
6200 #endif /* VMS */
6201           sb_out[i] = (char) ((!tntermflg && islower(*ttn)) ?
6202                               toupper(*ttn) :
6203                               *ttn);
6204     }
6205     ttn = (char *)sb_out;                   /* Point back to beginning */
6206 #ifdef DEBUG
6207     if (deblog || tn_deb || debses) {
6208         sb_out[i] = '\0';                   /* For debugging */
6209         ckmakxmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB ",
6210                  TELOPT(TELOPT_TTYPE)," IS ",(char *)sb_out+4," IAC SE",
6211                  NULL,NULL,NULL,NULL,NULL,NULL,NULL);
6212     }
6213 #endif /* DEBUG */
6214     sb_out[i++] = (CHAR) IAC;               /* End of Subnegotiation */
6215     sb_out[i++] = (CHAR) SE;                /* marked by IAC SE */
6216 #ifdef OS2
6217     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
6218 #endif
6219 #ifdef DEBUG
6220     debug(F100,tn_msg_out,"",0);
6221     if (tn_deb || debses) tn_debug(tn_msg_out);
6222 #endif /* DEBUG */
6223     rc = (ttol((CHAR *)sb_out,i) < 0);       /* Send it. */
6224 #ifdef OS2
6225     ReleaseTelnetMutex();
6226 #endif
6227     if (rc)
6228         return(-1);
6229 #ifndef NOTERM
6230 #ifdef OS2
6231     if (settype)
6232         settermtype(tt_type,0);
6233     else {
6234         ipadl25();
6235         VscrnIsDirty(VTERM);
6236     }
6237 #endif /* OS2 */
6238 #endif /* NOTERM */
6239     return(1);
6240 }
6241
6242 #ifdef CK_ENVIRONMENT
6243 #ifdef CK_XDISPLOC
6244
6245 /* Telnet send xdisplay location */
6246 /* Returns -1 on error, 0 if nothing happens, 1 if type sent successfully */
6247
6248 int
6249 tn_sxdisploc() {                        /* Send telnet X display location. */
6250     char * disp=NULL;
6251     int i,rc;
6252
6253     if (ttnet != NET_TCPB) return(0);
6254     if (ttnproto != NP_TELNET) return(0);
6255
6256     if (!TELOPT_ME(TELOPT_XDISPLOC)) return(0);
6257
6258 #ifdef CK_SSL
6259     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
6260         return(0);
6261     }
6262 #endif /* CK_SSL */
6263
6264 #ifdef CK_FORWARD_X
6265     if (TELOPT_U(TELOPT_FORWARD_X)) {
6266         disp = NULL;
6267     } else
6268 #endif /* CK_FORWARD_X */
6269         disp = (char *)tn_get_display();
6270     debug(F110,"tn_sxdisploc",disp,0);
6271
6272     if (!disp) {
6273         /* Can't do both, send WONT */
6274         if (tn_sopt(WONT,TELOPT_XDISPLOC) < 0)
6275             return(-1);
6276         TELOPT_UNANSWERED_WONT(TELOPT_XDISPLOC) = 1;
6277         return(0);
6278     }
6279
6280     sb_out[0] = (CHAR) IAC;                 /* I Am a Command */
6281     sb_out[1] = (CHAR) SB;                  /* Subnegotiation */
6282     sb_out[2] = TELOPT_XDISPLOC;            /* X-Display Location */
6283     sb_out[3] = (CHAR) 0;                   /* Is... */
6284     for (i = 4; *disp; disp++,i++) {      /* Copy and uppercase it */
6285         sb_out[i] = (char) *disp;
6286     }
6287 #ifdef DEBUG
6288     if (deblog || tn_deb || debses) {
6289         sb_out[i] = '\0';                   /* For debugging */
6290         ckmakxmsg( tn_msg_out,TN_MSG_LEN,
6291                   "TELNET SENT SB ",TELOPT(TELOPT_XDISPLOC),
6292                   " IS ",(char *)sb_out+4," IAC SE",
6293                   NULL,NULL,NULL,NULL,NULL,NULL,NULL);
6294     }
6295 #endif /* DEBUG */
6296     sb_out[i++] = (CHAR) IAC;               /* End of Subnegotiation */
6297     sb_out[i++] = (CHAR) SE;                /* marked by IAC SE */
6298 #ifdef OS2
6299     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
6300 #endif
6301 #ifdef DEBUG
6302     debug(F100,tn_msg_out,"",0);
6303     if (tn_deb || debses) tn_debug(tn_msg_out);
6304 #endif /* DEBUG */
6305     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
6306 #ifdef OS2
6307     ReleaseTelnetMutex();
6308 #endif
6309     if (rc)
6310         return(-1);
6311     return(1);
6312 }
6313 #endif /* CK_XDISPLOC */
6314 #endif /* CK_ENVIRONMENT */
6315
6316 #ifdef CK_FORWARD_X
6317 int
6318 tn_sndfwdx() {                          /* Send Fwd X Screen number to host */
6319     unsigned char screen = 0;
6320     char * disp;
6321     int i,rc;
6322
6323     if (!TELOPT_U(TELOPT_FORWARD_X)) return(0);
6324 #ifdef CK_SSL
6325     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
6326         return(0);
6327     }
6328 #endif /* CK_SSL */
6329
6330     /*
6331      * The format of the DISPLAY variable is [<host>:]<display>[.<screen>]
6332      * where <host> is an optional DNS name or ip address with a default of
6333      * the localhost; the screen defaults to 0
6334      */
6335
6336     disp = tn_get_display();
6337     if (disp) {
6338         int colon,dot;
6339         colon = ckindex(":",disp,0,0,1);
6340         dot   = ckindex(".",&disp[colon],0,0,1);
6341
6342         if ( dot ) {
6343             screen = atoi(&disp[colon+dot]);
6344         }
6345     } else {
6346         screen = 0;
6347     }
6348
6349     i = 0;
6350     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
6351     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
6352     sb_out[i++] = TELOPT_FORWARD_X;           /* Forward X */
6353     sb_out[i++] = FWDX_SCREEN;                /* Screen */
6354     sb_out[i++] = screen;
6355     if ( screen == IAC )
6356         sb_out[i++] = IAC;
6357     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
6358     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
6359 #ifdef DEBUG
6360     if (deblog || tn_deb || debses) {
6361         ckmakxmsg( tn_msg_out,TN_MSG_LEN,
6362                    "TELNET SENT SB ",TELOPT(TELOPT_FORWARD_X),
6363                    " SCREEN ",ckctox(screen,1)," IAC SE",
6364                    NULL,NULL,NULL,NULL,NULL,NULL,NULL);
6365     }
6366 #endif /* DEBUG */
6367 #ifdef OS2
6368     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
6369 #endif
6370 #ifdef DEBUG
6371     debug(F100,tn_msg_out,"",0);
6372     if (tn_deb || debses) tn_debug(tn_msg_out);
6373 #endif /* DEBUG */
6374     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
6375 #ifdef OS2
6376     ReleaseTelnetMutex();
6377 #endif
6378     if (rc)
6379         return(-1);
6380     return(0);
6381 }
6382 #endif /* CK_FORWARD_X */
6383
6384 #ifdef CK_SNDLOC
6385 int
6386 tn_sndloc() {                           /* Send location. */
6387     int i,rc;                              /* Worker. */
6388     char *ttloc;
6389
6390     if (!TELOPT_ME(TELOPT_SNDLOC)) return(0);
6391
6392 #ifdef CK_SSL
6393     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
6394         return(0);
6395     }
6396 #endif /* CK_SSL */
6397     ttloc = (tn_loc ? tn_loc : "");     /* In case we are being called even */
6398                                         /* though there is no location. */
6399     sb_out[0] = (CHAR) IAC;                 /* I Am a Command */
6400     sb_out[1] = (CHAR) SB;                  /* Subnegotiation */
6401     sb_out[2] = TELOPT_SNDLOC;              /* Location */
6402     for (i = 3; *ttloc && i < TSBUFSIZ; ttloc++,i++) /* Copy it */
6403       sb_out[i] = (char) *ttloc;
6404     sb_out[i++] = (CHAR) IAC;               /* End of Subnegotiation */
6405     sb_out[i++] = (CHAR) SE;                /* marked by IAC SE */
6406
6407 #ifdef DEBUG
6408     if (deblog || tn_deb || debses) {
6409         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
6410                   "TELNET SENT SB ",TELOPT(TELOPT_SNDLOC)," ",(char *)sb_out+3,
6411                   " IAC SE", NULL,NULL,NULL,NULL,NULL,NULL,NULL);
6412     }
6413 #endif /* DEBUG */
6414 #ifdef OS2
6415     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
6416 #endif
6417 #ifdef DEBUG
6418     debug(F100,tn_msg_out,"",0);
6419     if (tn_deb || debses) tn_debug(tn_msg_out);
6420 #endif /* DEBUG */
6421     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
6422 #ifdef OS2
6423     ReleaseTelnetMutex();
6424 #endif
6425     if (rc)
6426         return(-1);
6427     sb_out[i-2] = '\0';                     /* For debugging */
6428     return(0);
6429 }
6430 #endif /* CK_SNDLOC */
6431
6432 #ifdef CK_NAWS                  /*  NAWS = Negotiate About Window Size  */
6433 int
6434 tn_snaws() {                    /*  Send terminal width and height, RFC 1073 */
6435 #ifndef NOLOCAL
6436     CHAR sb_out[24];            /*  multiple threads */
6437     int i = 0,rc;
6438 #ifdef OS2
6439     int x = VscrnGetWidth(VTERM),
6440     y = VscrnGetHeight(VTERM) - (tt_status[VTERM] ? 1 : 0);
6441 #else /* OS2 */
6442     int x = tt_cols, y = tt_rows;
6443 #endif /* OS2 */
6444
6445     if (ttnet != NET_TCPB) return(0);
6446     if (ttnproto != NP_TELNET) return(0);
6447     if (!TELOPT_ME(TELOPT_NAWS)) return(0);
6448
6449 #ifdef CK_SSL
6450     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
6451         return(0);
6452     }
6453 #endif /* CK_SSL */
6454     if (x < 0) x = 0;
6455     if (y < 0) y = 0;
6456
6457     if (x == TELOPT_SB(TELOPT_NAWS).naws.x && /* Only send if changed */
6458         y == TELOPT_SB(TELOPT_NAWS).naws.y
6459         )
6460       return(0);
6461     TELOPT_SB(TELOPT_NAWS).naws.x = x;  /* Remember the size     */
6462     TELOPT_SB(TELOPT_NAWS).naws.y = y;
6463
6464     sb_out[i++] = (CHAR) IAC;               /* Send the subnegotiation */
6465     sb_out[i++] = (CHAR) SB;
6466     sb_out[i++] = TELOPT_NAWS;
6467     sb_out[i++] = (CHAR) (x >> 8) & 0xff;
6468     if ((CHAR) sb_out[i-1] == (CHAR) IAC)   /* IAC in data must be doubled */
6469       sb_out[i++] = (CHAR) IAC;
6470     sb_out[i++] = (CHAR) (x & 0xff);
6471     if ((CHAR) sb_out[i-1] == (CHAR) IAC)
6472       sb_out[i++] = (CHAR) IAC;
6473     sb_out[i++] = (CHAR) (y >> 8) & 0xff;
6474     if ((CHAR) sb_out[i-1] == (CHAR) IAC)
6475       sb_out[i++] = (CHAR) IAC;
6476     sb_out[i++] = (CHAR) (y & 0xff);
6477     if ((CHAR) sb_out[i-1] == (CHAR) IAC)
6478       sb_out[i++] = (CHAR) IAC;
6479     sb_out[i++] = (CHAR) IAC;
6480     sb_out[i++] = (CHAR) SE;
6481 #ifdef DEBUG
6482     if (deblog || tn_deb || debses) {
6483         ckmakxmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB NAWS ",
6484                   ckitoa(x)," ",ckitoa(y)," IAC SE",
6485                    NULL,NULL,NULL,NULL,NULL,NULL,NULL);
6486     }
6487 #endif /* DEBUG */
6488 #ifdef OS2
6489     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
6490 #endif
6491 #ifdef DEBUG
6492     debug(F100,tn_msg_out,"",0);
6493     if (tn_deb || debses) tn_debug(tn_msg_out);
6494 #endif /* DEBUG */
6495     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
6496 #ifdef OS2
6497     ReleaseTelnetMutex();
6498 #endif
6499     if (rc)
6500         return(-1);
6501 #endif /* NOLOCAL */
6502     return (0);
6503 }
6504 #endif /* CK_NAWS */
6505
6506 #ifdef TN_COMPORT
6507 static char * tnc_signature = NULL;
6508 static int tnc_ls_mask = 0;
6509 static int tnc_ls = 0;
6510 static int tnc_ms_mask = 255;
6511 static int tnc_ms = 0;
6512 static int tnc_oflow = 0;
6513 static int tnc_iflow = 0;
6514 static int tnc_bps = 0;
6515 static int tnc_datasize = 0;
6516 static int tnc_parity = 0;
6517 static int tnc_stopbit = 0;
6518 static int tnc_break = 0;
6519 static int tnc_dtr = 0;
6520 static int tnc_rts = 0;
6521 static int tnc_suspend_xmit = 0;
6522 static int tnc_bps_index = -1;
6523
6524 int
6525 #ifdef CK_ANSIC
6526 tnc_init(void)
6527 #else /* CK_ANSIC */
6528 tnc_init()
6529 #endif /* CK_ANSIC */
6530 /* tnc_init */ {
6531     debug(F100,"tnc_init","",0);
6532
6533     if (tnc_signature) {
6534         free(tnc_signature);
6535         tnc_signature = NULL;
6536     }
6537     tnc_ls_mask = 0;
6538     tnc_ls = 0;
6539     tnc_ms_mask = 255;
6540     tnc_ms = 0;
6541     tnc_oflow = 0;
6542     tnc_iflow = 0;
6543     tnc_bps = 0;
6544     tnc_datasize = 0;
6545     tnc_parity = 0;
6546     tnc_stopbit = 0;
6547     tnc_break = 0;
6548     tnc_dtr = 0;
6549     tnc_rts = 0;
6550     tnc_suspend_xmit = 0;
6551     tnc_bps_index = -1;
6552     return(0);
6553 }
6554
6555 int
6556 #ifdef CK_ANSIC
6557 tn_sndcomport(void)
6558 #else /* CK_ANSIC */
6559 tn_sndcomport()
6560 #endif /* CK_ANSIC */
6561 /* tn_sndcomport */ {
6562     int baud, datasize, parity, stopsize, oflow, iflow;
6563     CONST char * signature;
6564
6565     debug(F100,"tnc_sndcomport","",0);
6566     signature = tnc_get_signature();
6567     baud = tnc_get_baud();
6568     datasize = tnc_get_datasize();
6569     parity = tnc_get_parity();
6570     stopsize = tnc_get_stopsize();
6571     oflow = tnc_get_oflow();
6572     iflow = tnc_get_iflow();
6573     tnc_set_ls_mask(255);
6574     tnc_set_ms_mask(255);
6575     return(0);
6576 }
6577
6578 int
6579 #ifdef CK_ANSIC
6580 tnc_wait(CHAR * msg, int ms)
6581 #else /* CK_ANSIC */
6582 tnc_wait(msg, ms) CHAR * msg; int ms;
6583 #endif /* CK_ANSIC */
6584 /* tnc_wait */ {
6585     int rc, tn_wait_save = tn_wait_flg;
6586     debug(F111,"tnc_wait","begin",ms);
6587     if ( ms )
6588         TELOPT_SB(TELOPT_COMPORT).comport.wait_for_ms = 1;
6589     else
6590         TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 1;
6591     tn_wait_flg = 1;
6592     rc = tn_wait((char *)msg);
6593     tn_push();
6594     debug(F110,"tnc_wait","end",0);
6595     tn_wait_flg = tn_wait_save;
6596     return(rc);
6597 }
6598
6599 /* Returns -1 on error, 0 on success */
6600 /* In order for this code to work, sb[len] == IAC          */
6601
6602 int
6603 #ifdef CK_ANSIC
6604 tnc_tn_sb(CHAR * sb, int len)
6605 #else
6606 tnc_tn_sb(sb, len) CHAR * sb; int len;
6607 #endif /* CK_ANSIC */
6608 /* tnc_tn_sb */ {
6609     if (ttnet != NET_TCPB) return(0);
6610     if (ttnproto != NP_TELNET) return(0);
6611     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
6612
6613     if (!sb) return(-1);
6614
6615 #ifdef CK_SSL
6616     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
6617         return(0);
6618     }
6619 #endif /* CK_SSL */
6620
6621     debug(F111,"tnc_tn_sb","sb[0]",sb[0]);
6622     debug(F111,"tnc_tn_sb","len",len);
6623
6624     switch (sb[0]) {
6625       case TNC_C2S_SIGNATURE:
6626       case TNC_S2C_SIGNATURE:
6627         debug(F111,"tnc_tn_sb","signature",len);
6628         if (len == 1) {
6629             tnc_send_signature("Kermit Telnet Com Port Option");
6630         } else {
6631             TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
6632             if (tnc_signature)
6633               free(tnc_signature);
6634             tnc_signature = malloc(len);
6635             if (tnc_signature) {
6636                 memcpy(tnc_signature,&sb[1],len-1);
6637                 tnc_signature[len-1] = '\0';
6638             }
6639         }
6640         break;
6641
6642       case TNC_C2S_SET_BAUDRATE:
6643       case TNC_S2C_SET_BAUDRATE: {
6644           long baudrate;
6645           char * br = (char *)&baudrate;
6646           TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
6647           if (len == 2) {
6648             /* Actual behavior of the Access Server... */
6649             debug(F111,"tnc_tn_sb","baudrate index",sb[1]);
6650             tnc_bps_index = 1;
6651             switch (sb[1]) {
6652             case TNC_BPS_300:
6653               tnc_bps = 300;
6654               break;
6655             case TNC_BPS_600:
6656               tnc_bps = 600;
6657               break;
6658             case TNC_BPS_1200:
6659               tnc_bps = 1200;
6660               break;
6661             case TNC_BPS_2400:
6662               tnc_bps = 2400;
6663               break;
6664             case TNC_BPS_4800:
6665               tnc_bps = 4800;
6666               break;
6667             case TNC_BPS_9600:
6668               tnc_bps = 9600;
6669               break;
6670             case TNC_BPS_14400:
6671               tnc_bps = 14400;
6672               break;
6673             case TNC_BPS_19200:
6674               tnc_bps = 19200;
6675               break;
6676             case TNC_BPS_28800:
6677               tnc_bps = 28800;
6678               break;
6679             case TNC_BPS_38400:
6680               tnc_bps = 38400;
6681               break;
6682             case TNC_BPS_57600:
6683               tnc_bps = 57600;
6684               break;
6685             case TNC_BPS_115200:
6686               tnc_bps = 115200;
6687               break;
6688             case TNC_BPS_230400:
6689               tnc_bps = 230400;
6690               break;
6691             case TNC_BPS_460800:
6692               tnc_bps = 460800;
6693               break;
6694             default:
6695               tnc_bps = -1;
6696             }
6697           } else if (len == 5) {
6698             /* This section attempts to follow RFC 2217 */
6699               tnc_bps_index = 0;
6700               br[0] = sb[1];
6701               br[1] = sb[2];
6702               br[2] = sb[3];
6703               br[3] = sb[4];
6704 #ifdef datageneral
6705               /* AOS/VS doesn't have ntohl() but MV's are big-endian */
6706               tnc_bps = baudrate;
6707 #else
6708               tnc_bps = ntohl(baudrate);
6709 #endif /* datageneral */
6710               debug(F111,"tnc_tn_sb","baudrate rfc",tnc_bps);
6711           } else {
6712               debug(F111,"tnc_tn_sb","baudrate invalid len",len);
6713               return(-1);
6714           }
6715           break;
6716       }
6717       case TNC_C2S_SET_DATASIZE:
6718       case TNC_S2C_SET_DATASIZE:
6719         TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
6720         if (len < 2)
6721           return(-1);
6722         tnc_datasize = sb[1];
6723         debug(F111,"tnc_tn_sb","datasize",sb[1]);
6724         break;
6725
6726       case TNC_C2S_SET_PARITY:
6727       case TNC_S2C_SET_PARITY:
6728         TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
6729         if (len < 2)
6730           return(-1);
6731         tnc_parity = sb[1];
6732         debug(F111,"tnc_tn_sb","parity",sb[1]);
6733         break;
6734
6735       case TNC_C2S_SET_STOPSIZE:
6736       case TNC_S2C_SET_STOPSIZE:
6737         TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
6738         if (len < 2)
6739           return(-1);
6740         tnc_stopbit = sb[1];
6741         debug(F111,"tnc_tn_sb","stopsize",sb[1]);
6742         break;
6743
6744       case TNC_C2S_SET_CONTROL:
6745       case TNC_S2C_SET_CONTROL:
6746         if (len < 2) {
6747             TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
6748             return(-1);
6749         }
6750
6751 #ifdef COMMENT
6752         /* This line should be removed when testing is complete. */
6753         TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
6754 #endif /* COMMENT */
6755
6756         switch ( sb[1] ) {
6757           case TNC_CTL_OFLOW_REQUEST:
6758             /* determine local outbound flow control and send to peer */
6759             /* Cisco IOS returns 0 (TNC_CTL_OFLOW_REQUEST) when attempting */
6760             /* to set the inbound flow control if it is not supported      */
6761             /* separately from outbound flow control.  So must reset       */
6762             /* wait for sb flag.                                           */
6763             debug(F110,"tnc_tn_sb","oflow request",0);
6764             TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
6765             break;
6766           case TNC_CTL_OFLOW_NONE:
6767           case TNC_CTL_OFLOW_XON_XOFF:
6768           case TNC_CTL_OFLOW_RTS_CTS:
6769           case TNC_CTL_OFLOW_DCD:
6770           case TNC_CTL_OFLOW_DSR:
6771             TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
6772             tnc_oflow = sb[1];
6773             debug(F111,"tnc_tn_sb","oflow",sb[1]);
6774             break;
6775           case TNC_CTL_BREAK_REQUEST:
6776             /* determine local break state and send to peer */
6777             debug(F110,"tnc_tn_sb","break request",0);
6778             break;
6779           case TNC_CTL_BREAK_ON:
6780             TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
6781             tnc_break = 1;
6782             debug(F110,"tnc_tn_sb","break on",0);
6783             break;
6784
6785           case TNC_CTL_BREAK_OFF:
6786             TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
6787             tnc_break = 0;
6788             debug(F110,"tnc_tn_sb","break off",0);
6789             break;
6790
6791           case TNC_CTL_DTR_REQUEST:
6792             /* determine local dtr state and send to peer */
6793             debug(F110,"tnc_tn_sb","dtr request",0);
6794             break;
6795
6796           case TNC_CTL_DTR_ON:
6797             TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
6798             tnc_dtr = 1;
6799             debug(F110,"tnc_tn_sb","dtr on",0);
6800             break;
6801
6802           case TNC_CTL_DTR_OFF:
6803             TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
6804             tnc_dtr = 0;
6805             debug(F110,"tnc_tn_sb","dtr off",0);
6806             break;
6807
6808           case TNC_CTL_RTS_REQUEST:
6809             /* determine local rts state and send to peer */
6810             debug(F110,"tnc_tn_sb","rts request",0);
6811             break;
6812
6813           case TNC_CTL_RTS_ON:
6814             TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
6815             tnc_rts = 1;
6816             debug(F110,"tnc_tn_sb","rts on",0);
6817             break;
6818
6819           case TNC_CTL_RTS_OFF:
6820             TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
6821             tnc_rts = 0;
6822             debug(F110,"tnc_tn_sb","rts off",0);
6823             break;
6824
6825           case TNC_CTL_IFLOW_REQUEST:
6826             /* determine local inbound flow control and send to peer */
6827             debug(F110,"tnc_tn_sb","iflow request",0);
6828             break;
6829
6830           case TNC_CTL_IFLOW_NONE:
6831           case TNC_CTL_IFLOW_XON_XOFF:
6832           case TNC_CTL_IFLOW_RTS_CTS:
6833           case TNC_CTL_IFLOW_DTR:
6834             TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
6835             tnc_iflow = sb[1];
6836             debug(F111,"tnc_tn_sb","iflow",sb[1]);
6837             break;
6838           default:
6839             return(-1);
6840         }
6841         break;
6842
6843       case TNC_C2S_NOTIFY_LINESTATE:
6844       case TNC_S2C_SEND_LS:
6845         if (len < 2)
6846           return(-1);
6847         tnc_ls = sb[1];
6848         debug(F111,"tnc_tn_sb","linestate",sb[1]);
6849         if (tn_deb || debses) {
6850             if (tnc_ls & TNC_MS_DATA_READY )
6851               tn_debug("  ComPort Linestate Data Ready");
6852             if (tnc_ls & TNC_MS_OVERRUN_ERROR )
6853               tn_debug("  ComPort Linestate Overrun Error");
6854             if (tnc_ls & TNC_MS_PARITY_ERROR )
6855               tn_debug("  ComPort Linestate Parity Error");
6856             if (tnc_ls & TNC_MS_FRAME_ERROR )
6857               tn_debug("  ComPort Linestate Framing Error");
6858             if (tnc_ls & TNC_MS_BREAK_ERROR )
6859               tn_debug("  ComPort Linestate Break Detect Error");
6860             if (tnc_ls & TNC_MS_HR_EMPTY )
6861               tn_debug("  ComPort Linestate Holding Register Empty");
6862             if (tnc_ls & TNC_MS_SR_EMPTY )
6863               tn_debug("  ComPort Linestate Shift Register Empty");
6864             if (tnc_ls & TNC_MS_TIMEOUT_ERROR )
6865               tn_debug("  ComPort Linestate Timeout Error");
6866         }
6867         break;
6868
6869       case TNC_C2S_NOTIFY_MODEMSTATE:
6870       case TNC_S2C_SEND_MS:
6871         TELOPT_SB(TELOPT_COMPORT).comport.wait_for_ms = 0;
6872         if (len < 2)
6873           return(-1);
6874         tnc_ms = sb[1];
6875         debug(F111,"tnc_tn_sb","modemstate",sb[1]);
6876         if (tn_deb || debses) {
6877             if (tnc_ms & TNC_MS_CTS_DELTA )
6878               tn_debug("  ComPort Modemstate CTS State Change");
6879             if (tnc_ms & TNC_MS_DSR_DELTA )
6880               tn_debug("  ComPort Modemstate DSR State Change");
6881             if (tnc_ms & TNC_MS_EDGE_RING )
6882               tn_debug("  ComPort Modemstate Trailing Edge Ring Detector On");
6883             else
6884               tn_debug("  ComPort Modemstate Trailing Edge Ring Detector Off");
6885             if (tnc_ms & TNC_MS_RLSD_DELTA )
6886               tn_debug("  ComPort Modemstate RLSD State Change");
6887             if (tnc_ms & TNC_MS_CTS_SIG )
6888               tn_debug("  ComPort Modemstate CTS Signal On");
6889             else
6890               tn_debug("  ComPort Modemstate CTS Signal Off");
6891             if (tnc_ms & TNC_MS_DSR_SIG )
6892               tn_debug("  ComPort Modemstate DSR Signal On");
6893             else
6894               tn_debug("  ComPort Modemstate DSR Signal Off");
6895             if (tnc_ms & TNC_MS_RI_SIG )
6896               tn_debug("  ComPort Modemstate Ring Indicator On");
6897             else
6898               tn_debug("  ComPort Modemstate Ring Indicator Off");
6899             if (tnc_ms & TNC_MS_RLSD_SIG )
6900               tn_debug("  ComPort Modemstate RLSD Signal On");
6901             else
6902               tn_debug("  ComPort Modemstate RLSD Signal Off");
6903         }
6904         break;
6905
6906       case TNC_C2S_FLOW_SUSPEND:
6907       case TNC_S2C_FLOW_SUSPEND:
6908         debug(F110,"tnc_tn_sb","flow suspend",0);
6909         tnc_suspend_xmit = 1;
6910         break;
6911
6912       case TNC_C2S_FLOW_RESUME:
6913       case TNC_S2C_FLOW_RESUME:
6914         debug(F110,"tnc_tn_sb","flow resume",0);
6915         tnc_suspend_xmit = 0;
6916         break;
6917
6918       case TNC_C2S_SET_LS_MASK:
6919       case TNC_S2C_SET_LS_MASK:
6920           TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
6921           if (len < 2)
6922           return(-1);
6923         debug(F111,"tnc_tn_sb","linestate mask",sb[1]);
6924         tnc_ls_mask = sb[1];
6925         break;
6926
6927       case TNC_C2S_SET_MS_MASK:
6928       case TNC_S2C_SET_MS_MASK:
6929           TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0;
6930           if (len < 2)
6931           return(-1);
6932         debug(F111,"tnc_tn_sb","modemstate mask",sb[1]);
6933         tnc_ls_mask = sb[1];
6934         break;
6935
6936       case TNC_C2S_PURGE:
6937       case TNC_S2C_PURGE:
6938         if (len < 2)
6939           return(-1);
6940         debug(F111,"tnc_tn_sb","purge",sb[1]);
6941         switch ( sb[1] ) {
6942           case TNC_PURGE_RECEIVE:
6943           case TNC_PURGE_TRANSMIT:
6944           case TNC_PURGE_BOTH:
6945             /* purge local buffers */
6946             break;
6947           default:
6948             return(-1);
6949         }
6950         break;
6951       default:
6952         return(-1);
6953     }
6954     return(0);
6955 }
6956
6957 CONST char *
6958 #ifdef CK_ANSIC
6959 tnc_get_signature(void)
6960 #else /* CK_ANSIC */
6961 tnc_get_signature()
6962 #endif /* CK_ANSIC */
6963 /* tnc_get_signature */ {
6964     /* send IAC SB COM-PORT SIGNATURE IAC SE */
6965     /* wait for response */
6966     int i = 0, rc;
6967
6968     if (ttnet != NET_TCPB) return(NULL);
6969     if (ttnproto != NP_TELNET) return(NULL);
6970
6971     if (!TELOPT_ME(TELOPT_COMPORT)) return(NULL);
6972
6973 #ifdef CK_SSL
6974     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
6975         return(NULL);
6976     }
6977 #endif /* CK_SSL */
6978
6979     if ( tnc_signature )
6980         return(tnc_signature);
6981
6982     sb_out[i++] = (CHAR) IAC;           /* I Am a Command */
6983     sb_out[i++] = (CHAR) SB;            /* Subnegotiation */
6984     sb_out[i++] = TELOPT_COMPORT;               /* ComPort */
6985     sb_out[i++] = TNC_C2S_SIGNATURE;    /* Signature */
6986     sb_out[i++] = (CHAR) IAC;               /* End of Subnegotiation */
6987     sb_out[i++] = (CHAR) SE;                /* marked by IAC SE */
6988
6989 #ifdef DEBUG
6990     if (deblog || tn_deb || debses) {
6991         ckmakmsg(tn_msg_out,TN_MSG_LEN,
6992                  "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
6993                  " SIGNATURE IAC SE", NULL);
6994     }
6995 #endif /* DEBUG */
6996 #ifdef OS2
6997     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
6998 #endif
6999 #ifdef DEBUG
7000     debug(F100,tn_msg_out,"",0);
7001     if (tn_deb || debses) tn_debug(tn_msg_out);
7002 #endif /* DEBUG */
7003     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
7004 #ifdef OS2
7005     ReleaseTelnetMutex();
7006 #endif
7007     if (rc)
7008         return(NULL);
7009
7010     if (tnc_wait((CHAR *)"comport signature request",0) < 0) {
7011         tn_push();
7012         return(NULL);
7013     }
7014     debug(F110,"tnc_get_signature",tnc_signature,0);
7015     return(tnc_signature);
7016 }
7017
7018 int
7019 #ifdef CK_ANSIC
7020 tnc_send_signature(char * signature)
7021 #else /* CK_ANSIC */
7022 tnc_send_signature(signature) char * signature;
7023 #endif /* CK_ANSIC */
7024 /* tnc_send_signature */ {
7025     /* send IAC SB COM-PORT SIGNATURE <text> IAC SE */
7026     int i = 0, j = 0, rc;
7027
7028     debug(F110,"tnc_send_signature",signature,0);
7029
7030     if (!signature || !signature[0])
7031       return(0);
7032
7033     if (ttnet != NET_TCPB) return(0);
7034     if (ttnproto != NP_TELNET) return(0);
7035
7036     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
7037
7038 #ifdef CK_SSL
7039     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
7040         return(0);
7041     }
7042 #endif /* CK_SSL */
7043
7044     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
7045     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
7046     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
7047     sb_out[i++] = TNC_C2S_SIGNATURE;      /* Signature */
7048     for (; signature[j]; i++,j++)
7049       sb_out[i] = signature[j];
7050     sb_out[i++] = (CHAR) IAC;               /* End of Subnegotiation */
7051     sb_out[i++] = (CHAR) SE;                /* marked by IAC SE */
7052
7053 #ifdef DEBUG
7054     if (deblog || tn_deb || debses) {
7055         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
7056                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
7057                   " SIGNATURE ", signature, " IAC SE", NULL,
7058                   NULL,NULL,NULL,NULL,NULL,NULL);
7059     }
7060 #endif /* DEBUG */
7061 #ifdef OS2
7062     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
7063 #endif
7064 #ifdef DEBUG
7065     debug(F100,tn_msg_out,"",0);
7066     if (tn_deb || debses) tn_debug(tn_msg_out);
7067 #endif /* DEBUG */
7068     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
7069 #ifdef OS2
7070     ReleaseTelnetMutex();
7071 #endif
7072     if (rc)
7073         return(-1);
7074     return(0);
7075 }
7076
7077 int
7078 #ifdef CK_ANSIC
7079 tnc_set_baud( long baud )
7080 #else /* CK_ANSIC */
7081 tnc_set_baud(baud) long baud;
7082 #endif /* CK_ANSIC */
7083 /* tnc_set_baud */ {
7084     /* send IAC SB COM-PORT SET-BAUD <value(4)> IAC SE  */
7085     /* wait for response */
7086     /* 0 is used to request the current baud rate and */
7087     /* may not be sent by this func */
7088     /* return new host value */
7089
7090     /*
7091      *   the above comes from the RFC.  But that is not what I am seeing
7092      *   instead I appear to be seeing to following:
7093      *
7094      *      Value               Baud
7095      *          1               ?
7096      *          2               ?
7097      *          3               300
7098      *          4               600
7099      *          5               1200
7100      *          6               2400
7101      *          7               4800      ?
7102      *          8               9600
7103      *          9                         ?
7104      *          10              19200     ?
7105      *          11                        ?
7106      *          12              38400
7107      *          13              57600     ?
7108      *          14              115200
7109      *          15              230400    ?
7110      *          16              460800    ?
7111      */
7112
7113     int i = 0, rc;
7114 #ifdef datageneral
7115     /* AOS/VS doesn't have htonl() but MV's are big-endian */
7116     long net_baud = baud;
7117 #else
7118     long net_baud = htonl(baud);
7119 #endif /* datageneral */
7120     CHAR b;
7121
7122     debug(F111,"tnc_set_baud","begin",baud);
7123
7124     if (ttnet != NET_TCPB) return(0);
7125     if (ttnproto != NP_TELNET) return(0);
7126
7127     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
7128
7129 #ifdef CK_SSL
7130     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
7131         return(0);
7132     }
7133 #endif /* CK_SSL */
7134
7135     if (baud <= 0)
7136         return(0);
7137
7138     if ( net_baud != 0 && net_baud == tnc_bps)
7139         return(tnc_bps);
7140
7141     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
7142     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
7143     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
7144     sb_out[i++] = TNC_C2S_SET_BAUDRATE;   /* Set Baud Rate */
7145
7146     if (tnc_bps_index) {
7147         /* IOS Access Server */
7148         if (baud <= 300)
7149             b = TNC_BPS_300;
7150         else if (baud <= 600)
7151             b = TNC_BPS_600;
7152         else if (baud <= 1200)
7153             b = TNC_BPS_1200;
7154         else if (baud <= 2400)
7155             b = TNC_BPS_2400;
7156         else if (baud <= 4800)
7157             b = TNC_BPS_4800;
7158         else if (baud <= 9600)
7159             b = TNC_BPS_9600;
7160         else if (baud <= 14400)
7161             b = TNC_BPS_14400;
7162         else if (baud <= 19200)
7163             b = TNC_BPS_19200;
7164         else if (baud <= 28800)
7165             b = TNC_BPS_28800;
7166         else if (baud <= 38400)
7167             b = TNC_BPS_38400;
7168         else if (baud <= 57600)
7169             b = TNC_BPS_57600;
7170         else if (baud <= 115200)
7171             b = TNC_BPS_115200;
7172         else if (baud <= 230400)
7173             b = TNC_BPS_230400;
7174         else
7175             b = TNC_BPS_460800;
7176         sb_out[i++] = b;
7177     } else {
7178         /* RFC 2217 */
7179         sb_out[i++] = ((char *)&net_baud)[0];
7180         sb_out[i++] = ((char *)&net_baud)[1];
7181         sb_out[i++] = ((char *)&net_baud)[2];
7182         sb_out[i++] = ((char *)&net_baud)[3];
7183     }
7184     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
7185     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
7186
7187 #ifdef DEBUG
7188     if (deblog || tn_deb || debses) {
7189         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
7190                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
7191                   " SET-BAUD-RATE ", ckltoa(baud)," IAC SE", NULL,
7192                   NULL,NULL,NULL,NULL,NULL,NULL);
7193     }
7194 #endif /* DEBUG */
7195
7196 #ifdef OS2
7197     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
7198 #endif
7199 #ifdef DEBUG
7200     debug(F100,tn_msg_out,"",0);
7201     if (tn_deb || debses) tn_debug(tn_msg_out);
7202 #endif /* DEBUG */
7203     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
7204 #ifdef OS2
7205     ReleaseTelnetMutex();
7206 #endif
7207     if (rc)
7208         return(-1);
7209
7210     if (tnc_wait((CHAR *)"comport set baud rate",0) < 0) {
7211         tn_push();
7212         return(-1);
7213     }
7214     debug(F111,"tnc_set_baud","end",tnc_bps);
7215     return(tnc_bps);
7216 }
7217
7218 int
7219 #ifdef CK_ANSIC
7220 tnc_get_baud(void)
7221 #else /* CK_ANSIC */
7222 tnc_get_baud()
7223 #endif /* CK_ANSIC */
7224 /* tnc_get_baud */ {
7225     /* send IAC SB COM-PORT SET-BAUD <value(4)=0> IAC SE  */
7226     /* wait for response */
7227     int i = 0, rc;
7228
7229     debug(F110,"tnc_get_baud","begin",0);
7230
7231     if (ttnet != NET_TCPB) return(0);
7232     if (ttnproto != NP_TELNET) return(0);
7233
7234     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
7235
7236 #ifdef CK_SSL
7237     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
7238         return(0);
7239     }
7240 #endif /* CK_SSL */
7241
7242     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
7243     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
7244     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
7245     sb_out[i++] = TNC_C2S_SET_BAUDRATE;   /* Set Baud Rate */
7246
7247     if (tnc_bps_index > 0) {
7248         /* Access Server */
7249         sb_out[i++] = 0;
7250     } else {
7251         /* RFC 2217 */
7252         sb_out[i++] = 0;
7253         sb_out[i++] = 0;
7254         sb_out[i++] = 0;
7255         sb_out[i++] = 0;
7256     }
7257     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
7258     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
7259
7260 #ifdef DEBUG
7261     if (deblog || tn_deb || debses) {
7262         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
7263                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
7264                   " SET-BAUD-RATE ", ckltoa(0)," IAC SE", NULL,
7265                   NULL,NULL,NULL,NULL,NULL,NULL);
7266     }
7267 #endif /* DEBUG */
7268 #ifdef OS2
7269     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
7270 #endif
7271 #ifdef DEBUG
7272     debug(F100,tn_msg_out,"",0);
7273     if (tn_deb || debses) tn_debug(tn_msg_out);
7274 #endif /* DEBUG */
7275     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
7276 #ifdef OS2
7277     ReleaseTelnetMutex();
7278 #endif
7279     if (rc)
7280         return(-1);
7281
7282     if (tnc_wait((CHAR *)"comport get baud rate",0) < 0) {
7283         tn_push();
7284         return(-1);
7285     }
7286     debug(F111,"tnc_get_baud","end",tnc_bps);
7287     return(tnc_bps);
7288 }
7289
7290 int
7291 #ifdef CK_ANSIC
7292 tnc_set_datasize(int datasize)
7293 #else /* CK_ANSIC */
7294 tnc_set_datasize(datasize) int datasize;
7295 #endif /* CK_ANSIC */
7296 /* tnc_set_datasize */ {
7297     /* IAC SB COM-PORT SET_DATASIZE <value(1)> IAC SE */
7298     /* Valid <value>s are 5 through 8 */
7299     /* Wait for response */
7300     /* return new host value */
7301
7302     int i = 0, rc;
7303
7304     debug(F111,"tnc_set_datasize","begin",datasize);
7305
7306     if (ttnet != NET_TCPB) return(0);
7307     if (ttnproto != NP_TELNET) return(0);
7308
7309     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
7310
7311 #ifdef CK_SSL
7312     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
7313         return(0);
7314     }
7315 #endif /* CK_SSL */
7316
7317     if ( !(datasize >= 5 && datasize <= 8) )
7318         return(0);
7319
7320     if ( datasize  != 0 &&  datasize == tnc_datasize )
7321         return(tnc_datasize);
7322
7323     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
7324     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
7325     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
7326     sb_out[i++] = TNC_C2S_SET_DATASIZE;   /* Set DataSize */
7327     sb_out[i++] = (unsigned char)(datasize & 0xFF);
7328     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
7329     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
7330
7331 #ifdef DEBUG
7332     if (deblog || tn_deb || debses) {
7333         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
7334                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
7335                   " SET-DATASIZE ", ckitoa(datasize)," IAC SE", NULL,
7336                   NULL,NULL,NULL,NULL,NULL,NULL);
7337     }
7338 #endif /* DEBUG */
7339 #ifdef OS2
7340     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
7341 #endif
7342 #ifdef DEBUG
7343     debug(F100,tn_msg_out,"",0);
7344     if (tn_deb || debses) tn_debug(tn_msg_out);
7345 #endif /* DEBUG */
7346     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
7347 #ifdef OS2
7348     ReleaseTelnetMutex();
7349 #endif
7350     if (rc)
7351         return(-1);
7352
7353     if (tnc_wait((CHAR *)"comport set datasize",0) < 0) {
7354         tn_push();
7355         return(-1);
7356     }
7357     debug(F111,"tnc_set_datasize","end",tnc_datasize);
7358     return(tnc_datasize);
7359 }
7360
7361 int
7362 #ifdef CK_ANSIC
7363 tnc_get_datasize(void)
7364 #else /* CK_ANSIC */
7365 tnc_get_datasize()
7366 #endif /* CK_ANSIC */
7367 /* tnc_get_datasize */ {
7368     /* IAC SB COM-PORT SET_DATASIZE <value(1)=0> IAC SE */
7369     /* Wait for response */
7370     int i = 0, rc;
7371
7372     debug(F110,"tnc_get_datasize","begin",0);
7373
7374     if (ttnet != NET_TCPB) return(0);
7375     if (ttnproto != NP_TELNET) return(0);
7376
7377     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
7378
7379 #ifdef CK_SSL
7380     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
7381         return(0);
7382     }
7383 #endif /* CK_SSL */
7384
7385     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
7386     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
7387     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
7388     sb_out[i++] = TNC_C2S_SET_DATASIZE;   /* Set DataSize */
7389     sb_out[i++] = 0;
7390     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
7391     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
7392
7393 #ifdef DEBUG
7394     if (deblog || tn_deb || debses) {
7395         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
7396                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
7397                   " SET-DATASIZE ", ckltoa(0)," IAC SE", NULL,
7398                   NULL,NULL,NULL,NULL,NULL,NULL);
7399     }
7400 #endif /* DEBUG */
7401 #ifdef OS2
7402     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
7403 #endif
7404 #ifdef DEBUG
7405     debug(F100,tn_msg_out,"",0);
7406     if (tn_deb || debses) tn_debug(tn_msg_out);
7407 #endif /* DEBUG */
7408     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
7409 #ifdef OS2
7410     ReleaseTelnetMutex();
7411 #endif
7412     if (rc)
7413         return(-1);
7414
7415     if (tnc_wait((CHAR *)"comport get datasize",0) < 0) {
7416         tn_push();
7417         return(-1);
7418     }
7419     debug(F111,"tnc_get_datasize","end",tnc_datasize);
7420     return(tnc_datasize);
7421 }
7422
7423 int
7424 #ifdef CK_ANSIC
7425 tnc_set_parity(int parity)
7426 #else /* CK_ANSIC */
7427 tnc_set_parity(parity) int parity;
7428 #endif /* CK_ANSIC */
7429 /* tnc_set_parity */ {
7430     /* IAC SB COM-PORT SET_PARITY <value(1)> IAC SE */
7431     /*        Value     Parity
7432      *          1       None
7433      *          2       Odd
7434      *          3       Even
7435      *          4       Mark
7436      *          5       Space
7437      */
7438     /* Wait for response.  Return new host value. */
7439     int i = 0, rc;
7440
7441     debug(F110,"tnc_set_parity","begin",parity);
7442
7443     if (ttnet != NET_TCPB) return(0);
7444     if (ttnproto != NP_TELNET) return(0);
7445
7446     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
7447
7448 #ifdef CK_SSL
7449     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
7450         return(0);
7451     }
7452 #endif /* CK_SSL */
7453
7454     if ( !(parity >= 1 && parity <= 5) )
7455         return(0);
7456
7457     if ( parity != 0 && parity == tnc_parity )
7458         return(tnc_parity);
7459
7460     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
7461     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
7462     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
7463     sb_out[i++] = TNC_C2S_SET_PARITY;     /* Set Parity */
7464     sb_out[i++] = (unsigned char)(parity & 0xFF);
7465     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
7466     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
7467
7468 #ifdef DEBUG
7469     if (deblog || tn_deb || debses) {
7470         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
7471                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
7472                   " SET-PARITY ", ckitoa(parity)," IAC SE", NULL,
7473                   NULL,NULL,NULL,NULL,NULL,NULL);
7474     }
7475 #endif /* DEBUG */
7476 #ifdef OS2
7477     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
7478 #endif
7479 #ifdef DEBUG
7480     debug(F100,tn_msg_out,"",0);
7481     if (tn_deb || debses) tn_debug(tn_msg_out);
7482 #endif /* DEBUG */
7483     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
7484 #ifdef OS2
7485     ReleaseTelnetMutex();
7486 #endif
7487     if (rc)
7488         return(-1);
7489
7490     if (tnc_wait((CHAR *)"comport set parity",0) < 0) {
7491         tn_push();
7492         return(-1);
7493     }
7494     debug(F111,"tnc_set_parity","end",tnc_parity);
7495     return(tnc_parity);
7496 }
7497
7498 int
7499 #ifdef CK_ANSIC
7500 tnc_get_parity(void)
7501 #else /* CK_ANSIC */
7502 tnc_get_parity()
7503 #endif /* CK_ANSIC */
7504 /* tnc_get_parity */ {
7505     /* IAC SB COM-PORT SET_PARITY <value(1)=0> IAC SE */
7506     /* wait for response */
7507     int i = 0, rc;
7508
7509     debug(F110,"tnc_get_parity","begin",0);
7510     if (ttnet != NET_TCPB) return(0);
7511     if (ttnproto != NP_TELNET) return(0);
7512
7513     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
7514
7515 #ifdef CK_SSL
7516     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
7517         return(0);
7518     }
7519 #endif /* CK_SSL */
7520
7521     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
7522     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
7523     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
7524     sb_out[i++] = TNC_C2S_SET_PARITY;     /* Set Parity */
7525     sb_out[i++] = 0;
7526     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
7527     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
7528
7529 #ifdef DEBUG
7530     if (deblog || tn_deb || debses) {
7531         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
7532                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
7533                   " SET-PARITY ", ckitoa(0)," IAC SE", NULL,
7534                   NULL,NULL,NULL,NULL,NULL,NULL);
7535     }
7536 #endif /* DEBUG */
7537 #ifdef OS2
7538     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
7539 #endif
7540 #ifdef DEBUG
7541     debug(F100,tn_msg_out,"",0);
7542     if (tn_deb || debses) tn_debug(tn_msg_out);
7543 #endif /* DEBUG */
7544     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
7545 #ifdef OS2
7546     ReleaseTelnetMutex();
7547 #endif
7548     if (rc)
7549         return(-1);
7550
7551     if (tnc_wait((CHAR *)"comport get parity",0) < 0) {
7552         tn_push();
7553         return(-1);
7554     }
7555     debug(F111,"tnc_get_parity","end",tnc_parity);
7556     return(tnc_parity);
7557 }
7558
7559 int
7560 #ifdef CK_ANSIC
7561 tnc_set_stopsize(int stopsize)
7562 #else /* CK_ANSIC */
7563 tnc_set_stopsize(stopsize) int stopsize;
7564 #endif /* CK_ANSIC */
7565 /* tnc_set_stopsize */ {
7566     /* IAC SB COM-PORT SET_STOPSIZE <value(1)> IAC SE */
7567     /*        Value     Stop Bit Size
7568      *          1       1
7569      *          2       2
7570      *          3       1.5
7571      */
7572     /* Wait for response.  Return new host value. */
7573     int i = 0, rc;
7574
7575     debug(F111,"tnc_set_stopsize","begin",stopsize);
7576     if (ttnet != NET_TCPB) return(0);
7577     if (ttnproto != NP_TELNET) return(0);
7578
7579     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
7580
7581 #ifdef CK_SSL
7582     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
7583         return(0);
7584     }
7585 #endif /* CK_SSL */
7586
7587     if (!(stopsize >= 1 && stopsize <= 3) )
7588       return(0);
7589
7590     if ( stopsize != 0 && stopsize == tnc_stopbit )
7591         return(tnc_stopbit);
7592
7593     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
7594     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
7595     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
7596     sb_out[i++] = TNC_C2S_SET_STOPSIZE;   /* Set Stop Bits */
7597     sb_out[i++] = (unsigned char)(stopsize & 0xFF);
7598     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
7599     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
7600
7601 #ifdef DEBUG
7602     if (deblog || tn_deb || debses) {
7603         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
7604                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
7605                   " SET-STOPSIZE ", ckitoa(stopsize)," IAC SE", NULL,
7606                   NULL,NULL,NULL,NULL,NULL,NULL);
7607     }
7608 #endif /* DEBUG */
7609 #ifdef OS2
7610     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
7611 #endif
7612 #ifdef DEBUG
7613     debug(F100,tn_msg_out,"",0);
7614     if (tn_deb || debses) tn_debug(tn_msg_out);
7615 #endif /* DEBUG */
7616     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
7617 #ifdef OS2
7618     ReleaseTelnetMutex();
7619 #endif
7620     if (rc)
7621         return(-1);
7622
7623     if (tnc_wait((CHAR *)"comport set stopsize",0) < 0) {
7624         tn_push();
7625         return(-1);
7626     }
7627     debug(F111,"tnc_set_stopsize","end",tnc_stopbit);
7628     return(tnc_stopbit);
7629 }
7630
7631 int
7632 #ifdef CK_ANSIC
7633 tnc_get_stopsize(void)
7634 #else /* CK_ANSIC */
7635 tnc_get_stopsize()
7636 #endif /* CK_ANSIC */
7637 /* tnc_get_stopsize */ {
7638     /* IAC SB COM-PORT SET_STOPSIZE <value(1)=0> IAC SE */
7639     /* Wait for response */
7640     int i = 0, rc;
7641
7642     debug(F110,"tnc_get_stopsize","begin",0);
7643     if (ttnet != NET_TCPB) return(0);
7644     if (ttnproto != NP_TELNET) return(0);
7645
7646     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
7647
7648 #ifdef CK_SSL
7649     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
7650         return(0);
7651     }
7652 #endif /* CK_SSL */
7653
7654     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
7655     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
7656     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
7657     sb_out[i++] = TNC_C2S_SET_STOPSIZE;   /* Set Stop Bits */
7658     sb_out[i++] = 0;
7659     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
7660     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
7661
7662 #ifdef DEBUG
7663     if (deblog || tn_deb || debses) {
7664         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
7665                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
7666                   " SET-STOPSIZE ", ckitoa(0)," IAC SE", NULL,
7667                   NULL,NULL,NULL,NULL,NULL,NULL);
7668     }
7669 #endif /* DEBUG */
7670 #ifdef OS2
7671     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
7672 #endif
7673 #ifdef DEBUG
7674     debug(F100,tn_msg_out,"",0);
7675     if (tn_deb || debses) tn_debug(tn_msg_out);
7676 #endif /* DEBUG */
7677     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
7678 #ifdef OS2
7679     ReleaseTelnetMutex();
7680 #endif
7681     if (rc)
7682         return(-1);
7683
7684     if (tnc_wait((CHAR *)"comport set stopsize",0) < 0) {
7685         tn_push();
7686         return(-1);
7687     }
7688     debug(F111,"tnc_get_stopsize","end",tnc_stopbit);
7689     return(tnc_stopbit);
7690 }
7691
7692 int
7693 #ifdef CK_ANSIC
7694 tnc_set_oflow(int control)
7695 #else /* CK_ANSIC */
7696 tnc_set_oflow(control) int control;
7697 #endif /* CK_ANSIC */
7698 /* tnc_set_oflow */ {
7699     /* IAC SB COM_PORT SET_CONTROL <value(1)> IAC SE */
7700     /*        Value     Flow Control
7701      *          1       No Flow Control
7702      *          2       Xon/Xoff
7703      *          3       Rts/Cts
7704      *         17       DCD
7705      *         19       DSR
7706      */
7707     /* wait for response, return new host value. */
7708     int i = 0, rc;
7709
7710     debug(F111,"tnc_set_oflow","begin",control);
7711     if (ttnet != NET_TCPB) return(0);
7712     if (ttnproto != NP_TELNET) return(0);
7713
7714     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
7715
7716 #ifdef CK_SSL
7717     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
7718         return(0);
7719     }
7720 #endif /* CK_SSL */
7721
7722     if (control != 1 && control != 2 && control != 3 &&
7723         control != 17 && control != 19)
7724       return(0);
7725
7726     if ( control != 0 && control == tnc_oflow )
7727         return(tnc_oflow);
7728
7729     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
7730     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
7731     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
7732     sb_out[i++] = TNC_C2S_SET_CONTROL;    /* Set Control */
7733     sb_out[i++] = (unsigned char)(control & 0xFF);
7734     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
7735     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
7736
7737 #ifdef DEBUG
7738     if (deblog || tn_deb || debses) {
7739         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
7740                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
7741                   " SET-CONTROL ", ckitoa(control)," IAC SE", NULL,
7742                   NULL,NULL,NULL,NULL,NULL,NULL);
7743     }
7744 #endif /* DEBUG */
7745 #ifdef OS2
7746     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
7747 #endif
7748 #ifdef DEBUG
7749     debug(F100,tn_msg_out,"",0);
7750     if (tn_deb || debses) tn_debug(tn_msg_out);
7751 #endif /* DEBUG */
7752     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
7753 #ifdef OS2
7754     ReleaseTelnetMutex();
7755 #endif
7756     if (rc)
7757         return(-1);
7758
7759     if (tnc_wait((CHAR *)"comport set outbound flow control",0) < 0) {
7760         tn_push();
7761         return(-1);
7762     }
7763     debug(F111,"tnc_set_oflow","end",tnc_oflow);
7764     return(tnc_oflow);
7765 }
7766
7767 int
7768 #ifdef CK_ANSIC
7769 tnc_get_oflow(void)
7770 #else /* CK_ANSIC */
7771 tnc_get_oflow()
7772 #endif /* CK_ANSIC */
7773 /* tnc_get_oflow */ {
7774     /* IAC SB COM_PORT SET_CONTROL <value(1)=0> IAC SE */
7775     /* wait for response */
7776     int i = 0, rc;
7777
7778     debug(F110,"tnc_get_oflow","begin",0);
7779     if (ttnet != NET_TCPB) return(0);
7780     if (ttnproto != NP_TELNET) return(0);
7781
7782     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
7783
7784 #ifdef CK_SSL
7785     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
7786         return(0);
7787     }
7788 #endif /* CK_SSL */
7789
7790     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
7791     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
7792     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
7793     sb_out[i++] = TNC_C2S_SET_CONTROL;    /* Set Control */
7794     sb_out[i++] = TNC_CTL_OFLOW_REQUEST;
7795     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
7796     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
7797
7798 #ifdef DEBUG
7799     if (deblog || tn_deb || debses) {
7800         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
7801                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
7802                   " SET-CONTROL ",
7803                    ckitoa(TNC_CTL_OFLOW_REQUEST),
7804                    " IAC SE", NULL,
7805                   NULL,NULL,NULL,NULL,NULL,NULL);
7806     }
7807 #endif /* DEBUG */
7808 #ifdef OS2
7809     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
7810 #endif
7811 #ifdef DEBUG
7812     debug(F100,tn_msg_out,"",0);
7813     if (tn_deb || debses) tn_debug(tn_msg_out);
7814 #endif /* DEBUG */
7815     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
7816 #ifdef OS2
7817     ReleaseTelnetMutex();
7818 #endif
7819     if (rc)
7820         return(-1);
7821
7822     if (tnc_wait((CHAR *)"comport get outbound flow control",0) < 0) {
7823         tn_push();
7824         return(-1);
7825     }
7826     debug(F111,"tnc_get_oflow","end",tnc_oflow);
7827     return(tnc_oflow);
7828 }
7829
7830 int
7831 #ifdef CK_ANSIC
7832 tnc_set_iflow(int control)
7833 #else /* CK_ANSIC */
7834 tnc_set_iflow(control) int control;
7835 #endif /* CK_ANSIC */
7836 /* tnc_set_iflow */ {
7837     /* IAC SB COM_PORT SET_CONTROL <value(1)> IAC SE */
7838     /*        Value     Flow Control
7839      *         14       No Flow Control
7840      *         15       Xon/Xoff
7841      *         16       Rts/Cts
7842      *         18       DTR
7843      */
7844     /* wait for response, return new host value. */
7845     int i = 0, rc;
7846
7847     debug(F111,"tnc_set_iflow","begin",control);
7848     if (ttnet != NET_TCPB) return(0);
7849     if (ttnproto != NP_TELNET) return(0);
7850
7851     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
7852
7853 #ifdef CK_SSL
7854     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
7855         return(0);
7856     }
7857 #endif /* CK_SSL */
7858
7859     if (control != 14 && control != 15 && control != 16 && control != 18)
7860       return(0);
7861
7862     if ( control != 0 && control == tnc_iflow )
7863         return(tnc_iflow);
7864
7865     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
7866     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
7867     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
7868     sb_out[i++] = TNC_C2S_SET_CONTROL;    /* Set Control */
7869     sb_out[i++] = (unsigned char)(control & 0xFF);
7870     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
7871     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
7872
7873 #ifdef DEBUG
7874     if (deblog || tn_deb || debses) {
7875         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
7876                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
7877                   " SET-CONTROL ", ckitoa(control)," IAC SE", NULL,
7878                   NULL,NULL,NULL,NULL,NULL,NULL);
7879     }
7880 #endif /* DEBUG */
7881 #ifdef OS2
7882     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
7883 #endif
7884 #ifdef DEBUG
7885     debug(F100,tn_msg_out,"",0);
7886     if (tn_deb || debses) tn_debug(tn_msg_out);
7887 #endif /* DEBUG */
7888     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
7889 #ifdef OS2
7890     ReleaseTelnetMutex();
7891 #endif
7892     if (rc)
7893       return(-1);
7894
7895     if (tnc_wait((CHAR *)"comport set inbound flow control",0) < 0) {
7896         tn_push();
7897         return(-1);
7898     }
7899     debug(F111,"tnc_set_iflow","end",tnc_iflow);
7900     return(tnc_iflow);
7901 }
7902
7903 int
7904 #ifdef CK_ANSIC
7905 tnc_get_iflow(void)
7906 #else /* CK_ANSIC */
7907 tnc_get_iflow()
7908 #endif /* CK_ANSIC */
7909 /* tnc_get_iflow */ {
7910     /* IAC SB COM_PORT SET_CONTROL <value(1)=13> IAC SE */
7911     /* wait for response */
7912     int i = 0, rc;
7913
7914     debug(F110,"tnc_get_iflow","begin",0);
7915     if (ttnet != NET_TCPB) return(0);
7916     if (ttnproto != NP_TELNET) return(0);
7917
7918     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
7919
7920 #ifdef CK_SSL
7921     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
7922         return(0);
7923     }
7924 #endif /* CK_SSL */
7925
7926     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
7927     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
7928     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
7929     sb_out[i++] = TNC_C2S_SET_CONTROL;    /* Set Control */
7930     sb_out[i++] = TNC_CTL_IFLOW_REQUEST;
7931     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
7932     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
7933
7934 #ifdef DEBUG
7935     if (deblog || tn_deb || debses) {
7936         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
7937                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
7938                   " SET-CONTROL ",
7939                   ckitoa(TNC_CTL_IFLOW_REQUEST),
7940                   " IAC SE", NULL,
7941                   NULL,NULL,NULL,NULL,NULL,NULL);
7942     }
7943 #endif /* DEBUG */
7944 #ifdef OS2
7945     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
7946 #endif
7947 #ifdef DEBUG
7948     debug(F100,tn_msg_out,"",0);
7949     if (tn_deb || debses) tn_debug(tn_msg_out);
7950 #endif /* DEBUG */
7951     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
7952 #ifdef OS2
7953     ReleaseTelnetMutex();
7954 #endif
7955     if (rc)
7956         return(-1);
7957
7958     if (tnc_wait((CHAR *)"comport get inbound flow control",0) < 0) {
7959         tn_push();
7960         return(-1);
7961     }
7962     debug(F111,"tnc_get_iflow","end",tnc_iflow);
7963     return(tnc_iflow);
7964 }
7965
7966 int
7967 #ifdef CK_ANSIC
7968 tnc_set_break_state(int onoff)
7969 #else /* CK_ANSIC */
7970 tnc_set_break_state(onoff) int onoff;
7971 #endif /* CK_ANSIC */
7972 /* tnc_set_break_state */ {
7973     /* IAC SB COM_PORT SET_CONTROL <value(1)> IAC SE */
7974     /*        Value     Break State
7975      *          5       On
7976      *          6       Off
7977      */
7978     /* wait for response, return new host value. */
7979     int i = 0, rc;
7980
7981     debug(F111,"tnc_set_break_state","begin",onoff);
7982     if (ttnet != NET_TCPB) return(0);
7983     if (ttnproto != NP_TELNET) return(0);
7984
7985     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
7986
7987 #ifdef CK_SSL
7988     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
7989         return(0);
7990     }
7991 #endif /* CK_SSL */
7992
7993     if ( onoff != 0 && onoff == tnc_break )
7994         return(tnc_break);
7995
7996     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
7997     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
7998     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
7999     sb_out[i++] = TNC_C2S_SET_CONTROL;    /* Set Control */
8000     sb_out[i++] = onoff ?
8001       TNC_CTL_BREAK_ON : TNC_CTL_BREAK_OFF;
8002     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
8003     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
8004
8005 #ifdef DEBUG
8006     if (deblog || tn_deb || debses) {
8007         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
8008                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
8009                   " SET-CONTROL ",
8010                   onoff ? "BREAK-ON" : "BREAK-OFF",
8011                   " IAC SE", NULL,
8012                   NULL,NULL,NULL,NULL,NULL,NULL);
8013     }
8014 #endif /* DEBUG */
8015 #ifdef OS2
8016     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
8017 #endif
8018 #ifdef DEBUG
8019     debug(F100,tn_msg_out,"",0);
8020     if (tn_deb || debses) tn_debug(tn_msg_out);
8021 #endif /* DEBUG */
8022     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
8023 #ifdef OS2
8024     ReleaseTelnetMutex();
8025 #endif
8026     if (rc)
8027         return(-1);
8028
8029     if (tnc_wait((CHAR *)"comport set break state",0) < 0) {
8030         tn_push();
8031         return(-1);
8032     }
8033     debug(F111,"tnc_set_break_state","end",tnc_break);
8034     return(tnc_break);
8035 }
8036
8037 int
8038 #ifdef CK_ANSIC
8039 tnc_get_break_state(void)
8040 #else /* CK_ANSIC */
8041 tnc_get_break_state()
8042 #endif /* CK_ANSIC */
8043 /* tnc_get_break_state */ {
8044     /* IAC SB COM_PORT SET_CONTROL <value(1)=4> IAC SE */
8045     /* wait for response */
8046     int i = 0, rc;
8047
8048     debug(F110,"tnc_get_break_state","begin",0);
8049     if (ttnet != NET_TCPB) return(0);
8050     if (ttnproto != NP_TELNET) return(0);
8051
8052     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
8053
8054 #ifdef CK_SSL
8055     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
8056         return(0);
8057     }
8058 #endif /* CK_SSL */
8059
8060     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
8061     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
8062     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
8063     sb_out[i++] = TNC_C2S_SET_CONTROL;    /* Set Control */
8064     sb_out[i++] = TNC_CTL_BREAK_REQUEST;
8065     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
8066     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
8067
8068 #ifdef DEBUG
8069     if (deblog || tn_deb || debses) {
8070         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
8071                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
8072                   " SET-CONTROL ",
8073                   "BREAK-REQUEST",
8074                   " IAC SE", NULL,
8075                   NULL,NULL,NULL,NULL,NULL,NULL);
8076     }
8077 #endif /* DEBUG */
8078 #ifdef OS2
8079     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
8080 #endif
8081 #ifdef DEBUG
8082     debug(F100,tn_msg_out,"",0);
8083     if (tn_deb || debses) tn_debug(tn_msg_out);
8084 #endif /* DEBUG */
8085     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
8086 #ifdef OS2
8087     ReleaseTelnetMutex();
8088 #endif
8089     if (rc)
8090         return(-1);
8091
8092     if (tnc_wait((CHAR *)"comport get break state",0) < 0) {
8093         tn_push();
8094         return(-1);
8095     }
8096     debug(F111,"tnc_get_break_state","end",tnc_break);
8097     return(tnc_break);
8098 }
8099
8100 int
8101 #ifdef CK_ANSIC
8102 tnc_set_dtr_state(int onoff)
8103 #else /* CK_ANSIC */
8104 tnc_set_dtr_state(onoff) int onoff;
8105 #endif /* CK_ANSIC */
8106 /* tnc_set_dtr_state */ {
8107     /* IAC SB COM_PORT SET_CONTROL <value(1)> IAC SE */
8108     /*        Value     Dtr State
8109      *          8       On
8110      *          9       Off
8111      */
8112     /* wait for response, return new host value. */
8113     int i = 0, rc;
8114
8115     debug(F111,"tnc_set_dtr_state","begin",onoff);
8116     if (ttnet != NET_TCPB) return(0);
8117     if (ttnproto != NP_TELNET) return(0);
8118
8119     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
8120
8121 #ifdef CK_SSL
8122     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
8123         return(0);
8124     }
8125 #endif /* CK_SSL */
8126
8127     if ( onoff != 0 && onoff == tnc_dtr )
8128         return(tnc_dtr);
8129
8130     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
8131     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
8132     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
8133     sb_out[i++] = TNC_C2S_SET_CONTROL;    /* Set Control */
8134     sb_out[i++] = onoff ?
8135         TNC_CTL_DTR_ON : TNC_CTL_DTR_OFF;
8136     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
8137     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
8138
8139 #ifdef DEBUG
8140     if (deblog || tn_deb || debses) {
8141         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
8142                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
8143                   " SET-CONTROL ",
8144                   onoff ? "DTR-ON" : "DTR-OFF",
8145                   " IAC SE", NULL,
8146                   NULL,NULL,NULL,NULL,NULL,NULL);
8147     }
8148 #endif /* DEBUG */
8149 #ifdef OS2
8150     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
8151 #endif
8152 #ifdef DEBUG
8153     debug(F100,tn_msg_out,"",0);
8154     if (tn_deb || debses) tn_debug(tn_msg_out);
8155 #endif /* DEBUG */
8156     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
8157 #ifdef OS2
8158     ReleaseTelnetMutex();
8159 #endif
8160     if (rc)
8161       return(-1);
8162
8163     if (tnc_wait((CHAR *)"comport set dtr state",0) < 0) {
8164         tn_push();
8165         return(-1);
8166     }
8167     debug(F111,"tnc_set_dtr_state","end",tnc_dtr);
8168     return(tnc_dtr);
8169 }
8170
8171 int
8172 #ifdef CK_ANSIC
8173 tnc_get_dtr_state(void)
8174 #else /* CK_ANSIC */
8175 tnc_get_dtr_state()
8176 #endif /* CK_ANSIC */
8177 /* tnc_get_dtr_state */ {
8178     /* IAC SB COM_PORT SET_CONTROL <value(1)=7> IAC SE */
8179     /* wait for response */
8180     int i = 0, rc;
8181
8182     debug(F110,"tnc_get_dtr_state","begin",0);
8183     if (ttnet != NET_TCPB) return(0);
8184     if (ttnproto != NP_TELNET) return(0);
8185
8186     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
8187
8188 #ifdef CK_SSL
8189     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
8190         return(0);
8191     }
8192 #endif /* CK_SSL */
8193
8194     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
8195     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
8196     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
8197     sb_out[i++] = TNC_C2S_SET_CONTROL;    /* Set Control */
8198     sb_out[i++] = TNC_CTL_DTR_REQUEST;
8199     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
8200     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
8201
8202 #ifdef DEBUG
8203     if (deblog || tn_deb || debses) {
8204         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
8205                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
8206                   " SET-CONTROL ",
8207                   "DTR-REQUEST",
8208                   " IAC SE", NULL,
8209                   NULL,NULL,NULL,NULL,NULL,NULL);
8210     }
8211 #endif /* DEBUG */
8212 #ifdef OS2
8213     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
8214 #endif
8215 #ifdef DEBUG
8216     debug(F100,tn_msg_out,"",0);
8217     if (tn_deb || debses) tn_debug(tn_msg_out);
8218 #endif /* DEBUG */
8219     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
8220 #ifdef OS2
8221     ReleaseTelnetMutex();
8222 #endif
8223     if (rc)
8224       return(-1);
8225
8226     if (tnc_wait((CHAR *)"comport get dtr state",0) < 0) {
8227         tn_push();
8228         return(-1);
8229     }
8230     debug(F111,"tnc_get_dtr_state","end",tnc_dtr);
8231     return(tnc_dtr);
8232 }
8233
8234 int
8235 #ifdef CK_ANSIC
8236 tnc_set_rts_state(int onoff)
8237 #else /* CK_ANSIC */
8238 tnc_set_rts_state(onoff) int onoff;
8239 #endif /* CK_ANSIC */
8240 /* tnc_set_rts_state */ {
8241     /* IAC SB COM_PORT SET_CONTROL <value(1)> IAC SE */
8242     /*        Value     Rts State
8243      *          5       On
8244      *          6       Off
8245      */
8246     /* wait for response, return new host value. */
8247     int i = 0, rc;
8248
8249     debug(F111,"tnc_set_rts_state","begin",onoff);
8250     if (ttnet != NET_TCPB) return(0);
8251     if (ttnproto != NP_TELNET) return(0);
8252
8253     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
8254
8255 #ifdef CK_SSL
8256     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
8257         return(0);
8258     }
8259 #endif /* CK_SSL */
8260
8261     if ( onoff != 0 && onoff == tnc_rts )
8262         return(tnc_rts);
8263
8264     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
8265     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
8266     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
8267     sb_out[i++] = TNC_C2S_SET_CONTROL;    /* Set Control */
8268     sb_out[i++] = onoff ?
8269       TNC_CTL_RTS_ON : TNC_CTL_RTS_OFF;
8270     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
8271     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
8272
8273 #ifdef DEBUG
8274     if (deblog || tn_deb || debses) {
8275         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
8276                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
8277                   " SET-CONTROL ",
8278                   onoff ? "RTS-ON" : "RTS-OFF",
8279                   " IAC SE", NULL,
8280                   NULL,NULL,NULL,NULL,NULL,NULL);
8281     }
8282 #endif /* DEBUG */
8283 #ifdef OS2
8284     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
8285 #endif
8286 #ifdef DEBUG
8287     debug(F100,tn_msg_out,"",0);
8288     if (tn_deb || debses) tn_debug(tn_msg_out);
8289 #endif /* DEBUG */
8290     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
8291 #ifdef OS2
8292     ReleaseTelnetMutex();
8293 #endif
8294     if (rc)
8295       return(-1);
8296
8297     if (tnc_wait((CHAR *)"comport set rts state",0) < 0) {
8298         tn_push();
8299         return(-1);
8300     }
8301     debug(F111,"tnc_set_rts_state","end",tnc_rts);
8302     return(tnc_rts);
8303 }
8304
8305 int
8306 #ifdef CK_ANSIC
8307 tnc_get_rts_state(void)
8308 #else /* CK_ANSIC */
8309 tnc_get_rts_state()
8310 #endif /* CK_ANSIC */
8311 /* tnc_get_rts_state */ {
8312     /* IAC SB COM_PORT SET_CONTROL <value(1)=10> IAC SE */
8313     /* wait for response */
8314     int i = 0, rc;
8315
8316     debug(F110,"tnc_get_rts_state","begin",0);
8317     if (ttnet != NET_TCPB) return(0);
8318     if (ttnproto != NP_TELNET) return(0);
8319
8320     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
8321
8322 #ifdef CK_SSL
8323     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
8324         return(0);
8325     }
8326 #endif /* CK_SSL */
8327
8328     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
8329     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
8330     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
8331     sb_out[i++] = TNC_C2S_SET_CONTROL;    /* Set Control */
8332     sb_out[i++] = TNC_CTL_RTS_REQUEST;
8333     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
8334     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
8335
8336 #ifdef DEBUG
8337     if (deblog || tn_deb || debses) {
8338         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
8339                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
8340                   " SET-CONTROL ",
8341                   "RTS-REQUEST",
8342                   " IAC SE", NULL,
8343                   NULL,NULL,NULL,NULL,NULL,NULL);
8344     }
8345 #endif /* DEBUG */
8346 #ifdef OS2
8347     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
8348 #endif
8349 #ifdef DEBUG
8350     debug(F100,tn_msg_out,"",0);
8351     if (tn_deb || debses) tn_debug(tn_msg_out);
8352 #endif /* DEBUG */
8353     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
8354 #ifdef OS2
8355     ReleaseTelnetMutex();
8356 #endif
8357     if (rc)
8358         return(-1);
8359
8360     if (tnc_wait((CHAR *)"comport get rts state",0) < 0) {
8361         tn_push();
8362         return(-1);
8363     }
8364     debug(F111,"tnc_get_rts_state","end",tnc_rts);
8365     return(tnc_rts);
8366 }
8367
8368 int
8369 #ifdef CK_ANSIC
8370 tnc_set_ls_mask(int mask)
8371 #else /* CK_ANSIC */
8372 tnc_set_ls_mask(mask) int mask;
8373 #endif /* CK_ANSIC */
8374 /* tnc_set_ls_mask */ {
8375     /* IAC SB COM_PORT SET_LINESTATE_MASK <value(1)> IAC SE */
8376     /*        Bit       Meaning
8377      *          0       Data Ready
8378      *          1       Overrun Error
8379      *          2       Parity Error
8380      *          3       Framing Error
8381      *          4       Break Detect Error
8382      *          5       Transfer Holding Register Empty
8383      *          6       Transfer Shift Register Empty
8384      *          7       Timeout Error
8385      */
8386     int i = 0, rc;
8387
8388     debug(F111,"tnc_set_ls_mask","begin",mask);
8389     if (ttnet != NET_TCPB) return(0);
8390     if (ttnproto != NP_TELNET) return(0);
8391
8392     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
8393
8394 #ifdef CK_SSL
8395     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
8396         return(0);
8397     }
8398 #endif /* CK_SSL */
8399
8400     if ( mask != 0 && mask == tnc_ls_mask )
8401         return(tnc_ls_mask);
8402
8403     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
8404     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
8405     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
8406     sb_out[i++] = TNC_C2S_SET_LS_MASK;
8407     sb_out[i++] = (unsigned char)(mask & 0xFF);
8408     if (sb_out[i-1] == IAC )
8409       sb_out[i++] = IAC;
8410     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
8411     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
8412
8413 #ifdef DEBUG
8414     if (deblog || tn_deb || debses) {
8415         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
8416                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
8417                   " SET-LINESTATE-MASK ",
8418                   ckitoa(mask & 0xFF),
8419                   " IAC SE", NULL,
8420                   NULL,NULL,NULL,NULL,NULL,NULL);
8421     }
8422 #endif /* DEBUG */
8423 #ifdef OS2
8424     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
8425 #endif
8426 #ifdef DEBUG
8427     debug(F100,tn_msg_out,"",0);
8428     if (tn_deb || debses) tn_debug(tn_msg_out);
8429 #endif /* DEBUG */
8430     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
8431 #ifdef OS2
8432     ReleaseTelnetMutex();
8433 #endif
8434     if (rc)
8435       return(-1);
8436
8437     tnc_ls_mask = mask;
8438     debug(F111,"tnc_set_ls_mask","end",tnc_ls_mask);
8439     return(0);
8440 }
8441
8442 int
8443 #ifdef CK_ANSIC
8444 tnc_get_ls_mask(void)
8445 #else /* CK_ANSIC */
8446 tnc_get_ls_mask()
8447 #endif /* CK_ANSIC */
8448 /* tnc_get_ls_mask */ {
8449     debug(F101,"tnc_get_ls_mask","",tnc_ls_mask);
8450     return(tnc_ls_mask);
8451 }
8452
8453 int
8454 #ifdef CK_ANSIC
8455 tnc_get_ls(void)
8456 #else /* CK_ANSIC */
8457 tnc_get_ls()
8458 #endif /* CK_ANSIC */
8459 /* tnc_get_ls */ {
8460     int ls = tnc_ls;
8461     debug(F101,"tnc_get_ls","",tnc_ls);
8462     return(ls);
8463 }
8464
8465 int
8466 #ifdef CK_ANSIC
8467 tnc_set_ms_mask(int mask)
8468 #else /* CK_ANSIC */
8469 tnc_set_ms_mask(mask) int mask;
8470 #endif /* CK_ANSIC */
8471 /* tnc_set_ms_mask */ {
8472     /* IAC SB COM_PORT SET_MODEMSTATE_MASK <value(1)> IAC SE */
8473     /*        Bit       Meaning
8474      *          0       Delta Clear To Send
8475      *          1       Delta Data Set Ready
8476      *          2       Trailing Edge Ring Detector
8477      *          3       Delta Receive Line Signal (Carrier) Detect
8478      *          4       Clear To Send Signal State
8479      *          5       Data-Set-Ready Signal State
8480      *          6       Ring Indicator
8481      *          7       Receive Line Signal (Carrier) Detect
8482      */
8483
8484     int i = 0, rc;
8485
8486     debug(F111,"tnc_set_ms_mask","begin",mask);
8487     if (ttnet != NET_TCPB) return(0);
8488     if (ttnproto != NP_TELNET) return(0);
8489
8490     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
8491
8492 #ifdef CK_SSL
8493     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
8494         return(0);
8495     }
8496 #endif /* CK_SSL */
8497
8498     if ( mask != 0 && mask == tnc_ms_mask )
8499         return(tnc_ms_mask);
8500
8501     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
8502     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
8503     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
8504     sb_out[i++] = TNC_C2S_SET_MS_MASK;
8505     sb_out[i++] = (unsigned char)(mask & 0xFF);
8506     if (sb_out[i-1] == IAC )
8507       sb_out[i++] = IAC;
8508     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
8509     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
8510
8511 #ifdef DEBUG
8512     if (deblog || tn_deb || debses) {
8513         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
8514                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
8515                   " SET-MODEMSTATE-MASK ",
8516                   ckitoa(mask & 0xFF),
8517                   " IAC SE", NULL,
8518                   NULL,NULL,NULL,NULL,NULL,NULL);
8519     }
8520 #endif /* DEBUG */
8521 #ifdef OS2
8522     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
8523 #endif
8524 #ifdef DEBUG
8525     debug(F100,tn_msg_out,"",0);
8526     if (tn_deb || debses) tn_debug(tn_msg_out);
8527 #endif /* DEBUG */
8528     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
8529 #ifdef OS2
8530     ReleaseTelnetMutex();
8531 #endif
8532     if (rc)
8533       return(-1);
8534
8535     tnc_ms_mask = mask;
8536     debug(F111,"tnc_set_ms_mask","end",tnc_ms_mask);
8537     return(0);
8538 }
8539
8540 int
8541 #ifdef CK_ANSIC
8542 tnc_get_ms_mask(void)
8543 #else /* CK_ANSIC */
8544 tnc_get_ms_mask()
8545 #endif /* CK_ANSIC */
8546 /* tnc_get_ms_mask */ {
8547     debug(F101,"tnc_get_gs_mask","",tnc_ms_mask);
8548     return(tnc_ms_mask);
8549 }
8550
8551 int
8552 #ifdef CK_ANSIC
8553 tnc_get_ms(void)
8554 #else /* CK_ANSIC */
8555 tnc_get_ms()
8556 #endif /* CK_ANSIC */
8557 /* tnc_get_ms */ {
8558     int ms = tnc_ms;
8559     debug(F101,"tnc_get_ms","",tnc_ms);
8560     return(ms);
8561 }
8562
8563 int
8564 #ifdef CK_ANSIC
8565 tnc_send_purge_data(int mode)
8566 #else /* CK_ANSIC */
8567 tnc_send_purge_data(mode) int mode;
8568 #endif /* CK_ANSIC */
8569 /* tnc_send_purge_data */ {
8570     /* IAC SB COM_PORT PURGE_DATA <value(1)> IAC SE */
8571     /*        Value     Meaning
8572      *          1       Purge access server receive data buffer
8573      *          2       Purge access server transmit data buffer
8574      *          3       Purge access server receive and transmit data buffers
8575      */
8576     /* No response */
8577     int i = 0, rc;
8578
8579     debug(F111,"tnc_send_purge_data","begin",mode);
8580     if (ttnet != NET_TCPB) return(0);
8581     if (ttnproto != NP_TELNET) return(0);
8582
8583     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
8584
8585 #ifdef CK_SSL
8586     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
8587         return(0);
8588     }
8589 #endif /* CK_SSL */
8590
8591     if ( !(mode >= 1 && mode <= 3) )
8592         return(0);
8593
8594     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
8595     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
8596     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
8597     sb_out[i++] = TNC_C2S_PURGE;
8598     sb_out[i++] = (unsigned char)(mode & 0xFF);
8599     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
8600     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
8601
8602 #ifdef DEBUG
8603     if (deblog || tn_deb || debses) {
8604         ckmakxmsg(tn_msg_out,TN_MSG_LEN,
8605                   "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
8606                   " PURGE-DATA ",
8607                   ckitoa(mode & 0xFF),
8608                   " IAC SE", NULL,
8609                   NULL,NULL,NULL,NULL,NULL,NULL);
8610     }
8611 #endif /* DEBUG */
8612 #ifdef OS2
8613     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
8614 #endif
8615 #ifdef DEBUG
8616     debug(F100,tn_msg_out,"",0);
8617     if (tn_deb || debses) tn_debug(tn_msg_out);
8618 #endif /* DEBUG */
8619     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
8620 #ifdef OS2
8621     ReleaseTelnetMutex();
8622 #endif
8623     if (rc)
8624       return(-1);
8625     debug(F110,"tnc_send_purge_data","end",0);
8626     return(0);
8627 }
8628
8629 int
8630 #ifdef CK_ANSIC
8631 tnc_flow_suspended(void)
8632 #else /* CK_ANSIC */
8633 tnc_flow_suspended()
8634 #endif /* CK_ANSIC */
8635 /* tnc_flow_suspended */ {
8636     debug(F111,"tnc_flow_suspended","",tnc_suspend_xmit);
8637     return(tnc_suspend_xmit);
8638 }
8639
8640 int
8641 #ifdef CK_ANSIC
8642 tnc_suspend_flow(void)
8643 #else /* CK_ANSIC */
8644 tnc_suspend_flow()
8645 #endif /* CK_ANSIC */
8646 /* tnc_suspend_flow */ {
8647     /* IAC SB COM_PORT FLOWCONTROL_SUSPEND IAC SE */
8648     int i = 0, rc;
8649
8650     debug(F110,"tnc_suspend_flow","begin",0);
8651     if (ttnet != NET_TCPB) return(0);
8652     if (ttnproto != NP_TELNET) return(0);
8653
8654     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
8655
8656 #ifdef CK_SSL
8657     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
8658         return(0);
8659     }
8660 #endif /* CK_SSL */
8661
8662     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
8663     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
8664     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
8665     sb_out[i++] = TNC_C2S_FLOW_SUSPEND;
8666     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
8667     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
8668
8669 #ifdef DEBUG
8670     if (deblog || tn_deb || debses) {
8671         ckmakmsg(tn_msg_out,TN_MSG_LEN,
8672                  "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
8673                  " FLOWCONTROL-SUSPEND IAC SE", NULL);
8674     }
8675 #endif /* DEBUG */
8676 #ifdef OS2
8677     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
8678 #endif
8679 #ifdef DEBUG
8680     debug(F100,tn_msg_out,"",0);
8681     if (tn_deb || debses) tn_debug(tn_msg_out);
8682 #endif /* DEBUG */
8683     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
8684 #ifdef OS2
8685     ReleaseTelnetMutex();
8686 #endif
8687     if (rc)
8688         return(-1);
8689     debug(F110,"tnc_suspend_flow","end",0);
8690     return(0);
8691 }
8692
8693 int
8694 #ifdef CK_ANSIC
8695 tnc_resume_flow(void)
8696 #else /* CK_ANSIC */
8697 tnc_resume_flow()
8698 #endif /* CK_ANSIC */
8699 /* tnc_resume_flow */ {
8700     /* IAC SB COM_PORT FLOWCONTROL_RESUME IAC SE */
8701     int i = 0, rc;
8702
8703     debug(F110,"tnc_resume_flow","begin",0);
8704     if (ttnet != NET_TCPB) return(0);
8705     if (ttnproto != NP_TELNET) return(0);
8706
8707     if (!TELOPT_ME(TELOPT_COMPORT)) return(0);
8708
8709 #ifdef CK_SSL
8710     if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) {
8711         return(0);
8712     }
8713 #endif /* CK_SSL */
8714
8715     sb_out[i++] = (CHAR) IAC;                 /* I Am a Command */
8716     sb_out[i++] = (CHAR) SB;                  /* Subnegotiation */
8717     sb_out[i++] = TELOPT_COMPORT;             /* ComPort */
8718     sb_out[i++] = TNC_C2S_FLOW_RESUME;
8719     sb_out[i++] = (CHAR) IAC;                 /* End of Subnegotiation */
8720     sb_out[i++] = (CHAR) SE;                  /* marked by IAC SE */
8721
8722 #ifdef DEBUG
8723     if (deblog || tn_deb || debses) {
8724         ckmakmsg(tn_msg_out,TN_MSG_LEN,
8725                  "TELNET SENT SB ",TELOPT(TELOPT_COMPORT),
8726                  " FLOWCONTROL-RESUME IAC SE", NULL);
8727     }
8728 #endif /* DEBUG */
8729 #ifdef OS2
8730     RequestTelnetMutex( SEM_INDEFINITE_WAIT );
8731 #endif
8732 #ifdef DEBUG
8733     debug(F100,tn_msg_out,"",0);
8734     if (tn_deb || debses) tn_debug(tn_msg_out);
8735 #endif /* DEBUG */
8736     rc = (ttol((CHAR *)sb_out,i) < 0);      /* Send it. */
8737 #ifdef OS2
8738     ReleaseTelnetMutex();
8739 #endif
8740     if (rc)
8741         return(-1);
8742     debug(F110,"tnc_resume_flow","end",0);
8743     return(0);
8744 }
8745
8746 int
8747 #ifdef CK_ANSIC
8748 tnsetflow(int nflow)
8749 #else
8750 tnsetflow(nflow) int nflow;
8751 #endif /* CK_ANSIC */
8752 /* tnsetflow */ {
8753
8754     int rc = -1;
8755
8756     debug(F111,"tnsetflow","begin",nflow);
8757     if (ttnet != NET_TCPB || ttnproto != NP_TELNET)
8758         return(-1);
8759
8760     if (TELOPT_ME(TELOPT_COMPORT)) {
8761         switch(nflow) {
8762           case FLO_XONX:
8763             rc = tnc_set_oflow(
8764                  TNC_CTL_OFLOW_XON_XOFF
8765                  );
8766             if (rc >= 0)
8767               rc = tnc_set_iflow(
8768                    TNC_CTL_IFLOW_XON_XOFF
8769                    );
8770             break;
8771           case FLO_RTSC:
8772             rc = tnc_set_oflow(
8773                  TNC_CTL_OFLOW_RTS_CTS
8774                  );
8775             if (rc >= 0)
8776               rc = tnc_set_iflow(
8777                    TNC_CTL_IFLOW_RTS_CTS
8778                    );
8779             break;
8780           case FLO_KEEP:
8781             /* leave things exactly as they are */
8782             rc = 0;
8783             break;
8784           case FLO_NONE:
8785           case FLO_DIAL:  /* dialing hack */
8786           case FLO_DIAX:  /* cancel dialing hack */
8787             rc = tnc_set_oflow(
8788                  TNC_CTL_OFLOW_NONE
8789                  );
8790             if (rc >= 0)
8791               rc = tnc_set_iflow(
8792                    TNC_CTL_IFLOW_NONE
8793                    );
8794             break;
8795           case FLO_DTRC:
8796           case FLO_ETXA:
8797           case FLO_STRG:
8798           case FLO_DTRT:
8799           default:
8800             /* not supported */
8801             rc = -1;
8802             break;
8803         }
8804     }
8805     debug(F111,"tnsetflow","end",rc);
8806     return(rc >= 0 ? 0 : -1);
8807 }
8808
8809 int
8810 #ifdef CK_ANSIC
8811 tnsettings(int par, int stop)
8812 #else
8813 tnsettings(par, stop) int par, stop;
8814 #endif /* CK_ANSIC */
8815 /* tnsettings */ {
8816     int rc = -1;
8817     int datasize = 0;
8818     extern int hwparity;
8819
8820     debug(F111,"tnsettings begin","par",par);
8821     debug(F111,"tnsettings begin","stop",stop);
8822     if (ttnet != NET_TCPB || ttnproto != NP_TELNET)
8823       return(-1);
8824
8825     datasize = par ? TNC_DS_7 : TNC_DS_8;
8826     if (!par) par = hwparity;
8827
8828     if (TELOPT_ME(TELOPT_COMPORT)) {
8829         switch (par) {
8830           case 'e':
8831             rc = tnc_set_parity(TNC_PAR_EVEN);
8832             if (rc >= 0)
8833               rc = tnc_set_datasize(datasize);
8834             break;
8835           case 'o':
8836             rc = tnc_set_parity(TNC_PAR_ODD);
8837             if (rc >= 0)
8838               rc = tnc_set_datasize(datasize);
8839             break;
8840           case 'm':
8841             rc = tnc_set_parity(TNC_PAR_MARK);
8842             if (rc >= 0)
8843               rc = tnc_set_datasize(datasize);
8844             break;
8845           case 's':
8846             rc = tnc_set_parity(TNC_PAR_SPACE);
8847             if (rc >= 0)
8848               rc = tnc_set_datasize(datasize);
8849             break;
8850           case 0:
8851           case 'n':
8852             rc = tnc_set_parity(TNC_PAR_NONE);
8853             if (rc >= 0)
8854               rc = tnc_set_datasize(datasize);
8855             break;
8856           default:
8857             /* no change */
8858             rc = 0;
8859         }
8860         switch(stop) {
8861           case 2:
8862             if (rc >= 0)
8863               rc = tnc_set_stopsize(TNC_SB_2);
8864             break;
8865           case 1:
8866             if (rc >= 0)
8867               rc = tnc_set_stopsize(TNC_SB_1);
8868             break;
8869           default:
8870             /* no change */
8871             if (rc >= 0)
8872               rc = 0;
8873         }
8874     }
8875     debug(F111,"tnsettings","end",rc);
8876     return((rc >= 0) ? 0 : -1);
8877 }
8878
8879 /*  T N G M D M  --  Telnet Get modem signals  */
8880 /*
8881  Looks for the modem signals CTS, DSR, and CTS, and returns those that are
8882  on in as its return value, in a bit mask as described for ttwmdm.
8883  Returns:
8884   -3 Not implemented
8885   -2 if the line does not have modem control
8886   -1 on error.
8887   >= 0 on success, with a bit mask containing the modem signals that are on.
8888 */
8889 int
8890 #ifdef CK_ANSIC
8891 tngmdm(void)
8892 #else
8893 tngmdm()
8894 #endif /* CK_ANSIC */
8895 /* tngmdm */ {
8896
8897     int rc = -1;
8898
8899     debug(F110,"tngmdm","begin",0);
8900     if (ttnet != NET_TCPB || ttnproto != NP_TELNET)
8901       return(-1);
8902
8903     if (TELOPT_ME(TELOPT_COMPORT)) {
8904         int modemstate = tnc_get_ms();
8905         int modem = 0;
8906         if (modemstate & TNC_MS_CTS_SIG)
8907           modem |= BM_CTS;
8908         if (modemstate & TNC_MS_DSR_SIG)
8909           modem |= BM_DSR;
8910         if (modemstate & TNC_MS_RI_SIG)
8911           modem |= BM_RNG;
8912         if (modemstate & TNC_MS_RLSD_SIG)
8913           modem |= BM_DCD;
8914         debug(F111,"tngmdm","end",modem);
8915         return(modem);
8916     } else {
8917         debug(F111,"tngmdm","end",-2);
8918         return(-2);
8919     }
8920 }
8921
8922 int
8923 #ifdef CK_ANSIC
8924 tnsndb(long wait)
8925 #else
8926 tnsndb(wait) long wait;
8927 #endif /* CK_ANSIC */
8928 /* tnsndb */ {
8929     int rc = -1;
8930
8931     debug(F111,"tnsndb","begin",wait);
8932     if (ttnet != NET_TCPB || ttnproto != NP_TELNET)
8933       return(-1);
8934
8935     if (TELOPT_ME(TELOPT_COMPORT)) {
8936         rc  = tnc_set_break_state(1);
8937         if (rc >= 0) {
8938             msleep(wait);                         /* ZZZzzz */
8939             rc = tnc_set_break_state(0);
8940         }
8941     }
8942     debug(F111,"tnsndb","end",rc);
8943     return((rc >= 0) ? 0 : -1);
8944 }
8945 #endif /* TN_COMPORT */
8946 #endif /* TNCODE */