source: trunk/third/kermit/ckucon.c @ 20081

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