|
|
1.1 root 1: char *connv = "CONNECT Command for UNIX, 5A(047) 23 Nov 92";
2:
3: /* C K U C O N -- Dumb terminal connection to remote system, for UNIX */
4: /*
5: Author: Frank da Cruz ([email protected], [email protected]),
6: Columbia University Center for Computing Activities.
7: First released January 1985.
8: Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
9: York. Permission is granted to any individual or institution to use this
10: software as long as it is not sold for profit. This copyright notice must be
11: retained. This software may not be included in commercial products without
12: written permission of Columbia University.
13: */
14:
15: #include "ckcdeb.h" /* Common things first */
16:
17: #ifdef NEXT
18: #undef NSIG
19: #include <sys/wait.h> /* For wait() */
20: #endif /* NEXT */
21:
22: #include <signal.h> /* Signals */
23: #include <errno.h> /* Error numbers */
24:
25: #ifdef ZILOG /* Longjumps */
26: #include <setret.h>
27: #else
28: #include <setjmp.h>
29: #endif /* ZILOG */
30:
31: /* Kermit-specific includes */
32:
33: #include "ckcasc.h" /* ASCII characters */
34: #include "ckcker.h" /* Kermit things */
35: #include "ckucmd.h" /* For xxesc() prototype */
36: #include "ckcnet.h" /* Network symbols */
37: #ifndef NOCSETS
38: #include "ckcxla.h" /* Character set translation */
39: #endif /* NOCSETS */
40:
41: /* Internal function prototypes */
42:
43: _PROTOTYP( VOID doesc, (char) );
44: _PROTOTYP( VOID logchar, (char) );
45: _PROTOTYP( int hconne, (void) );
46: _PROTOTYP( VOID shomdm, (void) );
47:
48: #ifndef SIGUSR1 /* User-defined signals */
49: #define SIGUSR1 30
50: #endif /* SIGUSR1 */
51:
52: #ifndef SIGUSR2
53: #define SIGUSR2 31
54: #endif /* SIGUSR2 */
55:
56: /* External variables */
57:
58: extern int local, escape, duplex, parity, flow, seslog, sessft, debses,
59: mdmtyp, ttnproto, cmask, cmdmsk, network, nettype, deblog, sosi, tnlm,
60: xitsta, what, ttyfd, quiet, backgrd, pflag, tt_crd, tn_nlm;
61: extern long speed;
62: extern char ttname[], sesfil[], myhost[], *ccntab[];
63:
64: #ifndef NOSETKEY /* Keyboard mapping */
65: extern KEY *keymap; /* Single-character key map */
66: extern MACRO *macrotab; /* Key macro pointer table */
67: static MACRO kmptr = NULL; /* Pointer to current key macro */
68: #endif /* NOSETKEY */
69:
70: /* Global variables local to this module */
71:
72: static int quitnow = 0, /* <esc-char>Q was typed */
73: dohangup = 0, /* <esc-char>H was typed */
74: sjval = 0, /* Setjump return value */
75: goterr = 0, /* I/O error flag */
76: #ifndef SUNX25
77: active = 0, /* Lower fork active flag */
78: #endif /* SUNX25 */
79: inshift = 0, /* SO/SI shift states */
80: outshift = 0;
81:
82: static char kbuf[10], *kbp; /* Keyboard buffer & pointer */
83: static PID_T parent_id = (PID_T)0; /* Process id of keyboard fork */
84:
85: static char *ibp; /* Input buffer pointer */
86: static int ibc = 0; /* Input buffer count */
87: #ifdef pdp11
88: #define IBUFL 1536 /* Input buffer length */
89: #else
90: #define IBUFL 4096
91: #endif /* pdp11 */
92:
93: static char *obp; /* Output buffer pointer */
94: static int obc = 0; /* Output buffer count */
95: #define OBUFL 1024 /* Output buffer length */
96:
97: #define TMPLEN 200 /* Temporary message buffer length */
98: #ifdef DYNAMIC
99: static char *ibuf = NULL, *obuf = NULL, *temp = NULL; /* Buffers */
100: #else
101: static char ibuf[IBUFL], obuf[OBUFL], temp[TMPLEN];
102: #endif /* DYNAMIC */
103:
104: /* SunLink X.25 items */
105:
106: #ifdef SUNX25
107: static char *p; /* General purpose pointer */
108: char x25ibuf[MAXIX25]; /* Input buffer */
109: char x25obuf[MAXOX25]; /* Output buffer */
110: int active = 0; /* Lower fork active flag */
111: int ibufl; /* Length of input buffer */
112: int obufl; /* Length of output buffer */
113: unsigned char tosend = 0;
114: int linkid, lcn;
115: static int dox25clr = 0;
116: CHAR padparms[MAXPADPARMS+1];
117: static int padpipe[2]; /* Pipe descriptor to pass PAD parms */
118: #endif /* SUNX25 */
119:
120: /* Character-set items */
121:
122: #ifndef NOCSETS
123: #ifdef CK_ANSIC /* ANSI C prototypes... */
124: extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
125: extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
126: static CHAR (*sxo)(CHAR); /* Local translation functions */
127: static CHAR (*rxo)(CHAR); /* for output (sending) terminal chars */
128: static CHAR (*sxi)(CHAR); /* and for input (receiving) terminal chars. */
129: static CHAR (*rxi)(CHAR);
130: #else /* Not ANSI C... */
131: extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */
132: extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */
133: static CHAR (*sxo)(); /* Local translation functions */
134: static CHAR (*rxo)(); /* for output (sending) terminal chars */
135: static CHAR (*sxi)(); /* and for input (receiving) terminal chars. */
136: static CHAR (*rxi)();
137: #endif /* CK_ANSIC */
138: extern int language; /* Current language. */
139: static int langsv; /* For remembering language setting. */
140: extern struct csinfo fcsinfo[]; /* File character set info. */
141: extern int tcsr, tcsl; /* Terminal character sets, remote & local. */
142: static int tcs; /* Intermediate ("transfer") character set. */
143:
144: #ifndef NOESCSEQ
145: /*
146: As of edit 178, the CONNECT command will skip past ANSI escape sequences
147: to avoid translating the characters within them. This allows the CONNECT
148: command to work correctly when connected to a remote host that uses a
149: 7-bit ISO 646 national character set, in which characters like '[' would
150: normally be translated into accented characters, ruining the terminal's
151: interpretation (and generation) of escape sequences.
152:
153: Escape sequences of non-ANSI/ISO-compliant terminals are not handled.
154: */
155: #ifndef SKIPESC
156: #define SKIPESC
157: #endif /* SKIPESC */
158: /*
159: States for the escape-sequence recognizer.
160: */
161: #define ES_NORMAL 0 /* Normal, not in escape sequence */
162: #define ES_GOTESC 1 /* Current character is ESC */
163: #define ES_ESCSEQ 2 /* Inside an escape sequence */
164: #define ES_GOTCSI 3 /* Inside a control sequence */
165: #define ES_STRING 4 /* Inside DCS,OSC,PM, or APC string */
166: #define ES_TERMIN 5 /* 1st char of string terminator */
167:
168: static int
169: skipesc = 0, /* Skip over ANSI escape sequences */
170: inesc = ES_NORMAL; /* State of sequence recognizer */
171: /*
172: ANSI escape sequence handling. Only the 7-bit form is treated, because
173: translation is not a problem in the 8-bit environment, in which all GL
174: characters are ASCII and no translation takes place. So we don't check
175: for the 8-bit single-character versions of CSI, DCS, OSC, APC, or ST.
176: Here is the ANSI sequence recognizer state table, followed by the code
177: that implements it.
178:
179: Definitions:
180: CAN = Cancel 01/08 Ctrl-X
181: SUB = Substitute 01/10 Ctrl-Z
182: DCS = Device Control Sequence 01/11 05/00 ESC P
183: CSI = Control Sequence Introducer 01/11 05/11 ESC [
184: ST = String Terminator 01/11 05/12 ESC \
185: OSC = Operating System Command 01/11 05/13 ESC ]
186: PM = Privacy Message 01/11 05/14 ESC ^
187: APC = Application Program Command 01/11 05/15 ESC _
188:
189: ANSI escape sequence recognizer:
190:
191: State Input New State ; Commentary
192:
193: NORMAL (start) ; Start in NORMAL state
194:
195: (any) CAN NORMAL ; ^X cancels
196: (any) SUB NORMAL ; ^Z cancels
197:
198: NORMAL ESC GOTESC ; Begin escape sequence
199: NORMAL other ; NORMAL control or graphic character
200:
201: GOTESC ESC ; Start again
202: GOTESC [ GOTCSI ; CSI
203: GOTESC P STRING ; DCS introducer, consume through ST
204: GOTESC ] STRING ; OSC introducer, consume through ST
205: GOTESC ^ STRING ; PM introducer, consume through ST
206: GOTESC _ STRING ; APC introducer, consume through ST
207: GOTESC 0..~ NORMAL ; 03/00 through 17/14 = Final character
208: GOTESC other ESCSEQ ; Intermediate or ignored control character
209:
210: ESCSEQ ESC GOTESC ; Start again
211: ESCSEQ 0..~ NORMAL ; 03/00 through 17/14 = Final character
212: ESCSEQ other ; Intermediate or ignored control character
213:
214: GOTCSI ESC GOTESC ; Start again
215: GOTCSI @..~ NORMAL ; 04/00 through 17/14 = Final character
216: GOTCSI other ; Intermediate char or ignored control char
217:
218: STRING ESC TERMIN ; Maybe have ST
219: STRING other ; Consume all else
220:
221: TERMIN \ NORMAL ; End of string
222: TERMIN other STRING ; Still in string
223: */
224: /*
225: chkaes() -- Check ANSI Escape Sequence.
226: Call with EACH character in input stream.
227: Sets global inesc variable according to escape sequence state.
228: */
229: VOID
230: #ifdef CK_ANSIC
231: chkaes(char c)
232: #else
233: chkaes(c) char c;
234: #endif /* CK_ANSIC */
235: /* chkaes */ {
236:
237: if (c == CAN || c == SUB) /* CAN and SUB cancel any sequence */
238: inesc = ES_NORMAL;
239: else /* Otherwise */
240: switch (inesc) { /* enter state switcher */
241:
242: case ES_NORMAL: /* NORMAL state */
243: if (c == ESC) /* Got an ESC */
244: inesc = ES_GOTESC; /* Change state to GOTESC */
245: break; /* Otherwise stay in NORMAL state */
246:
247: case ES_GOTESC: /* GOTESC state */
248: if (c == '[') /* Left bracket after ESC is CSI */
249: inesc = ES_GOTCSI; /* Change to GOTCSI state */
250: else if (c > 057 && c < 0177) /* Final character '0' thru '~' */
251: inesc = ES_NORMAL; /* Back to normal */
252: else if (c == 'P' || (c > 0134 && c < 0140)) /* P, [, ^, or _ */
253: inesc = ES_STRING; /* Switch to STRING-absorption state */
254: else if (c != ESC) /* ESC in an escape sequence... */
255: inesc = ES_ESCSEQ; /* starts a new escape sequence */
256: break; /* Intermediate or ignored ctrl char */
257:
258: case ES_ESCSEQ: /* ESCSEQ -- in an escape sequence */
259: if (c > 057 && c < 0177) /* Final character '0' thru '~' */
260: inesc = ES_NORMAL; /* Return to NORMAL state. */
261: else if (c == ESC) /* ESC ... */
262: inesc = ES_GOTESC; /* starts a new escape sequence */
263: break; /* Intermediate or ignored ctrl char */
264:
265: case ES_GOTCSI: /* GOTCSI -- In a control sequence */
266: if (c > 077 && c < 0177) /* Final character '@' thru '~' */
267: inesc = ES_NORMAL; /* Return to NORMAL. */
268: else if (c == ESC) /* ESC ... */
269: inesc = ES_GOTESC; /* starts over. */
270: break; /* Intermediate or ignored ctrl char */
271:
272: case ES_STRING: /* Inside a string */
273: if (c == ESC) /* ESC may be 1st char of terminator */
274: inesc = ES_TERMIN; /* Go see. */
275: break; /* Absorb all other characters. */
276:
277: case ES_TERMIN: /* May have a string terminator */
278: if (c == '\\') /* which must be backslash */
279: inesc = ES_NORMAL; /* If so, back to NORMAL */
280: else /* Otherwise */
281: inesc = ES_STRING; /* Back to string absorption. */
282: }
283: }
284: #endif /* NOESCSEQ */
285: #endif /* NOCSETS */
286:
287: /* Connect state parent/child communication signal handlers */
288:
289: static jmp_buf con_env; /* Environment pointer for connect errors */
290: /*
291: Note: Some C compilers (e.g. Cray UNICOS) interpret the ANSI C standard
292: about setjmp() in a way that disallows constructions like:
293:
294: if ((var = setjmp(env)) == 0) ...
295:
296: which prevents the value returned by longjmp() from being used at all.
297: So the following handlers set a global variable instead.
298: */
299: static
300: SIGTYP
301: conn_int(foo) int foo; { /* Modem read failure handler, */
302: signal(SIGUSR1,SIG_IGN); /* Disarm the interrupt */
303: sjval = 1; /* Set global variable */
304: longjmp(con_env,sjval); /* Notifies parent process to stop */
305: }
306:
307: static
308: SIGTYP
309: mode_chg(foo) int foo; {
310: signal(SIGUSR2,mode_chg); /* Re-arm the signal immediately. */
311:
312: #ifdef SUNX25 /* X.25 read new params from pipe */
313: if (nettype == NET_SX25) {
314: read(padpipe[0],padparms,MAXPADPARMS);
315: debug(F100,"pad_chg","",0);
316: /*
317: NOTE: we can probably skip this longjmp, just as we do in the "else" case.
318: But I don't (yet) have any way to test this.
319: */
320: sjval = 2; /* Set global variable. */
321: longjmp(con_env,sjval);
322: debug(F100,"mode_chg X.25","",0);
323: } else {
324: #endif /* SUNX25 */
325: duplex = 1 - duplex; /* Toggle duplex mode. */
326: debug(F101,"mode_chg duplex","",duplex);
327: #ifdef SUNX25
328: }
329: #endif /* SUNX25 */
330: }
331:
332: /* C K C P U T C -- C-Kermit CONNECT Put Character to Screen */
333: /*
334: Output is buffered to avoid slow screen writes on fast connections.
335: */
336: int
337: ckcputf() { /* Dump the output buffer */
338: int x = 0;
339: if (obc > 0) /* If we have any characters, */
340: x = conxo(obc,obuf); /* dump them, */
341: obp = obuf; /* reset the pointer */
342: obc = 0; /* and the counter. */
343: return(x); /* Return conxo's return code */
344: }
345:
346: int
347: ckcputc(c) int c; {
348: int x;
349:
350: *obp++ = c & 0xff; /* Deposit the character */
351: obc++; /* Count it */
352: if (ibc == 0 || /* If input buffer about empty */
353: obc == OBUFL) { /* or output buffer full */
354: debug(F101,"CKCPUTC obc","",obc);
355: x = conxo(obc,obuf); /* dump the buffer, */
356: obp = obuf; /* reset the pointer */
357: obc = 0; /* and the counter. */
358: return(x); /* Return conxo's return code */
359: } else return(0);
360: }
361:
362: /* C K C G E T C -- C-Kermit CONNECT Get Character */
363: /*
364: Buffered read from communication device.
365: Returns the next character, refilling the buffer if necessary.
366: On error, returns ttinc's return code (see ttinc() description).
367: Dummy argument for compatible calling conventions with ttinc().
368: */
369: int
370: ckcgetc(dummy) int dummy; {
371: int c, n;
372:
373: debug(F101,"CKCGETC 1 ibc","",ibc); /* Log */
374: if (ibc < 1) { /* Need to refill buffer? */
375: ibc = 0; /* Yes, reset count */
376: ibp = ibuf; /* and buffer pointer */
377: debug(F100,"CKCGETC 1 calling ttinc(0)","",0); /* Log */
378: c = ttinc(0); /* Read one character, blocking */
379: debug(F101,"CKCGETC 1 ttinc(0)","",c); /* Log */
380: if (c < 0) { /* If error, return error code */
381: return(c);
382: } else { /* Otherwise, got one character */
383: *ibp++ = c; /* Advance buffer pointer */
384: ibc++; /* and count. */
385: }
386:
387: /* Now quickly read any more that might have arrived */
388:
389: if ((n = ttchk()) > 0) { /* Any more waiting? */
390: if (n > (IBUFL - ibc)) /* Get them all at once. */
391: n = IBUFL - ibc; /* Don't overflow buffer */
392: if ((n = ttxin(n,(CHAR *)ibp)) > 0) {
393: ibp += n; /* Advance pointer */
394: ibc += n; /* and counter */
395: } else return(-1);
396: }
397: debug(F101,"CKCGETC 2 ibc","",ibc); /* Log how many */
398: ibp = ibuf;
399: }
400: c = *ibp++ & 0xff; /* Get next character from buffer */
401: ibc--; /* Reduce buffer count */
402: return(c); /* Return the character */
403: }
404:
405: /* C O N E C T -- Perform terminal connection */
406:
407: int
408: conect() {
409: PID_T pid; /* Process id of child (modem reader) */
410: int n; /* General purpose counter */
411:
412: int c; /* c is a character, but must be signed
413: integer to pass thru -1, which is the
414: modem disconnection signal, and is
415: different from the character 0377 */
416: int c2; /* A copy of c */
417: int csave; /* Another copy of c */
418: int tx; /* tn_doop() return code */
419: #ifdef SUNX25
420: int i; /* Worker for X.25 code*/
421: #endif /* SUNX25 */
422:
423: #ifdef DYNAMIC
424: if (!(ibuf = malloc(IBUFL+1))) { /* Allocate input line buffer */
425: printf("Sorry, CONNECT input buffer can't be allocated\n");
426: return(0);
427: }
428: if (!(obuf = malloc(OBUFL+1))) { /* Allocate input line buffer */
429: printf("Sorry, CONNECT output buffer can't be allocated\n");
430: free(ibuf);
431: return(0);
432: }
433: if (!(temp = malloc(TMPLEN+1))) { /* Allocate temporary buffer */
434: printf("Sorry, CONNECT temporary buffer can't be allocated\n");
435: free(obuf);
436: return(0);
437: }
438: #endif /* DYNAMIC */
439:
440: if (!local) {
441: #ifdef NETCONN
442: printf("Sorry, you must SET LINE or SET HOST first\n");
443: #else
444: printf("Sorry, you must SET LINE first\n");
445: #endif /* NETCONN */
446: return(0);
447: }
448: if (speed < 0L && network == 0) {
449: printf("Sorry, you must SET SPEED first\n");
450: return(0);
451: }
452: #ifdef TCPSOCKET
453: if (network && (nettype != NET_TCPB)
454: #ifdef SUNX25
455: && (nettype != NET_SX25)
456: #endif /* SUNX25 */
457: ) {
458: printf("Sorry, network type not supported\n");
459: return(0);
460: }
461: #endif /* TCPSOCKET */
462:
463: if (ttyfd < 0) { /* If communication device not open */
464: debug(F111,"ckucon opening",ttname,0); /* Open it now */
465: if (ttopen(ttname,
466: &local,
467: network ? -nettype : mdmtyp,
468: 0
469: ) < 0) {
470: sprintf(temp,"Sorry, can't open %s",ttname);
471: perror(temp);
472: debug(F110,"ckucon open failure",temp,0);
473: return(0);
474: }
475: }
476: dohangup = 0; /* Hangup not requested yet */
477: #ifdef SUNX25
478: dox25clr = 0; /* X.25 clear not requested yet */
479: #endif /* SUNX25 */
480:
481: if (!quiet) {
482: #ifdef NETCONN
483: if (network) {
484: printf("Connecting to host %s",ttname);
485: #ifdef SUNX25
486: if (nettype == NET_SX25)
487: printf(", Link ID %d, LCN %d",linkid,lcn);
488: #endif /* SUNX25 */
489: } else {
490: #endif /* NETCONN */
491: printf("Connecting to %s",ttname);
492: if (speed > -1L) printf(", speed %ld",speed);
493: #ifdef NETCONN
494: }
495: #endif /* NETCONN */
496: printf(".\r\nThe escape character is Ctrl-%c (ASCII %d, %s)\r\n",
497: ctl(escape), escape, (escape == 127 ? "DEL" : ccntab[escape]));
498: printf("Type the escape character followed by C to get back,\r\n");
499: printf("or followed by ? to see other options.\r\n");
500: if (seslog) {
501: printf("(Session logged to %s, ",sesfil);
502: printf("%s)\r\n", sessft ? "binary" : "text");
503: }
504: if (debses) printf("Debugging Display...)\r\n");
505: fflush(stdout);
506: }
507:
508: /* Condition console terminal and communication line */
509:
510: if (conbin((char)escape) < 0) {
511: printf("Sorry, can't condition console terminal\n");
512: return(0);
513: }
514: debug(F101,"connect cmask","",cmask);
515: debug(F101,"connect cmdmsk","",cmdmsk);
516: goterr = 0;
517: if ((n = ttvt(speed,flow)) < 0) { /* Enter "virtual terminal" mode */
518: debug(F101,"CONNECT ttvt","",n);
519: goterr = 1; /* Error recovery... */
520: tthang(); /* Hang up and close the device. */
521: ttclos(0);
522: if (ttopen(ttname, /* Open it again... */
523: &local,
524: network ? -nettype : mdmtyp,
525: 0
526: ) < 0) {
527: sprintf(temp,"Sorry, can't reopen %s",ttname);
528: perror(temp);
529: return(0);
530: }
531: if (ttvt(speed,flow) < 0) { /* Try virtual terminal mode again. */
532: conres(); /* Failure this time is fatal. */
533: printf("Sorry, Can't condition communication line\n");
534: return(0);
535: }
536: #ifdef NETCONN
537: if (network && ttnproto == NP_TELNET)
538: tn_ini(); /* Just in case ttopen didn't... */
539: #endif /* NETCONN */
540: }
541: debug(F101,"connect ttvt ok, escape","",escape);
542:
543: #ifndef NOCSETS
544: /* Set up character set translations */
545:
546: tcs = gettcs(tcsr,tcsl); /* Get intermediate set. */
547:
548: if (tcsr == tcsl) { /* Remote and local sets the same? */
549: sxo = rxo = NULL; /* If so, no translation. */
550: sxi = rxi = NULL;
551: } else { /* Otherwise, set up */
552: sxo = xls[tcs][tcsl]; /* translation function */
553: rxo = xlr[tcs][tcsr]; /* pointers for output functions */
554: sxi = xls[tcs][tcsr]; /* and for input functions. */
555: rxi = xlr[tcs][tcsl];
556: }
557: /*
558: This is to prevent use of zmstuff() and zdstuff() by translation functions.
559: They only work with disk i/o, not with communication i/o. Luckily Russian
560: translation functions don't do any stuffing...
561: */
562: langsv = language;
563: #ifndef NOCYRIL
564: if (language != L_RUSSIAN)
565: #endif /* NOCYRIL */
566: language = L_USASCII;
567:
568: #ifdef SKIPESC
569: /*
570: We need to activate the "skip escape sequence" feature when:
571: (a) translation is elected, and
572: (b) the local and/or remote set is a 7-bit set other than US ASCII.
573: */
574: skipesc = (tcs != TC_TRANSP) && /* Not transparent */
575: (fcsinfo[tcsl].size == 128 || fcsinfo[tcsr].size == 128) && /* 7 bits */
576: (fcsinfo[tcsl].code != FC_USASCII); /* But not ASCII */
577: inesc = ES_NORMAL; /* Initial state of recognizer */
578: #ifdef COMMENT
579: debug(F101,"tcs","",tcs);
580: debug(F101,"tcsl","",tcsl);
581: debug(F101,"tcsr","",tcsr);
582: debug(F101,"fcsinfo[tcsl].size","",fcsinfo[tcsl].size);
583: debug(F101,"fcsinfo[tcsr].size","",fcsinfo[tcsr].size);
584: #endif /* COMMENT */
585: debug(F101,"skipesc","",skipesc);
586: #endif /* SKIPESC */
587: #endif /* NOCSETS */
588:
589: /*
590: This is a label we jump back to when the lower fork sensed the need
591: to change modes. As of 5A(178), this is used only by X.25 code
592: (perhaps unnecessarily? -- The X.25 code needs a lot of testing and
593: cleaning up...)
594: */
595: newfork:
596: debug(F100,"CONNECT newfork","",0);
597: parent_id = getpid(); /* Get parent id for signalling */
598: signal(SIGUSR1,SIG_IGN); /* Don't kill myself */
599: #ifdef SUNX25
600: pipe(padpipe); /* Create pipe to pass PAD parms */
601: #endif /* SUNX25 */
602: pid = fork(); /* All ok, make a fork */
603: if (pid == (PID_T) -1) { /* Can't create it. */
604: conres(); /* Reset the console. */
605: perror("Can't create keyboard fork");
606: if (!quiet) {
607: printf("\r\nCommunications disconnect (Back at %s)\r\n",
608: *myhost ?
609: myhost :
610: #ifdef COHERENT
611: "Local COHERENT system"
612: #else
613: #endif /* COHERENT */
614:
615: #ifdef UNIX
616: "local UNIX system"
617: #else
618: "local system"
619: #endif /* UNIX */
620: );
621: }
622: printf("\n");
623: what = W_NOTHING; /* So console modes are set right. */
624: #ifndef NOCSETS
625: language = langsv; /* Restore language */
626: #endif /* NOCSETS */
627: parent_id = (PID_T) 0; /* Clean up */
628: #ifdef DYNAMIC
629: if (temp) free(temp); /* Free allocated memory */
630: if (ibuf) free(ibuf);
631: if (obuf) free(obuf);
632: #endif /* DYNAMIC */
633: return(1);
634: }
635: if (pid) { /* Top fork reads, sends keystrokes */
636: what = W_CONNECT; /* Keep track of what we're doing */
637: active = 1;
638: debug(F101,"CONNECT keyboard fork duplex","",duplex);
639:
640: /* Catch communication errors or mode changes in lower fork */
641:
642: if (setjmp(con_env) == 0) { /* Normal entry... */
643: sjval = 0; /* Initialize setjmp return code. */
644: signal(SIGUSR1,conn_int); /* Routine for child process exit. */
645: signal(SIGUSR2,mode_chg); /* Routine for mode change. */
646: #ifdef SUNX25
647: if (network && nettype == NET_SX25) {
648: obufl = 0;
649: bzero (x25obuf,sizeof(x25obuf)) ;
650: }
651: #endif /* SUNX25 */
652:
653: /*
654: Here is the big loop that gets characters from the keyboard and sends them
655: out the communication device. There are two components to the communication
656: path: the connection from the keyboard to C-Kermit, and from C-Kermit to
657: the remote computer. The treatment of the 8th bit of keyboard characters
658: is governed by SET COMMAND BYTESIZE (cmdmsk). The treatment of the 8th bit
659: of characters sent to the remote is governed by SET TERMINAL BYTESIZE
660: (cmask). This distinction was introduced in edit 5A(164).
661: */
662: while (active) {
663: #ifndef NOSETKEY
664: if (kmptr) { /* Have current macro? */
665: debug(F100,"kmptr non NULL","",0);
666: if ((c = (CHAR) *kmptr++) == NUL) { /* Get char from it */
667: kmptr = NULL; /* If no more chars, */
668: debug(F100,"macro empty, continuing","",0);
669: continue; /* reset pointer and continue */
670: }
671: debug(F000,"char from macro","",c);
672: } else /* No macro... */
673: #endif /* NOSETKEY */
674: c = congks(0); /* Read from keyboard */
675:
676: debug(F111,"** KEYB",dbchr(c),c);
677:
678: if (c == -1) { /* If read() got an error... */
679: #ifdef COMMENT
680: /*
681: This seems to cause problems. If read() returns -1, the signal has already
682: been delivered, and nothing will wake up the pause().
683: */
684: pause(); /* Wait for transmitter to finish. */
685: #else
686: #ifdef A986
687: /*
688: On Altos machines with Xenix 3.0, pressing DEL in connect mode brings us
689: here (reason unknown). The console line discipline at this point has
690: intr = ^C. The communications tty has intr = DEL but we get here after
691: pressing DEL on the keyboard, even when the remote system has been set not
692: to echo. With A986 defined, we stay in the read loop and beep only if the
693: offending character is not DEL.
694: */
695: if ((c & 127) != 127) conoc(BEL);
696: #else
697: conoc(BEL); /* Beep */
698: active = 0; /* and terminate the read loop */
699: continue;
700: #endif /* A986 */
701: #endif /* COMMENT */
702: }
703: c &= cmdmsk; /* Do any requested masking */
704: #ifndef NOSETKEY
705: /*
706: Note: kmptr is NULL if we got character c from the keyboard, and it is
707: not NULL if it came from a macro. In the latter case, we must avoid
708: expanding it again.
709: */
710: if (!kmptr && macrotab[c]) { /* Macro definition for c? */
711: kmptr = macrotab[c]; /* Yes, set up macro pointer */
712: continue; /* and restart the loop, */
713: } else c = keymap[c]; /* else use single-char keymap */
714: #endif /* NOSETKEY */
715: if (
716: #ifndef NOSETKEY
717: !kmptr &&
718: #endif /* NOSETKEY */
719: ((c & 0x7f) == escape)) { /* Escape character? */
720: debug(F000,"connect got escape","",c);
721: c = congks(0) & 0177; /* Got esc, get its arg */
722: /* No key mapping here */
723: doesc((char) c); /* Now process it */
724:
725: } else { /* It's not the escape character */
726: csave = c; /* Save it before translation */
727: /* for local echoing. */
728: #ifndef NOCSETS
729: #ifndef SKIPESC
730: /* Translate character sets */
731: if (sxo) c = (*sxo)(c); /* From local to intermediate. */
732: if (rxo) c = (*rxo)(c); /* From intermediate to remote. */
733: #else
734: if (inesc == ES_NORMAL) { /* If not inside escape seq.. */
735: /* Translate character sets */
736: if (sxo) c = (*sxo)((char)c); /* Local-intermediate */
737: if (rxo) c = (*rxo)((char)c); /* Intermediate-remote */
738: }
739: if (skipesc) chkaes((char)c); /* Check escape seq status */
740: #endif /* SKIPESC */
741: #endif /* NOCSETS */
742: /*
743: If Shift-In/Shift-Out is selected and we have a 7-bit connection,
744: handle shifting here.
745: */
746: if (sosi) { /* Shift-In/Out selected? */
747: if (cmask == 0177) { /* In 7-bit environment? */
748: if (c & 0200) { /* 8-bit character? */
749: if (outshift == 0) { /* If not shifted, */
750: ttoc(dopar(SO)); /* shift. */
751: outshift = 1;
752: }
753: } else {
754: if (outshift == 1) { /* 7-bit character */
755: ttoc(dopar(SI)); /* If shifted, */
756: outshift = 0; /* unshift. */
757: }
758: }
759: }
760: if (c == SO) outshift = 1; /* User typed SO */
761: if (c == SI) outshift = 0; /* User typed SI */
762: }
763: c &= cmask; /* Apply Kermit-to-host mask now. */
764: #ifdef SUNX25
765: if (network && nettype == NET_SX25) {
766: if (padparms[PAD_ECHO]) {
767: if (debses)
768: conol(dbchr(c)) ;
769: else
770: if ((c != padparms[PAD_CHAR_DELETE_CHAR]) &&
771: (c != padparms[PAD_BUFFER_DELETE_CHAR]) &&
772: (c != padparms[PAD_BUFFER_DISPLAY_CHAR]))
773: conoc(c) ;
774: if (seslog) logchar(c);
775: }
776: if (c == CR && (padparms[PAD_LF_AFTER_CR] == 4 ||
777: padparms[PAD_LF_AFTER_CR] == 5)) {
778: if (debses)
779: conol(dbchr(LF)) ;
780: else
781: conoc(LF) ;
782: if (seslog) logchar(LF);
783: }
784: if (c == padparms[PAD_BREAK_CHARACTER])
785: breakact();
786: else if (padparms[PAD_DATA_FORWARD_TIMEOUT]) {
787: tosend = 1;
788: x25obuf [obufl++] = c;
789: } else if (((c == padparms[PAD_CHAR_DELETE_CHAR]) ||
790: (c == padparms[PAD_BUFFER_DELETE_CHAR]) ||
791: (c == padparms[PAD_BUFFER_DISPLAY_CHAR]))
792: && (padparms[PAD_EDITING]))
793: if (c == padparms[PAD_CHAR_DELETE_CHAR])
794: if (obufl > 0) {
795: conol("\b \b"); obufl--;
796: } else {}
797: else if (c == padparms[PAD_BUFFER_DELETE_CHAR]) {
798: conol ("\r\nPAD Buffer Deleted\r\n");
799: obufl = 0;
800: }
801: else if (c == padparms[PAD_BUFFER_DISPLAY_CHAR]) {
802: conol("\r\n");
803: conol(x25obuf);
804: conol("\r\n");
805: } else {}
806: else {
807: x25obuf [obufl++] = c;
808: if (obufl == MAXOX25) tosend = 1;
809: else if (c == CR) tosend = 1;
810: }
811: if (tosend)
812: if (ttol(x25obuf,obufl) < 0) {
813: perror ("\r\nCan't send characters");
814: active = 0;
815: } else {
816: bzero (x25obuf,sizeof(x25obuf));
817: obufl = 0;
818: tosend = 0;
819: } else {};
820: } else {
821: #endif /* SUNX25 */
822:
823: /* If we have a CR, handle CR/CRLF mapping... */
824:
825: if (c == '\015') {
826: if (tnlm /* TERMINAL NEWLINE ON */
827: #ifdef TNCODE /* And for TELNET... */
828: || (network && ttnproto == NP_TELNET)
829: #endif /* TNCODE */
830: ) {
831: ttoc(dopar('\015')); /* Send CR */
832: if (duplex) conoc('\015'); /* Maybe echo CR */
833: #ifdef TNCODE
834: if (network && !tn_nlm && ttnproto == NP_TELNET)
835: c = '\0'; /* Stuff NUL */
836: else
837: #endif /* TNCODE */
838: c = '\012'; /* Stuff LF */
839: csave = c;
840: }
841: } /* Now process the LF or NUL... */
842: #ifdef TNCODE
843: /* If user types the 0xff character (TELNET IAC), it must be doubled. */
844: else
845: if (c == IAC && network && ttnproto == NP_TELNET) {
846: /* Send one copy now */
847: ttoc((char)IAC); /* and the other one just below. */
848: }
849: #endif /* TNCODE */
850:
851: /* Send the character */
852:
853: if (ttoc((char)dopar((CHAR) c)) > -1) {
854: if (duplex) { /* If half duplex, must echo */
855: if (debses)
856: conol(dbchr(csave)); /* the original char */
857: else /* not the translated one */
858: conoc((char)csave);
859: if (seslog) { /* And maybe log it too */
860: c2 = csave;
861: if (sessft == 0 && csave == '\r')
862: c2 = '\n';
863: logchar((char)c2);
864: }
865: }
866: } else {
867: perror("\r\nCan't send character");
868: active = 0;
869: }
870: #ifdef SUNX25
871: }
872: #endif /* SUNX25 */
873: }
874: }
875: } /* Come here on death of child */
876: debug(F100,"CONNECT killing port fork","",0);
877: kill(pid,9); /* Done, kill inferior fork. */
878: wait((WAIT_T *)0); /* Wait till gone. */
879: if (sjval == 1) { /* Read error on comm device */
880: dohangup = 1;
881: #ifdef NETCONN
882: if (network) {
883: ttclos(0);
884: #ifdef SUNX25
885: if (nettype == NET_SX25) initpad();
886: #endif /* SUNX25 */
887: }
888: #endif /* NETCONN */
889: }
890: if (sjval == 2) /* If it was a mode change, go back */
891: goto newfork; /* and coordinate with other fork. */
892: conres(); /* Reset the console. */
893: if (quitnow) doexit(GOOD_EXIT,xitsta); /* Exit now if requested. */
894: if (dohangup > 0) { /* If hangup requested, do that. */
895: #ifndef NODIAL
896: if (dohangup > 1) /* User asked for it */
897: if (mdmhup() < 1) /* Maybe hang up via modem */
898: #endif /* NODIAL */
899: tthang(); /* And make sure we don't hang up */
900: dohangup = 0; /* again unless requested again. */
901: }
902: #ifdef SUNX25
903: if (dox25clr) { /* If X.25 clear requested */
904: x25clear(); /* do that. */
905: initpad();
906: dox25clr = 0; /* But only once. */
907: }
908: #endif /* SUNX25 */
909: if (!quiet)
910: #ifdef COHERENT
911: printf("(Back at %s)", *myhost ? myhost : "local COHERENT system");
912: #else
913: printf("(Back at %s)", *myhost ? myhost : "local UNIX system");
914: #endif /* COHERENT */
915: printf("\n");
916: what = W_NOTHING; /* So console modes set right. */
917: #ifndef NOCSETS
918: language = langsv; /* Restore language */
919: #endif /* NOCSETS */
920: parent_id = (PID_T) 0;
921: #ifdef DYNAMIC
922: if (temp) free(temp); /* Free allocated memory */
923: if (ibuf) free(ibuf);
924: if (obuf) free(obuf);
925: #endif /* DYNAMIC */
926: return(1);
927:
928: } else { /* Inferior reads, prints port input */
929:
930: #ifndef OXOS
931: if (priv_can()) { /* Cancel all privs */
932: printf("?setuid error - fatal\n");
933: doexit(BAD_EXIT,-1);
934: }
935: #endif /* OXOS */
936: signal(SIGINT, SIG_IGN); /* In case these haven't been */
937: signal(SIGQUIT, SIG_IGN); /* inherited from above... */
938:
939: inshift = outshift = 0; /* Initial SO/SI shift state. */
940: sleep(1); /* Wait for parent's handler setup. */
941: ibp = ibuf; /* Initialize input buffering */
942: ibc = 0; /* And output buffering. */
943: obp = obuf;
944: obc = 0;
945: debug(F100,"CONNECT starting port fork","",0);
946: while (1) { /* Fresh read, wait for a character. */
947: #ifdef SUNX25
948: if (network && (nettype == NET_SX25)) {
949: bzero(x25ibuf,sizeof(x25ibuf)) ;
950: if ((ibufl = ttxin(MAXIX25,x25ibuf)) < 0) {
951: if (ibufl == -2) { /* PAD parms changes */
952: write(padpipe[1],padparms,MAXPADPARMS);
953: kill(parent_id,SIGUSR2);
954: } else {
955: if (!quiet)
956: printf("\r\nCommunications disconnect ");
957: kill(parent_id,SIGUSR1);
958: }
959: pause();
960: }
961: if (debses) { /* Debugging output */
962: p = x25ibuf ;
963: while (ibufl--) { c = *p++; conol(dbchr(c)); }
964: } else {
965: if (sosi
966: #ifndef NOCSETS
967: || tcsl != tcsr
968: #endif /* NOCSETS */
969: ) { /* Character at a time */
970: for (i = 1; i < ibufl; i++) {
971: c = x25ibuf[i] & cmask;
972: if (sosi) { /* Handle SI/SO */
973: if (c == SO) {
974: inshift = 1;
975: continue;
976: } else if (c == SI) {
977: inshift = 0;
978: continue;
979: }
980: if (inshift)
981: c |= 0200;
982: }
983: #ifndef NOCSETS
984: #ifndef SKIPESC
985: /* Translate character sets */
986: if (sxo) c = (*sxo)(c); /* From local to intermediate. */
987: if (rxo) c = (*rxo)(c); /* From intermediate to remote. */
988:
989: #else /* Skipping escape sequences... */
990:
991: if (inesc == ES_NORMAL) { /* If not inside escape seq.. */
992: /* Translate character sets */
993: if (sxo) c = (*sxo)(c); /* Local to intermediate. */
994: if (rxo) c = (*rxo)(c); /* Intermediate to remote. */
995: }
996: if (skipesc) chkaes(c); /* Check escape sequence status */
997: #endif /* SKIPESC */
998: #endif /* NOCSETS */
999: c &= cmdmsk; /* Apply command mask. */
1000: conoc(c); /* Output to screen */
1001: logchar(c); /* and session log */
1002: }
1003: } else { /* All at once */
1004: for (i = 1; i < ibufl; i++)
1005: x25ibuf[i] &= (cmask & cmdmsk);
1006: conxo(ibufl,x25ibuf);
1007: if (seslog) zsoutx(ZSFILE,x25ibuf,ibufl);
1008: }
1009: }
1010: continue;
1011:
1012: } else { /* Not X.25... */
1013: #endif /* SUNX25 */
1014: /*
1015: Get the next communication line character from our internal buffer.
1016: If the buffer is empty, refill it.
1017: */
1018: c = ckcgetc(0); /* Get next character */
1019: /* debug(F101,"CONNECT c","",c); */
1020: if (c < 0) {
1021: if (!quiet) { /* Failed... */
1022: printf("\r\nCommunications disconnect ");
1023: if ( c == -3
1024: #ifdef UTEK
1025: /* This happens on UTEK if there's no carrier */
1026: && errno != EWOULDBLOCK
1027: #endif /* UTEK */
1028: )
1029: perror("\r\nCan't read character");
1030: }
1031: tthang(); /* Hang up the connection */
1032: kill(parent_id,SIGUSR1); /* Notify parent */
1033: for (;;) pause(); /* and wait to be killed */
1034: }
1035: debug(F111,"** PORT",dbchr(c),c);
1036: #ifdef TNCODE
1037: /* Handle TELNET negotiations here */
1038: if (c == IAC && network && ttnproto == NP_TELNET) {
1039: ckcputf(); /* Dump output buffer */
1040: if ((tx = tn_doop((CHAR)(c & 0xff),duplex,ckcgetc)) == 0) {
1041: continue;
1042: } else if (tx == -1) { /* I/O error */
1043: if (!quiet)
1044: printf("\r\nCommunications disconnect ");
1045: kill(parent_id,SIGUSR1); /* Notify parent. */
1046: for (;;) pause(); /* Wait to be killed. */
1047: } else if ((tx == 1) && (!duplex)) { /* ECHO change */
1048: kill(parent_id,SIGUSR2); /* Tell the parent fork */
1049: duplex = 1;
1050: } else if ((tx == 2) && (duplex)) { /* ECHO change */
1051: kill(parent_id,SIGUSR2);
1052: duplex = 0;
1053: } else if (tx == 3) { /* Quoted IAC */
1054: c = 255;
1055: } else continue; /* Negotiation OK, get next char. */
1056: }
1057: #endif /* TNCODE */
1058: if (debses) { /* Output character to screen */
1059: char *s; /* Debugging display... */
1060: s = dbchr(c);
1061: while (*s)
1062: ckcputc(*s++);
1063: } else { /* Regular display ... */
1064: c &= cmask; /* Apply Kermit-to-remote mask */
1065: if (sosi) { /* Handle SI/SO */
1066: if (c == SO) { /* Shift Out */
1067: inshift = 1;
1068: continue;
1069: } else if (c == SI) { /* Shift In */
1070: inshift = 0;
1071: continue;
1072: }
1073: if (inshift) c |= 0200;
1074: }
1075: #ifndef NOCSETS
1076: #ifndef SKIPESC
1077: /* Translate character sets */
1078: if (sxi) c = (*sxi)((CHAR)c);
1079: if (rxi) c = (*rxi)((CHAR)c);
1080: #else
1081: if (inesc == ES_NORMAL) {
1082: /* Translate character sets */
1083: if (sxi) c = (*sxi)((CHAR)c);
1084: if (rxi) c = (*rxi)((CHAR)c);
1085: }
1086: /* Adjust escape sequence status */
1087: if (skipesc) chkaes((char)c);
1088: #endif /* SKIPESC */
1089: #endif /* NOCSETS */
1090: c &= cmdmsk; /* Apply command mask. */
1091: if (c == CR && tt_crd) { /* SET TERM CR-DISPLAY CRLF ? */
1092: ckcputc(c); /* Yes, output CR */
1093: if (seslog) logchar((char)c);
1094: c = LF; /* and insert a linefeed */
1095: }
1096: ckcputc(c); /* Output character to screen */
1097: if (seslog) logchar((char)c); /* Do session log */
1098: }
1099: #ifdef SUNX25
1100: }
1101: #endif /* SUNX25 */
1102: }
1103: }
1104: }
1105:
1106:
1107: /* H C O N N E -- Give help message for connect. */
1108:
1109: int
1110: hconne() {
1111: int c;
1112: static char *hlpmsg[] = {
1113: "\r\n ? for this message",
1114: "\r\n 0 (zero) to send a null",
1115: "\r\n B to send a BREAK",
1116: #ifdef CK_LBRK
1117: "\r\n L to send a Long BREAK",
1118: #endif /* CK_LBRK */
1119: #ifdef NETCONN
1120: "\r\n I to send a network interrupt packet",
1121: #ifdef TCPSOCKET
1122: "\r\n A to send Are You There?",
1123: #endif /* TCPSOCKET */
1124: #ifdef SUNX25
1125: "\r\n R to reset X.25 virtual circuit",
1126: #endif /* SUNX25 */
1127: #endif /* NETCONN */
1128: "\r\n H to hangup and close the connection",
1129: "\r\n Q to hangup and quit Kermit",
1130: "\r\n S for status",
1131: "\r\n ! to push to local shell",
1132: "\r\n Z to suspend",
1133: "\r\n \\ backslash code:",
1134: "\r\n \\nnn decimal character code",
1135: "\r\n \\Onnn octal character code",
1136: "\r\n \\Xhh hexadecimal character code",
1137: "\r\n terminate with carriage return.",
1138: "\r\n Type the escape character again to send the escape character, or",
1139: "\r\n press the space-bar to resume the CONNECT command.\r\n\r\n",
1140: "" };
1141: conol("\r\nPress C to return to ");
1142: conol(*myhost ? myhost : "the C-Kermit prompt");
1143: conol(", or:");
1144: conola(hlpmsg); /* Print the help message. */
1145: conol("Command>"); /* Prompt for command. */
1146: c = congks(0) & 0177; /* Get character, strip any parity. */
1147: /* No key mapping or translation here */
1148: if (c != CMDQ)
1149: conoll("");
1150: return(c); /* Return it. */
1151: }
1152:
1153:
1154: /* D O E S C -- Process an escape character argument */
1155:
1156: VOID
1157: #ifdef CK_ANSIC
1158: doesc(char c)
1159: #else
1160: doesc(c) char c;
1161: #endif /* CK_ANSIC */
1162: /* doesc */ {
1163: CHAR d;
1164:
1165: while (1) {
1166: if (c == escape) { /* Send escape character */
1167: d = dopar((CHAR) c); ttoc((char) d); return;
1168: } else /* Or else look it up below. */
1169: if (isupper(c)) c = tolower(c);
1170:
1171: switch(c) {
1172:
1173: case 'c': /* Escape back to prompt */
1174: case '\03':
1175: active = 0; conol("\r\n"); return;
1176:
1177: case 'b': /* Send a BREAK signal */
1178: case '\02':
1179: ttsndb(); return;
1180:
1181: #ifdef NETCONN
1182: case 'i': /* Send Interrupt */
1183: case '\011':
1184: #ifdef TCPSOCKET
1185: #ifndef IP
1186: #define IP 244
1187: #endif /* IP */
1188: if (network && ttnproto == NP_TELNET) { /* TELNET */
1189: temp[0] = IAC; /* I Am a Command */
1190: temp[1] = IP; /* Interrupt Process */
1191: temp[2] = NUL;
1192: ttol((CHAR *)temp,2);
1193: } else
1194: #endif /* TCPSOCKET */
1195: #ifdef SUNX25
1196: if (network && (nettype == NET_SX25)) { /* X.25 */
1197: (VOID) x25intr(0); /* X.25 interrupt packet */
1198: conol("\r\n");
1199: } else
1200: #endif /* SUNX25 */
1201: conoc(BEL);
1202: return;
1203:
1204: #ifdef TCPSOCKET
1205: case 'a': /* "Are You There?" */
1206: case '\01':
1207: #ifndef AYT
1208: #define AYT 246
1209: #endif /* AYT */
1210: if (network && ttnproto == NP_TELNET) {
1211: temp[0] = IAC; /* I Am a Command */
1212: temp[1] = AYT; /* Are You There? */
1213: temp[2] = NUL;
1214: ttol((CHAR *)temp,2);
1215: } else conoc(BEL);
1216: return;
1217: #endif /* TCPSOCKET */
1218: #endif /* NETCONN */
1219:
1220: #ifdef CK_LBRK
1221: case 'l': /* Send a Long BREAK signal */
1222: ttsndlb(); return;
1223: #endif /* CK_LBRK */
1224:
1225: case 'h': /* Hangup */
1226: case '\010':
1227: #ifdef SUNX25
1228: if (network && (nettype == NET_SX25)) dox25clr = 1;
1229: else
1230: #endif /* SUNX25 */
1231: dohangup = 2; active = 0; conol("\r\nHanging up "); return;
1232:
1233: #ifdef SUNX25
1234: case 'r': /* Reset the X.25 virtual circuit */
1235: case '\022':
1236: if (network && (nettype == NET_SX25)) (VOID) x25reset();
1237: conol("\r\n"); return;
1238: #endif /* SUNX25 */
1239:
1240: case 'q': /* Quit */
1241: quitnow = 1; active = 0; conol("\r\n"); return;
1242:
1243: case 's': /* Status */
1244: sprintf(temp,
1245: "\r\nConnected %s %s", network ? "to" : "through", ttname);
1246: conol(temp);
1247: #ifdef SUNX25
1248: if (network && (nettype == NET_SX25)) {
1249: sprintf(temp,", Link ID %d, LCN %d",linkid,lcn); conol(temp);
1250: }
1251: #endif /* SUNX25 */
1252: if (speed >= 0L) {
1253: sprintf(temp,", speed %ld", speed);
1254: conoll(temp);
1255: } else conoll("");
1256: sprintf(temp,
1257: "Terminal bytesize: %d, Command bytesize: %d, Parity: ",
1258: (cmask == 0177) ? 7 : 8,
1259: (cmdmsk == 0177) ? 7 : 8 );
1260: conol(temp);
1261:
1262: switch (parity) {
1263: case 0: conoll("none"); break;
1264: case 'e': conoll("even"); break;
1265: case 'o': conoll("odd"); break;
1266: case 's': conoll("space"); break;
1267: case 'm': conoll("mark"); break;
1268: }
1269: sprintf(temp,"Terminal echo: %s", duplex ? "local" : "remote");
1270: conoll(temp);
1271: if (seslog) {
1272: conol("Logging to: "); conoll(sesfil);
1273: }
1274: if (!network) shomdm();
1275: return;
1276:
1277: case '?': /* Help */
1278: c = hconne(); continue;
1279:
1280: case '0': /* Send a null */
1281: c = '\0'; d = dopar((CHAR) c); ttoc((char) d); return;
1282:
1283: #ifndef NOPUSH
1284: case 'z': case '\032': /* Suspend */
1285: stptrap(0); return;
1286:
1287: case '@': /* Start inferior command processor */
1288: case '!':
1289: conres(); /* Put console back to normal */
1290: zshcmd(""); /* Fork a shell. */
1291: if (conbin((char)escape) < 0) {
1292: printf("Error resuming CONNECT session\n");
1293: active = 0;
1294: }
1295: return;
1296: #endif /* NOPUSH */
1297:
1298: case SP: /* Space, ignore */
1299: return;
1300:
1301: default: /* Other */
1302: if (c == CMDQ) { /* Backslash escape */
1303: int x;
1304: kbp = kbuf;
1305: *kbp++ = c;
1306: while (((c = (congks(0) & cmdmsk)) != '\r') && (c != '\n'))
1307: *kbp++ = c;
1308: *kbp = NUL; kbp = kbuf;
1309: x = xxesc(&kbp); /* Interpret it */
1310: if (x >= 0) { /* No key mapping here */
1311: c = dopar((CHAR) x);
1312: ttoc((char) c);
1313: return;
1314: } else { /* Invalid backslash code. */
1315: conoc(BEL);
1316: return;
1317: }
1318: }
1319: conoc(BEL); return; /* Invalid esc arg, beep */
1320: }
1321: }
1322: }
1323:
1324: VOID
1325: #ifdef CK_ANSIC
1326: logchar(char c)
1327: #else
1328: logchar(c) char c;
1329: #endif /* CK_ANSIC */
1330: /* logchar */ { /* Log character c to session log */
1331: if (seslog)
1332: if ((sessft != 0) ||
1333: (c != '\r' &&
1334: c != '\0' &&
1335: c != XON &&
1336: c != XOFF))
1337: if (zchout(ZSFILE,c) < 0) {
1338: conoll("");
1339: conoll("ERROR WRITING SESSION LOG, LOG CLOSED!");
1340: seslog = 0;
1341: }
1342: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.