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