apply 010_makefile-destdir-support
[ckermit.git] / ckucns.c
1 #include "ckcsym.h"
2 char *connv = "CONNECT Command for UNIX:select(), 8.0.135, 29 Nov 2002";
3
4 /*  C K U C N S  --  Terminal connection to remote system, for UNIX  */
5 /*
6   Author: Frank da Cruz <fdc@columbia.edu>,
7   Columbia University Academic Information Systems, New York City.
8
9   Copyright (C) 1985, 2004,
10     Trustees of Columbia University in the City of New York.
11     All rights reserved.  See the C-Kermit COPYING.TXT file or the
12     copyright text in the ckcmai.c module for disclaimer and permissions.
13 */
14
15 /*
16   This version of the UNIX CONNECT module uses select(), which is required for
17   Kerberos encryption.  Thus it can be used only on UNIX systems that support
18   select() on both TCP/IP and serial connections.  A separate module that uses
19   a completely portable fork() structure can be used on systems where select()
20   is not available or does not work as required.
21 */
22
23 #include "ckcdeb.h"                     /* Common things first */
24
25 #ifndef NOLOCAL
26
27 #ifdef OSF13
28 #ifdef CK_ANSIC
29 #ifdef _NO_PROTO
30 #undef _NO_PROTO
31 #endif /* _NO_PROTO */
32 #endif /* CK_ANSIC */
33 #endif /* OSF13 */
34
35 #include <errno.h>                      /* Error numbers */
36
37 #ifndef NOTIMEH
38 #include <time.h>                       /* For FD_blah */
39 #ifdef SYSTIMEH                         /* (IRIX 5.3) */
40 #include <sys/time.h>
41 #endif /* SYSTIMEH */
42 #endif /* NOTIMEH */
43
44 #ifdef BSD42HACK                        /* Why is this necessary? */
45 #ifndef DCLTIMEVAL
46 #define DCLTIMEVAL
47 #endif /* DCLTIMEVAL */
48 #endif /* BSD42HACK */
49
50 /* Kermit-specific includes */
51
52 #include "ckcasc.h"                     /* ASCII characters */
53 #include "ckcker.h"                     /* Kermit things */
54 #include "ckucmd.h"                     /* For xxesc() prototype */
55 #include "ckcnet.h"                     /* Network symbols */
56 #ifndef NOCSETS
57 #include "ckcxla.h"                     /* Character set translation */
58 #endif /* NOCSETS */
59
60 #ifdef BEBOX
61 #include <kernel/OS.h>
62 #include <socket.h>
63 #include <stdio.h>
64 #endif /* BEBOX */
65
66 #include <signal.h>                     /* Signals */
67
68 /* All the following is for select()... */
69
70 #ifdef CKTIDLE                          /* Timeouts only for SET TERM IDLE */
71
72 #ifndef DCLTIMEVAL
73 #ifdef UNIXWARE
74 #ifndef UW7
75 #define DCLTIMEVAL
76 #endif /* UW7 */
77 #endif /* UNIXWARE */
78 #endif /* DCLTIMEVAL */
79
80 #ifdef DCLTIMEVAL                       /* Declare timeval ourselves */
81 struct timeval {
82     long tv_sec;
83     long tv_usec;
84 };
85 #else  /* !DCLTIMEVAL */
86 #ifndef NOSYSTIMEBH
87 #ifdef SYSTIMEBH
88 #include <sys/timeb.h>
89 #endif /* SYSTIMEBH */
90 #endif /* NOSYSTIMEBH */
91 #endif /* DCLTIMEVAL */
92 #endif /* CKTIDLE */
93
94 #ifndef SCO_OSR504
95 #ifdef SELECT_H
96 #include <sys/select.h>
97 #endif /* SELECT_H */
98 #endif /* SCO_OSR504 */
99
100 #ifndef FD_SETSIZE
101 #ifdef CK_FORWARD_X
102 #define FD_SETSIZE 256
103 #else
104 #define FD_SETSIZE 32
105 #endif /* CK_FORWARD_X */
106 #endif /* FD_SETSIZE */
107
108 #ifdef HPUX
109 #ifndef HPUX10
110 #ifndef HPUX1100
111 /* The three interior args to select() are (int *) rather than (fd_set *) */
112 #ifndef INTSELECT
113 #define INTSELECT
114 #endif /* INTSELECT */
115 #endif /* HPUX1100 */
116 #endif /* HPUX10 */
117 #endif /* HPUX */
118
119 /* Internal function prototypes */
120
121 #ifdef NEWFTP
122 #endif /* NEWFTP */
123 _PROTOTYP( VOID ttflux, (void) );
124 _PROTOTYP( VOID doesc, (char) );
125 _PROTOTYP( int hconne, (void) );
126 #ifndef NOSHOW
127 _PROTOTYP( VOID shomdm, (void) );
128 #endif /* NOSHOW */
129 _PROTOTYP( static int kbget, (void) );
130 _PROTOTYP( static int ckcputf, (void) );
131
132 /* External variables */
133
134 extern struct ck_p ptab[];
135
136 extern int local, escape, duplex, parity, flow, seslog, sessft, debses,
137  mdmtyp, ttnproto, cmask, cmdmsk, network, nettype, sosi, tnlm,
138  xitsta, what, ttyfd, ttpipe, quiet, backgrd, pflag, tt_crd, tn_nlm, ttfdflg,
139  tt_escape, justone, carrier, ttpty, hwparity;
140
141 #ifndef NODIAL
142 extern int dialmhu, dialsta;
143 #endif /* NODIAL */
144
145 #ifdef CKLEARN
146 extern FILE * learnfp;
147 extern int learning;
148 static ULONG learnt1;
149 static char learnbuf[LEARNBUFSIZ] = { NUL, NUL };
150 static int  learnbc = 0;
151 static int  learnbp = 0;
152 static int  learnst = 0;
153 #endif /* CKLEARN */
154
155 extern long speed;
156 extern char ttname[], sesfil[], myhost[], *ccntab[];
157 #ifdef TNCODE
158 extern int tn_b_nlm, tn_rem_echo;
159 #endif /* TNCODE */
160
161 #ifdef CK_TRIGGER
162 extern char * tt_trigger[], * triggerval;
163 #endif /* CK_TRIGGER */
164
165 #ifdef CKTIDLE
166 extern int tt_idlelimit, tt_idleact;
167 extern char * tt_idlestr;
168 static int idlelimit = 0;
169 #endif /* CKTIDLE */
170 extern int cx_status;                   /* CONNECT status code */
171
172 extern int nopush;
173
174 #ifdef CK_APC
175 extern int apcactive;                   /* Application Program Command (APC) */
176 extern int apcstatus;                   /* items ... */
177 static int apclength = 0;
178 #ifdef DCMDBUF
179 extern char *apcbuf;
180 #else
181 extern char apcbuf[];
182 #endif /* DCMDBUF */
183 static int apcbuflen = APCBUFLEN - 2;
184 extern int protocol;
185 #endif /* CK_APC */
186 #ifndef NOXFER
187 extern int autodl;                      /* Auto download */
188 #endif /* NOXFER */
189
190 #ifdef CK_AUTODL
191 extern CHAR ksbuf[];
192 extern CHAR stchr;
193 extern int kstartactive;
194 #endif /* CK_AUTODL */
195
196 #ifdef CK_ENCRYPTION
197 extern int me_auth;
198 #endif /* CK_ENCRYPTION */
199
200 #ifdef CK_XYZ
201 #ifdef XYZ_INTERNAL
202 static int zmdlok = 1;                  /* Zmodem autodownloads available */
203 #else
204 static int zmdlok = 0;                  /* Depends on external protocol def */
205 #endif /* XYZ_INTERNAL */
206 #else
207 static int zmdlok = 0;                  /* Not available at all */
208 #endif /* CK_XYZ */
209
210 #ifndef NOSETKEY                        /* Keyboard mapping */
211 extern KEY *keymap;                     /* Single-character key map */
212 extern MACRO *macrotab;                 /* Key macro pointer table */
213 static MACRO kmptr = NULL;              /* Pointer to current key macro */
214 #endif /* NOSETKEY */
215
216 /* Global variables local to this module */
217
218 static int
219   active = 0,
220   quitnow = 0,                          /* <esc-char>Q was typed */
221   dohangup = 0,                         /* <esc-char>H was typed */
222   inshift = 0,                          /* SO/SI shift states */
223   outshift = 0;
224
225 static char ecbuf[10], *ecbp;           /* Escape char buffer & pointer */
226
227 #ifdef CK_SMALL
228 #define IBUFL 1536                      /* Input buffer length */
229 #else
230 #define IBUFL 4096
231 #endif /* CK_SMALL */
232
233 static int obc = 0;                     /* Output buffer count */
234
235 #ifndef OXOS
236 #define OBUFL 1024                      /* Output buffer length */
237 #else
238 #define OBUFL IBUFL
239 #endif /* OXOS */
240
241 #ifdef BIGBUFOK
242 #define TMPLEN 4096                     /* Temporary message buffer length */
243 #else
244 #define TMPLEN 200
245 #endif /* BIGBUFOK */
246
247 #ifdef DYNAMIC
248 static char *ibuf = NULL, *obuf = NULL, *temp = NULL; /* Buffers */
249 #else
250 static char ibuf[IBUFL], obuf[OBUFL], temp[TMPLEN];
251 #endif /* DYNAMIC */
252
253 #ifdef TNCODE
254 static char tnopt[4];
255 #endif /* TNCODE */
256
257 #ifdef DYNAMIC
258 static char *ibp;                       /* Input buffer pointer */
259 #else
260 static char *ibp = ibuf;                /* Input buffer pointer */
261 #endif /*DYNAMIC */
262 static int ibc = 0;                     /* Input buffer count */
263
264 #ifdef DYNAMIC
265 static char *obp;                       /* Output buffer pointer */
266 #else
267 static char *obp = obuf;                /* Output buffer pointer */
268 #endif /* DYNAMIC */
269
270 /* Character-set items */
271
272 static int unicode = 0;
273
274 #ifndef NOCSETS
275 #ifdef CK_ANSIC /* ANSI C prototypes... */
276 extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
277 extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
278 static CHAR (*sxo)(CHAR);       /* Local translation functions */
279 static CHAR (*rxo)(CHAR);       /* for output (sending) terminal chars */
280 static CHAR (*sxi)(CHAR);       /* and for input (receiving) terminal chars. */
281 static CHAR (*rxi)(CHAR);
282 #else /* Not ANSI C... */
283 extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */
284 extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */
285 static CHAR (*sxo)();           /* Local translation functions */
286 static CHAR (*rxo)();           /* for output (sending) terminal chars */
287 static CHAR (*sxi)();           /* and for input (receiving) terminal chars. */
288 static CHAR (*rxi)();
289 #endif /* CK_ANSIC */
290 extern int language;            /* Current language. */
291 static int langsv;              /* For remembering language setting. */
292 extern struct csinfo fcsinfo[]; /* File character set info. */
293 extern int tcsr, tcsl;          /* Terminal character sets, remote & local. */
294 static int tcs;                 /* Intermediate ("transfer") character set. */
295 static int tcssize = 0;         /* Size of tcs */
296 #ifdef UNICODE                          /* UTF-8 support */
297 #ifdef CK_ANSIC
298 extern int (*xl_ufc[MAXFCSETS+1])(USHORT);  /* Unicode to FCS */
299 extern USHORT (*xl_fcu[MAXFCSETS+1])(CHAR); /* FCS to Unicode */
300 extern int (*xuf)(USHORT);              /* Translation function UCS to FCS */
301 extern USHORT (*xfu)(CHAR);             /* Translation function FCS to UCS */
302 #else
303 extern int (*xl_ufc[MAXFCSETS+1])();
304 extern USHORT (*xl_fcu[MAXFCSETS+1])();
305 extern int (*xuf)();
306 extern USHORT (*xfu)();
307 #endif /* CK_ANSIC */
308 #endif /* UNICODE */
309 #endif /* NOCSETS */
310
311 static int printing = 0;
312
313 /*
314   We do not need to parse and recognize escape sequences if we are being built
315   without character-set support AND without APC support.
316 */
317 #ifdef NOESCSEQ
318 #ifdef XPRINT
319 #undef XPRINT
320 #endif /* XPRINT */
321
322 #else  /* NOESCSEQ not defined from outside */
323
324 #ifdef NOCSETS                          /* No character sets */
325 #ifndef CK_APC                          /* No APC */
326 #ifndef XPRINT                          /* No transparent printing */
327 #define NOESCSEQ                        /* So no escape sequence recognizer */
328 #endif /* XPRINT */
329 #endif /* CK_APC */
330 #endif /* NOCSETS */
331 #endif /* NOESCSEQ */
332
333 static int escseq = 0;                  /* 1 = Recognizer is active */
334 static int inesc[2] = { 0, 0 };         /* State of sequence recognizer */
335 static int oldesc[2] = { -1, -1 };      /* Previous state of recognizer */
336
337 #ifdef NOESCSEQ
338 #define chkaes(x,y) 0
339 #else
340 /*
341   As of C-Kermit 5A(178), the CONNECT command skips past ANSI escape sequences
342   to avoid translating the characters within them.  This allows the CONNECT
343   command to work correctly with a host that uses a 7-bit ISO 646 national
344   character set, in which characters like '[' would normally be translated
345   into accented characters, ruining the terminal's interpretation (and
346   generation) of escape sequences.
347
348   As of 5A(190), the CONNECT command responds to APC escape sequences
349   (ESC _ text ESC \) if the user SETs TERMINAL APC ON or UNCHECKED, and the
350   program was built with CK_APC defined.
351
352   Non-ANSI/ISO-compliant escape sequences are not handled. */
353
354 /* States for the escape-sequence recognizer. */
355
356 #define ES_NORMAL 0                     /* Normal, not in an escape sequence */
357 #define ES_GOTESC 1                     /* Current character is ESC */
358 #define ES_ESCSEQ 2                     /* Inside an escape sequence */
359 #define ES_GOTCSI 3                     /* Inside a control sequence */
360 #define ES_STRING 4                     /* Inside DCS,OSC,PM, or APC string */
361 #define ES_TERMIN 5                     /* 1st char of string terminator */
362
363 /*
364   ANSI escape sequence handling.  Only the 7-bit form is treated, because
365   translation is not a problem in the 8-bit environment, in which all GL
366   characters are ASCII and no translation takes place.  So we don't check
367   for the 8-bit single-character versions of CSI, DCS, OSC, APC, or ST.
368   Here is the ANSI sequence recognizer state table, followed by the code
369   that implements it.
370
371   Definitions:
372     CAN = Cancel                       01/08         Ctrl-X
373     SUB = Substitute                   01/10         Ctrl-Z
374     DCS = Device Control Sequence      01/11 05/00   ESC P
375     CSI = Control Sequence Introducer  01/11 05/11   ESC [
376     ST  = String Terminator            01/11 05/12   ESC \
377     OSC = Operating System Command     01/11 05/13   ESC ]
378     PM  = Privacy Message              01/11 05/14   ESC ^
379     APC = Application Program Command  01/11 05/15   ESC _
380
381   ANSI escape sequence recognizer:
382
383     State    Input  New State  ; Commentary
384
385     NORMAL   (start)           ; Start in NORMAL state
386
387     (any)    CAN    NORMAL     ; ^X cancels
388     (any)    SUB    NORMAL     ; ^Z cancels
389
390     NORMAL   ESC    GOTESC     ; Begin escape sequence
391     NORMAL   other             ; NORMAL control or graphic character
392
393     GOTESC   ESC               ; Start again
394     GOTESC   [      GOTCSI     ; CSI
395     GOTESC   P      STRING     ; DCS introducer, consume through ST
396     GOTESC   ]      STRING     ; OSC introducer, consume through ST
397     GOTESC   ^      STRING     ; PM  introducer, consume through ST
398     GOTESC   _      STRING     ; APC introducer, consume through ST
399     GOTESC   0..~   NORMAL     ; 03/00 through 17/14 = Final character
400     GOTESC   other  ESCSEQ     ; Intermediate or ignored control character
401
402     ESCSEQ   ESC    GOTESC     ; Start again
403     ESCSEQ   0..~   NORMAL     ; 03/00 through 17/14 = Final character
404     ESCSEQ   other             ; Intermediate or ignored control character
405
406     GOTCSI   ESC    GOTESC     ; Start again
407     GOTCSI   @..~   NORMAL     ; 04/00 through 17/14 = Final character
408     GOTCSI   other             ; Intermediate char or ignored control char
409
410     STRING   ESC    TERMIN     ; Maybe have ST
411     STRING   other             ; Consume all else
412
413     TERMIN   \      NORMAL     ; End of string
414     TERMIN   other  STRING     ; Still in string
415 */
416
417 #ifdef XPRINT                           /* Transparent print support */
418 /*
419   We can't just print each byte as it comes in because then the printer-off
420   sequence would be sent to the printer.  Thus we have to buffer up escape
421   sequences and print them only when they are complete AND we know they are
422   not the printer-off sequence.  All printing is done via zsoutx(ZMFILE,s,n).
423   This allows for strings that contain NULs.  Don't mix calls to zsoutx() with
424   calls to zchout(), or the output will be scrambled.  Also note that when
425   printing a saved-up escape sequence, we never print its final character
426   because that will be printed in the mainline code, upon return from
427   chkaes().  Note that the printer-on sequence is passed to the screen; this
428   is unavoidable, since we don't know what it is until after we get to the
429   end, and for screen display purposes we can't buffer up escape sequences
430   for numerous reasons.  Therefore we also must output the printer-off
431   sequence, otherwise a real terminal or emulator will be stuck in print mode.
432 */
433 extern int tt_print;
434 #define ESCBUFLEN 63
435 static char escbuf[ESCBUFLEN+1] = { NUL, NUL };
436 static int escbufc = 0;
437 static int dontprint = 0;
438
439 VOID
440 printon() {                             /* Turn printing on */
441     int x, pp;
442     char * p;
443     extern int printpipe, noprinter;
444     extern char * printername;
445
446     if (noprinter) {
447         debug(F110,"PRINTER ON NOPRINTER","",0);
448         return;
449     }
450     p = printername;
451     pp = printpipe;
452     if (!p) p = "";
453     if (!*p) {
454 #ifdef ANYBSD
455         p = "lpr";
456 #else
457         p = "lp";
458 #endif /* ANYBSD */
459         pp = 1;
460         debug(F110,"PRINTER DEFAULT",p,0);
461     }
462     debug(F111,"PRINTER ON",p,pp);
463     if (pp) {                           /* Printing to pipe */
464         x = zxcmd(ZMFILE,p);
465     } else {                            /* Append to file */
466         struct filinfo xx;
467         xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
468         xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = NUL;
469         xx.lblopts = 0;
470         x = zopeno(ZMFILE,p,NULL,&xx);
471     }
472     debug(F101,"PRINTER OPEN","",x);
473     printing = 1;
474 }
475
476 VOID
477 printoff() {                            /* Turn printing off */
478     int x;
479     extern int noprinter;
480     if (noprinter) {
481         printing = 0;
482         debug(F100,"PRINTER OFF NOPRINTER","",0);
483         return;
484     }
485     debug(F100,"PRINTER OFF","",0);
486     if (printing) {
487         x = zclose(ZMFILE);
488         debug(F101,"PRINTER CLOSE","",x);
489         printing = 0;
490     }
491 }
492 #endif /* XPRINT */
493
494 /*
495   C H K A E S  --  Check ANSI Escape Sequence.
496
497   Call with EACH character in input stream.
498   src = 0 means c is incoming from remote; 1 = char from keyboard.
499   Sets global inesc[src] variable according to escape sequence state.
500   Returns 0 normally, 1 if an APC sequence is to be executed.
501   Handles transparent printing internally.
502 */
503 int
504 #ifdef CK_ANSIC
505 chkaes(char c, int src)
506 #else
507 chkaes(c,src) char c; int src;
508 #endif /* CK_ANSIC */
509 /* chkaes */ {
510
511     debug(F111,"chkaes entry inesc",ckitoa(src),inesc[src]);
512     debug(F101,"chkaes c","",c);
513
514     if (src < 0 || src > 1)             /* Don't allow bad args. */
515       return(0);
516
517     oldesc[src] = inesc[src];           /* Remember previous state */
518
519 #ifdef XPRINT
520     if (inesc[src] && !src) {           /* Save up escape seq for printing  */
521         if (!c) return(0);              /* Ignore NULs */
522         if (escbufc < ESCBUFLEN) {
523             escbuf[escbufc++] = c;
524             escbuf[escbufc] = NUL;
525             debug(F111,"ESCBUF 1",escbuf,escbufc);
526         } else {                        /* Buffer overrun */
527             if (printing && escbufc)    /* Print what's there so far */
528               zsoutx(ZMFILE,escbuf,escbufc);
529             escbufc = 1;                /* clear it out */
530             escbuf[0] = c;              /* and start off fresh buffer */
531             escbuf[1] = NUL;            /* with this character. */
532         }
533     }
534 #endif /* XPRINT */
535
536     if (c == CAN || c == SUB) {         /* CAN and SUB cancel any sequence */
537 #ifdef XPRINT
538         if (!src) {
539             if (printing && escbufc > 1)
540               zsoutx(ZMFILE,escbuf,escbufc-1);
541             escbufc = 0;                /* Clear buffer */
542             escbuf[0] = NUL;
543         }
544 #endif /* XPRINT */
545         inesc[src] = ES_NORMAL;
546     } else                              /* Otherwise */
547
548       switch (inesc[src]) {             /* enter state switcher */
549         case ES_NORMAL:                 /* NORMAL state */
550           if (c == ESC) {               /* Got an ESC */
551               inesc[src] = ES_GOTESC;   /* Change state to GOTESC */
552 #ifdef XPRINT
553               if (!src) {
554                   escbufc = 1;          /* Clear escape sequence buffer */
555                   escbuf[0] = c;        /* and deposit the ESC */
556                   escbuf[1] = NUL;
557                   debug(F111,"ESCBUF 2",escbuf,escbufc);
558               }
559 #endif /* XPRINT */
560           }
561           break;                        /* Otherwise stay in NORMAL state */
562
563         case ES_GOTESC:                 /* GOTESC state - prev char was ESC*/
564           if (c == '[') {               /* Left bracket after ESC is CSI */
565               inesc[src] = ES_GOTCSI;   /* Change to GOTCSI state */
566           } else if (c == 'P' || (c > 0134 && c < 0140)) { /* P, ], ^, or _ */
567               inesc[src] = ES_STRING;   /* Switch to STRING-absorption state */
568 #ifdef XPRINT
569               debug(F111,"ESCBUF STRING",escbuf,escbufc);
570 #endif /* XPRINT */
571 #ifdef CK_APC
572               /* If APC not disabled */
573               if (!src && c == '_' && (apcstatus & APC_ON)) {
574                   debug(F100,"CONNECT APC begin","",0);
575                   apcactive = APC_REMOTE; /* Set APC-Active flag */
576                   apclength = 0;        /* and reset APC buffer pointer */
577               }
578 #endif /* CK_APC */
579           } else if (c > 057 && c < 0177) { /* Final character '0' thru '~' */
580               inesc[src] = ES_NORMAL;   /* Back to normal */
581 #ifdef XPRINT
582               if (!src) {
583                   if (printing && escbufc > 1) {
584                       /* Dump esc seq buf to printer */
585                       zsoutx(ZMFILE,escbuf,escbufc-1);
586                       debug(F111,"ESCBUF PRINT 1",escbuf,escbufc);
587                   }
588
589                   escbufc = 0;          /* Clear parameter buffer */
590                   escbuf[0] = NUL;
591               }
592 #endif /* XPRINT */
593           } else if (c != ESC) {        /* ESC in an escape sequence... */
594               inesc[src] = ES_ESCSEQ;   /* starts a new escape sequence */
595           }
596           break;                        /* Intermediate or ignored ctrl char */
597
598         case ES_ESCSEQ:                 /* ESCSEQ -- in an escape sequence */
599           if (c > 057 && c < 0177) {    /* Final character '0' thru '~' */
600               inesc[src] = ES_NORMAL;   /* Return to NORMAL state. */
601 #ifdef XPRINT
602               if (!src) {
603                   if (printing && escbufc > 1) {
604                       zsoutx(ZMFILE,escbuf,escbufc-1);
605                       debug(F111,"ESCBUF PRINT 2",escbuf,escbufc);
606                   }
607                   escbufc = 0;          /* Clear escseq buffer */
608                   escbuf[0] = NUL;
609               }
610 #endif /* XPRINT */
611           } else if (c == ESC) {        /* ESC ... */
612               inesc[src] = ES_GOTESC;   /* starts a new escape sequence */
613           }
614           break;                        /* Intermediate or ignored ctrl char */
615
616         case ES_GOTCSI:                 /* GOTCSI -- In a control sequence */
617           if (c > 077 && c < 0177) {    /* Final character '@' thru '~' */
618 #ifdef XPRINT
619               if (!src && tt_print) {   /* Printer enabled? */
620                   if (c == 'i') {       /* Final char is "i"? */
621                       char * p = (char *) (escbuf + escbufc - 4);
622                       if (!strncmp(p, "\033[5i", 4)) { /* Turn printer on */
623                           printon();
624                       } else if (!strncmp(p, "\033[4i", 4)) { /* Or off... */
625                           int i;
626                           printoff();                   /* Turn off printer. */
627                           dontprint = 1;
628                           for (i = 0; i < escbufc; i++) /* And output the */
629                             ckcputc(escbuf[i]);         /* sequence. */
630                       } else if (printing && escbufc > 1) {
631                           zsoutx(ZMFILE,escbuf,escbufc-1);
632                           debug(F011,"ESCBUF PRINT 3",escbuf,escbufc);
633                       }
634                   } else if (printing && escbufc > 1) {
635                       zsoutx(ZMFILE,escbuf,escbufc-1);
636                       debug(F111,"ESCBUF PRINT 4",escbuf,escbufc);
637                   }
638               }
639               if (!src) {
640                   escbufc = 0;          /* Clear esc sequence buffer */
641                   escbuf[0] = NUL;
642               }
643 #endif /* XPRINT */
644               inesc[src] = ES_NORMAL;   /* Return to NORMAL. */
645           } else if (c == ESC) {        /* ESC ... */
646               inesc[src] = ES_GOTESC;   /* starts over. */
647           }
648           break;
649
650         case ES_STRING:                 /* Inside a string */
651           if (c == ESC)                 /* ESC may be 1st char of terminator */
652             inesc[src] = ES_TERMIN;     /* Go see. */
653 #ifdef CK_APC
654           else if (apcactive) {         /* If in APC */
655               if (apclength < apcbuflen) { /* and there is room... */
656                   apcbuf[apclength++] = c; /* deposit this character. */
657               } else {                  /* Buffer overrun */
658                   apcactive = 0;        /* Discard what we got */
659                   apclength = 0;        /* and go back to normal */
660                   apcbuf[0] = 0;        /* Not pretty, but what else */
661                   inesc[src] = ES_NORMAL; /* can we do?  (ST might not come) */
662               }
663           }
664 #endif /* CK_APC */
665           break;                        /* Absorb all other characters. */
666
667         case ES_TERMIN:                 /* Maybe a string terminator */
668           if (c == '\\') {              /* which must be backslash */
669               inesc[src] = ES_NORMAL;   /* If so, back to NORMAL */
670 #ifdef XPRINT
671               if (!src) {
672                   if (printing && escbufc > 1) { /* If printing... */
673                       /* Print esc seq buffer */
674                       zsoutx(ZMFILE,escbuf,escbufc-1);
675                       debug(F111,"ESCBUF PRINT 5",escbuf,escbufc);
676                   }
677                   escbufc = 0;          /* Clear escseq buffer */
678                   escbuf[0] = NUL;
679               }
680 #endif /* XPRINT */
681 #ifdef CK_APC
682               if (!src && apcactive) {  /* If it was an APC string, */
683                   debug(F101,"CONNECT APC terminated","",c);
684                   apcbuf[apclength] = NUL; /* terminate it and then ... */
685                   return(1);
686               }
687 #endif /* CK_APC */
688           } else {                      /* It's not a backslash so... */
689               inesc[src] = ES_STRING;   /* back to string absorption. */
690 #ifdef CK_APC
691               if (apcactive) {          /* In APC string */
692                   if (apclength+1 < apcbuflen) { /* If enough room */
693                       apcbuf[apclength++] = ESC; /* deposit the Esc */
694                       apcbuf[apclength++] = c;   /* and this character too. */
695                   } else {              /* Buffer overrun */
696                       apcactive = 0;
697                       apclength = 0;
698                       apcbuf[0] = 0;
699                       inesc[src] = ES_NORMAL;
700                   }
701               }
702 #endif /* CK_APC */
703           }
704       } /* switch() */
705     debug(F111,"chkaes exit inesc",ckitoa(src),inesc[src]);
706     return(0);
707 }
708 #endif /* NOESCSEQ */
709
710 /*  C K C P U T C  --  C-Kermit CONNECT Put Character to Screen  */
711 /*
712   Output is buffered to avoid slow screen writes on fast connections.
713 */
714 static int
715 ckcputf() {                             /* Dump the console output buffer */
716     int x = 0;
717     if (obc > 0)                        /* If we have any characters, */
718       x = conxo(obc,obuf);              /* dump them, */
719     obp = obuf;                         /* reset the pointer */
720     obc = 0;                            /* and the counter. */
721     return(x);                          /* Return conxo's return code */
722 }
723
724 /*
725   NOTE: This is probably the right place for character-set translation,
726   rather than down below in the mainline code.  ckcputc() would act like
727   xpnbyte() in ckcfns.c, and ckcgetc() would act like xgnbyte().  This
728   would shield the rest of the code from all the complexities of many-to-one
729   and one-to-many conversions, and would allow handling of Kanji and other
730   CJK sets along with UTF-8 and the rest.
731 */
732 int
733 ckcputc(c) int c; {
734     int x;
735
736     *obp++ = c & 0xff;                  /* Deposit the character */
737     obc++;                              /* Count it */
738     if (ibc == 0 ||                     /* If input buffer about empty */
739         obc == OBUFL) {                 /* or output buffer full */
740         debug(F101,"CONNECT CKCPUTC obc","",obc);
741         x = conxo(obc,obuf);            /* dump the buffer, */
742         obp = obuf;                     /* reset the pointer */
743         obc = 0;                        /* and the counter. */
744         return(x);                      /* Return conxo's return code */
745     } else return(0);
746 }
747
748 /*  C K C G E T C  --  C-Kermit CONNECT Get Character  */
749 /*
750   Buffered read from communication device.
751   Returns the next character, refilling the buffer if necessary.
752   On error, returns ttinc's return code (see ttinc() description).
753   Dummy argument for compatible calling conventions with ttinc()
754   so a pointer to this function can be passed to tn_doop().
755 */
756 int
757 ckcgetc(dummy) int dummy; {
758     int c, n;
759 #ifdef CK_SSL
760     extern int ssl_active_flag, tls_active_flag;
761 #endif /* CK_SSL */
762
763 #ifdef CK_ENCRYPTION
764     /* No buffering for possibly encrypted connections */
765     if (network && IS_TELNET() && TELOPT_ME(TELOPT_AUTHENTICATION))
766       return(ttinc(0));
767 #endif /* CK_ENCRYPTION */
768 #ifdef CK_SSL
769     if (ssl_active_flag || tls_active_flag)
770         return(ttinc(0));
771 #endif /* CK_SSL */
772
773     if (ibc < 1) {                      /* Need to refill buffer? */
774         ibc = 0;                        /* Yes, reset count */
775         ibp = ibuf;                     /* and buffer pointer */
776         c = ttinc(0);                   /* Read one character, blocking */
777         if (c < 0) {                    /* If error, return error code */
778             return(c);
779         } else {                        /* Otherwise, got one character */
780             *ibp++ = c;                 /* Advance buffer pointer */
781             ibc++;                      /* and count. */
782         }
783         if ((n = ttchk()) > 0) {        /* Any more waiting? */
784             if (n > (IBUFL - ibc))      /* Get them all at once. */
785               n = IBUFL - ibc;          /* Don't overflow buffer */
786               if ((n = ttxin(n,(CHAR *)ibp)) > 0) {
787                   ibc += n;             /* Advance counter */
788               }
789         } else if (n < 0) {             /* Error? */
790             return(n);                  /* Return the error code */
791         }
792         ibp = ibuf;                     /* Point to beginning of buffer */
793     }
794     c = *ibp++ & 0xff;                  /* Get next character from buffer */
795     ibc--;                              /* Reduce buffer count */
796     /* debug(F000,"CKCGETC","",c); */
797     return(c);                          /* Return the character */
798 }
799
800 /*
801    Keyboard handling, buffered for speed, which is needed when C-Kermit is
802    in CONNECT mode between two other computers that are transferring data.
803 */
804 static char *kbp;                       /* Keyboard input buffer pointer */
805 static int kbc;                         /* Keyboard input buffer count */
806
807 #ifdef CK_SMALL                         /* Keyboard input buffer length */
808 #define KBUFL 32                        /* Small for PDP-11 UNIX */
809 #else
810 #define KBUFL 257                       /* Regular kernel size for others */
811 #endif /* CK_SMALL */
812
813 #ifdef DYNAMIC
814 static char *kbuf = NULL;
815 #else
816 static char kbuf[KBUFL];
817 #endif /* DYNAMIC */
818
819 /* Macro for reading keystrokes. */
820
821 #define CONGKS() (((--kbc)>=0) ? ((int)(*kbp++) & 0377) : kbget())
822
823 /*
824   Note that we call read() directly here, normally a no-no, but in this case
825   we know it's UNIX and we're only doing what coninc(0) would have done,
826   except we're reading a block of characters rather than just one.  There is,
827   at present, no conxin() analog to ttxin() for chunk reads, and instituting
828   one would only add function-call overhead as it would only be a wrapper for
829   a read() call anyway.
830
831   Another note: We stick in this read() till the user types something.
832   But we know they already did, since select() said so.  Therefore something
833   would need to be mighty wrong before we get stuck here.
834 */
835 static int                              /* Keyboard buffer filler */
836 kbget() {
837 #ifdef EINTR
838     int tries = 10;                     /* If read() is interrupted, */
839     int ok = 0;
840     while (tries-- > 0) {               /* try a few times... */
841 #endif /* EINTR */
842         kbc = conchk();                 /* How many chars waiting? */
843         debug(F101,"kbget kbc","",kbc);
844         if (kbc < 1)
845           kbc = 1;                      /* If none or dunno, wait for one. */
846         else if (kbc > KBUFL)           /* If too many, */
847           kbc = KBUFL;                  /* only read this many. */
848         if ((kbc = read(0, kbuf, kbc)) < 1) { /* Now read it/them. */
849             debug(F101,"CONNECT kbget errno","",errno); /* Got an error. */
850 #ifdef EINTR
851             if (errno == EINTR)         /* Interrupted system call. */
852               continue;                 /* Try again, up to limit. */
853             else                        /* Something else. */
854 #endif /* EINTR */
855               return(-1);               /* Pass along read() error. */
856         }
857 #ifdef EINTR
858         else { ok = 1; break; }
859     }
860     if (!ok) return(-1);
861 #endif /* EINTR */
862     kbp = kbuf;                         /* Adjust buffer pointer, */
863     kbc--;                              /* count, */
864     return((int)(*kbp++) & 0377);       /* and return first character. */
865 }
866
867 #ifdef BEBOX
868 /*
869  * CreateSocketPair --
870  *
871  *      This procedure creates a connected socket pair
872  *
873  * Results:
874  *      0 if OK, the error if not OK.
875  *
876  * Side effects:
877  *      None
878  */
879 int
880 socketpair(int *pair) {
881     int servsock;
882     int val;
883     struct sockaddr_in serv_addr, cli_addr;
884     extern char myipaddr[];
885
886     debug(F110,"socketpair",myipaddr,0);
887
888     if (myipaddr[0] == 0)
889       getlocalipaddr();
890
891     servsock = socket(AF_INET, SOCK_STREAM, 0);
892     if (servsock == 0) {
893         return h_errno;
894     }
895     debug(F111,"socketpair","socket",servsock);
896
897     memset(&serv_addr, 0, sizeof(serv_addr));
898     serv_addr.sin_family = AF_INET;
899     serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
900     serv_addr.sin_port = htons(0);
901
902     val = sizeof(serv_addr);
903     if (bind(servsock, (struct sockaddr *) &serv_addr, val) < 0) {
904         closesocket(servsock);
905         return h_errno;
906     }
907     debug(F111,"socketpair","bind",0);
908
909     listen(servsock, 1);
910     debug(F111,"socketpair","listen",0);
911
912     if (getsockname(servsock, (struct sockaddr *) &serv_addr, &val) < 0) {
913         closesocket(servsock);
914         return h_errno;
915     }
916     debug(F111,"socketpair","getsockname",0);
917
918     pair[0] = socket(AF_INET, SOCK_STREAM, 0);
919     if (pair[0] == 0) {
920         closesocket(servsock);
921         return h_errno;
922     }
923     debug(F111,"socketpair","socket",pair[0]);
924
925     memset(&cli_addr, 0, sizeof(cli_addr));
926     cli_addr.sin_family = AF_INET;
927     cli_addr.sin_addr.s_addr = inet_addr(myipaddr[0]?myipaddr:"127.0.0.1");
928     cli_addr.sin_port = serv_addr.sin_port;
929
930     if (connect(pair[0],(struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0) {
931         closesocket(pair[0]);
932         closesocket(servsock);
933         return h_errno;
934     }
935     debug(F111,"socketpair","connect",0);
936
937     pair[1] = accept(servsock, (struct sockaddr *) &serv_addr, &val);
938     if (pair[1] == 0) {
939         closesocket(pair[0]);
940         closesocket(servsock);
941         return h_errno;
942     }
943     debug(F111,"socketpair","accept",pair[1]);
944
945     closesocket(servsock);
946     debug(F111,"socketpair","closesocket",0);
947     return 0;
948 }
949
950 long
951 kbdread(void * param) {
952     int sock = (int) param;
953     char ch;
954     int rc = 0;
955
956     debug(F111,"kbdread","sock",sock);
957
958     while (rc >= 0) {
959         rc = read(fileno(stdin), &ch, 1); /* Read a character. */
960         if (rc > 0) {
961             rc = send(sock,&ch,1,0);
962             /* debug(F000,"kbdread","send()",ch); */
963             printf("\r\ngot: %c rc = %d\r\n",ch,rc);
964         } else
965           msleep(100);
966     }
967     debug(F110,"kbdread","terminating",0);
968     return(rc);
969 }
970 #endif /* BEBOX */
971
972 #ifdef CKLEARN
973 static VOID
974 learnchar(c) int c; {                   /* Learned script keyboard character */
975     int cc;
976     char xbuf[8];
977
978     if (!learning || !learnfp)
979       return;
980
981     switch (learnst) {                  /* Learn state... */
982       case 0:                           /* Neutral */
983       case 1:                           /* Net */
984         if (learnbc > 0) {              /* Have net characters? */
985             char buf[LEARNBUFSIZ];
986             int i, j, n;
987             ULONG t;
988
989             t = (ULONG) time(0);        /* Calculate INPUT timeout */
990             j = t - learnt1;
991             j += (j / 4) > 0 ? (j / 4) : 1; /* Add some slop */
992             if (j < 2) j = 2;               /* 2 seconds minimum */
993
994             fputs("\nINPUT ",learnfp);  /* Give INPUT command for them */
995             fputs(ckitoa(j),learnfp);
996             fputs(" {",learnfp);
997             learnt1 = t;
998
999             n = LEARNBUFSIZ;
1000             if (learnbc < LEARNBUFSIZ) {  /* Circular buffer */
1001                 n = learnbc;              /*  hasn't wrapped yet. */
1002                 learnbp = 0;
1003             }
1004             j = 0;                      /* Copy to linear buffer */
1005             for (i = 0; i < n; i++) {   /* Number of chars in circular buf */
1006
1007                 cc = learnbuf[(learnbp + i) % LEARNBUFSIZ];
1008
1009                 /* Later account for prompts that end with a newline? */
1010
1011                 if (cc == CR && j > 0) {
1012                     if (buf[j-1] != LF)
1013                       j = 0;
1014                 }
1015                 buf[j++] = cc;
1016             }
1017             for (i = 0; i < j; i++) {   /* Now copy out the buffer */
1018                 cc = buf[i];            /* interpreting control chars */
1019                 if (cc == 0) {          /* We don't INPUT NULs */
1020                     continue;
1021                 } else if (cc < SP ||   /* Controls need quoting */
1022                            (cc > 126 && cc < 160)) {
1023                     ckmakmsg(xbuf,8,"\\{",ckitoa((int)cc),"}",NULL);
1024                     fputs(xbuf,learnfp);
1025                 } else {                /* Plain character */
1026                     putc(cc,learnfp);
1027                 }
1028             }
1029             fputs("}\nIF FAIL STOP 1 INPUT timeout",learnfp);
1030             learnbc = 0;
1031         }
1032         learnbp = 0;
1033         fputs("\nPAUSE 1\nOUTPUT ",learnfp); /* Emit OUTPUT and fall thru */
1034
1035       case 2:                           /* Already in Keyboard state */
1036         if (c == 0) {
1037             fputs("\\N",learnfp);
1038         } else if (c == -7) {
1039             fputs("\\B",learnfp);
1040         } else if (c == -8) {
1041             fputs("\\L",learnfp);
1042         } else if (c < SP || (c > 126 && c < 160)) {
1043             ckmakmsg(xbuf,8,"\\{",ckitoa((int)c),"}",NULL);
1044             fputs(xbuf,learnfp);
1045         } else {
1046             putc(c,learnfp);
1047         }
1048     }
1049 }
1050 #endif /* CKLEARN */
1051
1052 static int printbar = 0;
1053
1054 #define OUTXBUFSIZ 15
1055 static CHAR inxbuf[OUTXBUFSIZ+1];       /* Host-to-screen expansion buffer */
1056 static int inxcount = 0;                /* and count */
1057 static CHAR outxbuf[OUTXBUFSIZ+1];      /* Keyboard-to-host expansion buf */
1058 static int outxcount = 0;               /* and count */
1059
1060 int
1061 conect() {
1062     int rc = 0;                         /* Return code: 0 = fail, 1 = OK */
1063     int i, x = 0, prev = -1;            /* Reason code in cx_status */
1064 #ifdef CKLEARN
1065     int crflag = 0;
1066 #endif /* CKLEARN */
1067     register int c = -1, c2, csave;     /* Characters */
1068 #ifdef TNCODE
1069     int tx;                             /* For Telnet negotiations */
1070 #endif /* TNCODE */
1071     int apcrc = 0;                      /* For APC and transparent print */
1072     int n, kbin, scrnout;               /* select() items... */
1073     fd_set in, out, err;                /* File descriptor sets */
1074     int gotnet = 0;                     /* Flag for net ready to read */
1075     int gotkbd = 0;                     /* Flag for keyboard ready to read */
1076     int oldprt = 0;                     /* Used with printing */
1077     int msgflg = 0;
1078     char cbuf[2];                       /* Ditto */
1079
1080 #ifdef BEBOX
1081     int tid = 0;                        /* Thread ID */
1082     int pair[2];                        /* Socket Pair */
1083     CHAR ch;
1084     CHAR buf[64];
1085 #endif /* BEBOX */
1086
1087     cx_status = CSX_INTERNAL;
1088     debok = 1;
1089
1090 #ifdef BEBOX
1091     {
1092         /* Create a socket pair to be used for the keyboard input */
1093         if (socketpair(pair)) {
1094             debug(F110,"conect","unable to create socket pair",0);
1095             return(-1);
1096         }
1097         debug(F111,"connect","socket pair[0]",pair[0]);
1098         debug(F111,"connect","socket pair[1]",pair[1]);
1099
1100         /* Assign one end of the socket to kbin */
1101         kbin = pair[0];
1102         tid = spawn_thread(kbdread,
1103                            "Kbd to Socket Pair",
1104                             B_NORMAL_PRIORITY,
1105                            (void *)pair[1]
1106                            );
1107         resume_thread(tid);
1108         debug(F110,"connect","tid",tid);
1109     }
1110 #else /* BEBOX */
1111     kbin = fileno(stdin);               /* stdin file descriptor */
1112 #endif /* BEBOX */
1113
1114     scrnout = fileno(stdout);           /* stdout file descriptor */
1115
1116 #ifdef CK_TRIGGER
1117     makestr(&triggerval,NULL);          /* Reset trigger */
1118 #endif /* CK_TRIGGER */
1119
1120 #ifdef XPRINT
1121     escbufc = 0;                        /* Reset esc-sequence buffer */
1122     escbuf[0] = NUL;
1123 #endif /* XPRINT */
1124     cbuf[1] = NUL;
1125
1126     ttimoff();                          /* Turn off any timer interrupts */
1127     if (!local) {                       /* Be sure we're not in remote mode */
1128 #ifdef NETCONN
1129 #ifdef NEWFTP
1130         if (ftpisconnected())
1131           printf("Sorry, you can't CONNECT to an FTP server\n");
1132         else
1133 #endif /* NEWFTP */
1134           printf("Sorry, you must SET LINE or SET HOST first\n");
1135 #else
1136         printf("Sorry, you must SET LINE first\n");
1137 #endif /* NETCONN */
1138         return(0);
1139     }
1140     if (speed < 0L && network == 0 && ttfdflg == 0) {
1141         printf("Sorry, you must SET SPEED first\n");
1142         return(0);
1143     }
1144 #ifdef TCPSOCKET
1145     if (network && !ttpipe && (nettype != NET_TCPB && nettype != NET_PTY)) {
1146         printf("Sorry, network type not supported\n");
1147         return(0);
1148     }
1149 #endif /* TCPSOCKET */
1150
1151 #ifdef DYNAMIC
1152     if (!ibuf) {
1153         if (!(ibuf = malloc(IBUFL+1))) { /* Allocate input line buffer */
1154             printf("Sorry, CONNECT input buffer can't be allocated\n");
1155             return(0);
1156         } else {
1157             ibp = ibuf;
1158             ibc = 0;
1159         }
1160     }
1161     if (!obuf) {
1162         if (!(obuf = malloc(OBUFL+1))) { /* Allocate output line buffer */
1163             printf("Sorry, CONNECT output buffer can't be allocated\n");
1164             return(0);
1165         } else {
1166             obp = obuf;
1167             obc = 0;
1168         }
1169     }
1170     if (!kbuf) {
1171         if (!(kbuf = malloc(KBUFL+1))) { /* Allocate keyboard input buffer */
1172             printf("Sorry, CONNECT keyboard buffer can't be allocated\n");
1173             return(0);
1174         }
1175     }
1176     if (!temp) {
1177         if (!(temp = malloc(TMPLEN+1))) { /* Allocate temporary buffer */
1178             printf("Sorry, CONNECT temporary buffer can't be allocated\n");
1179             return(0);
1180         }
1181     }
1182 #else
1183     obp = obuf;
1184     obc = 0;
1185 #endif /* DYNAMIC */
1186
1187     kbp = kbuf;                         /* Always clear these. */
1188     *kbp = NUL;                         /* No need to preserve them between */
1189     kbc = 0;                            /* CONNECT sessions. */
1190
1191 #ifdef DEBUG
1192     if (deblog) {
1193         debug(F101,"CONNECT conect entry ttyfd","",ttyfd);
1194         debug(F101,"CONNECT conect entry ibc","",ibc);
1195         debug(F101,"CONNECT conect entry obc","",obc);
1196         debug(F101,"CONNECT conect entry kbc","",kbc);
1197 #ifdef CK_TRIGGER
1198         debug(F110,"CONNECT conect trigger",tt_trigger[0],0);
1199 #endif /* CK_TRIGGER */
1200         if (ttyfd > -1) {
1201             n = ttchk();
1202             debug(F101,"CONNECT conect entry ttchk","",n);
1203         }
1204     }
1205 #endif /* DEBUG */
1206
1207     if (ttyfd < 0) {                    /* If communication device not open */
1208 #ifdef TTLEBUF
1209         int n = le_inbuf();
1210         debug(F111,"CONNECT le_inbuf()","ttyfd < 0",n);
1211         if (n > 0) {
1212             while (n--) {
1213                 CHAR ch;
1214                 le_getchar(&ch);
1215                 conoc(ch);
1216             }
1217             return(0);
1218         }
1219 #endif /* TTLEBUF */
1220
1221         debug(F101,"CONNECT ttnproto","",ttnproto);
1222         debug(F111,"CONNECT opening",ttname,0); /* Open it now */
1223         if (ttopen(ttname,
1224                    &local,
1225                    network ? -nettype : mdmtyp,
1226                    0
1227                    ) < 0) {
1228             ckmakmsg(temp,TMPLEN,"Sorry, can't open ",ttname,NULL,NULL);
1229             perror(temp);
1230             debug(F110,"CONNECT open failure",ttname,0);
1231             return(0);
1232         }
1233
1234 #ifdef IKS_OPTION
1235         /* If peer is in Kermit server mode, return now. */
1236         if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
1237             cx_status = CSX_IKSD;
1238             return(0);
1239         }
1240 #endif /* IKS_OPTION */
1241     }
1242     dohangup = 0;                       /* Hangup not requested yet */
1243
1244     msgflg = !quiet
1245 #ifdef CK_APC
1246       && !apcactive
1247 #endif /* CK_APC */
1248         ;
1249
1250     if (msgflg) {
1251 #ifdef NETCONN
1252         if (network) {
1253 #ifdef CK_ENCRYPTION
1254             extern int me_encrypt, u_encrypt;
1255             if (ck_tn_encrypting() && ck_tn_decrypting())
1256               printf("SECURE connection to host %s",ttname);
1257             else
1258 #endif /* CK_ENCRYPTION */
1259               if (ttpipe || ttpty)
1260                 printf("Connecting via command \"%s\"",ttname);
1261               else
1262                 printf("Connecting to host %s",ttname);
1263         } else {
1264 #endif /* NETCONN */
1265             printf("Connecting to %s",ttname);
1266             if (speed > -1L) printf(", speed %ld",speed);
1267 #ifdef NETCONN
1268         }
1269 #endif /* NETCONN */
1270         if (tt_escape) {
1271             printf("\r\n");
1272             shoesc(escape);
1273             printf("Type the escape character followed by C to get back,\r\n");
1274             printf("or followed by ? to see other options.\r\n");
1275         } else {
1276             printf(".\r\n\nESCAPE CHARACTER IS DISABLED\r\n\n");
1277         }
1278         if (seslog) {
1279             extern int slogts;
1280             char * s = "";
1281             switch (sessft) {
1282               case XYFT_D:
1283                 s = "debug"; break;
1284               case XYFT_T:
1285                 s = slogts ? "timestamped-text" : "text"; break;
1286               default:
1287                 s = "binary";
1288             }
1289             printf("Session Log: %s, %s\r\n",sesfil,s);
1290         }
1291         if (debses) printf("Debugging Display...)\r\n");
1292     }
1293
1294 /* Condition console terminal and communication line */
1295
1296     if (conbin((char)escape) < 0) {
1297         printf("Sorry, can't condition console terminal\n");
1298         fflush(stdout);
1299         return(0);
1300     }
1301     debug(F101,"CONNECT cmask","",cmask);
1302     debug(F101,"CONNECT cmdmsk","",cmdmsk);
1303     debug(F101,"CONNECT speed before ttvt","",speed);
1304     if ((n = ttvt(speed,flow)) < 0) {   /* Enter "virtual terminal" mode */
1305         if (!network) {
1306             debug(F101,"CONNECT ttvt","",n);
1307             tthang();                   /* Hang up and close the device. */
1308             ttclos(0);
1309             dologend();
1310             if (ttopen(ttname,          /* Open it again... */
1311                        &local,
1312                        network ? -nettype : mdmtyp,
1313                        0
1314                        ) < 0) {
1315                 cx_status = CSX_INTERNAL;
1316                 ckmakmsg(temp,TMPLEN,"Sorry, can't reopen ",ttname,NULL,NULL);
1317                 perror(temp);
1318                 return(0);
1319             }
1320 #ifdef IKS_OPTION
1321             if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start) {
1322                 cx_status = CSX_IKSD;
1323                 return(0);
1324             }
1325 #endif /* IKS_OPTION */
1326
1327             if (ttvt(speed,flow) < 0) { /* Try virtual terminal mode again. */
1328                 conres();               /* Failure this time is fatal. */
1329                 printf("Sorry, Can't condition communication line\n");
1330                 cx_status = CSX_INTERNAL;
1331                 return(0);
1332             }
1333         }
1334     }
1335     debug(F101,"CONNECT ttvt ok, escape","",escape);
1336
1337     /* Despite ttvt() this is still needed in HP-UX */
1338     /* because of the HP-9000 <RESET> key.*/
1339
1340     signal(SIGINT, SIG_IGN);
1341     signal(SIGQUIT, SIG_IGN);
1342
1343     debug(F101,"CONNECT carrier-watch","",carrier);
1344     if ((!network 
1345 #ifdef TN_COMPORT
1346         || istncomport()
1347 #endif /* TN_COMPORT */
1348         ) && (carrier != CAR_OFF)) {
1349         int x;
1350         x = ttgmdm();
1351         debug(F100,"CONNECT ttgmdm","",x);
1352         if ((x > -1) && !(x & BM_DCD)) {
1353 #ifndef NOHINTS
1354             extern int hints;
1355 #endif /* NOHINTS */
1356             debug(F100,"CONNECT ttgmdm CD test fails","",x);
1357             conres();
1358             printf("?Carrier required but not detected.\n");
1359 #ifndef NOHINTS
1360             cx_status = CSX_CARRIER;
1361             if (!hints)
1362               return(0);
1363             printf("***********************************\n");
1364             printf(" Hint: To CONNECT to a serial device that\n");
1365             printf(" is not presenting the Carrier Detect signal,\n");
1366             printf(" first tell C-Kermit to:\n\n");
1367             printf("   SET CARRIER-WATCH OFF\n\n");
1368             printf("***********************************\n\n");
1369 #endif /* NOHINTS */
1370             return(0);
1371         }
1372         debug(F100,"CONNECT ttgmdm ok","",0);
1373     }
1374
1375     /* Now we are connected. */
1376
1377     if (msgflg || printbar)
1378       printf("----------------------------------------------------\r\n");
1379     fflush(stdout);
1380
1381 #ifndef NOCSETS
1382 /* Set up character set translations */
1383
1384     unicode = 0;                        /* Assume Unicode won't be involved */
1385     tcs = 0;                            /* "Transfer" or "Other" charset */
1386     sxo = rxo = NULL;                   /* Initialize byte-to-byte functions */
1387     sxi = rxi = NULL;
1388
1389     if (tcsr != tcsl) {                 /* Remote and local sets differ... */
1390 #ifdef UNICODE
1391         if (tcsr == FC_UTF8 ||          /* Remote charset is UTF-8 */
1392             tcsl == FC_UTF8) {          /* or local one is. */
1393             xuf = xl_ufc[tcsl];         /* Incoming Unicode to local */
1394             if (xuf || tcsl == FC_UTF8) {
1395                 tcs = (tcsr == FC_UTF8) ? tcsl : tcsr; /* The "other" set */
1396                 xfu = xl_fcu[tcs];      /* Local byte to remote Unicode */
1397                 if (xfu)
1398                   unicode = (tcsr == FC_UTF8) ? 1 : 2;
1399             }
1400             tcssize = fcsinfo[tcs].size; /* Size of other character set. */
1401         } else {
1402 #endif /* UNICODE */
1403             tcs = gettcs(tcsr,tcsl);    /* Get intermediate set. */
1404             sxo = xls[tcs][tcsl];       /* translation function */
1405             rxo = xlr[tcs][tcsr];       /* pointers for output functions */
1406             sxi = xls[tcs][tcsr];       /* and for input functions. */
1407             rxi = xlr[tcs][tcsl];
1408 #ifdef UNICODE
1409         }
1410 #endif /* UNICODE */
1411     }
1412 /*
1413   This is to prevent use of zmstuff() and zdstuff() by translation functions.
1414   They only work with disk i/o, not with communication i/o.  Luckily Russian
1415   translation functions don't do any stuffing...
1416 */
1417     langsv = language;
1418 #ifndef NOCYRIL
1419     if (language != L_RUSSIAN)
1420 #endif /* NOCYRIL */
1421       language = L_USASCII;
1422
1423 #ifdef COMMENT
1424 #ifdef DEBUG
1425     if (deblog) {
1426         debug(F101,"CONNECT tcs","",tcs);
1427         debug(F101,"CONNECT tcsl","",tcsl);
1428         debug(F101,"CONNECT tcsr","",tcsr);
1429         debug(F101,"CONNECT fcsinfo[tcsl].size","",fcsinfo[tcsl].size);
1430         debug(F101,"CONNECT fcsinfo[tcsr].size","",fcsinfo[tcsr].size);
1431         debug(F101,"CONNECT unicode","",unicode);
1432     }
1433 #endif /* DEBUG */
1434 #endif /* COMMENT */
1435
1436 #ifdef CK_XYZ
1437 #ifndef XYZ_INTERNAL
1438     {
1439         extern int binary;              /* See about ZMODEM autodownloads */
1440         char * s;
1441         s = binary ? ptab[PROTO_Z].p_b_rcmd : ptab[PROTO_Z].p_t_rcmd;
1442         if (!s) s = "";
1443         zmdlok = (*s != NUL);           /* OK if we have external commands */
1444     }
1445 #endif /* XYZ_INTERNAL */
1446 #endif /* CK_XYZ */
1447
1448 #ifndef NOESCSEQ
1449 /*
1450   We need to activate the escape-sequence recognition feature when:
1451    (a) translation is elected, AND
1452    (b) the local and/or remote set is a 7-bit set other than US ASCII.
1453   Or:
1454    SET TERMINAL APC is not OFF (handled in the next statement).
1455 */
1456     escseq = (tcs != TC_TRANSP) &&      /* Not transparent */
1457       (fcsinfo[tcsl].size == 128 || fcsinfo[tcsr].size == 128) && /* 7 bits */
1458         (fcsinfo[tcsl].code != FC_USASCII); /* But not ASCII */
1459 #endif /* NOESCSEQ */
1460 #endif /* NOCSETS */
1461
1462 #ifndef NOESCSEQ
1463 #ifdef CK_APC
1464     escseq = escseq || (apcstatus & APC_ON);
1465     apcactive = 0;                      /* An APC command is not active */
1466     apclength = 0;                      /* ... */
1467 #endif /* CK_APC */
1468 #ifdef XPRINT
1469     escseq |= tt_print;
1470 #endif /* XPRINT */
1471     inesc[0] = ES_NORMAL;               /* Initial state of recognizer */
1472     inesc[1] = ES_NORMAL;
1473     debug(F101,"CONNECT escseq","",escseq);
1474 #endif /* NOESCSEQ */
1475
1476     if (ttyfd > -1) {                   /* (just in case...) */
1477         what = W_CONNECT;               /* Keep track of what we're doing */
1478         active = 1;
1479     }
1480 #ifdef CKLEARN
1481     if (learning) {                     /* Learned script active... */
1482         learnbp = 0;                    /* INPUT buffer pointer */
1483         learnbc = 0;                    /* INPUT buffer count */
1484         learnst = 0;                    /* State (0 = neutral, none) */
1485         learnt1 = (ULONG) time(0);
1486     }
1487 #endif /* CKLEARN */
1488
1489 #ifdef CKTIDLE
1490     idlelimit = tt_idlelimit;
1491 #endif /* CKTIDLE */
1492
1493     while (active) {                    /* Big loop... */
1494         debug(F100,"CONNECT top of loop","",0);
1495         FD_ZERO(&in);                   /* Clear select() structs */
1496         FD_ZERO(&out);
1497         FD_ZERO(&err);
1498         gotkbd = 0;
1499         gotnet = ttpeek();              /* Something sitting in ckutio buf */
1500         debug(F101,"CONNECT ttpeek","",gotnet);
1501
1502         if (
1503 #ifndef NOSETKEY
1504             !kmptr                      /* Check for key macro active */
1505 #else
1506             1
1507 #endif /* NOSETKEY */
1508             ) {
1509             if (obc) {                  /* No key macro - set up for select */
1510                 FD_SET(ttyfd, &out);    /* Have stuff to send to net */
1511             } else {
1512                 FD_SET(kbin, &in);      /* Need to read stuff from keyboard */
1513             }
1514 #ifdef BEBOX
1515             if (!(ibc || gotnet > 0))
1516                 FD_SET(ttyfd, &in);     /* Need to read stuff from net */
1517 #else /* BEBOX */
1518             if (ibc || gotnet > 0) {
1519                 FD_SET(scrnout, &out);  /* Have stuff to put on screen */
1520             } else {
1521                 FD_SET(ttyfd, &in);     /* Need to read stuff from net */
1522             }
1523 #endif /* BEBOX */
1524             FD_SET(ttyfd, &err);
1525 #ifdef CK_FORWARD_X
1526             fwdx_init_fd_set(&in);
1527 #endif /* CK_FORWARD_X */
1528
1529             /* Wait till the first one of the above is ready for i/o */
1530             /* or TERM IDLE-SEND is active and we time out. */
1531
1532             errno = 0;
1533 #ifdef CKTIDLE
1534             /* This really could be moved out of the loop... */
1535             if (idlelimit) {            /* Idle timeout set */
1536                 struct timeval tv;
1537                 if (idlelimit > 0) {    /* Positive = sec */
1538                     tv.tv_sec = (long) idlelimit;
1539                     tv.tv_usec = 0L;
1540                 } else {                /* Negative = millisec */
1541                     long u = (0 - idlelimit);
1542                     tv.tv_sec = u / 1000L;
1543                     tv.tv_usec = ((u % 1000L) * 1000L);
1544                 }
1545 #ifdef INTSELECT
1546                 c = select(FD_SETSIZE,(int *)&in,(int *)&out,(int *)&err, &tv);
1547 #else
1548                 c = select(FD_SETSIZE, &in, &out, &err, &tv);
1549 #endif /* INTSELECT */
1550             } else
1551 #endif /* CKTIDLE */
1552 #ifdef INTSELECT
1553               c = select(FD_SETSIZE, (int *)&in, (int *)&out, (int *)&err, 0);
1554 #else
1555               c = select(FD_SETSIZE, &in, &out, &err, 0);
1556 #endif /* INTSELECT */
1557             if (c < 1) {
1558 #ifdef CKTIDLE
1559                 if (c == 0) {           /* Timeout */
1560                     debug(F101,"CONNECT select() timeout","",tt_idleact);
1561                     switch (tt_idleact) {
1562                       case IDLE_HANG: { /* Hang up */
1563                           int x = 0;
1564 #ifndef NODIAL
1565                           if (dialmhu)
1566                             x = mdmhup();
1567                           if (x < 1)
1568 #endif /* NODIAL */
1569                             tthang();   /* fall thru deliberately... */
1570                       }
1571                       case IDLE_RET:    /* Return to command mode */
1572                         cx_status = CSX_IDLE;
1573                         active = 0;
1574                         continue;
1575                       case IDLE_OUT:    /* OUTPUT a string */
1576                         if (tt_idlestr) {
1577                             int len = strlen(tt_idlestr);
1578                             if (len > 0)
1579                               ttol((CHAR *)tt_idlestr,len);
1580                             else
1581                               ttoc(NUL); /* No string, send a NUL */
1582                         } else
1583                           ttoc(NUL);    /* No string, send a NUL */
1584                         continue;
1585                       case IDLE_EXIT:   /* Exit from Kermit */
1586                         doexit(GOOD_EXIT,xitsta);
1587 #ifdef TNCODE
1588                       case IDLE_TAYT:   /* Send Telnet Are You There? */
1589                         if (network && IS_TELNET()) {
1590                             tnopt[0] = (CHAR) IAC;
1591                             tnopt[1] = (CHAR) TN_AYT;
1592                             tnopt[2] = NUL;
1593                             if (ttol((CHAR *)tnopt,2) < 0)
1594                               active = 0;
1595                         }
1596                         continue;
1597
1598                       case IDLE_TNOP:   /* Send Telnet NOP */
1599                         if (network && IS_TELNET()) {
1600                             tnopt[0] = (CHAR) IAC;
1601                             tnopt[1] = (CHAR) TN_NOP;
1602                             tnopt[2] = NUL;
1603                             if (ttol((CHAR *)tnopt,2) < 0)
1604                               active = 0;
1605                         }
1606                         continue;
1607 #endif /* TNCODE */
1608                     }
1609                 }
1610 #endif /* CKTIDLE */
1611
1612                 debug(F101,"CONNECT select() errno","",errno);
1613                 /* A too-big first arg to select() gets EBADF */
1614 #ifdef EINTR
1615                 if (c == -1) {
1616                     if (errno == EINTR) {
1617                         continue;
1618                     }
1619                 }
1620 #endif /* EINTR */
1621                 sleep(1);
1622                 continue;
1623             }
1624 #ifndef BEBOX
1625 #ifdef DEBUG
1626             if (FD_ISSET(scrnout, &out)) {
1627                 debug(F100,"CONNECT SELECT scrnout","",0);
1628             }
1629 #endif /* DEBUG */
1630 #endif /* BEBOX */
1631
1632 #ifdef CK_FORWARD_X
1633             fwdx_check_sockets(&in);
1634 #endif /* CK_FORWARD_X */
1635
1636             if (FD_ISSET(ttyfd, &in)) { /* Read from net? */
1637                 debug(F110,"CONNECT SELECT ttyfd","in",0);
1638                 FD_CLR(ttyfd, &in);
1639                 gotnet = 1;             /* Net is ready */
1640             }
1641             if (FD_ISSET(kbin, &in)) {  /* Read from keyboard? */
1642                 debug(F100,"CONNECT SELECT kbin","",0);
1643                 FD_CLR(kbin, &in);
1644                 gotkbd = 1;             /* Keyboard is ready */
1645             }
1646             if (FD_ISSET(ttyfd, &err)) {
1647                 debug(F110,"CONNECT SELECT ttyfd","err",0);
1648                 FD_CLR(ttyfd, &err);
1649 #ifdef NETPTY
1650 #ifdef HAVE_PTYTRAP
1651                 /* Special handling for HP-UX pty i/o */
1652                 if (ttpty) {
1653                     if (pty_trap_handler(ttyfd) > 0) {
1654                         ttclos(0);
1655                         goto conret1;
1656                     }
1657                     continue;
1658                 }
1659 #endif /* HAVE_PTYTRAP */
1660 #endif /* NETPTY */
1661                 gotnet = 1;             /* Net is ready (don't set if pty) */
1662             }
1663         }
1664 #ifdef DEBUG
1665         if (deblog) {
1666             debug(F101,"CONNECT gotkbd","",gotkbd);
1667             debug(F101,"CONNECT kbc","",kbc);
1668 #ifndef NOSETKEY
1669             debug(F101,"CONNECT kmptr","",kmptr);
1670 #endif /* NOSETKEY */
1671         }
1672 #endif /* DEBUG */
1673
1674         while (gotkbd || kbc > 0        /* If we have keyboard chars */
1675 #ifndef NOSETKEY
1676                || kmptr
1677 #endif /* NOSETKEY */
1678                ) {
1679 #ifndef NOSETKEY
1680             if (kmptr) {                /* Have current macro? */
1681                 debug(F100,"CONNECT kmptr non NULL","",0);
1682                 if ((c = (CHAR) *kmptr++) == NUL) { /* Get char from it */
1683                     debug(F100,"CONNECT macro empty, continuing","",0);
1684                     kmptr = NULL;       /* If no more chars,  */
1685                     continue;           /* Reset pointer and continue */
1686                 }
1687                 debug(F000,"CONNECT char from macro","",c);
1688             } else {                    /* No macro... */
1689 #endif /* NOSETKEY */
1690 #ifdef BEBOX
1691                 {
1692                     int rc = 0;
1693                     if ((rc = recv(kbin,buf,1,0)) > 0)
1694                       c = buf[0];
1695                     else
1696                       c = -1;
1697                     debug(F111,"recv","rc",rc);
1698                     printf("\r\nrecv: %c rc=%d\r\n",buf[0],rc);
1699                 }
1700 #else /* BEBOX */
1701                 c = CONGKS();           /* Yes, read from keyboard */
1702 #endif /* BEBOX */
1703                 gotkbd = 0;             /* Turn off select() result flag */
1704 #ifndef NOSETKEY
1705             }
1706 #endif /* NOSETKEY */
1707             if (c == -1) {
1708 #ifdef EINTR
1709                 if (errno == EINTR)
1710                   continue;
1711 #endif /* EINTR */
1712                 cx_status = CSX_IOERROR;
1713                 conoc(BEL);
1714                 goto conret0;
1715             }
1716             c &= cmdmsk;                /* Do any requested masking */
1717
1718 #ifndef NOSETKEY
1719 /*
1720   Note: kmptr is NULL if we got character c from the keyboard, and it is
1721   not NULL if it came from a macro.  In the latter case, we must avoid
1722   expanding it again.
1723 */
1724             if (!kmptr && macrotab[c]) { /* Macro definition for c? */
1725                 debug(F000,"CONNECT macro key",macrotab[c],c);
1726                 kmptr = macrotab[c];    /* Yes, set up macro pointer */
1727                 continue;               /* and restart the loop, */
1728             } else c = keymap[c];       /* else use single-char keymap */
1729 #endif /* NOSETKEY */
1730             if (
1731 #ifndef NOSETKEY
1732                 !kmptr &&
1733 #endif /* NOSETKEY */
1734                 (tt_escape && ((c & 0xff) == escape))) { /* Escape char? */
1735                 debug(F000,"CONNECT got escape","",c);
1736 #ifdef BEBOX
1737                 if (recv(kbin,buf,1,0)>=0)
1738                   c = buf[0];
1739                 else
1740                   c = -1;
1741 #else /* BEBOX */
1742                 c = CONGKS() & 0x7f;    /* Read argument */
1743 #endif /* BEBOX */
1744                 doesc((char) c);        /* Handle it */
1745                 continue;               /* Back to loop */
1746             }
1747             csave = c;                  /* Save it before translation */
1748                                         /* for local echoing. */
1749 #ifdef CKLEARN
1750             crflag = (c == CR);         /* Remember if it was CR. */
1751 #endif /* CKLEARN */
1752
1753 #ifndef NOCSETS
1754             if (inesc[1] == ES_NORMAL) { /* If not inside escape seq.. */
1755                 /* Translate character sets */
1756 #ifdef UNICODE
1757                 int x;
1758                 if (unicode == 1) {     /* Remote is UTF-8 */
1759                     outxcount = b_to_u((CHAR)c,outxbuf,OUTXBUFSIZ,tcssize);
1760                     outxbuf[outxcount] = NUL;
1761                 } else if (unicode == 2) { /* Local is UTF-8 */
1762                     
1763                     x = u_to_b((CHAR)c);
1764                     if (x < 0)
1765                       continue;
1766                     outxbuf[0] = (unsigned)(x & 0xff);
1767                     outxcount = 1;
1768                     outxbuf[outxcount] = NUL;
1769                 } else {
1770 #endif /* UNICODE */
1771                     if (sxo) c = (*sxo)((char)c); /* Local-intermediate */
1772                     if (rxo) c = (*rxo)((char)c); /* Intermediate-remote */
1773                     outxbuf[0] = c;
1774                     outxcount = 1;
1775                     outxbuf[outxcount] = NUL;
1776 #ifdef UNICODE
1777                 }
1778 #endif /* UNICODE */
1779             } else {
1780                 outxbuf[0] = c;
1781                 outxcount = 1;
1782                 outxbuf[outxcount] = NUL;
1783             }
1784             if (escseq)
1785               apcrc = chkaes((char)c,1);
1786 #else
1787             outxbuf[0] = c;
1788             outxcount = 1;
1789             outxbuf[outxcount] = NUL;
1790 #endif /* NOCSETS */
1791
1792             debug(F111,"OUTXBUF",outxbuf,outxcount);
1793
1794             for (i = 0; i < outxcount; i++) {
1795                 c = outxbuf[i];
1796 /*
1797  If Shift-In/Shift-Out is selected and we have a 7-bit connection,
1798  handle shifting here.
1799 */
1800                 if (sosi) {                      /* Shift-In/Out selected? */
1801                     if (cmask == 0177) {         /* In 7-bit environment? */
1802                         if (c & 0200) {          /* 8-bit character? */
1803                             if (outshift == 0) { /* If not shifted, */
1804                                 ttoc(dopar(SO)); /* shift. */
1805                                 outshift = 1;
1806                             }
1807                         } else {
1808                             if (outshift == 1) { /* 7-bit character */
1809                                 ttoc(dopar(SI)); /* If shifted, */
1810                                 outshift = 0;    /* unshift. */
1811                             }
1812                         }
1813                     }
1814                     if (c == SO) outshift = 1; /* User typed SO */
1815                     if (c == SI) outshift = 0; /* User typed SI */
1816                 }
1817                 c &= cmask;             /* Apply Kermit-to-host mask now. */
1818                 if (c == '\015') {      /* Carriage Return */
1819                     int stuff = -1;
1820                     if (tnlm) {         /* TERMINAL NEWLINE ON */
1821                         stuff = LF;     /* Stuff LF */
1822 #ifdef TNCODE
1823                     } else if (network && /* TELNET NEWLINE ON/OFF/RAW */
1824                                IS_TELNET()) {
1825                         switch (!TELOPT_ME(TELOPT_BINARY) ? tn_nlm : tn_b_nlm){
1826                           case TNL_CRLF:
1827                             stuff = LF;
1828                             break;
1829                           case TNL_CRNUL:
1830                             stuff = NUL;
1831                             break;
1832                         }
1833 #endif /* TNCODE */
1834                     }
1835                     if (stuff > -1) {
1836                         ttoc(dopar('\015'));    /* Send CR */
1837                         if (duplex) conoc('\015'); /* Maybe echo CR */
1838                         c = stuff;      /* Char to stuff */
1839                         csave = c;
1840                     }
1841                 }
1842 #ifdef TNCODE
1843 /* If user types the 0xff character (TELNET IAC), it must be doubled. */
1844                 else            /* Not CR */
1845                   if ((dopar((CHAR) c) == IAC) && /* IAC (0xff) */
1846                       network && IS_TELNET()) { /* Send one now */
1847                       ttoc((char)IAC); /* and the other one just below. */
1848                   }
1849 #endif /* TNCODE */
1850                 /* Send the character */
1851
1852                 x = ttoc((char)dopar((CHAR) c));
1853                 if (x > -1) {
1854 #ifdef CKLEARN
1855                     if (learning) {     /* Learned script active */
1856                         if (crflag) {   /* User typed CR */
1857                             learnchar(CR); /* Handle CR */
1858                             learnst = 0;   /* Shift to Neutral */
1859                         } else {
1860                             learnchar(c);  /* Not CR */
1861                             learnst = 2;   /* Change state to Keyboard */
1862                         }
1863                     }
1864 #endif /* CKLEARN */
1865                     if (duplex) {       /* If half duplex, must echo */
1866                         if (debses)
1867                           conol(dbchr(csave)); /* the original char */
1868                         else            /* not the translated one */
1869                           conoc((char)csave);
1870                         if (seslog) {   /* And maybe log it too */
1871                             c2 = csave;
1872                             if (sessft == 0 && csave == '\r')
1873                               c2 = '\n';
1874                             logchar((char)c2);
1875                         }
1876                     }
1877                 } else {
1878                     perror("\r\nCan't send character");
1879                     cx_status = CSX_IOERROR;
1880                     active = 0;
1881                     break;
1882                 }
1883             }
1884         }
1885         if (FD_ISSET(ttyfd, &out)) {
1886             FD_CLR(ttyfd, &out);
1887         }
1888         while (gotnet > 0 || ibc > 0) {
1889             gotnet = 0;
1890             prev = c;
1891             c = ckcgetc(0);             /* Get next character */
1892             /* debug(F101,"CONNECT c","",c); */
1893             if (c < 0) {                /* Failed... */
1894                 ckcputf();              /* Flush CONNECT output buffer */
1895                 if (msgflg) {
1896                     printf("\r\nCommunications disconnect ");
1897 #ifdef COMMENT
1898                     if (c == -3
1899 #ifdef ultrix
1900 /* This happens on Ultrix if there's no carrier */
1901                         && errno != EIO
1902 #endif /* ultrix */
1903 #ifdef UTEK
1904 /* This happens on UTEK if there's no carrier */
1905                         && errno != EWOULDBLOCK
1906 #endif /* UTEK */
1907                         )
1908                       perror("\r\nCan't read character");
1909 #endif /* COMMENT */
1910                 }
1911 #ifdef NOSETBUF
1912                 fflush(stdout);
1913 #endif /* NOSETBUF */
1914                 dologend();
1915                 tthang();               /* Hang up the connection */
1916                 debug(F111,"CONNECT i/o error 1",ck_errstr(),errno);
1917                 cx_status = CSX_HOSTDISC;
1918                 goto conret0;
1919             }
1920 #ifdef TNCODE
1921             tx = 0;
1922             if ((c == NUL) && network && IS_TELNET()) {
1923                 if (prev == CR) {    /* Discard <NUL> of <CR><NUL> if peer */
1924                     if (!TELOPT_U(TELOPT_BINARY)) {  /* not in binary mode */
1925                         debug(F111,"CONNECT NUL",ckitoa(prev),c);
1926                         ckcputf();      /* Flush screen output buffer */
1927                         break;
1928                     }
1929                 }
1930             }
1931             debug(F111,"CONNECT","c",c);
1932             debug(F111,"CONNECT","network",network);
1933             debug(F111,"CONNECT","IS_TELNET",IS_TELNET());
1934             if ((c == IAC) && network && IS_TELNET()) {
1935 #ifdef CK_ENCRYPTION
1936                 int x_auth = TELOPT_ME(TELOPT_AUTHENTICATION);
1937 #else
1938                 int x_auth = 0;
1939 #endif /* CK_ENCRYPTION */
1940                 int me_bin = TELOPT_ME(TELOPT_BINARY);
1941                 int u_bin = TELOPT_U(TELOPT_BINARY);
1942                 debug(F100,"CONNECT got IAC","",0);
1943                 ckcputf();              /* Dump screen-output buffer */
1944                 if ((tx = tn_doop((CHAR)(c & 0xff),duplex,ckcgetc)) == 0) {
1945                     if (me_bin != TELOPT_ME(TELOPT_BINARY)) {
1946                         me_bin = TELOPT_ME(TELOPT_BINARY);
1947                     } else if (u_bin != TELOPT_U(TELOPT_BINARY)) {
1948                         u_bin = TELOPT_U(TELOPT_BINARY);
1949 #ifdef CK_ENCRYPTION
1950 /*
1951   Here we have to push back any bytes we have read using block reads, so we
1952   can read them again using single-character reads, so they can be decrypted
1953   in case there was a switch to encryption in the block.  Note that we can't
1954   handle switches in the encryption state itself this way -- which would be
1955   nice, since it would eliminate the need for single-character reads.  Why?
1956   Because if a series of characters has already been decrypted that shouldn't
1957   have been, then (a) it's ruined, and (b) so is the state of the decryption
1958   machine.  Too bad.
1959 */
1960                     } else if (TELOPT_ME(TELOPT_AUTHENTICATION) != 0 &&
1961                                TELOPT_ME(TELOPT_AUTHENTICATION) != x_auth
1962                                ) {
1963                         if (ttpushback((CHAR *)ibp,ibc) > -1) {
1964                             ibc = 0;
1965                             ibp = ibuf;
1966                         }
1967 #endif /* CK_ENCRYPTION */
1968                     }
1969                     continue;
1970                 } else if (tx == -1) {  /* I/O error */
1971                     if (msgflg)
1972                       printf("\r\nCommunications disconnect ");
1973 #ifdef NOSETBUF
1974                     fflush(stdout);
1975 #endif /* NOSETBUF */
1976                     dologend();
1977                     debug(F111,"CONNECT i/o error 2",ck_errstr(),errno);
1978                     cx_status = CSX_IOERROR;
1979                     goto conret0;
1980                 } else if (tx == -2) {  /* I/O error */
1981                     if (msgflg)
1982                       printf("\r\nConnection closed by peer");
1983 #ifdef NOSETBUF
1984                     fflush(stdout);
1985 #endif /* NOSETBUF */
1986                     dologend();
1987                     debug(F111,"CONNECT i/o error 3",ck_errstr(),errno);
1988                     cx_status = CSX_IOERROR;
1989                     goto conret0;
1990                 } else if (tx == -3) {  /* I/O error */
1991                     if (msgflg)
1992                       printf("\r\nConnection closed due to telnet policy");
1993 #ifdef NOSETBUF
1994                     fflush(stdout);
1995 #endif /* NOSETBUF */
1996                     dologend();
1997                     debug(F111,"CONNECT i/o error 4",ck_errstr(),errno);
1998                     cx_status = CSX_IOERROR;
1999                     goto conret0;
2000                 } else if ((tx == 1) && (!duplex)) { /* ECHO change */
2001                     duplex = 1;         /* Turn on local echo */
2002                     continue;
2003                 } else if ((tx == 2) && (duplex)) { /* ECHO change */
2004                     duplex = 0;
2005                     continue;
2006                 } else if (tx == 3) {   /* Quoted IAC */
2007                     c = parity ? 127 : 255;
2008                 }
2009 #ifdef IKS_OPTION
2010                 else if (tx == 4) {   /* IKS State Change */
2011                     if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
2012                         !tcp_incoming
2013                         ) {
2014                         /* here we need to print a msg that the other */
2015                         /* side is in SERVER mode and that REMOTE     */
2016                         /* commands should be used.  And CONNECT mode */
2017                         /* should be ended.                           */
2018                         cx_status = CSX_IKSD;
2019                         active = 0;
2020                     }
2021                 }
2022 #endif /* IKS_OPTION */
2023                 else if (tx == 6) {
2024                     /* DO LOGOUT was received */
2025                     if (msgflg)
2026                       printf("\r\nRemote Logout ");
2027 #ifdef NOSETBUF
2028                     fflush(stdout);
2029 #endif /* NOSETBUF */
2030                     debug(F100,"CONNECT Remote Logout","",0);
2031                     cx_status = CSX_TRIGGER;
2032                     goto conret0;
2033                 } else
2034                   continue;             /* Negotiation OK, get next char. */
2035             } else if (parity)
2036               c &= 0x7f;
2037
2038             /* I'm echoing for the remote */
2039             if (TELOPT_ME(TELOPT_ECHO) && tn_rem_echo)
2040               ttoc((char)c);
2041 #endif /* TNCODE */
2042
2043 #ifdef CKLEARN
2044          /* Learned script: Record incoming chars if not in Keyboard state */
2045
2046             if (learning && learnst != 2) { /* Learned script active */
2047                 learnbuf[learnbp++] = c;    /* Save for INPUT command */
2048                 if (learnbp >= LEARNBUFSIZ) /* in circular buffer */
2049                   learnbp = 0;              /* wrapping if at end. */
2050                 learnbc++;                  /* Count this byte. */
2051                 learnst = 1;                /* State is Net. */
2052             }
2053 #endif /* CKLEARN */
2054
2055             if (debses) {               /* Output character to screen */
2056                 char *s;                /* Debugging display... */
2057                 s = dbchr(c);
2058                 while (*s)
2059                   ckcputc(*s++);
2060             } else {                    /* Regular display ... */
2061                 c &= cmask;             /* Apply Kermit-to-remote mask */
2062                 if (seslog && sessft)   /* If binary session log */
2063                   logchar((char)c);     /* log the character now. */
2064 #ifndef NOXFER
2065 #ifdef CK_AUTODL
2066 /*
2067   Autodownload.  Check for Kermit S packet prior to translation, since that
2068   can change the packet and make it unrecognizable (as when the terminal
2069   character set is an ISO 646 one)...  Ditto for Zmodem start packet.
2070 */
2071                 if (autodl              /* Autodownload enabled? */
2072 #ifdef IKS_OPTION
2073                     || TELOPT_SB(TELOPT_KERMIT).kermit.me_start
2074 #endif /* IKS_OPTION */
2075                     ) {
2076                     int k = 0;
2077
2078                     if (kstartactive || c == stchr /* Kermit S or I packet? */
2079 #ifdef COMMENT
2080                         || adl_kmode == ADLSTR /* Not used in C-Kermit */
2081 #endif /* COMMENT */
2082                         )
2083                       k = kstart((CHAR)c);
2084 #ifdef CK_XYZ
2085                     if (!k && zmdlok)   /* Or an "sz" start? */
2086                       k = zstart((CHAR)c);
2087 #endif /* CK_XYZ */
2088                     if (k) {
2089                         int ksign = 0;
2090                         debug(F101,"CONNECT autodownload k","",k);
2091                         if (k < 0) { /* Minus-Protocol? */
2092 #ifdef NOSERVER
2093                             goto noserver; /* Need server mode for this */
2094 #else
2095                             ksign = 1; /* Remember */
2096                             k = 0 - k; /* Convert to actual protocol */
2097                             justone = 1; /* Flag for protocol module */
2098 #endif /* NOSERVER */
2099                         } else
2100                           justone = 0;
2101                         k--;            /* Adjust [kz]start's return value */
2102                         if (k == PROTO_K
2103 #ifdef CK_XYZ
2104                             || k == PROTO_Z
2105 #endif /* CK_XYZ */
2106                             ) {
2107                             /* Damage the packet so that it doesn't trigger */
2108                             /* autodownload detection downstream. */
2109                             if (k == PROTO_K) {
2110                                 int i, len = strlen((char *)ksbuf);
2111                                 for (i = 0; i < len; i++)
2112                                   ckcputc(BS);
2113                             }
2114 #ifdef CK_XYZ
2115                             else {
2116                                 int i;
2117                                 for (i = 0; i < 3; i++)
2118                                   ckcputc(CAN);
2119                             }
2120 #endif /* CK_XYZ */
2121
2122 #ifndef NOICP
2123                             /* sprintf is safe here (builtin keywords) */
2124                             sprintf(apcbuf,
2125                                     "set proto %s, %s, set proto %s",
2126                                     ptab[k].p_name,
2127                                     ksign ? "server" : "receive",
2128                                     ptab[protocol].p_name
2129                                     );
2130                             apclength = strlen(apcbuf);
2131                             debug(F111,"CONNECT ksbuf",ksbuf,k);
2132                             debug(F110,"CONNECT autodownload",apcbuf,0);
2133                             apcactive = APC_LOCAL;
2134                             ckcputf();  /* Force screen update */
2135                             cx_status = CSX_APC;
2136                             goto conret1;
2137 #else
2138 /*
2139   Here's another way that doesn't require APC, but then we'll have to change
2140   all the other CONNECT modules, and then the mainline code that calls them.
2141 */
2142                             {
2143                                 extern char sstate;
2144                                 sstate = ksign ? 'x' : 'v';
2145                                 proto();
2146                             }
2147 #endif /* NOICP */
2148                         }
2149                     }
2150                 }
2151 #ifdef NOSERVER
2152               noserver:
2153 #endif /* NOSERVER */
2154
2155 #endif /* CK_AUTODL */
2156 #endif /* NOXFER */
2157                 if (sosi) {             /* Handle SI/SO */
2158                     if (c == SO) {      /* Shift Out */
2159                         inshift = 1;
2160                         continue;
2161                     } else if (c == SI) { /* Shift In */
2162                         inshift = 0;
2163                         continue;
2164                     }
2165                     if (inshift) c |= 0200;
2166                 }
2167                 inxbuf[0] = c;          /* In case there is no translation */
2168                 inxcount = 1;           /* ... */
2169 #ifndef NOCSETS
2170                 if (inesc[0] == ES_NORMAL /* If not in an escape sequence */
2171                     && !printing        /* and not in transparent print */
2172                     ) {                 /* Translate character sets */
2173 #ifdef UNICODE
2174                     int x;
2175                     if (unicode == 1) { /* Remote is UTF-8 */
2176                         x = u_to_b((CHAR)c);
2177                         if (x == -1)
2178                           continue;
2179                         else if (x == -2) { /* LS or PS */
2180                             inxbuf[0] = CR;
2181                             inxbuf[1] = LF;
2182                             inxcount = 2;
2183                         } else if (x == -9) { /* UTF-8 error */
2184                             inxbuf[0] = '?';
2185                             inxbuf[1] = u_to_b2();
2186                             inxcount = 2;
2187                         } else {
2188                             inxbuf[0] = (unsigned)(x & 0xff);
2189                         }
2190                         c = inxbuf[0];
2191                     } else if (unicode == 2) { /* Local is UTF-8 */
2192                         inxcount = b_to_u((CHAR)c,inxbuf,OUTXBUFSIZ,tcssize);
2193                         c = inxbuf[0];
2194                     } else {
2195 #endif /* UNICODE */
2196                         if (sxi) c = (*sxi)((CHAR)c);
2197                         if (rxi) c = (*rxi)((CHAR)c);
2198                         inxbuf[0] = c;
2199 #ifdef UNICODE
2200                     }
2201 #endif /* UNICODE */
2202                 }
2203 #endif /* NOCSETS */
2204
2205 #ifndef NOESCSEQ
2206                 if (escseq) {           /* If handling escape sequences */
2207                     oldprt = printing;       /* remember printer state */
2208                     apcrc = chkaes((char)c,0); /* and update escseq state. */
2209                     if (printing && !oldprt) /* If printer was turned on */
2210                       continue;         /* don't print final char of escseq */
2211                 }
2212 #ifdef CK_APC
2213 /*
2214   If we are handling APCs, we have several possibilities at this point:
2215    1. Ordinary character to be written to the screen.
2216    2. An Esc; we can't write it because it might be the beginning of an APC.
2217    3. The character following an Esc, in which case we write Esc, then char,
2218       but only if we have not just entered an APC sequence.
2219 */
2220                 if (escseq && (apcstatus & APC_ON)) {
2221                     if (inesc[0] == ES_GOTESC) /* Don't write ESC yet */
2222                       continue;
2223                     else if (oldesc[0] == ES_GOTESC && !apcactive) {
2224                         ckcputc(ESC);   /* Write saved ESC */
2225                         if (seslog && !sessft) logchar((char)ESC);
2226                     } else if (apcrc) { /* We have an APC */
2227                         debug(F111,"CONNECT APC complete",apcbuf,apclength);
2228                         ckcputf();      /* Force screen update */
2229                         cx_status = CSX_APC;
2230                         goto conret1;
2231                     }
2232                 }
2233 #endif /* CK_APC */
2234 #endif /* NOESCSEQ */
2235
2236                 debug(F111,"INXBUF",inxbuf,inxcount);
2237                 for (i = 0; i < inxcount; i++) { /* Loop thru */
2238                     c = inxbuf[i];      /* input expansion buffer... */
2239                     if (
2240 #ifdef CK_APC
2241                         !apcactive &&   /* Don't display APC sequences */
2242 #endif /* CK_APC */
2243                         !printing       /* or transparent print material */
2244
2245                         ) {
2246                         c &= cmdmsk;    /* Apply command mask. */
2247                         if (c == CR && tt_crd) { /* SET TERM CR-DISPLA CRLF? */
2248                             ckcputc(c); /* Yes, output CR */
2249                             if (seslog && !sessft) logchar((char)c);
2250                             c = LF;     /* and insert a linefeed */
2251                         }
2252                         if (dontprint)  { /* Do transparent printing. */
2253                             dontprint = 0;
2254                             continue;
2255                         } else
2256
2257                         ckcputc(c);     /* Write character to screen */
2258                     }
2259                     if (seslog && !sessft) /* Handle session log. */
2260                       logchar((char)c);
2261 #ifdef XPRINT
2262                     if (printing && !inesc[0]) {
2263                         /* zchout() can't be used because */
2264                         /* it's buffered differently. */
2265                         cbuf[0] = c;
2266                         zsoutx(ZMFILE,(char *)cbuf,1);
2267                     }
2268 #endif /* XPRINT */
2269
2270 #ifdef CK_TRIGGER
2271                     /* Check for trigger string */
2272                     if (tt_trigger[0]) {
2273                         int i;
2274                         if ((i = autoexitchk((CHAR)c)) > -1) {
2275                             makestr(&triggerval,tt_trigger[i]);
2276                             ckcputf();  /* Force screen update */
2277 #ifdef NOSETBUF
2278                             fflush(stdout); /* I mean really force it */
2279 #endif /* NOSETBUF */
2280                             cx_status = CSX_TRIGGER;
2281                             goto conret1;
2282                         }
2283                     }
2284 #endif /* CK_TRIGGER */
2285                 }
2286             }
2287         }
2288 #ifndef BEBOX
2289         if (FD_ISSET(scrnout, &out)) {
2290             FD_CLR(scrnout, &out);
2291         }
2292 #endif /* BEBOX */
2293     } /* End of big loop */
2294   conret1:                              /* Come here to succeed */
2295     rc = 1;
2296   conret0:                              /* Common exit point */
2297 #ifdef BEBOX
2298     {
2299         long ret_val;
2300         closesocket(pair[0]);
2301         closesocket(pair[1]);
2302         x = kill(tid,SIGKILLTHR);       /* Kill thread */
2303         wait_for_thread (tid, &ret_val);
2304     }
2305 #endif /* BEBOX */
2306
2307 #ifdef CKLEARN
2308     if (learning && learnfp)
2309       fputs("\n",learnfp);
2310 #endif /* CKLEARN */
2311
2312     conres();
2313     if (dohangup > 0) {
2314 #ifdef NETCONN
2315         if (network
2316 #ifdef TNCODE
2317             && !TELOPT_ME(TELOPT_COMPORT)
2318 #endif /* TNCODE */
2319             )
2320           ttclos(0);
2321 #endif /* NETCONN */
2322
2323 #ifndef COMMENT
2324 /*
2325   This is bad because if they said SET MODEM HANGUP-METHOD MODEM-COMMAND,
2326   they mean it -- we shouldn't fall back on tthang() if mdmhup() fails,
2327   because maybe they have some special kind of connection.  On the other
2328   hand, making this change prevents dialing from working at all in some
2329   cases.  Further study needed.
2330 */
2331 #ifndef NODIAL
2332         if (dohangup > 1)               /* User asked for it */
2333           if (mdmhup() < 1)             /* Maybe hang up via modem */
2334 #endif /* NODIAL */
2335             tthang();                   /* And make sure we don't hang up */
2336 #else
2337         if (!network) {                 /* Serial connection. */
2338 #ifndef NODIAL
2339             if (dialmhu)                /* Hang up the way they said to. */
2340               mdmhup();
2341             else
2342 #endif /* NODIAL */
2343               tthang();
2344         }
2345 #endif /* COMMENT */
2346         dologend();
2347         dohangup = 0;                   /* again unless requested again. */
2348     }
2349     if (quitnow)                        /* Exit now if requested. */
2350       doexit(GOOD_EXIT,xitsta);
2351     if (msgflg
2352 #ifdef CK_APC
2353         && !apcactive
2354 #endif /* CK_APC */
2355         )
2356       printf("(Back at %s)", *myhost ? myhost : "local UNIX system");
2357 #ifdef CK_APC
2358     if (!apcactive)
2359 #endif /* CK_APC */
2360       printf("\n");
2361     what = W_NOTHING;                   /* So console modes set right. */
2362 #ifndef NOCSETS
2363     language = langsv;                  /* Restore language */
2364 #endif /* NOCSETS */
2365 #ifdef CK_APC
2366     debug(F101,"CONNECT exit apcactive","",apcactive);
2367     debug(F101,"CONNECT exit justone","",justone);
2368 #endif /* CK_APC */
2369     if (msgflg) {
2370 #ifdef CK_APC
2371         if (apcactive == APC_LOCAL)
2372           printf("\n");
2373 #endif /* CK_APC */
2374         printf("----------------------------------------------------\n");
2375         printbar = 1;
2376     } else
2377         printbar = 0;
2378     fflush(stdout);
2379     return(rc);
2380 }
2381
2382 /*  H C O N N E  --  Give help message for connect.  */
2383
2384 #define CXM_SER 1                       /* Serial connections only */
2385 #define CXM_NET 2                       /* Network only (but not Telnet) */
2386 #define CXM_TEL 4                       /* Telnet only */
2387
2388 static struct hmsgtab {
2389     char * hmsg;
2390     int hflags;
2391 } hlpmsg[] = {
2392     {"  ? or H for this message",                0},
2393     {"  0 (zero) to send the NUL (0) character", 0},
2394     {"  B to send a BREAK signal (0.275sec)",  CXM_SER},
2395 #ifdef NETCONN
2396     {"  B to send a network BREAK",            CXM_NET},
2397     {"  B to send a Telnet BREAK",             CXM_TEL},
2398 #endif /* NETCONN */
2399 #ifdef CK_LBRK
2400     {"  L to send a Long BREAK (1.5sec)",      CXM_SER},
2401 #endif /* CK_LBRK */
2402 #ifdef NETCONN
2403     {"  I to send a network interrupt packet", CXM_NET},
2404     {"  I to send a Telnet Interrupt request", CXM_TEL},
2405 #ifdef TNCODE
2406     {"  A to send Telnet Are-You-There?",      CXM_TEL},
2407 #endif /* TNCODE */
2408 #endif /* NETCONN */
2409     {"  U to hangup and close the connection", 0},
2410     {"  Q to hangup and quit Kermit",          0},
2411     {"  S for status",                         0},
2412 #ifdef NOPUSH
2413     {"  ! to push to local shell (disabled)",  0},
2414     {"  Z to suspend (disabled)",              0},
2415 #else
2416     {"  ! to push to local shell",             0},
2417 #ifdef NOJC
2418     {"  Z to suspend (disabled)",              0},
2419 #else
2420     {"  Z to suspend",                         0},
2421 #endif /* NOJC */
2422 #endif /* NOPUSH */
2423     {"  \\ backslash code:",                   0},
2424     {"    \\nnn  decimal character code",      0},
2425     {"    \\Onnn octal character code",        0},
2426     {"    \\Xhh  hexadecimal character code;", 0},
2427     {"    terminate with Carriage Return.",    0},
2428     {"  Type the escape character again to send the escape character itself,",
2429        0},
2430     {"  or press the space-bar to resume the CONNECT session.", 0},
2431     {NULL, 0}
2432 };
2433
2434 int
2435 hconne() {
2436     int c, i, cxtype;
2437     if (network)
2438       cxtype = IS_TELNET() ? CXM_TEL : CXM_NET;
2439     else
2440       cxtype = CXM_SER;
2441
2442     conol("\r\n----------------------------------------------------\r\n");
2443     conoll("Press:");
2444     conol("  C to return to ");
2445     conoll(*myhost ? myhost : "the C-Kermit prompt");
2446     for (i = 0; hlpmsg[i].hmsg; i++) {
2447         if (!(hlpmsg[i].hflags) || (hlpmsg[i].hflags == cxtype))
2448           conoll(hlpmsg[i].hmsg);
2449     }
2450     conol("Press a key>");              /* Prompt for command. */
2451     c = CONGKS() & 0177;                /* Get character, strip any parity. */
2452     /* No key mapping or translation here */
2453     if (c != CMDQ)
2454       conoll("");
2455     conoll("----------------------------------------------------");
2456     return(c);                          /* Return it. */
2457 }
2458
2459
2460 /*  D O E S C  --  Process an escape character argument  */
2461
2462 VOID
2463 #ifdef CK_ANSIC
2464 doesc(char c)
2465 #else
2466 doesc(c) char c;
2467 #endif /* CK_ANSIC */
2468 /* doesc */ {
2469     CHAR d;
2470
2471     debug(F101,"CONNECT doesc","",c);
2472     while (1) {
2473         if (c == escape) {              /* Send escape character */
2474             d = dopar((CHAR) c); ttoc((char) d); return;
2475         } else                          /* Or else look it up below. */
2476             if (isupper(c)) c = tolower(c);
2477
2478         switch(c) {
2479
2480           case 'c':                     /* Escape back to prompt */
2481           case '\03':
2482             cx_status = CSX_ESCAPE;
2483 #ifdef NOICP
2484             conoll("");
2485             conoll("");
2486             conoll(
2487 "  WARNING: This version of C-Kermit has no command processor to escape"
2488                    );
2489             conoll(
2490 "  back to.  To return to your local system, log out from the remote and/or"
2491                    );
2492             conoll(
2493 "  use the escape character followed by the letter U to close (hang Up) the"
2494                    );
2495             conoll(
2496 "  connection.  Resuming your session..."
2497                    );
2498             conoll("");
2499             return;
2500 #else
2501             active = 0; conol("\r\n"); return;
2502 #endif /* NOICP */
2503
2504           case 'b':                     /* Send a BREAK signal */
2505           case '\02':
2506 #ifdef CKLEARN
2507             learnchar(-7);
2508 #endif /* CKLEARN */
2509             ttsndb(); return;
2510
2511 #ifdef NETCONN
2512           case 'i':                     /* Send Interrupt */
2513           case '\011':
2514 #ifdef TCPSOCKET
2515             if (network && IS_TELNET()) { /* TELNET */
2516                 temp[0] = (CHAR) IAC;   /* I Am a Command */
2517                 temp[1] = (CHAR) TN_IP; /* Interrupt Process */
2518                 temp[2] = NUL;
2519                 ttol((CHAR *)temp,2);
2520             } else
2521 #endif /* TCPSOCKET */
2522               conoc(BEL);
2523             return;
2524
2525 #ifdef TCPSOCKET
2526           case 'a':                     /* "Are You There?" */
2527           case '\01':
2528             if (network && IS_TELNET()) {
2529                 temp[0] = (CHAR) IAC;   /* I Am a Command */
2530                 temp[1] = (CHAR) TN_AYT; /* Are You There? */
2531                 temp[2] = NUL;
2532                 ttol((CHAR *)temp,2);
2533             } else conoc(BEL);
2534             return;
2535 #endif /* TCPSOCKET */
2536 #endif /* NETCONN */
2537
2538 #ifdef CK_LBRK
2539           case 'l':                     /* Send a Long BREAK signal */
2540 #ifdef CKLEARN
2541             learnchar(-8);
2542 #endif /* CKLEARN */
2543             ttsndlb(); return;
2544 #endif /* CK_LBRK */
2545
2546           case 'u':                     /* Hangup */
2547        /* case '\010': */               /* No, too dangerous */
2548             cx_status = CSX_USERDISC;
2549             dohangup = 2; active = 0; conol("\r\nHanging up "); return;
2550
2551           case 'q':                     /* Quit */
2552             cx_status = CSX_USERDISC;
2553             dohangup = 2; quitnow = 1; active = 0; conol("\r\n"); return;
2554
2555           case 's':                     /* Status */
2556             conoll("");
2557             conoll("----------------------------------------------------");
2558 #ifdef PTYORPIPE
2559             if (ttpipe)
2560               ckmakmsg(temp,TMPLEN," Pipe: \"",ttname,"\"",NULL);
2561             else if (ttpty)
2562               ckmakmsg(temp,TMPLEN," Pty: \"",ttname,"\"",NULL);
2563             else
2564 #endif /* PTYORPIPE */
2565               ckmakmsg(temp,
2566                        TMPLEN,
2567                        " ",
2568                        (network ? "Host" : "Device"),
2569                        ": ",
2570                        ttname
2571                        );
2572             conoll(temp);
2573
2574             /* The following sprintf's are safe, temp[] size is at least 200 */
2575
2576             if (!network && speed >= 0L) {
2577                 sprintf(temp,"Speed %ld", speed);
2578                 conoll(temp);
2579             }
2580             sprintf(temp," Terminal echo: %s", duplex ? "local" : "remote");
2581             conoll(temp);
2582             sprintf(temp," Terminal bytesize: %d", (cmask == 0177) ? 7 : 8);
2583             conoll(temp);
2584             sprintf(temp," Command bytesize: %d", (cmdmsk == 0177) ? 7 : 8);
2585             conoll(temp);
2586             if (hwparity)
2587               sprintf(temp," Parity[hardware]: %s",parnam(hwparity));
2588             else            
2589               sprintf(temp," Parity: %s", parnam(parity));
2590             conoll(temp);
2591 #ifndef NOXFER
2592             sprintf(temp," Autodownload: %s", autodl ? "on" : "off");
2593             conoll(temp);
2594 #endif /* NOXFER */
2595             ckmakmsg(temp,              /* (would not be safe for sprintf) */
2596                      TMPLEN,
2597                      " Session log: ",
2598                      *sesfil ? sesfil : "(none)",
2599                      NULL,
2600                      NULL
2601                      );
2602             conoll(temp);
2603 #ifndef NOSHOW
2604             if (!network) shomdm();
2605 #endif /* NOSHOW */
2606 #ifdef CKLOGDIAL
2607             {
2608                 long z;
2609                 z = dologshow(0);
2610                 if (z > -1L) {
2611                     sprintf(temp," Elapsed time: %s",hhmmss(z));
2612                     conoll(temp);
2613                 }
2614             }
2615 #endif /* CKLOGDIAL */
2616             conoll("----------------------------------------------------");
2617             return;
2618
2619           case 'h':                     /* Help */
2620           case '?':                     /* Help */
2621             c = hconne(); continue;
2622
2623           case '0':                     /* Send a null */
2624             c = '\0'; d = dopar((CHAR) c); ttoc((char) d); return;
2625
2626           case 'z': case '\032':        /* Suspend */
2627 #ifndef NOPUSH
2628             if (!nopush)
2629               stptrap(0);
2630             else
2631               conoc(BEL);
2632 #else
2633             conoc(BEL);
2634 #endif /* NOPUSH */
2635             return;
2636
2637           case '@':                     /* Start inferior command processor */
2638           case '!':
2639 #ifndef NOPUSH
2640             if (!nopush) {
2641                 conres();                     /* Put console back to normal */
2642                 zshcmd("");                   /* Fork a shell. */
2643                 if (conbin((char)escape) < 0) {
2644                     cx_status = CSX_INTERNAL;
2645                     printf("Error resuming CONNECT session\n");
2646                     active = 0;
2647                 }
2648             } else conoc(BEL);
2649 #else
2650             conoc(BEL);
2651 #endif /* NOPUSH */
2652             return;
2653
2654           case SP:                      /* Space, ignore */
2655             return;
2656
2657           default:                      /* Other */
2658             if (c == CMDQ) {            /* Backslash escape */
2659                 int x;
2660                 ecbp = ecbuf;
2661                 *ecbp++ = c;
2662                 while (((c = (CONGKS() & cmdmsk)) != '\r') && (c != '\n'))
2663                   *ecbp++ = c;
2664                 *ecbp = NUL; ecbp = ecbuf;
2665                 x = xxesc(&ecbp);       /* Interpret it */
2666                 if (x >= 0) {           /* No key mapping here */
2667                     c = dopar((CHAR) x);
2668                     ttoc((char) c);
2669                     return;
2670                 } else {                /* Invalid backslash code. */
2671                     conoc(BEL);
2672                     return;
2673                 }
2674             }
2675             conoc(BEL); return;         /* Invalid esc arg, beep */
2676         }
2677     }
2678 }
2679 #endif /* NOLOCAL */