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 (fdc@columbia.edu, FDCCU@CUVMA.BITNET), 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 UNIX 611: "local UNIX system" 612: #else 613: "local system" 614: #endif /* UNIX */ 615: ); 616: } 617: printf("\n"); 618: what = W_NOTHING; /* So console modes are set right. */ 619: #ifndef NOCSETS 620: language = langsv; /* Restore language */ 621: #endif /* NOCSETS */ 622: parent_id = (PID_T) 0; /* Clean up */ 623: #ifdef DYNAMIC 624: if (temp) free(temp); /* Free allocated memory */ 625: if (ibuf) free(ibuf); 626: if (obuf) free(obuf); 627: #endif /* DYNAMIC */ 628: return(1); 629: } 630: if (pid) { /* Top fork reads, sends keystrokes */ 631: what = W_CONNECT; /* Keep track of what we're doing */ 632: active = 1; 633: debug(F101,"CONNECT keyboard fork duplex","",duplex); 634: 635: /* Catch communication errors or mode changes in lower fork */ 636: 637: if (setjmp(con_env) == 0) { /* Normal entry... */ 638: sjval = 0; /* Initialize setjmp return code. */ 639: signal(SIGUSR1,conn_int); /* Routine for child process exit. */ 640: signal(SIGUSR2,mode_chg); /* Routine for mode change. */ 641: #ifdef SUNX25 642: if (network && nettype == NET_SX25) { 643: obufl = 0; 644: bzero (x25obuf,sizeof(x25obuf)) ; 645: } 646: #endif /* SUNX25 */ 647: 648: /* 649: Here is the big loop that gets characters from the keyboard and sends them 650: out the communication device. There are two components to the communication 651: path: the connection from the keyboard to C-Kermit, and from C-Kermit to 652: the remote computer. The treatment of the 8th bit of keyboard characters 653: is governed by SET COMMAND BYTESIZE (cmdmsk). The treatment of the 8th bit 654: of characters sent to the remote is governed by SET TERMINAL BYTESIZE 655: (cmask). This distinction was introduced in edit 5A(164). 656: */ 657: while (active) { 658: #ifndef NOSETKEY 659: if (kmptr) { /* Have current macro? */ 660: debug(F100,"kmptr non NULL","",0); 661: if ((c = (CHAR) *kmptr++) == NUL) { /* Get char from it */ 662: kmptr = NULL; /* If no more chars, */ 663: debug(F100,"macro empty, continuing","",0); 664: continue; /* reset pointer and continue */ 665: } 666: debug(F000,"char from macro","",c); 667: } else /* No macro... */ 668: #endif /* NOSETKEY */ 669: c = congks(0); /* Read from keyboard */ 670: 671: debug(F111,"** KEYB",dbchr(c),c); 672: 673: if (c == -1) { /* If read() got an error... */ 674: #ifdef COMMENT 675: /* 676: This seems to cause problems. If read() returns -1, the signal has already 677: been delivered, and nothing will wake up the pause(). 678: */ 679: pause(); /* Wait for transmitter to finish. */ 680: #else 681: #ifdef A986 682: /* 683: On Altos machines with Xenix 3.0, pressing DEL in connect mode brings us 684: here (reason unknown). The console line discipline at this point has 685: intr = ^C. The communications tty has intr = DEL but we get here after 686: pressing DEL on the keyboard, even when the remote system has been set not 687: to echo. With A986 defined, we stay in the read loop and beep only if the 688: offending character is not DEL. 689: */ 690: if ((c & 127) != 127) conoc(BEL); 691: #else 692: conoc(BEL); /* Beep */ 693: active = 0; /* and terminate the read loop */ 694: continue; 695: #endif /* A986 */ 696: #endif /* COMMENT */ 697: } 698: c &= cmdmsk; /* Do any requested masking */ 699: #ifndef NOSETKEY 700: /* 701: Note: kmptr is NULL if we got character c from the keyboard, and it is 702: not NULL if it came from a macro. In the latter case, we must avoid 703: expanding it again. 704: */ 705: if (!kmptr && macrotab[c]) { /* Macro definition for c? */ 706: kmptr = macrotab[c]; /* Yes, set up macro pointer */ 707: continue; /* and restart the loop, */ 708: } else c = keymap[c]; /* else use single-char keymap */ 709: #endif /* NOSETKEY */ 710: if ( 711: #ifndef NOSETKEY 712: !kmptr && 713: #endif /* NOSETKEY */ 714: ((c & 0x7f) == escape)) { /* Escape character? */ 715: debug(F000,"connect got escape","",c); 716: c = congks(0) & 0177; /* Got esc, get its arg */ 717: /* No key mapping here */ 718: doesc((char) c); /* Now process it */ 719: 720: } else { /* It's not the escape character */ 721: csave = c; /* Save it before translation */ 722: /* for local echoing. */ 723: #ifndef NOCSETS 724: #ifndef SKIPESC 725: /* Translate character sets */ 726: if (sxo) c = (*sxo)(c); /* From local to intermediate. */ 727: if (rxo) c = (*rxo)(c); /* From intermediate to remote. */ 728: #else 729: if (inesc == ES_NORMAL) { /* If not inside escape seq.. */ 730: /* Translate character sets */ 731: if (sxo) c = (*sxo)((char)c); /* Local-intermediate */ 732: if (rxo) c = (*rxo)((char)c); /* Intermediate-remote */ 733: } 734: if (skipesc) chkaes((char)c); /* Check escape seq status */ 735: #endif /* SKIPESC */ 736: #endif /* NOCSETS */ 737: /* 738: If Shift-In/Shift-Out is selected and we have a 7-bit connection, 739: handle shifting here. 740: */ 741: if (sosi) { /* Shift-In/Out selected? */ 742: if (cmask == 0177) { /* In 7-bit environment? */ 743: if (c & 0200) { /* 8-bit character? */ 744: if (outshift == 0) { /* If not shifted, */ 745: ttoc(dopar(SO)); /* shift. */ 746: outshift = 1; 747: } 748: } else { 749: if (outshift == 1) { /* 7-bit character */ 750: ttoc(dopar(SI)); /* If shifted, */ 751: outshift = 0; /* unshift. */ 752: } 753: } 754: } 755: if (c == SO) outshift = 1; /* User typed SO */ 756: if (c == SI) outshift = 0; /* User typed SI */ 757: } 758: c &= cmask; /* Apply Kermit-to-host mask now. */ 759: #ifdef SUNX25 760: if (network && nettype == NET_SX25) { 761: if (padparms[PAD_ECHO]) { 762: if (debses) 763: conol(dbchr(c)) ; 764: else 765: if ((c != padparms[PAD_CHAR_DELETE_CHAR]) && 766: (c != padparms[PAD_BUFFER_DELETE_CHAR]) && 767: (c != padparms[PAD_BUFFER_DISPLAY_CHAR])) 768: conoc(c) ; 769: if (seslog) logchar(c); 770: } 771: if (c == CR && (padparms[PAD_LF_AFTER_CR] == 4 || 772: padparms[PAD_LF_AFTER_CR] == 5)) { 773: if (debses) 774: conol(dbchr(LF)) ; 775: else 776: conoc(LF) ; 777: if (seslog) logchar(LF); 778: } 779: if (c == padparms[PAD_BREAK_CHARACTER]) 780: breakact(); 781: else if (padparms[PAD_DATA_FORWARD_TIMEOUT]) { 782: tosend = 1; 783: x25obuf [obufl++] = c; 784: } else if (((c == padparms[PAD_CHAR_DELETE_CHAR]) || 785: (c == padparms[PAD_BUFFER_DELETE_CHAR]) || 786: (c == padparms[PAD_BUFFER_DISPLAY_CHAR])) 787: && (padparms[PAD_EDITING])) 788: if (c == padparms[PAD_CHAR_DELETE_CHAR]) 789: if (obufl > 0) { 790: conol("\b \b"); obufl--; 791: } else {} 792: else if (c == padparms[PAD_BUFFER_DELETE_CHAR]) { 793: conol ("\r\nPAD Buffer Deleted\r\n"); 794: obufl = 0; 795: } 796: else if (c == padparms[PAD_BUFFER_DISPLAY_CHAR]) { 797: conol("\r\n"); 798: conol(x25obuf); 799: conol("\r\n"); 800: } else {} 801: else { 802: x25obuf [obufl++] = c; 803: if (obufl == MAXOX25) tosend = 1; 804: else if (c == CR) tosend = 1; 805: } 806: if (tosend) 807: if (ttol(x25obuf,obufl) < 0) { 808: perror ("\r\nCan't send characters"); 809: active = 0; 810: } else { 811: bzero (x25obuf,sizeof(x25obuf)); 812: obufl = 0; 813: tosend = 0; 814: } else {}; 815: } else { 816: #endif /* SUNX25 */ 817: 818: /* If we have a CR, handle CR/CRLF mapping... */ 819: 820: if (c == '\015') { 821: if (tnlm /* TERMINAL NEWLINE ON */ 822: #ifdef TNCODE /* And for TELNET... */ 823: || (network && ttnproto == NP_TELNET) 824: #endif /* TNCODE */ 825: ) { 826: ttoc(dopar('\015')); /* Send CR */ 827: if (duplex) conoc('\015'); /* Maybe echo CR */ 828: #ifdef TNCODE 829: if (network && !tn_nlm && ttnproto == NP_TELNET) 830: c = '\0'; /* Stuff NUL */ 831: else 832: #endif /* TNCODE */ 833: c = '\012'; /* Stuff LF */ 834: csave = c; 835: } 836: } /* Now process the LF or NUL... */ 837: #ifdef TNCODE 838: /* If user types the 0xff character (TELNET IAC), it must be doubled. */ 839: else 840: if (c == IAC && network && ttnproto == NP_TELNET) { 841: /* Send one copy now */ 842: ttoc((char)IAC); /* and the other one just below. */ 843: } 844: #endif /* TNCODE */ 845: 846: /* Send the character */ 847: 848: if (ttoc((char)dopar((CHAR) c)) > -1) { 849: if (duplex) { /* If half duplex, must echo */ 850: if (debses) 851: conol(dbchr(csave)); /* the original char */ 852: else /* not the translated one */ 853: conoc((char)csave); 854: if (seslog) { /* And maybe log it too */ 855: c2 = csave; 856: if (sessft == 0 && csave == '\r') 857: c2 = '\n'; 858: logchar((char)c2); 859: } 860: } 861: } else { 862: perror("\r\nCan't send character"); 863: active = 0; 864: } 865: #ifdef SUNX25 866: } 867: #endif /* SUNX25 */ 868: } 869: } 870: } /* Come here on death of child */ 871: debug(F100,"CONNECT killing port fork","",0); 872: kill(pid,9); /* Done, kill inferior fork. */ 873: wait((WAIT_T *)0); /* Wait till gone. */ 874: if (sjval == 1) { /* Read error on comm device */ 875: dohangup = 1; 876: #ifdef NETCONN 877: if (network) { 878: ttclos(0); 879: #ifdef SUNX25 880: if (nettype == NET_SX25) initpad(); 881: #endif /* SUNX25 */ 882: } 883: #endif /* NETCONN */ 884: } 885: if (sjval == 2) /* If it was a mode change, go back */ 886: goto newfork; /* and coordinate with other fork. */ 887: conres(); /* Reset the console. */ 888: if (quitnow) doexit(GOOD_EXIT,xitsta); /* Exit now if requested. */ 889: if (dohangup > 0) { /* If hangup requested, do that. */ 890: #ifndef NODIAL 891: if (dohangup > 1) /* User asked for it */ 892: if (mdmhup() < 1) /* Maybe hang up via modem */ 893: #endif /* NODIAL */ 894: tthang(); /* And make sure we don't hang up */ 895: dohangup = 0; /* again unless requested again. */ 896: } 897: #ifdef SUNX25 898: if (dox25clr) { /* If X.25 clear requested */ 899: x25clear(); /* do that. */ 900: initpad(); 901: dox25clr = 0; /* But only once. */ 902: } 903: #endif /* SUNX25 */ 904: if (!quiet) 905: printf("(Back at %s)", *myhost ? myhost : "local UNIX system"); 906: printf("\n"); 907: what = W_NOTHING; /* So console modes set right. */ 908: #ifndef NOCSETS 909: language = langsv; /* Restore language */ 910: #endif /* NOCSETS */ 911: parent_id = (PID_T) 0; 912: #ifdef DYNAMIC 913: if (temp) free(temp); /* Free allocated memory */ 914: if (ibuf) free(ibuf); 915: if (obuf) free(obuf); 916: #endif /* DYNAMIC */ 917: return(1); 918: 919: } else { /* Inferior reads, prints port input */ 920: 921: #ifndef OXOS 922: if (priv_can()) { /* Cancel all privs */ 923: printf("?setuid error - fatal\n"); 924: doexit(BAD_EXIT,-1); 925: } 926: #endif /* OXOS */ 927: signal(SIGINT, SIG_IGN); /* In case these haven't been */ 928: signal(SIGQUIT, SIG_IGN); /* inherited from above... */ 929: 930: inshift = outshift = 0; /* Initial SO/SI shift state. */ 931: sleep(1); /* Wait for parent's handler setup. */ 932: ibp = ibuf; /* Initialize input buffering */ 933: ibc = 0; /* And output buffering. */ 934: obp = obuf; 935: obc = 0; 936: debug(F100,"CONNECT starting port fork","",0); 937: while (1) { /* Fresh read, wait for a character. */ 938: #ifdef SUNX25 939: if (network && (nettype == NET_SX25)) { 940: bzero(x25ibuf,sizeof(x25ibuf)) ; 941: if ((ibufl = ttxin(MAXIX25,x25ibuf)) < 0) { 942: if (ibufl == -2) { /* PAD parms changes */ 943: write(padpipe[1],padparms,MAXPADPARMS); 944: kill(parent_id,SIGUSR2); 945: } else { 946: if (!quiet) 947: printf("\r\nCommunications disconnect "); 948: kill(parent_id,SIGUSR1); 949: } 950: pause(); 951: } 952: if (debses) { /* Debugging output */ 953: p = x25ibuf ; 954: while (ibufl--) { c = *p++; conol(dbchr(c)); } 955: } else { 956: if (sosi 957: #ifndef NOCSETS 958: || tcsl != tcsr 959: #endif /* NOCSETS */ 960: ) { /* Character at a time */ 961: for (i = 1; i < ibufl; i++) { 962: c = x25ibuf[i] & cmask; 963: if (sosi) { /* Handle SI/SO */ 964: if (c == SO) { 965: inshift = 1; 966: continue; 967: } else if (c == SI) { 968: inshift = 0; 969: continue; 970: } 971: if (inshift) 972: c |= 0200; 973: } 974: #ifndef NOCSETS 975: #ifndef SKIPESC 976: /* Translate character sets */ 977: if (sxo) c = (*sxo)(c); /* From local to intermediate. */ 978: if (rxo) c = (*rxo)(c); /* From intermediate to remote. */ 979: 980: #else /* Skipping escape sequences... */ 981: 982: if (inesc == ES_NORMAL) { /* If not inside escape seq.. */ 983: /* Translate character sets */ 984: if (sxo) c = (*sxo)(c); /* Local to intermediate. */ 985: if (rxo) c = (*rxo)(c); /* Intermediate to remote. */ 986: } 987: if (skipesc) chkaes(c); /* Check escape sequence status */ 988: #endif /* SKIPESC */ 989: #endif /* NOCSETS */ 990: c &= cmdmsk; /* Apply command mask. */ 991: conoc(c); /* Output to screen */ 992: logchar(c); /* and session log */ 993: } 994: } else { /* All at once */ 995: for (i = 1; i < ibufl; i++) 996: x25ibuf[i] &= (cmask & cmdmsk); 997: conxo(ibufl,x25ibuf); 998: if (seslog) zsoutx(ZSFILE,x25ibuf,ibufl); 999: } 1000: } 1001: continue; 1002: 1003: } else { /* Not X.25... */ 1004: #endif /* SUNX25 */ 1005: /* 1006: Get the next communication line character from our internal buffer. 1007: If the buffer is empty, refill it. 1008: */ 1009: c = ckcgetc(0); /* Get next character */ 1010: /* debug(F101,"CONNECT c","",c); */ 1011: if (c < 0) { 1012: if (!quiet) { /* Failed... */ 1013: printf("\r\nCommunications disconnect "); 1014: if ( c == -3 1015: #ifdef UTEK 1016: /* This happens on UTEK if there's no carrier */ 1017: && errno != EWOULDBLOCK 1018: #endif /* UTEK */ 1019: ) 1020: perror("\r\nCan't read character"); 1021: } 1022: tthang(); /* Hang up the connection */ 1023: kill(parent_id,SIGUSR1); /* Notify parent */ 1024: for (;;) pause(); /* and wait to be killed */ 1025: } 1026: debug(F111,"** PORT",dbchr(c),c); 1027: #ifdef TNCODE 1028: /* Handle TELNET negotiations here */ 1029: if (c == IAC && network && ttnproto == NP_TELNET) { 1030: ckcputf(); /* Dump output buffer */ 1031: if ((tx = tn_doop((CHAR)(c & 0xff),duplex,ckcgetc)) == 0) { 1032: continue; 1033: } else if (tx == -1) { /* I/O error */ 1034: if (!quiet) 1035: printf("\r\nCommunications disconnect "); 1036: kill(parent_id,SIGUSR1); /* Notify parent. */ 1037: for (;;) pause(); /* Wait to be killed. */ 1038: } else if ((tx == 1) && (!duplex)) { /* ECHO change */ 1039: kill(parent_id,SIGUSR2); /* Tell the parent fork */ 1040: duplex = 1; 1041: } else if ((tx == 2) && (duplex)) { /* ECHO change */ 1042: kill(parent_id,SIGUSR2); 1043: duplex = 0; 1044: } else if (tx == 3) { /* Quoted IAC */ 1045: c = 255; 1046: } else continue; /* Negotiation OK, get next char. */ 1047: } 1048: #endif /* TNCODE */ 1049: if (debses) { /* Output character to screen */ 1050: char *s; /* Debugging display... */ 1051: s = dbchr(c); 1052: while (*s) 1053: ckcputc(*s++); 1054: } else { /* Regular display ... */ 1055: c &= cmask; /* Apply Kermit-to-remote mask */ 1056: if (sosi) { /* Handle SI/SO */ 1057: if (c == SO) { /* Shift Out */ 1058: inshift = 1; 1059: continue; 1060: } else if (c == SI) { /* Shift In */ 1061: inshift = 0; 1062: continue; 1063: } 1064: if (inshift) c |= 0200; 1065: } 1066: #ifndef NOCSETS 1067: #ifndef SKIPESC 1068: /* Translate character sets */ 1069: if (sxi) c = (*sxi)((CHAR)c); 1070: if (rxi) c = (*rxi)((CHAR)c); 1071: #else 1072: if (inesc == ES_NORMAL) { 1073: /* Translate character sets */ 1074: if (sxi) c = (*sxi)((CHAR)c); 1075: if (rxi) c = (*rxi)((CHAR)c); 1076: } 1077: /* Adjust escape sequence status */ 1078: if (skipesc) chkaes((char)c); 1079: #endif /* SKIPESC */ 1080: #endif /* NOCSETS */ 1081: c &= cmdmsk; /* Apply command mask. */ 1082: if (c == CR && tt_crd) { /* SET TERM CR-DISPLAY CRLF ? */ 1083: ckcputc(c); /* Yes, output CR */ 1084: if (seslog) logchar((char)c); 1085: c = LF; /* and insert a linefeed */ 1086: } 1087: ckcputc(c); /* Output character to screen */ 1088: if (seslog) logchar((char)c); /* Do session log */ 1089: } 1090: #ifdef SUNX25 1091: } 1092: #endif /* SUNX25 */ 1093: } 1094: } 1095: } 1096: 1097: 1098: /* H C O N N E -- Give help message for connect. */ 1099: 1100: int 1101: hconne() { 1102: int c; 1103: static char *hlpmsg[] = { 1104: "\r\n ? for this message", 1105: "\r\n 0 (zero) to send a null", 1106: "\r\n B to send a BREAK", 1107: #ifdef CK_LBRK 1108: "\r\n L to send a Long BREAK", 1109: #endif /* CK_LBRK */ 1110: #ifdef NETCONN 1111: "\r\n I to send a network interrupt packet", 1112: #ifdef TCPSOCKET 1113: "\r\n A to send Are You There?", 1114: #endif /* TCPSOCKET */ 1115: #ifdef SUNX25 1116: "\r\n R to reset X.25 virtual circuit", 1117: #endif /* SUNX25 */ 1118: #endif /* NETCONN */ 1119: "\r\n H to hangup and close the connection", 1120: "\r\n Q to hangup and quit Kermit", 1121: "\r\n S for status", 1122: "\r\n ! to push to local shell", 1123: "\r\n Z to suspend", 1124: "\r\n \\ backslash code:", 1125: "\r\n \\nnn decimal character code", 1126: "\r\n \\Onnn octal character code", 1127: "\r\n \\Xhh hexadecimal character code", 1128: "\r\n terminate with carriage return.", 1129: "\r\n Type the escape character again to send the escape character, or", 1130: "\r\n press the space-bar to resume the CONNECT command.\r\n\r\n", 1131: "" }; 1132: conol("\r\nPress C to return to "); 1133: conol(*myhost ? myhost : "the C-Kermit prompt"); 1134: conol(", or:"); 1135: conola(hlpmsg); /* Print the help message. */ 1136: conol("Command>"); /* Prompt for command. */ 1137: c = congks(0) & 0177; /* Get character, strip any parity. */ 1138: /* No key mapping or translation here */ 1139: if (c != CMDQ) 1140: conoll(""); 1141: return(c); /* Return it. */ 1142: } 1143: 1144: 1145: /* D O E S C -- Process an escape character argument */ 1146: 1147: VOID 1148: #ifdef CK_ANSIC 1149: doesc(char c) 1150: #else 1151: doesc(c) char c; 1152: #endif /* CK_ANSIC */ 1153: /* doesc */ { 1154: CHAR d; 1155: 1156: while (1) { 1157: if (c == escape) { /* Send escape character */ 1158: d = dopar((CHAR) c); ttoc((char) d); return; 1159: } else /* Or else look it up below. */ 1160: if (isupper(c)) c = tolower(c); 1161: 1162: switch(c) { 1163: 1164: case 'c': /* Escape back to prompt */ 1165: case '\03': 1166: active = 0; conol("\r\n"); return; 1167: 1168: case 'b': /* Send a BREAK signal */ 1169: case '\02': 1170: ttsndb(); return; 1171: 1172: #ifdef NETCONN 1173: case 'i': /* Send Interrupt */ 1174: case '\011': 1175: #ifdef TCPSOCKET 1176: #ifndef IP 1177: #define IP 244 1178: #endif /* IP */ 1179: if (network && ttnproto == NP_TELNET) { /* TELNET */ 1180: temp[0] = IAC; /* I Am a Command */ 1181: temp[1] = IP; /* Interrupt Process */ 1182: temp[2] = NUL; 1183: ttol((CHAR *)temp,2); 1184: } else 1185: #endif /* TCPSOCKET */ 1186: #ifdef SUNX25 1187: if (network && (nettype == NET_SX25)) { /* X.25 */ 1188: (VOID) x25intr(0); /* X.25 interrupt packet */ 1189: conol("\r\n"); 1190: } else 1191: #endif /* SUNX25 */ 1192: conoc(BEL); 1193: return; 1194: 1195: #ifdef TCPSOCKET 1196: case 'a': /* "Are You There?" */ 1197: case '\01': 1198: #ifndef AYT 1199: #define AYT 246 1200: #endif /* AYT */ 1201: if (network && ttnproto == NP_TELNET) { 1202: temp[0] = IAC; /* I Am a Command */ 1203: temp[1] = AYT; /* Are You There? */ 1204: temp[2] = NUL; 1205: ttol((CHAR *)temp,2); 1206: } else conoc(BEL); 1207: return; 1208: #endif /* TCPSOCKET */ 1209: #endif /* NETCONN */ 1210: 1211: #ifdef CK_LBRK 1212: case 'l': /* Send a Long BREAK signal */ 1213: ttsndlb(); return; 1214: #endif /* CK_LBRK */ 1215: 1216: case 'h': /* Hangup */ 1217: case '\010': 1218: #ifdef SUNX25 1219: if (network && (nettype == NET_SX25)) dox25clr = 1; 1220: else 1221: #endif /* SUNX25 */ 1222: dohangup = 2; active = 0; conol("\r\nHanging up "); return; 1223: 1224: #ifdef SUNX25 1225: case 'r': /* Reset the X.25 virtual circuit */ 1226: case '\022': 1227: if (network && (nettype == NET_SX25)) (VOID) x25reset(); 1228: conol("\r\n"); return; 1229: #endif /* SUNX25 */ 1230: 1231: case 'q': /* Quit */ 1232: quitnow = 1; active = 0; conol("\r\n"); return; 1233: 1234: case 's': /* Status */ 1235: sprintf(temp, 1236: "\r\nConnected %s %s", network ? "to" : "through", ttname); 1237: conol(temp); 1238: #ifdef SUNX25 1239: if (network && (nettype == NET_SX25)) { 1240: sprintf(temp,", Link ID %d, LCN %d",linkid,lcn); conol(temp); 1241: } 1242: #endif /* SUNX25 */ 1243: if (speed >= 0L) { 1244: sprintf(temp,", speed %ld", speed); 1245: conoll(temp); 1246: } else conoll(""); 1247: sprintf(temp, 1248: "Terminal bytesize: %d, Command bytesize: %d, Parity: ", 1249: (cmask == 0177) ? 7 : 8, 1250: (cmdmsk == 0177) ? 7 : 8 ); 1251: conol(temp); 1252: 1253: switch (parity) { 1254: case 0: conoll("none"); break; 1255: case 'e': conoll("even"); break; 1256: case 'o': conoll("odd"); break; 1257: case 's': conoll("space"); break; 1258: case 'm': conoll("mark"); break; 1259: } 1260: sprintf(temp,"Terminal echo: %s", duplex ? "local" : "remote"); 1261: conoll(temp); 1262: if (seslog) { 1263: conol("Logging to: "); conoll(sesfil); 1264: } 1265: if (!network) shomdm(); 1266: return; 1267: 1268: case '?': /* Help */ 1269: c = hconne(); continue; 1270: 1271: case '0': /* Send a null */ 1272: c = '\0'; d = dopar((CHAR) c); ttoc((char) d); return; 1273: 1274: #ifndef NOPUSH 1275: case 'z': case '\032': /* Suspend */ 1276: stptrap(0); return; 1277: 1278: case '@': /* Start inferior command processor */ 1279: case '!': 1280: conres(); /* Put console back to normal */ 1281: zshcmd(""); /* Fork a shell. */ 1282: if (conbin((char)escape) < 0) { 1283: printf("Error resuming CONNECT session\n"); 1284: active = 0; 1285: } 1286: return; 1287: #endif /* NOPUSH */ 1288: 1289: case SP: /* Space, ignore */ 1290: return; 1291: 1292: default: /* Other */ 1293: if (c == CMDQ) { /* Backslash escape */ 1294: int x; 1295: kbp = kbuf; 1296: *kbp++ = c; 1297: while (((c = (congks(0) & cmdmsk)) != '\r') && (c != '\n')) 1298: *kbp++ = c; 1299: *kbp = NUL; kbp = kbuf; 1300: x = xxesc(&kbp); /* Interpret it */ 1301: if (x >= 0) { /* No key mapping here */ 1302: c = dopar((CHAR) x); 1303: ttoc((char) c); 1304: return; 1305: } else { /* Invalid backslash code. */ 1306: conoc(BEL); 1307: return; 1308: } 1309: } 1310: conoc(BEL); return; /* Invalid esc arg, beep */ 1311: } 1312: } 1313: } 1314: 1315: VOID 1316: #ifdef CK_ANSIC 1317: logchar(char c) 1318: #else 1319: logchar(c) char c; 1320: #endif /* CK_ANSIC */ 1321: /* logchar */ { /* Log character c to session log */ 1322: if (seslog) 1323: if ((sessft != 0) || 1324: (c != '\r' && 1325: c != '\0' && 1326: c != XON && 1327: c != XOFF)) 1328: if (zchout(ZSFILE,c) < 0) { 1329: conoll(""); 1330: conoll("ERROR WRITING SESSION LOG, LOG CLOSED!"); 1331: seslog = 0; 1332: } 1333: }