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

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