3 char *connv = "CONNECT Command for UNIX:fork(), 9.0.117, 14 Jul 2011";
5 /* C K U C O N -- Terminal connection to remote system, for UNIX */
7 Author: Frank da Cruz <fdc@columbia.edu>,
8 Columbia University Academic Information Systems, New York City.
10 Copyright (C) 1985, 2011,
11 Trustees of Columbia University in the City of New York.
12 All rights reserved. See the C-Kermit COPYING.TXT file or the
13 copyright text in the ckcmai.c module for disclaimer and permissions.
15 NOTE: This module has been superseded on most platforms by ckucns.c, which
16 uses select() rather than fork() for multiplexing its i/o. This module
17 is still needed for platforms that do not support select(), and also for
18 its X.25 support. Although the two modules share large amounts of code,
19 their structure is radically different and therefore attempts at merging
20 them have so far been unsuccessful. (November 1998.)
22 Special thanks to Eduard Vopicka, Prague University of Economics,
23 Czech Republic, for valuable contributions to this module in July 1994,
24 and to Neal P. Murphy of the Motorola Cellular Infrastructure Group in 1996
25 for rearranging the code to allow operation on the BeBox, yet still work
28 #include "ckcdeb.h" /* Common things first */
33 static double time_started = 0.0;
34 #include <kernel/OS.h>
35 _PROTOTYP( static long concld, (void *) );
37 _PROTOTYP( static VOID concld, (void) );
38 #endif /* BEOSORBEBOX */
42 #include <sys/wait.h> /* For wait() */
45 #include <signal.h> /* Signals */
48 #include <errno.h> /* Error number symbols */
50 #ifndef ERRNO_INCLUDED
51 #include <errno.h> /* Error number symbols */
52 #endif /* ERRNO_INCLUDED */
53 #endif /* HPUXPRE65 */
55 #ifdef ZILOG /* Longjumps */
62 /* Kermit-specific includes */
64 #include "ckcasc.h" /* ASCII characters */
65 #include "ckcker.h" /* Kermit things */
66 #include "ckucmd.h" /* For xxesc() prototype */
67 #include "ckcnet.h" /* Network symbols */
69 #include "ckcxla.h" /* Character set translation */
72 /* Internal function prototypes */
74 _PROTOTYP( VOID ttflux, (void) );
75 _PROTOTYP( VOID doesc, (char) );
76 _PROTOTYP( VOID logchar, (char) );
77 _PROTOTYP( int hconne, (void) );
79 _PROTOTYP( VOID shomdm, (void) );
81 _PROTOTYP( static int kbget, (void) );
82 _PROTOTYP( static int pipemsg, (int) );
83 _PROTOTYP( static int ckcputf, (void) );
84 _PROTOTYP( static VOID ck_sndmsg, (void) );
86 For inter-fork signaling. Normally we use SIGUSR1, except on SCO, where
87 we use SIGUSR2 because SIGUSR1 is used by the system. You can define
88 CK_FORK_SIG to be whatever other signal you might want to use at compile
89 time. We don't use SIGUSR2 everywhere because in some systems, like
90 UnixWare, the default action for SIGUSR2 is to kill the process that gets it.
94 #ifndef SIGUSR1 /* User-defined signals */
103 #define CK_FORK_SIG SIGUSR2 /* SCO - use SIGUSR2 */
105 #define CK_FORK_SIG SIGUSR1 /* Others - use SIGUSR1 */
108 #endif /* CK_FORK_SIG */
110 /* External variables */
112 extern struct ck_p ptab[];
114 extern int local, escape, duplex, parity, flow, seslog, sessft, debses,
115 mdmtyp, ttnproto, cmask, cmdmsk, network, nettype, deblog, sosi, tnlm,
116 xitsta, what, ttyfd, ttpipe, quiet, backgrd, pflag, tt_crd, tt_lfd,
118 tt_escape, justone, carrier, hwparity;
121 extern char ttname[], sesfil[], myhost[], *ccntab[];
123 extern int tn_b_nlm, tn_rem_echo;
127 extern char * tt_trigger[], * triggerval;
128 #endif /* CK_TRIGGER */
133 extern int apcactive; /* Application Program Command (APC) */
134 extern int apcstatus; /* items ... */
135 static int apclength = 0;
139 extern char apcbuf[];
141 static int apcbuflen = APCBUFLEN - 2;
142 extern int protocol; /* Auto download */
148 #endif /* CK_AUTODL */
152 static int zmdlok = 1; /* Zmodem autodownloads available */
154 static int zmdlok = 0; /* Depends on external protocol def */
155 #endif /* XYZ_INTERNAL */
157 static int zmdlok = 0; /* Not available at all */
160 #ifndef NOSETKEY /* Keyboard mapping */
161 extern KEY *keymap; /* Single-character key map */
162 extern MACRO *macrotab; /* Key macro pointer table */
163 static MACRO kmptr = NULL; /* Pointer to current key macro */
164 #endif /* NOSETKEY */
166 /* Global variables local to this module */
169 quitnow = 0, /* <esc-char>Q was typed */
170 jbset = 0, /* Flag whether jmp buf is set. */
171 dohangup = 0, /* <esc-char>H was typed */
172 sjval, /* Setjump return value */
173 goterr = 0, /* Fork/pipe creation error flag */
174 inshift = 0, /* SO/SI shift states */
177 int active = 0; /* Lower fork active flag */
179 static PID_T parent_id = (PID_T)0; /* Process ID of keyboard fork */
181 static char ecbuf[10], *ecbp; /* Escape char buffer & pointer */
184 #define IBUFL 1536 /* Input buffer length */
187 #endif /* CK_SMALL */
189 static int obc = 0; /* Output buffer count */
192 #define OBUFL 1024 /* Output buffer length */
198 #define TMPLEN 4096 /* Temporary message buffer length */
201 #endif /* BIGBUFOK */
204 static char *ibuf = NULL, *obuf = NULL, *temp = NULL; /* Buffers */
206 static char ibuf[IBUFL], obuf[OBUFL], temp[TMPLEN];
210 static char *ibp; /* Input buffer pointer */
212 static char *ibp = ibuf; /* Input buffer pointer */
214 static int ibc = 0; /* Input buffer count */
217 static char *obp; /* Output buffer pointer */
219 static char *obp = obuf; /* Output buffer pointer */
225 static char *p; /* General purpose pointer */
226 char x25ibuf[MAXIX25]; /* Input buffer */
227 char x25obuf[MAXOX25]; /* Output buffer */
228 int ibufl; /* Length of input buffer */
229 int obufl; /* Length of output buffer */
230 unsigned char tosend = 0;
232 static int dox25clr = 0;
234 extern CHAR padparms[];
238 static int xpipe[2] = {-1, -1}; /* Pipe descriptor for child-parent messages */
239 static PID_T pid = (PID_T) 0; /* Process ID of child */
241 /* Character-set items */
243 static int unicode = 0;
245 static int escseq = 0; /* 1 = Recognizer is active */
246 int inesc = 0; /* State of sequence recognizer */
247 int oldesc = -1; /* Previous state of recognizer */
249 #define OUTXBUFSIZ 15
250 static CHAR inxbuf[OUTXBUFSIZ+1]; /* Host-to-screen expansion buffer */
251 static int inxcount = 0; /* and count */
252 static CHAR outxbuf[OUTXBUFSIZ+1]; /* Keyboard-to-host expansion buf */
253 static int outxcount = 0; /* and count */
256 #ifdef CK_ANSIC /* ANSI C prototypes... */
257 extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
258 extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
259 static CHAR (*sxo)(CHAR); /* Local translation functions */
260 static CHAR (*rxo)(CHAR); /* for output (sending) terminal chars */
261 static CHAR (*sxi)(CHAR); /* and for input (receiving) terminal chars. */
262 static CHAR (*rxi)(CHAR);
263 #else /* Not ANSI C... */
264 extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */
265 extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */
266 static CHAR (*sxo)(); /* Local translation functions */
267 static CHAR (*rxo)(); /* for output (sending) terminal chars */
268 static CHAR (*sxi)(); /* and for input (receiving) terminal chars. */
269 static CHAR (*rxi)();
270 #endif /* CK_ANSIC */
271 extern int language; /* Current language. */
272 static int langsv; /* For remembering language setting. */
273 extern struct csinfo fcsinfo[]; /* File character set info. */
274 extern int tcsr, tcsl; /* Terminal character sets, remote & local. */
275 static int tcs; /* Intermediate ("transfer") character set. */
276 static int tcssize = 0; /* Size of tcs */
277 #ifdef UNICODE /* UTF-8 support */
279 extern int (*xl_ufc[MAXFCSETS+1])(USHORT); /* Unicode to FCS */
280 extern USHORT (*xl_fcu[MAXFCSETS+1])(CHAR); /* FCS to Unicode */
281 extern int (*xuf)(USHORT); /* Translation function UCS to FCS */
282 extern USHORT (*xfu)(CHAR); /* Translation function FCS to UCS */
284 extern int (*xl_ufc[MAXFCSETS+1])();
285 extern USHORT (*xl_fcu[MAXFCSETS+1])();
287 extern USHORT (*xfu)();
288 #endif /* CK_ANSIC */
293 We do not need to parse and recognize escape sequences if we are being built
294 without character-set support AND without APC support.
296 #ifdef NOCSETS /* No character sets */
297 #ifndef CK_APC /* No APC */
299 #define NOESCSEQ /* So no escape sequence recognizer */
300 #endif /* NOESCSEQ */
304 /* Child process events and messages */
306 #define CEV_NO 0 /* No event */
307 #define CEV_HUP 1 /* Communications hangup */
308 #define CEV_PAD 2 /* X.25 - change PAD parameters */
309 #define CEV_DUP 3 /* Toggle duplex */
310 #define CEV_APC 4 /* Execute APC */
312 #define CEV_MEBIN 5 /* Change of me_binary */
313 #define CEV_UBIN 6 /* Change of u_binary */
315 #define CEV_ADL 7 /* Autodownload */
316 #define CEV_AUL 8 /* Autoupload */
317 #define CEV_TRI 9 /* Trigger string */
323 As of edit 178, the CONNECT command skips past ANSI escape sequences to
324 avoid translating the characters within them. This allows the CONNECT
325 command to work correctly with a host that uses a 7-bit ISO 646 national
326 character set, in which characters like '[' would normally be translated
327 into accented characters, ruining the terminal's interpretation (and
328 generation) of escape sequences.
330 As of edit 190, the CONNECT command responds to APC escape sequences
331 (ESC _ text ESC \) if the user SETs TERMINAL APC ON or UNCHECKED, and the
332 program was built with CK_APC defined.
334 Non-ANSI/ISO-compliant escape sequences are not handled.
337 /* States for the escape-sequence recognizer. */
339 #define ES_NORMAL 0 /* Normal, not in an escape sequence */
340 #define ES_GOTESC 1 /* Current character is ESC */
341 #define ES_ESCSEQ 2 /* Inside an escape sequence */
342 #define ES_GOTCSI 3 /* Inside a control sequence */
343 #define ES_STRING 4 /* Inside DCS,OSC,PM, or APC string */
344 #define ES_TERMIN 5 /* 1st char of string terminator */
347 ANSI escape sequence handling. Only the 7-bit form is treated, because
348 translation is not a problem in the 8-bit environment, in which all GL
349 characters are ASCII and no translation takes place. So we don't check
350 for the 8-bit single-character versions of CSI, DCS, OSC, APC, or ST.
351 Here is the ANSI sequence recognizer state table, followed by the code
355 CAN = Cancel 01/08 Ctrl-X
356 SUB = Substitute 01/10 Ctrl-Z
357 DCS = Device Control Sequence 01/11 05/00 ESC P
358 CSI = Control Sequence Introducer 01/11 05/11 ESC [
359 ST = String Terminator 01/11 05/12 ESC \
360 OSC = Operating System Command 01/11 05/13 ESC ]
361 PM = Privacy Message 01/11 05/14 ESC ^
362 APC = Application Program Command 01/11 05/15 ESC _
364 ANSI escape sequence recognizer:
366 State Input New State ; Commentary
368 NORMAL (start) ; Start in NORMAL state
370 (any) CAN NORMAL ; ^X cancels
371 (any) SUB NORMAL ; ^Z cancels
373 NORMAL ESC GOTESC ; Begin escape sequence
374 NORMAL other ; NORMAL control or graphic character
376 GOTESC ESC ; Start again
377 GOTESC [ GOTCSI ; CSI
378 GOTESC P STRING ; DCS introducer, consume through ST
379 GOTESC ] STRING ; OSC introducer, consume through ST
380 GOTESC ^ STRING ; PM introducer, consume through ST
381 GOTESC _ STRING ; APC introducer, consume through ST
382 GOTESC 0..~ NORMAL ; 03/00 through 17/14 = Final character
383 GOTESC other ESCSEQ ; Intermediate or ignored control character
385 ESCSEQ ESC GOTESC ; Start again
386 ESCSEQ 0..~ NORMAL ; 03/00 through 17/14 = Final character
387 ESCSEQ other ; Intermediate or ignored control character
389 GOTCSI ESC GOTESC ; Start again
390 GOTCSI @..~ NORMAL ; 04/00 through 17/14 = Final character
391 GOTCSI other ; Intermediate char or ignored control char
393 STRING ESC TERMIN ; Maybe have ST
394 STRING other ; Consume all else
396 TERMIN \ NORMAL ; End of string
397 TERMIN other STRING ; Still in string
400 chkaes() -- Check ANSI Escape Sequence.
401 Call with EACH character in input stream.
402 Sets global inesc variable according to escape sequence state.
403 Returns 0 normally, 1 if an APC sequence is to be executed.
410 #endif /* CK_ANSIC */
413 oldesc = inesc; /* Remember previous state */
414 if (c == CAN || c == SUB) /* CAN and SUB cancel any sequence */
417 switch (inesc) { /* enter state switcher */
419 case ES_NORMAL: /* NORMAL state */
420 if (c == ESC) /* Got an ESC */
421 inesc = ES_GOTESC; /* Change state to GOTESC */
422 break; /* Otherwise stay in NORMAL state */
424 case ES_GOTESC: /* GOTESC state */
425 if (c == '[') /* Left bracket after ESC is CSI */
426 inesc = ES_GOTCSI; /* Change to GOTCSI state */
427 else if (c == 'P' || (c > 0134 && c < 0140)) { /* P, [, ^, or _ */
428 inesc = ES_STRING; /* Switch to STRING-absorption state */
430 if (c == '_' && pid == 0 && /* APC handled in child only */
431 (apcstatus & APC_ON)) { /* and only if not disabled. */
432 debug(F100,"CONNECT APC begin","",0);
433 apcactive = APC_REMOTE; /* Set APC-Active flag */
434 apclength = 0; /* and reset APC buffer pointer */
437 } else if (c > 057 && c < 0177) /* Final character '0' thru '~' */
438 inesc = ES_NORMAL; /* Back to normal */
439 else if (c != ESC) /* ESC in an escape sequence... */
440 inesc = ES_ESCSEQ; /* starts a new escape sequence */
441 break; /* Intermediate or ignored ctrl char */
443 case ES_ESCSEQ: /* ESCSEQ -- in an escape sequence */
444 if (c > 057 && c < 0177) /* Final character '0' thru '~' */
445 inesc = ES_NORMAL; /* Return to NORMAL state. */
446 else if (c == ESC) /* ESC ... */
447 inesc = ES_GOTESC; /* starts a new escape sequence */
448 break; /* Intermediate or ignored ctrl char */
450 case ES_GOTCSI: /* GOTCSI -- In a control sequence */
451 if (c > 077 && c < 0177) /* Final character '@' thru '~' */
452 inesc = ES_NORMAL; /* Return to NORMAL. */
453 else if (c == ESC) /* ESC ... */
454 inesc = ES_GOTESC; /* starts over. */
455 break; /* Intermediate or ignored ctrl char */
457 case ES_STRING: /* Inside a string */
458 if (c == ESC) /* ESC may be 1st char of terminator */
459 inesc = ES_TERMIN; /* Go see. */
461 else if (apcactive && (apclength < apcbuflen)) /* If in APC, */
462 apcbuf[apclength++] = c; /* deposit this character. */
463 else { /* Buffer overrun */
464 apcactive = 0; /* Discard what we got */
465 apclength = 0; /* and go back to normal */
466 apcbuf[0] = 0; /* Not pretty, but what else */
467 inesc = ES_NORMAL; /* can we do? (ST might not come) */
470 break; /* Absorb all other characters. */
472 case ES_TERMIN: /* May have a string terminator */
473 if (c == '\\') { /* which must be backslash */
474 inesc = ES_NORMAL; /* If so, back to NORMAL */
476 if (apcactive) { /* If it was an APC string, */
477 debug(F101,"CONNECT APC terminated","",c);
478 apcbuf[apclength] = NUL; /* terminate it and then ... */
482 } else { /* Otherwise */
483 inesc = ES_STRING; /* Back to string absorption. */
485 if (apcactive && (apclength+1 < apcbuflen)) { /* In APC string */
486 apcbuf[apclength++] = ESC; /* deposit the Esc character */
487 apcbuf[apclength++] = c; /* and this character too */
494 #endif /* NOESCSEQ */
496 /* Connect state parent/child communication signal handlers */
498 /* Routines used by the child process */
501 pipemsg(n) int n; { /* Send message ID to parent */
503 return(write(xpipe[1], &code, sizeof(code)));
506 /* Environment pointer for CK_FORK_SIG signal handling in child... */
509 static sigjmp_buf sig_env;
511 static jmp_buf sig_env;
512 #endif /* CK_POSIX_SIG */
514 static SIGTYP /* CK_FORK_SIG handling in child ... */
515 forkint(foo) int foo; {
516 /* It is important to disable CK_FORK_SIG before longjmp */
517 signal(CK_FORK_SIG, SIG_IGN); /* Set to ignore CK_FORK_SIG */
518 debug(F100,"CONNECT forkint - CK_FORK_SIG", "", 0);
519 /* Force return from ck_sndmsg() */
520 cklongjmp(sig_env, 1);
525 ck_sndmsg() { /* Executed by child only ... */
526 debug(F100,"CONNECT ck_sndmsg, active", "", active);
532 #endif /* CK_POSIX_SIG */
534 debug(F100,"CONNECT ck_sndmsg signaling parent","",0);
535 signal(CK_FORK_SIG, forkint); /* Set up signal handler */
536 kill(parent_id, CK_FORK_SIG); /* Kick the parent */
537 debug(F100,"ck_sndmsg pausing","",0);
538 for (;;) pause(); /* Wait for CK_FORK_SIG or SIGKILL */
541 /* We come here from forkint() via [sig]cklongjmp(sig_env,1) */
542 debug(F100,"CONNECT ck_sndmsg is parent - returning", "", 0);
545 /* Routines used by the parent process */
547 #ifdef CK_POSIX_SIG /* Environment pointer for CONNECT errors */
548 static sigjmp_buf con_env;
550 static jmp_buf con_env;
551 #endif /* CK_POSIX_SIG */
553 pipeint() handles CK_FORK_SIG signals from the lower (port) fork.
554 It reads a function code from the pipe that connects the two forks,
555 then reads additional data from the pipe, then handles it.
558 pipeint(arg) int arg; { /* Dummy argument */
559 int code, cx, x, i /* , n */ ;
562 extern ckjmpbuf cmjbuf;
563 #endif /* NOCCTRAP */
565 IMPORTANT: At this point, the child fork is waiting for CK_FORK_SIG
566 (eventually for SIGKILL) inside of ck_sndmsg(). So we can't get any
567 subsequent CK_FORK_SIG from child before we send it CK_FORK_SIG.
569 signal(CK_FORK_SIG, SIG_IGN); /* Ignore CK_FORK_SIG now */
570 debug(F101,"CONNECT pipeint arg","",arg);
572 read(xpipe[0], &code, sizeof(code)); /* Get function code from pipe */
573 debug(F101,"CONNECT pipeint code","",code);
574 cx = code & 255; /* 8-bit version of function code */
580 #endif /* NOCCTRAP */
582 Read info passed back up to us by the lower fork, depending on the function
583 requested. The same number of items must be read from the pipe in the same
584 order as the lower fork put them there. Trying to read something that's not
585 there makes the program hang uninterruptibly. Pay close attention -- notice
586 how we fall through some of the cases rather than break; that's deliberate.
590 case CEV_TRI: /* Trigger string */
591 debug(F100,"CONNECT trigger","",0);
592 read(xpipe[0], (char *)&i, sizeof(i)); /* Trigger index */
593 debug(F101,"CONNECT trigger index","",i);
594 makestr(&triggerval,tt_trigger[i]); /* Make a copy of the trigger */
595 debug(F110,"CONNECT triggerval",triggerval,0);
596 read(xpipe[0], (char *)&ibc, sizeof(ibc)); /* Copy child's */
597 debug(F101,"CONNECT trigger ibc (upper)","",ibc); /* input buffer. */
599 read(xpipe[0], (char *)&ibp, sizeof(ibp));
600 read(xpipe[0], ibp, ibc);
604 #endif /* CK_TRIGGER */
608 The CEV_HUP case is executed when the other side has hung up on us.
609 In some cases, this happens before we have had a chance to execute the
610 setjmp(con_env,1) call, and in that case we'd better not take the longjmp!
611 A good example is when you TELNET to port 13 on the local host; it prints
612 its asctime() string (26 chars) and then closes the connection.
616 sjval = CEV_TRI; /* Set global variable. */
618 #endif /* CK_TRIGGER */
620 if (jbset) { /* jmp_buf is initialized */
621 cklongjmp(con_env,sjval); /* so do the right thing. */
625 /* jmp_buf not init'd yet a close approximation... */
628 #endif /* CK_TRIGGER */
629 ttclos(0); /* Close our end of the connection */
631 debug(F101,"CONNECT trigger killing pid","",pid);
635 x = kill(pid,SIGKILLTHR); /* Kill lower fork */
636 wait_for_thread (pid, &ret_val);
640 x = kill(pid, SIGKILL); /* (should always use this really) */
642 x = kill(pid,9); /* Kill lower fork (history) */
644 wait((WAIT_T *)0); /* Wait till gone. */
646 printf("ERROR: Failure to kill pid %ld: %s, errno=%d\n",
647 (long) pid, ck_errstr(), errno);
648 debug(F111,"CONNECT error killing stale pid",
652 #endif /* BEOSORBEBOX */
654 conres(); /* Reset the console. */
656 printf("\r\n(Back at %s)\r\n",
665 what = W_NOTHING; /* So console modes are set right. */
666 printf("\r\n"); /* prevent prompt-stomping */
667 cklongjmp(cmjbuf,0); /* Do what the Ctrl-C handler does */
669 printf("\r\nLongjump failure - fatal\r\n");
670 doexit(GOOD_EXIT,-1); /* Better than dumping core... */
671 #endif /* USECCJMPBUF */
675 #endif /* USECCJMPBUF */
677 case CEV_DUP: /* Child sends duplex change */
678 read(xpipe[0], (char *)&duplex, sizeof(duplex));
679 debug(F101,"CONNECT pipeint duplex","",duplex);
682 case CEV_MEBIN: /* Child sends me_binary change */
684 (char *)&TELOPT_ME(TELOPT_BINARY),
685 sizeof(TELOPT_ME(TELOPT_BINARY))
687 debug(F101,"CONNECT pipeint me_binary","",TELOPT_ME(TELOPT_BINARY));
689 case CEV_UBIN: /* Child sends u_binary change */
691 (char *)&TELOPT_U(TELOPT_BINARY),
692 sizeof(TELOPT_U(TELOPT_BINARY))
694 debug(F101,"CONNECT pipeint u_binary","",TELOPT_U(TELOPT_BINARY));
699 case CEV_AUL: /* Autoupload */
701 debug(F100,"CONNECT autoupload at parent","",0);
703 case CEV_ADL: /* Autodownload */
704 apcactive = APC_LOCAL;
705 if (!justone) debug(F100,"CONNECT autodownload at parent","",0);
706 /* Copy child's Kermit packet if any */
707 read(xpipe[0], (char *)&x, sizeof(x));
708 debug(F101,"CONNECT trigger ibc (upper)","",ibc);
710 read(xpipe[0], (char *)ksbuf, x+1);
711 #endif /* CK_AUTODL */
712 case CEV_APC: /* Application Program Command */
713 read(xpipe[0], (char *)&apclength, sizeof(apclength));
714 read(xpipe[0], apcbuf, apclength+1); /* Include trailing zero byte */
715 debug(F111,"CONNECT APC at parent",apcbuf,apclength);
716 read(xpipe[0], (char *)&ibc, sizeof(ibc)); /* Copy child's */
717 if (ibc > 0) { /* input buffer. */
718 read(xpipe[0], (char *)&ibp, sizeof(ibp));
719 read(xpipe[0], ibp, ibc);
721 obc = 0; obp = obuf; *obuf = NUL; /* Because port fork flushed */
723 cklongjmp(con_env,sjval);
728 case CEV_PAD: /* X.25 PAD parameter change */
729 debug(F100,"CONNECT pipeint PAD change","",0);
730 read(xpipe[0],padparms,MAXPADPARMS);
731 sjval = CEV_PAD; /* Set global variable. */
732 #ifdef COMMENT /* We might not need to do this... */
733 cklongjmp(con_env,sjval);
740 signal(CK_FORK_SIG, pipeint); /* Set up signal handler */
741 kill(pid, CK_FORK_SIG); /* Signal the port fork ... */
744 /* C K C P U T C -- C-Kermit CONNECT Put Character to Screen */
746 Output is buffered to avoid slow screen writes on fast connections.
747 NOTE: These could (easily?) become macros ...
750 ckcputf() { /* Dump the output buffer */
752 if (obc > 0) /* If we have any characters, */
753 x = conxo(obc,obuf); /* dump them, */
754 obp = obuf; /* reset the pointer */
755 obc = 0; /* and the counter. */
756 return(x); /* Return conxo's return code */
763 *obp++ = c & 0xff; /* Deposit the character */
764 obc++; /* Count it */
765 if (ibc == 0 || /* If input buffer about empty */
766 obc == OBUFL) { /* or output buffer full */
767 debug(F101,"CONNECT CKCPUTC obc","",obc);
768 x = conxo(obc,obuf); /* dump the buffer, */
769 obp = obuf; /* reset the pointer */
770 obc = 0; /* and the counter. */
771 return(x); /* Return conxo's return code */
775 /* C K C G E T C -- C-Kermit CONNECT Get Character */
777 Buffered read from communication device.
778 Returns the next character, refilling the buffer if necessary.
779 On error, returns ttinc's return code (see ttinc() description).
780 Dummy argument for compatible calling conventions with ttinc().
781 NOTE: We don't have a macro for this because we have to pass
782 a pointer to this function as an argument to tn_doop().
785 ckcgetc(dummy) int dummy; {
788 extern int ssl_active_flag, tls_active_flag;
792 /* No buffering for possibly encrypted connections */
793 if (network && IS_TELNET() && TELOPT_ME(TELOPT_AUTHENTICATION))
795 #endif /* CK_ENCRYPTION */
797 if (ssl_active_flag || tls_active_flag)
802 debug(F101,"CONNECT CKCGETC 1 ibc","",ibc); /* Log */
804 if (ibc < 1) { /* Need to refill buffer? */
805 ibc = 0; /* Yes, reset count */
806 ibp = ibuf; /* and buffer pointer */
807 /* debug(F100,"CONNECT CKCGETC 1 calling ttinc(0)","",0); */
810 This check is not worth the overhead. Scenario: ttchk() returns 0, so we
811 fall through to the blocking ttinc(). While in ttinc(), the connection is
812 lost. But the read() that ttinc() calls does not notice, and never returns.
813 This happens at least in HP-UX, and can be seen when we turn off the modem.
815 if (!network && (carrier != CAR_OFF))
816 if ((n = ttchk()) < 0) /* Make sure connection is not lost */
819 c = ttinc(0); /* Read one character, blocking */
820 /* debug(F101,"CONNECT CKCGETC 1 ttinc(0)","",c); */
821 if (c < 0) { /* If error, return error code */
823 } else { /* Otherwise, got one character */
824 *ibp++ = c; /* Advance buffer pointer */
825 ibc++; /* and count. */
827 if ((n = ttchk()) > 0) { /* Any more waiting? */
828 if (n > (IBUFL - ibc)) /* Get them all at once. */
829 n = IBUFL - ibc; /* Don't overflow buffer */
830 if ((n = ttxin(n,(CHAR *)ibp)) > 0) {
832 if (TELOPT_U(TELOPT_ENCRYPTION))
833 ck_tn_decrypt(ibp,n);
834 #endif /* CK_ENCRYPTION */
835 ibc += n; /* Advance counter */
837 } else if (n < 0) { /* Error? */
838 return(n); /* Return the error code */
840 debug(F101,"CONNECT CKCGETC 2 ibc","",ibc); /* Log how many */
841 ibp = ibuf; /* Point to beginning of buffer */
843 c = *ibp++ & 0xff; /* Get next character from buffer */
844 ibc--; /* Reduce buffer count */
845 return(c); /* Return the character */
849 Keyboard handling, buffered for speed, which is needed when C-Kermit is
850 in CONNECT mode between two other computers that are transferring data.
852 static char *kbp; /* Keyboard input buffer pointer */
853 static int kbc; /* Keyboard input buffer count */
855 #ifdef CK_SMALL /* Keyboard input buffer length */
856 #define KBUFL 32 /* Small for PDP-11 UNIX */
858 #define KBUFL 257 /* Regular kernel size for others */
859 #endif /* CK_SMALL */
862 static char *kbuf = NULL;
864 static char kbuf[KBUFL];
867 /* Macro for reading keystrokes. */
869 #define CONGKS() (((--kbc)>=0) ? ((int)(*kbp++) & 0377) : kbget())
872 Note that we call read() directly here, normally a no-no, but in this case
873 we know it's UNIX and we're only doing what coninc(0) would have done,
874 except we're reading a block of characters rather than just one. There is,
875 at present, no conxin() analog to ttxin() for chunk reads, and instituting
876 one would only add function-call overhead as it would only be a wrapper for
877 a read() call anyway.
880 Another note: We stick in this read() till the user types something.
881 But the other (lower) fork is running too, and on TELNET connections,
882 it will signal us to indicate echo-change negotiations, and this can
883 interrupt the read(). Some UNIXes automatically restart the interrupted
884 system call, others return from it with errno == EINTR.
886 static int /* Keyboard buffer filler */
889 int tries = 10; /* If read() is interrupted, */
891 while (tries-- > 0) { /* try a few times... */
893 if ((kbc = conchk()) < 1) /* How many chars waiting? */
894 kbc = 1; /* If none or dunno, wait for one. */
895 else if (kbc > KBUFL) /* If too many, */
896 kbc = KBUFL; /* only read this many. */
897 if ((kbc = read(0, kbuf, kbc)) < 1) { /* Now read it/them. */
898 debug(F101,"CONNECT kbget errno","",errno); /* Got an error. */
900 if (errno == EINTR) /* Interrupted system call. */
901 continue; /* Try again, up to limit. */
902 else /* Something else. */
904 return(-1); /* Pass along read() error. */
907 else { ok = 1; break; }
911 kbp = kbuf; /* Adjust buffer pointer, */
913 return((int)(*kbp++) & 0377); /* and return first character. */
916 /* C O N C L D -- Interactive terminal connection child function */
923 #endif /* BEOSORBEBOX */
927 #endif /* BEOSORBEBOX */
929 int n; /* General purpose counter */
930 int i; /* For loops... */
931 int c = -1; /* c is a character, but must be signed
932 integer to pass thru -1, which is the
933 modem disconnection signal, and is
934 different from the character 0377 */
937 int tx; /* tn_doop() return code */
940 int ix; /* Trigger index */
941 #endif /* CK_TRIGGER */
944 #endif /* NOESCSEQ */
947 int conret = 0; /* Return value from conect() */
950 jbset = 0; /* jmp_buf not set yet, don't use it */
951 debug(F101,"CONNECT concld entry","",CK_FORK_SIG);
952 /* *** */ /* Inferior reads, prints port input */
954 if (priv_can()) { /* Cancel all privs */
955 printf("?setuid error - fatal\n");
958 signal(SIGINT, SIG_IGN); /* In case these haven't been */
959 signal(SIGQUIT, SIG_IGN); /* inherited from above... */
960 signal(CK_FORK_SIG, SIG_IGN); /* CK_FORK_SIG not expected yet */
962 inshift = outshift = 0; /* Initial SO/SI shift state. */
963 { /* Wait for parent's setup */
965 while ((i = read(xpipe[0], &c, 1)) <= 0) {
967 debug(F101,"CONNECT concld setup error","",i);
968 debug(F111,"CONNECT concld setup error",ck_errstr(),errno);
969 pipemsg(CEV_HUP); /* Read error - hangup */
970 ck_sndmsg(); /* Send and wait to be killed */
972 } /* Restart interrupted read() */
975 close(xpipe[0]); xpipe[0] = -1; /* Child - prevent future reads */
978 debug(F100,"CONNECT starting port fork","",0);
979 debug(F101,"CONNECT port fork ibc","",ibc);
980 debug(F101,"CONNECT port fork obc","",obc);
985 while (1) { /* Fresh read, wait for a character. */
987 if (network && (nettype == NET_SX25)) {
988 bzero(x25ibuf,sizeof(x25ibuf)) ;
989 if ((ibufl = ttxin(MAXIX25,(CHAR *)x25ibuf)) < 0) {
991 if (ibufl == -2) { /* PAD parms changes */
993 write(xpipe[1],padparms,MAXPADPARMS);
998 printf("\r\nCommunications disconnect ");
1001 ck_sndmsg(); /* Wait to be killed */
1006 /* pause(); <--- SHOULD BE OBSOLETE NOW! */
1007 /* BECAUSE pause() is done inside of ck_sndmsg() */
1009 if (debses) { /* Debugging output */
1011 while (ibufl--) { c = *p++; conol(dbchr(c)); }
1013 if (seslog && sessft) /* Binary session log */
1014 logchar((char)c); /* Log char before translation */
1019 #endif /* NOCSETS */
1020 ) { /* Character at a time */
1021 for (i = 1; i < ibufl; i++) {
1022 c = x25ibuf[i] & cmask;
1023 if (sosi) { /* Handle SI/SO */
1027 } else if (c == SI) {
1035 if (inesc == ES_NORMAL) {
1038 if (unicode == 1) { /* Remote is UTF-8 */
1039 x = u_to_b((CHAR)c);
1042 else if (x == -2) { /* LS or PS */
1047 inxbuf[0] = (unsigned)(x & 0xff);
1050 } else if (unicode == 2) { /* Local is UTF-8 */
1052 b_to_u((CHAR)c,inxbuf,OUTXBUFSIZ,tcssize);
1055 #endif /* UNICODE */
1056 if (sxi) c = (*sxi)((CHAR)c);
1057 if (rxi) c = (*rxi)((CHAR)c);
1061 #endif /* UNICODE */
1063 #endif /* NOCSETS */
1064 c &= cmdmsk; /* Apply command mask. */
1065 conoc(c); /* Output to screen */
1066 if (seslog && !sessft) /* and session log */
1069 } else { /* All at once */
1070 for (i = 1; i < ibufl; i++)
1071 x25ibuf[i] &= (cmask & cmdmsk);
1072 conxo(ibufl,x25ibuf);
1073 if (seslog) zsoutx(ZSFILE,x25ibuf,ibufl);
1078 } else { /* Not X.25... */
1081 Get the next communication line character from our internal buffer.
1082 If the buffer is empty, refill it.
1084 prev = c; /* Remember previous character */
1085 c = ckcgetc(0); /* Get next character */
1086 /* debug(F101,"CONNECT c","",c); */
1087 if (c < 0) { /* Failed... */
1088 debug(F101,"CONNECT disconnect ibc","",ibc);
1089 debug(F101,"CONNECT disconnect obc","",obc);
1090 ckcputf(); /* Flush CONNECT output buffer */
1092 printf("\r\nCommunications disconnect ");
1096 /* This happens on Ultrix if there's no carrier */
1100 /* This happens on UTEK if there's no carrier */
1101 && errno != EWOULDBLOCK
1104 perror("\r\nCan't read character");
1105 #endif /* COMMENT */
1109 #endif /* NOSETBUF */
1110 tthang(); /* Hang up the connection */
1111 debug(F111,"CONNECT concld i/o error",ck_errstr(),errno);
1113 ck_sndmsg(); /* Wait to be killed */
1117 debug(F101,"CONNECT ** PORT","",c); /* Got character c OK. */
1118 #endif /* COMMENT */
1120 /* Handle TELNET negotiations... */
1122 if ((c == NUL) && network && IS_TELNET()) {
1123 if (prev == CR) /* Discard <NUL> of <CR><NUL> */
1124 if (!TELOPT_U(TELOPT_BINARY))
1127 if ((c == IAC) && network && IS_TELNET()) {
1128 int me_bin = TELOPT_ME(TELOPT_BINARY);
1129 int u_bin = TELOPT_U(TELOPT_BINARY);
1130 debug(F100,"CONNECT got IAC","",0);
1131 ckcputf(); /* Dump screen-output buffer */
1132 if ((tx = tn_doop((CHAR)(c & 0xff),duplex,ckcgetc)) == 0) {
1133 if (me_bin != TELOPT_ME(TELOPT_BINARY)) {
1135 "CONNECT TELNET me_bin",
1137 TELOPT_ME(TELOPT_BINARY)
1139 pipemsg(CEV_MEBIN); /* Tell parent */
1141 &TELOPT_ME(TELOPT_BINARY),
1142 sizeof(TELOPT_ME(TELOPT_BINARY))
1144 ck_sndmsg(); /* Tell the parent fork */
1145 } else if (u_bin != TELOPT_U(TELOPT_BINARY)) {
1147 "CONNECT TELNET u_bin",
1149 TELOPT_U(TELOPT_BINARY)
1151 pipemsg(CEV_UBIN); /* Tell parent */
1153 &TELOPT_U(TELOPT_BINARY),
1154 sizeof(TELOPT_U(TELOPT_BINARY))
1156 ck_sndmsg(); /* Tell the parent fork */
1159 } else if (tx == -1) { /* I/O error */
1161 printf("\r\nCommunications disconnect ");
1164 #endif /* NOSETBUF */
1166 debug(F111,"CONNECT concld i/o error 2",ck_errstr(),errno);
1168 ck_sndmsg(); /* Wait to be killed */
1170 } else if (tx == -3) { /* I/O error */
1172 printf("\r\nConnection closed due to telnet policy ");
1175 #endif /* NOSETBUF */
1177 debug(F111,"CONNECT concld i/o error 2",ck_errstr(),errno);
1179 ck_sndmsg(); /* Wait to be killed */
1181 } else if (tx == -2) { /* I/O error */
1183 printf("\r\nConnection closed by peer ");
1186 #endif /* NOSETBUF */
1188 debug(F111,"CONNECT concld i/o error 2",ck_errstr(),errno);
1190 ck_sndmsg(); /* Wait to be killed */
1192 } else if ((tx == 1) && (!duplex)) { /* ECHO change */
1193 duplex = 1; /* Turn on local echo */
1194 debug(F101,"CONNECT TELNET duplex change","",duplex);
1195 pipemsg(CEV_DUP); /* Tell parent */
1196 write(xpipe[1], &duplex, sizeof(duplex));
1197 ck_sndmsg(); /* Tell the parent fork */
1199 } else if ((tx == 2) && (duplex)) { /* ECHO change */
1201 debug(F101,"CONNECT TELNET duplex change","",duplex);
1203 write(xpipe[1], &duplex, sizeof(duplex));
1206 } else if (tx == 3) { /* Quoted IAC */
1207 c = parity ? 127 : 255;
1210 else if (tx == 4) { /* IKS State Change */
1211 if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
1214 /* here we need to print a msg that the other */
1215 /* side is in SERVER mode and that REMOTE */
1216 /* commands should be used. And CONNECT mode */
1217 /* should be ended. */
1221 #endif /* IKS_OPTION */
1223 /* DO LOGOUT received */
1225 printf("\r\nRemote Logout ");
1228 #endif /* NOSETBUF */
1229 debug(F100,"CONNECT Remote Logout","",0);
1231 ck_sndmsg(); /* Wait to be killed */
1234 continue; /* Negotiation OK, get next char. */
1239 if (TELOPT_ME(TELOPT_ECHO) && tn_rem_echo)
1240 ttoc(c); /* I'm echoing for the remote */
1243 if (debses) { /* Output character to screen */
1244 char *s; /* Debugging display... */
1248 } else { /* Regular display ... */
1249 c &= cmask; /* Apply Kermit-to-remote mask */
1252 Autodownload. Check for Kermit S packet prior to translation, since that
1253 can change the packet and make it unrecognizable (as when the terminal
1254 character set is an ISO 646 one)... Ditto for Zmodem start packet.
1256 if (autodl /* Autodownload enabled? */
1258 || TELOPT_SB(TELOPT_KERMIT).kermit.me_start
1259 #endif /* IKS_OPTION */
1262 k = kstart((CHAR)c); /* Kermit S or I packet? */
1264 if (!k && zmdlok) /* Or an "sz" start? */
1265 k = zstart((CHAR)c);
1269 debug(F101,"CONNECT autodownload k","",k);
1270 if (k < 0) { /* Minus-Protocol? */
1272 goto noserver; /* Need server mode for this */
1274 ksign = 1; /* Remember */
1275 k = 0 - k; /* Convert to actual protocol */
1276 justone = 1; /* Flag for protocol module */
1277 #endif /* NOSERVER */
1280 k--; /* Adjust [kz]start's return value */
1287 /* Now damage the packet so that it does not */
1288 /* trigger autodownload detection on subsquent */
1292 int i, len = strlen((char*)ksbuf);
1293 for (i = 0; i < len; i++)
1299 for (i = 0; i < 3; i++)
1304 pipemsg(justone ? CEV_AUL : CEV_ADL);
1306 Send our memory back up to the top fork thru the pipe.
1307 CAREFUL -- Write this stuff in the same order it is to be read!
1309 /* Copy our Kermit packet to the parent fork */
1310 n = (int) strlen((char *)ksbuf);
1311 write(xpipe[1], (char *)&n, sizeof(n));
1313 write(xpipe[1], (char *)ksbuf, n+1);
1314 debug(F111,"CONNECT autodownload ksbuf",ksbuf,n);
1315 debug(F101,"CONNECT autodownload justone","",
1317 /* Construct the APC command */
1319 "set proto %s, %s, set proto %s",
1321 ksign ? "server" : "receive",
1322 ptab[protocol].p_name
1324 apclength = strlen(apcbuf);
1325 debug(F111,"CONNECT ksbuf",ksbuf,k);
1326 debug(F110,"CONNECT autodownload",apcbuf,0);
1327 apcactive = APC_LOCAL;
1328 ckcputf(); /* Force screen update */
1330 /* Write buffer including trailing NUL byte */
1331 debug(F101,"CONNECT write xpipe apclength","",
1337 debug(F110,"CONNECT write xpipe apcbuf",apcbuf,0);
1338 write(xpipe[1], apcbuf, apclength+1);
1340 /* Copy our input buffer to the parent fork */
1342 debug(F101,"CONNECT autodownload complete ibc",
1344 debug(F101,"CONNECT autodownload complete obc",
1346 write(xpipe[1], (char *)&ibc, sizeof(ibc));
1348 write(xpipe[1], (char *)&ibp, sizeof(ibp));
1349 write(xpipe[1], ibp, ibc);
1351 ck_sndmsg(); /* Wait to be killed */
1358 #endif /* NOSERVER */
1359 #endif /* CK_AUTODL */
1360 if (sosi) { /* Handle SI/SO */
1361 if (c == SO) { /* Shift Out */
1364 } else if (c == SI) { /* Shift In */
1368 if (inshift) c |= 0200;
1370 inxbuf[0] = c; /* In case there is no translation */
1371 inxcount = 1; /* ... */
1373 if (inesc == ES_NORMAL) { /* If not in an escape sequence */
1375 int x; /* Translate character sets */
1378 if (unicode == 1) { /* Remote is UTF-8 */
1382 inxbuf[0] = (unsigned)(x & 0xff);
1384 } else if (unicode == 2) { /* Local is UTF-8 */
1385 inxcount = b_to_u(ch,inxbuf,OUTXBUFSIZ,tcssize);
1388 #endif /* UNICODE */
1389 if (sxi) c = (*sxi)((CHAR)c);
1390 if (rxi) c = (*rxi)((CHAR)c);
1394 #endif /* UNICODE */
1396 #endif /* NOCSETS */
1399 if (escseq) /* If handling escape sequences */
1400 apcrc = chkaes((char)c); /* update our state */
1403 If we are handling APCs, we have several possibilities at this point:
1404 1. Ordinary character to be written to the screen.
1405 2. An Esc; we can't write it because it might be the beginning of an APC.
1406 3. The character following an Esc, in which case we write Esc, then char,
1407 but only if we have not just entered an APC sequence.
1409 if (escseq && (apcstatus & APC_ON)) {
1410 if (inesc == ES_GOTESC) /* Don't write ESC yet */
1412 else if (oldesc == ES_GOTESC && !apcactive) {
1413 ckcputc(ESC); /* Write saved ESC */
1414 if (seslog && !sessft)
1416 } else if (apcrc) { /* We have an APC */
1417 debug(F111,"CONNECT APC complete",apcbuf,apclength);
1418 ckcputf(); /* Force screen update */
1419 pipemsg(CEV_APC); /* Notify parent */
1424 /* Write buffer including trailing NUL byte */
1426 write(xpipe[1], apcbuf, apclength+1);
1428 /* Copy our input buffer to the parent fork */
1430 debug(F101,"CONNECT APC complete ibc","",ibc);
1431 debug(F101,"CONNECT APC complete obc","",obc);
1432 write(xpipe[1], (char *)&ibc, sizeof(ibc));
1434 write(xpipe[1], (char *)&ibp, sizeof(ibp));
1435 write(xpipe[1], ibp, ibc);
1437 ck_sndmsg(); /* Wait to be killed */
1442 #endif /* NOESCSEQ */
1444 for (i = 0; i < inxcount; i++) { /* Loop thru */
1445 c = inxbuf[i]; /* input expansion buffer... */
1448 !apcactive /* Ignore APC sequences */
1453 c &= cmdmsk; /* Apply command mask. */
1454 if (c == CR && tt_crd) { /* SET TERM CR-DISPLA CRLF? */
1455 ckcputc(c); /* Yes, output CR */
1456 if (seslog && !sessft)
1458 c = LF; /* and insert a linefeed */
1460 if (c == LF && tt_lfd) { /* SET TERM CR-DISPLA CRLF? */
1461 ckcputc(CR); /* Yes, output CR */
1462 if (seslog && !sessft) logchar((char)CR);
1464 ckcputc(c); /* Write character to screen */
1466 if (seslog && !sessft) /* Handle session log */
1469 /* Check for trigger string */
1470 if (tt_trigger[0]) if ((ix = autoexitchk((CHAR)c)) > -1) {
1471 ckcputf(); /* Force screen update */
1473 fflush(stdout); /* I mean really force it */
1474 #endif /* NOSETBUF */
1475 pipemsg(CEV_TRI); /* Send up trigger indication */
1476 write(xpipe[1], (char *)&ix, sizeof(ix)); /* index */
1477 write(xpipe[1], (char *)&ibc, sizeof(ibc));
1479 write(xpipe[1], (char *)&ibp, sizeof(ibp));
1480 write(xpipe[1], ibp, ibc);
1482 debug(F100,"CONNECT concld trigger","",0);
1483 ck_sndmsg(); /* Wait to be killed */
1484 active = 0; /* Shouldn't be necessary... */
1488 #endif /* CK_TRIGGER */
1498 /* C O N E C T -- Interactive terminal connection */
1502 int n; /* General purpose counter */
1503 int i; /* For loops... */
1504 int c; /* c is a character, but must be signed
1505 integer to pass thru -1, which is the
1506 modem disconnection signal, and is
1507 different from the character 0377 */
1508 int c2; /* A copy of c */
1509 int csave; /* Another copy of c */
1512 #endif /* NOESCSEQ */
1514 int conret = 0; /* Return value from conect() */
1516 /* jbchksum = -1L; */
1517 jbset = 0; /* jmp_buf not set yet, don't use it */
1520 debug(F101,"CONNECT fork signal","",CK_FORK_SIG);
1521 debug(F101,"CONNECT entry pid","",pid);
1529 The following is to handle a fork left behind if we exit CONNECT mode
1530 without killing it, and then return to CONNECT mode. This happened in
1531 HP-UX, where the Reset key would raise SIGINT even though SIGINT was set to
1532 SIG_IGN. The code below fixes the symptom; the real fix is in the main
1533 SIGINT handler (if SIGINT shows up during CONNECT, just return rather than
1534 taking the longjmp).
1536 if (pid) { /* This should be 0 */
1538 debug(F101,"CONNECT entry killing stale pid","",pid);
1539 printf("WARNING: Old CONNECT fork seems to be active.\n");
1540 printf("Attempting to remove it...");
1544 x = kill(pid,SIGKILLTHR); /* Kill lower fork */
1545 wait_for_thread (pid, &ret_val);
1549 x = kill(pid,SIGKILL); /* Kill lower fork */
1553 #endif /* BEOSORBEBOX */
1554 wait((WAIT_T *)0); /* Wait till gone. */
1556 printf("ERROR: Failure to kill pid %d: %s, errno=%d\n",
1557 (int) pid, ck_errstr(), errno);
1558 debug(F111,"CONNECT error killing stale pid",ck_errstr(),pid);
1563 signal(CK_FORK_SIG, SIG_IGN); /* Initial CK_FORK_SIG handling, */
1565 The following ttimoff() call should not be necessary, but evidently there
1566 are cases where a timer is left active and then goes off, taking a longjmp
1567 to nowhere after the program's stack has changed. In any case, this is
1568 safe because the CONNECT module uses no timer of any kind, and no other timer
1569 should be armed while Kermit is in CONNECT mode.
1571 ttimoff(); /* Turn off any timer interrupts */
1574 makestr(&triggerval,NULL); /* Reset trigger */
1575 #endif /* CK_TRIGGER */
1579 printf("Sorry, you must SET LINE or SET HOST first\n");
1581 printf("Sorry, you must SET LINE first\n");
1582 #endif /* NETCONN */
1585 if (speed < 0L && network == 0 && ttfdflg == 0) {
1586 printf("Sorry, you must SET SPEED first\n");
1590 if (network && (nettype != NET_TCPB)
1592 && (nettype != NET_SX25)
1595 && (nettype != NET_IX25)
1598 && (nettype != NET_CMD)
1601 && (nettype != NET_PTY)
1604 printf("Sorry, network type not supported\n");
1607 #endif /* TCPSOCKET */
1611 if (!(ibuf = malloc(IBUFL+1))) { /* Allocate input line buffer */
1612 printf("Sorry, CONNECT input buffer can't be allocated\n");
1620 if (!(obuf = malloc(OBUFL+1))) { /* Allocate output line buffer */
1621 printf("Sorry, CONNECT output buffer can't be allocated\n");
1629 if (!(kbuf = malloc(KBUFL+1))) { /* Allocate keyboard input buffer */
1630 printf("Sorry, CONNECT keyboard buffer can't be allocated\n");
1635 if (!(temp = malloc(TMPLEN+1))) { /* Allocate temporary buffer */
1636 printf("Sorry, CONNECT temporary buffer can't be allocated\n");
1644 #endif /* COMMENT */
1647 #endif /* DYNAMIC */
1649 kbp = kbuf; /* Always clear these. */
1650 *kbp = NUL; /* No need to preserve them between */
1651 kbc = 0; /* CONNECT sessions. */
1655 debug(F101,"CONNECT conect entry ttyfd","",ttyfd);
1656 debug(F101,"CONNECT conect entry ibc","",ibc);
1657 debug(F101,"CONNECT conect entry obc","",obc);
1658 debug(F101,"CONNECT conect entry kbc","",kbc);
1660 debug(F110,"CONNECT conect trigger",tt_trigger[0],0);
1661 #endif /* CK_TRIGGER */
1664 debug(F101,"CONNECT conect entry ttchk","",n);
1669 if (ttyfd < 0) { /* If communication device not open */
1670 debug(F101,"CONNECT ttnproto","",ttnproto);
1671 debug(F111,"CONNECT opening",ttname,0); /* Open it now */
1674 network ? -nettype : mdmtyp,
1677 ckmakmsg(temp,TMPLEN,"Sorry, can't open ",ttname,NULL,NULL);
1679 debug(F110,"CONNECT open failure",ttname,0);
1683 /* If peer is in Kermit server mode, return now. */
1684 if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start)
1686 #endif /* IKS_OPTION */
1688 dohangup = 0; /* Hangup not requested yet */
1690 dox25clr = 0; /* X.25 clear not requested yet */
1697 printf("Connecting via command \"%s\"",ttname);
1699 printf("Connecting to host %s",ttname);
1701 if (nettype == NET_SX25 || nettype == NET_IX25)
1702 printf(", Link ID %d, LCN %d",linkid,lcn);
1705 #endif /* NETCONN */
1706 printf("Connecting to %s",ttname);
1707 if (speed > -1L) printf(", speed %ld",speed);
1710 #endif /* NETCONN */
1714 printf("Type the escape character followed by C to get back,\r\n");
1715 printf("or followed by ? to see other options.\r\n");
1717 printf(".\r\n\nESCAPE CHARACTER IS DISABLED\r\n\n");
1726 s = slogts ? "timestamped-text" : "text"; break;
1730 printf("Session Log: %s, %s\r\n",sesfil,s);
1732 if (debses) printf("Debugging Display...)\r\n");
1733 printf("----------------------------------------------------\r\n");
1737 /* Condition console terminal and communication line */
1739 if (conbin((char)escape) < 0) {
1740 printf("Sorry, can't condition console terminal\n");
1743 debug(F101,"CONNECT cmask","",cmask);
1744 debug(F101,"CONNECT cmdmsk","",cmdmsk);
1745 debug(F101,"CONNECT speed before ttvt","",speed);
1746 if ((n = ttvt(speed,flow)) < 0) { /* Enter "virtual terminal" mode */
1748 debug(F101,"CONNECT ttvt","",n);
1749 tthang(); /* Hang up and close the device. */
1752 if (ttopen(ttname, /* Open it again... */
1754 network ? -nettype : mdmtyp,
1757 ckmakmsg(temp,TMPLEN,"Sorry, can't reopen ",ttname,NULL,NULL);
1762 if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start)
1764 #endif /* IKS_OPTION */
1765 if (ttvt(speed,flow) < 0) { /* Try virtual terminal mode again. */
1766 conres(); /* Failure this time is fatal. */
1767 printf("Sorry, Can't condition communication line\n");
1772 debug(F101,"CONNECT ttvt ok, escape","",escape);
1774 debug(F101,"CONNECT carrier-watch","",carrier);
1778 #endif /* TN_COMPORT */
1779 ) && (carrier != CAR_OFF)) {
1782 debug(F100,"CONNECT ttgmdm","",x);
1783 if ((x > -1) && !(x & BM_DCD)) {
1786 #endif /* NOHINTS */
1787 debug(F100,"CONNECT ttgmdm CD test fails","",x);
1789 printf("?Carrier required but not detected.\n");
1793 printf("***********************************\n");
1794 printf(" Hint: To CONNECT to a serial device that\n");
1795 printf(" is not presenting the Carrier Detect signal,\n");
1796 printf(" first tell C-Kermit to:\n\n");
1797 printf(" SET CARRIER-WATCH OFF\n\n");
1798 printf("***********************************\n\n");
1799 #endif /* NOHINTS */
1802 debug(F100,"CONNECT ttgmdm ok","",0);
1805 /* Set up character set translations */
1807 unicode = 0; /* Assume Unicode won't be involved */
1808 tcs = 0; /* "Transfer" or "Other" charset */
1809 sxo = rxo = NULL; /* Initialize byte-to-byte functions */
1811 if (tcsr != tcsl) { /* Remote and local sets differ... */
1813 if (tcsr == FC_UTF8 || /* Remote charset is UTF-8 */
1814 tcsl == FC_UTF8) { /* or local one is. */
1815 xuf = xl_ufc[tcsl]; /* Incoming Unicode to local */
1816 if (xuf || tcsl == FC_UTF8) {
1817 tcs = (tcsr == FC_UTF8) ? tcsl : tcsr; /* The "other" set */
1818 xfu = xl_fcu[tcs]; /* Local byte to remote Unicode */
1820 unicode = (tcsr == FC_UTF8) ? 1 : 2;
1822 tcssize = fcsinfo[tcs].size; /* Size of other character set. */
1824 #endif /* UNICODE */
1825 tcs = gettcs(tcsr,tcsl); /* Get intermediate set. */
1826 sxo = xls[tcs][tcsl]; /* translation function */
1827 rxo = xlr[tcs][tcsr]; /* pointers for output functions */
1828 sxi = xls[tcs][tcsr]; /* and for input functions. */
1829 rxi = xlr[tcs][tcsl];
1832 #endif /* UNICODE */
1835 This is to prevent use of zmstuff() and zdstuff() by translation functions.
1836 They only work with disk i/o, not with communication i/o. Luckily Russian
1837 translation functions don't do any stuffing...
1841 if (language != L_RUSSIAN)
1842 #endif /* NOCYRIL */
1843 language = L_USASCII;
1848 debug(F101,"CONNECT tcs","",tcs);
1849 debug(F101,"CONNECT tcsl","",tcsl);
1850 debug(F101,"CONNECT tcsr","",tcsr);
1851 debug(F101,"CONNECT fcsinfo[tcsl].size","",fcsinfo[tcsl].size);
1852 debug(F101,"CONNECT fcsinfo[tcsr].size","",fcsinfo[tcsr].size);
1853 debug(F101,"CONNECT unicode","",unicode);
1856 #endif /* COMMENT */
1859 #ifndef XYZ_INTERNAL
1861 extern int binary; /* See about ZMODEM autodownloads */
1863 s = binary ? ptab[PROTO_Z].p_b_rcmd : ptab[PROTO_Z].p_t_rcmd;
1865 zmdlok = (*s != NUL); /* OK if we have external commands */
1867 #endif /* XYZ_INTERNAL */
1872 We need to activate the escape-sequence recognition feature when:
1873 (a) translation is elected, AND
1874 (b) the local and/or remote set is a 7-bit set other than US ASCII.
1876 SET TERMINAL APC is not OFF (handled in the next statement).
1878 escseq = (tcs != TC_TRANSP) && /* Not transparent */
1879 (fcsinfo[tcsl].size == 128 || fcsinfo[tcsr].size == 128) && /* 7 bits */
1880 (fcsinfo[tcsl].code != FC_USASCII); /* But not ASCII */
1881 #endif /* NOESCSEQ */
1882 #endif /* NOCSETS */
1886 escseq = escseq || (apcstatus & APC_ON);
1887 apcactive = 0; /* An APC command is not active */
1888 apclength = 0; /* ... */
1890 inesc = ES_NORMAL; /* Initial state of recognizer */
1891 debug(F101,"CONNECT escseq","",escseq);
1892 #endif /* NOESCSEQ */
1894 parent_id = getpid(); /* Get parent's pid for signalling */
1895 debug(F101,"CONNECT parent pid","",parent_id);
1897 if (xpipe[0] > -1) /* If old pipe hanging around, close */
1903 goterr = 0; /* Error flag for pipe & fork */
1904 if (pipe(xpipe) != 0) { /* Create new pipe to pass info */
1905 perror("Can't make pipe"); /* between forks. */
1906 debug(F101,"CONNECT pipe error","",errno);
1911 pid = spawn_thread(concld, "Lower Fork", B_NORMAL_PRIORITY, NULL);
1915 if ((pid = fork()) == (PID_T) -1) { /* Pipe OK, make port fork. */
1916 perror("Can't make port fork");
1917 debug(F101,"CONNECT fork error","",errno);
1920 #endif /* BEOSORBEBOX */
1921 debug(F101,"CONNECT created fork, pid","",pid);
1922 if (goterr) { /* Failed to make pipe or fork */
1923 conres(); /* Reset the console. */
1925 printf("\r\nCommunications disconnect (Back at %s)\r\n",
1936 what = W_NOTHING; /* So console modes are set right. */
1938 language = langsv; /* Restore language */
1939 #endif /* NOCSETS */
1940 parent_id = (PID_T) 0; /* Clean up */
1943 debug(F101,"CONNECT fork pid","",pid);
1945 /* Upper fork (KEYB fork) reads keystrokes and sends them out. */
1947 if (pid) { /* pid != 0, so I am the upper fork. */
1949 Before doing anything significant, the child fork must wait for a go-ahead
1950 character from xpipe[0]. Before starting to wait, we have enough time to
1951 clear buffers and set up the signal handler. When done with this, we will
1952 allow the child to continue by satisfying its pending read.
1954 Remember the child and parent have separate address space. The child has
1955 its own copy of input buffers, so we must clear the input buffers in the
1956 parent. Otherwise strange effects may occur, like chunks of characters
1957 repeatedly echoed on terminal screen. The child process is designed to
1958 empty its input buffers by reading all available characters and either
1959 echoing them on the terminal screen or saving them for future use in the
1960 parent. The latter case happens during APC processing - see the code around
1961 CEV_APC occurrences to see how the child passes its ibuf etc to parent via
1962 xpipe, for preservation until the next entry to this module, to ensure that
1963 no characters are lost between CONNECT sessions.
1967 This one needs a bit of extra explanation... In addition to the CONNECT
1968 module's own buffers, which are communicated and synchronized via xpipe,
1969 the low-level UNIX communication routines (ttinc, ttxin, etc) are also
1970 buffered, statically, in the ckutio.c module. But when the two CONNECT
1971 forks split off, the lower fork is updating this buffer's pointers and
1972 counts, but the upper fork never finds out about it and still has the old
1973 ones. The following UNIX-specific call to the ckutio.c module takes care
1974 of this... Without it, we get dual echoing of incoming characters.
1978 At this point, perhaps you are wondering why we use forks at all. It is
1979 simply because there is no other method portable among all UNIX variations.
1980 Not threads, not select(), ... (Yes, select() is more common now; it might
1981 actually be worth writing a variation of this module that works like BSD
1982 Telnet, one fork, driven by select()).
1984 ibp = ibuf; /* Clear ibuf[]. */
1985 ibc = 0; /* Child now has its own copy */
1986 signal(CK_FORK_SIG, pipeint); /* Handler for messages from child. */
1987 write(xpipe[1], ibuf, 1); /* Allow child to proceed */
1988 close(xpipe[1]); xpipe[1] = -1; /* Parent - prevent future writes */
1990 what = W_CONNECT; /* Keep track of what we're doing */
1992 debug(F101,"CONNECT keyboard fork duplex","",duplex);
1994 Catch communication errors or mode changes in lower fork.
1996 Note: Some C compilers (e.g. Cray UNICOS) interpret the ANSI C standard
1997 about setjmp() in a way that disallows constructions like:
1999 if ((var = [sig]setjmp(env)) == 0) ...
2001 which prevents the value returned by cklongjmp() from being used at all.
2002 So the signal handlers set a global variable, sjval, instead.
2006 sigsetjmp(con_env,1)
2009 #endif /* CK_POSIX_SIG */
2010 == 0) { /* Normal entry... */
2011 jbset = 1; /* Now we have a longjmp buffer */
2012 sjval = CEV_NO; /* Initialize setjmp return code. */
2014 debug(F101,"CONNECT setjmp normal entry","",sjval);
2017 if (network && (nettype == NET_SX25 || nettype == NET_IX25)) {
2019 bzero (x25obuf,sizeof(x25obuf));
2023 Here is the big loop that gets characters from the keyboard and sends them
2024 out the communication device. There are two components to the communication
2025 path: the connection from the keyboard to C-Kermit, and from C-Kermit to
2026 the remote computer. The treatment of the 8th bit of keyboard characters
2027 is governed by SET COMMAND BYTESIZE (cmdmsk). The treatment of the 8th bit
2028 of characters sent to the remote is governed by SET TERMINAL BYTESIZE
2029 (cmask). This distinction was introduced in edit 5A(164).
2033 if (kmptr) { /* Have current macro? */
2034 debug(F100,"CONNECT kmptr non NULL","",0);
2035 if ((c = (CHAR) *kmptr++) == NUL) { /* Get char from it */
2036 kmptr = NULL; /* If no more chars, */
2037 debug(F100,"CONNECT macro empty, continuing","",0);
2038 continue; /* reset pointer and continue */
2040 debug(F000,"CONNECT char from macro","",c);
2041 } else /* No macro... */
2042 #endif /* NOSETKEY */
2043 c = CONGKS(); /* Read from keyboard */
2047 debug(F101,"CONNECT ** KEYB","",c);
2048 #endif /* COMMENT */
2049 if (c == -1) { /* If read() got an error... */
2050 debug(F101,"CONNECT keyboard read errno","",errno);
2053 This seems to cause problems. If read() returns -1, the signal has already
2054 been delivered, and nothing will wake up the pause().
2056 pause(); /* Wait for transmitter to finish. */
2060 On Altos machines with Xenix 3.0, pressing DEL in connect mode brings us
2061 here (reason unknown). The console line discipline at this point has
2062 intr = ^C. The communications tty has intr = DEL but we get here after
2063 pressing DEL on the keyboard, even when the remote system has been set not
2064 to echo. With A986 defined, we stay in the read loop and beep only if the
2065 offending character is not DEL.
2067 if ((c & 127) != 127) conoc(BEL);
2071 This can be caused by the other fork signalling this one about
2072 an echoing change during TELNET negotiations.
2077 conoc(BEL); /* Otherwise, beep */
2078 active = 0; /* and terminate the read loop */
2081 #endif /* COMMENT */
2083 c &= cmdmsk; /* Do any requested masking */
2086 Note: kmptr is NULL if we got character c from the keyboard, and it is
2087 not NULL if it came from a macro. In the latter case, we must avoid
2090 if (!kmptr && macrotab[c]) { /* Macro definition for c? */
2091 kmptr = macrotab[c]; /* Yes, set up macro pointer */
2092 continue; /* and restart the loop, */
2093 } else c = keymap[c]; /* else use single-char keymap */
2094 #endif /* NOSETKEY */
2098 #endif /* NOSETKEY */
2099 (tt_escape && (c & 0xff) == escape)) { /* Escape char? */
2100 debug(F000,"CONNECT got escape","",c);
2101 c = CONGKS() & 0177; /* Got esc, get its arg */
2102 /* No key mapping here */
2103 doesc((char) c); /* Now process it */
2105 } else { /* It's not the escape character */
2106 csave = c; /* Save it before translation */
2107 /* for local echoing. */
2109 if (inesc == ES_NORMAL) { /* If not inside escape seq.. */
2110 /* Translate character sets */
2115 if (unicode == 1) { /* Remote is UTF-8 */
2116 outxcount = b_to_u(ch,outxbuf,OUTXBUFSIZ,tcssize);
2117 outxbuf[outxcount] = NUL;
2118 } else if (unicode == 2) { /* Local is UTF-8 */
2119 x = u_to_b(ch); /* So translate to remote byte */
2122 outxbuf[0] = (unsigned)(x & 0xff);
2124 outxbuf[outxcount] = NUL;
2126 #endif /* UNICODE */
2127 /* Local-to-intermediate */
2128 if (sxo) c = (*sxo)((char)c);
2129 /* Intermediate-to-remote */
2130 if (rxo) c = (*rxo)((char)c);
2133 outxbuf[outxcount] = NUL;
2136 #endif /* UNICODE */
2139 apcrc = chkaes((char)c);
2143 outxbuf[outxcount] = NUL;
2144 #endif /* NOCSETS */
2145 for (i = 0; i < outxcount; i++) {
2148 If Shift-In/Shift-Out is selected and we have a 7-bit connection,
2149 handle shifting here.
2151 if (sosi) { /* Shift-In/Out selected? */
2152 if (cmask == 0177) { /* In 7-bit environment? */
2153 if (c & 0200) { /* 8-bit character? */
2154 if (outshift == 0) { /* If not shifted, */
2155 ttoc(dopar(SO)); /* shift. */
2159 if (outshift == 1) { /* 7-bit character */
2160 ttoc(dopar(SI)); /* If shifted, */
2161 outshift = 0; /* unshift. */
2165 if (c == SO) outshift = 1; /* User typed SO */
2166 if (c == SI) outshift = 0; /* User typed SI */
2168 c &= cmask; /* Apply Kermit-to-host mask now. */
2170 if (network && nettype == NET_SX25) {
2171 if (padparms[PAD_ECHO]) {
2175 if ((c != padparms[PAD_CHAR_DELETE_CHAR]) &&
2176 (c != padparms[PAD_BUFFER_DELETE_CHAR]) &&
2177 (c != padparms[PAD_BUFFER_DISPLAY_CHAR]))
2179 if (seslog && !sessft)
2182 if (c == CR && (padparms[PAD_LF_AFTER_CR] == 4 ||
2183 padparms[PAD_LF_AFTER_CR] == 5)) {
2188 if (seslog && !sessft)
2191 if (c == padparms[PAD_BREAK_CHARACTER]) {
2193 } else if (padparms[PAD_DATA_FORWARD_TIMEOUT]) {
2195 x25obuf [obufl++] = c;
2196 } else if (((c == padparms[PAD_CHAR_DELETE_CHAR])||
2197 (c == padparms[PAD_BUFFER_DELETE_CHAR]) ||
2198 (c == padparms[PAD_BUFFER_DISPLAY_CHAR]))
2199 && (padparms[PAD_EDITING])) {
2200 if (c == padparms[PAD_CHAR_DELETE_CHAR]) {
2202 conol("\b \b"); obufl--;
2205 (c == padparms[PAD_BUFFER_DELETE_CHAR]) {
2206 conol ("\r\nPAD Buffer Deleted\r\n");
2209 (c==padparms[PAD_BUFFER_DISPLAY_CHAR]) {
2215 x25obuf [obufl++] = c;
2216 if (obufl == MAXOX25) tosend = 1;
2217 else if (c == CR) tosend = 1;
2220 if (ttol((CHAR *)x25obuf,obufl) < 0) {
2221 perror ("\r\nCan't send characters");
2224 bzero (x25obuf,sizeof(x25obuf));
2231 if (c == '\015') { /* Carriage Return */
2233 if (tnlm) { /* TERMINAL NEWLINE ON */
2234 stuff = LF; /* Stuff LF */
2236 } else if (network && /* TELNET NEWLINE */
2238 switch (!TELOPT_ME(TELOPT_BINARY) ?
2252 ttoc(dopar('\015')); /* Send CR */
2253 if (duplex) conoc('\015'); /* Echo CR */
2254 c = stuff; /* Char to stuff */
2259 /* If user types the 0xff character (TELNET IAC), it must be doubled. */
2261 if ((dopar((CHAR) c) == IAC) && /* IAC (0xff) */
2262 network && IS_TELNET()) {
2263 /* Send one copy now */
2264 /* and the other one just below. */
2268 /* Send the character */
2270 if (ttoc((char)dopar((CHAR) c)) > -1) {
2271 if (duplex) { /* If half duplex, must echo */
2273 conol(dbchr(csave)); /* original char */
2274 else /* not the translated one */
2276 if (seslog) { /* And maybe log it too */
2278 if (sessft == 0 && csave == '\r')
2284 perror("\r\nCan't send character");
2294 /* now active == 0 */
2295 signal(CK_FORK_SIG, SIG_IGN); /* Turn off CK_FORK_SIG */
2296 sjval = CEV_NO; /* Set to hangup */
2297 } /* Come here on termination of child */
2299 /* cklongjmp() executed in pipeint() (parent only!) comes here */
2302 Now the child fork is gone or is waiting for CK_FORK_SIG in ck_sndmsg().
2303 So we can't get (in the parent) any subsequent CK_FORK_SIG signals until
2304 we signal the child with CK_FORK_SIG.
2306 debug(F100,"CONNECT signaling port fork","",0);
2307 signal(CK_FORK_SIG, SIG_IGN); /* Turn this off */
2308 debug(F101,"CONNECT killing port fork","",pid);
2314 x = kill(pid,SIGKILLTHR); /* Kill lower fork */
2315 wait_for_thread(pid, &ret_val);
2319 x = kill(pid,SIGKILL); /* Kill lower fork */
2323 #endif /* BEOSORBEBOX */
2324 wait((WAIT_T *)0); /* Wait till gone. */
2326 printf("WARNING: Failure to kill fork, pid %d: %s, errno=%d\n",
2327 (int) pid, ck_errstr(), errno);
2328 debug(F111,"CONNECT error killing pid",ck_errstr(),errno);
2330 debug(F101,"CONNECT killed port fork","",pid);
2333 if (sjval == CEV_HUP) { /* Read error on comm device */
2334 dohangup = 1; /* so we want to hang up our side */
2336 if (network) { /* and/or close network connection */
2340 if (nettype == NET_SX25) /* If X.25, restore the PAD params */
2344 #endif /* NETCONN */
2347 if (sjval == CEV_APC) { /* Application Program Command rec'd */
2348 apcactive = APC_REMOTE; /* Flag APC as active */
2349 active = 0; /* Flag CONNECT as inactive */
2352 conres(); /* Reset the console. */
2353 if (dohangup > 0) { /* If hangup requested, do that. */
2355 if (dohangup > 1) /* User asked for it */
2356 if (mdmhup() < 1) /* Maybe hang up via modem */
2358 tthang(); /* And make sure we don't hang up */
2359 dohangup = 0; /* again unless requested again. */
2365 if (network && sigpiph) /* Restore previous SIGPIPE handler */
2366 (VOID) signal(SIGPIPE, sigpiph);
2367 #endif /* SIGPIPE */
2368 #endif /* NETCONN */
2369 #endif /* COMMENT */
2372 if (dox25clr) { /* If X.25 Clear requested */
2373 x25clear(); /* do that. */
2377 dox25clr = 0; /* But only once. */
2381 if (quitnow) doexit(GOOD_EXIT,xitsta); /* Exit now if requested. */
2383 printf("(Back at %s)", *myhost ? myhost : "local UNIX system");
2388 what = W_NOTHING; /* So console modes set right. */
2390 language = langsv; /* Restore language */
2391 #endif /* NOCSETS */
2392 parent_id = (PID_T) 0;
2397 else { /* *** */ /* Inferior reads, prints port input */
2398 concld(/* (void *)&pid */);
2400 #endif /* BEOSORBEBOX */
2405 signal(CK_FORK_SIG, SIG_IGN); /* In case this wasn't done already */
2406 debug(F101,"CONNECT conect exit ibc","",ibc);
2407 debug(F101,"CONNECT conect exit obc","",obc);
2408 close(xpipe[0]); xpipe[0] = -1; /* Close the pipe */
2409 close(xpipe[1]); xpipe[1] = -1;
2412 if (apcactive == APC_LOCAL)
2415 printf("----------------------------------------------------\r\n");
2422 /* H C O N N E -- Give help message for connect. */
2427 static char *hlpmsg[] = {
2428 "\r\n ? for this message",
2429 "\r\n 0 (zero) to send a null",
2430 "\r\n B to send a BREAK",
2432 "\r\n L to send a Long BREAK",
2433 #endif /* CK_LBRK */
2435 "\r\n I to send a network interrupt packet",
2437 "\r\n A to send Are You There?",
2438 #endif /* TCPSOCKET */
2440 "\r\n R to reset X.25 virtual circuit",
2442 #endif /* NETCONN */
2443 "\r\n U to hangup and close the connection",
2444 "\r\n Q to hangup and quit Kermit",
2445 "\r\n S for status",
2447 "\r\n ! to push to local shell (disabled)",
2448 "\r\n Z to suspend (disabled)",
2450 "\r\n ! to push to local shell",
2452 "\r\n Z to suspend (disabled)",
2454 "\r\n Z to suspend",
2457 "\r\n \\ backslash code:",
2458 "\r\n \\nnn decimal character code",
2459 "\r\n \\Onnn octal character code",
2460 "\r\n \\Xhh hexadecimal character code",
2461 "\r\n terminate with carriage return.",
2462 "\r\n Type the escape character again to send the escape character, or",
2463 "\r\n press the space-bar to resume the CONNECT command.\r\n",
2466 conol("\r\n----------------------------------------------------");
2467 conol("\r\nPress C to return to ");
2468 conol(*myhost ? myhost : "the C-Kermit prompt");
2470 conola(hlpmsg); /* Print the help message. */
2471 conol("Command>"); /* Prompt for command. */
2472 c = CONGKS() & 0177; /* Get character, strip any parity. */
2473 /* No key mapping or translation here */
2476 conoll("----------------------------------------------------");
2477 return(c); /* Return it. */
2481 /* D O E S C -- Process an escape character argument */
2488 #endif /* CK_ANSIC */
2492 debug(F101,"CONNECT doesc","",c);
2494 if (c == escape) { /* Send escape character */
2495 d = dopar((CHAR) c); ttoc((char) d); return;
2496 } else /* Or else look it up below. */
2497 if (isupper(c)) c = tolower(c);
2501 case 'c': /* Escape back to prompt */
2503 active = 0; conol("\r\n"); return;
2505 case 'b': /* Send a BREAK signal */
2510 case 'i': /* Send Interrupt */
2516 if (network && IS_TELNET()) { /* TELNET */
2517 temp[0] = (CHAR) IAC; /* I Am a Command */
2518 temp[1] = (CHAR) IP; /* Interrupt Process */
2520 ttol((CHAR *)temp,2);
2522 #endif /* TCPSOCKET */
2524 if (network && (nettype == NET_SX25)) {
2525 (VOID) x25intr(0); /* X.25 interrupt packet */
2533 case 'a': /* "Are You There?" */
2538 if (network && IS_TELNET()) {
2539 temp[0] = (CHAR) IAC; /* I Am a Command */
2540 temp[1] = (CHAR) AYT; /* Are You There? */
2542 ttol((CHAR *)temp,2);
2545 #endif /* TCPSOCKET */
2546 #endif /* NETCONN */
2549 case 'l': /* Send a Long BREAK signal */
2551 #endif /* CK_LBRK */
2553 case 'u': /* Hangup */
2554 /* case '\010': */ /* No, too dangerous */
2556 if (network && (nettype == NET_SX25 || nettype == NET_IX25))
2560 dohangup = 2; active = 0; conol("\r\nHanging up "); return;
2563 case 'r': /* Reset the X.25 virtual circuit */
2565 if (network && (nettype == NET_SX25 || nettype == NET_IX25))
2566 (VOID) x25reset(0,0);
2571 case 'q': /* Quit */
2572 dohangup = 2; quitnow = 1; active = 0; conol("\r\n"); return;
2574 case 's': /* Status */
2576 conoll("----------------------------------------------------");
2579 ckmakmsg(temp,TMPLEN," Pipe: \"",ttname,"\"",NULL);
2585 (network ? "Host" : "Device"),
2590 if (!network && speed >= 0L) {
2591 sprintf(temp,"Speed %ld", speed);
2594 sprintf(temp," Terminal echo: %s", duplex ? "local" : "remote");
2596 sprintf(temp," Terminal bytesize: %d", (cmask == 0177) ? 7 : 8);
2598 sprintf(temp," Command bytesize: %d", (cmdmsk == 0177) ? 7 : 8 );
2601 sprintf(temp," Parity[hardware]: %s",parnam((char)hwparity));
2603 sprintf(temp," Parity: %s", parnam((char)parity));
2605 sprintf(temp," Autodownload: %s", autodl ? "on" : "off");
2607 ckmakmsg(temp, /* (would not be safe for sprintf) */
2610 *sesfil ? sesfil : "(none)",
2616 if (!network) shomdm();
2623 sprintf(temp," Elapsed time: %s",hhmmss(z));
2627 #endif /* CKLOGDIAL */
2628 conoll("----------------------------------------------------");
2631 case 'h': /* Help */
2632 case '?': /* Help */
2633 c = hconne(); continue;
2635 case '0': /* Send a null */
2636 c = '\0'; d = dopar((CHAR) c); ttoc((char) d); return;
2638 case 'z': case '\032': /* Suspend */
2649 case '@': /* Start inferior command processor */
2653 conres(); /* Put console back to normal */
2654 zshcmd(""); /* Fork a shell. */
2655 if (conbin((char)escape) < 0) {
2656 printf("Error resuming CONNECT session\n");
2665 case SP: /* Space, ignore */
2668 default: /* Other */
2669 if (c == CMDQ) { /* Backslash escape */
2673 while (((c = (CONGKS() & cmdmsk)) != '\r') && (c != '\n'))
2675 *ecbp = NUL; ecbp = ecbuf;
2676 x = xxesc(&ecbp); /* Interpret it */
2677 if (x >= 0) { /* No key mapping here */
2678 c = dopar((CHAR) x);
2681 } else { /* Invalid backslash code. */
2686 conoc(BEL); return; /* Invalid esc arg, beep */
2690 #endif /* NOLOCAL */