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