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