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
printon()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
printoff()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
chkaes(char c,int src)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
LOGCHAR(char c)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
ckcputf()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
ckcputc(c)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
ckcgetc(dummy)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 */
kbget()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
socketpair(int * pair)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
kbdread(void * param)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
learnchar(c)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
conect()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
hconne()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
doesc(char c)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 */
2721