1: char *userv = "User Interface 4C(052), 2 Aug 85"; 2: 3: /* C K U U S R -- "User Interface" for Unix Kermit (Part 1) */ 4: 5: /* 6: Author: Frank da Cruz (SY.FDC@CU20B), 7: Columbia University Center for Computing Activities, January 1985. 8: Copyright (C) 1985, Trustees of Columbia University in the City of New York. 9: Permission is granted to any individual or institution to use, copy, or 10: redistribute this software so long as it is not sold for profit, provided this 11: copyright notice is retained. 12: */ 13: 14: /* 15: The ckuser module contains the terminal input and output functions for Unix 16: Kermit. It includes a simple Unix-style command line parser as well as 17: an interactive prompting keyword command parser. It depends on the existence 18: of Unix facilities like fopen, fgets, feof, (f)printf, argv/argc, etc. Other 19: functions that are likely to vary among Unix implementations -- like setting 20: terminal modes or interrupts -- are invoked via calls to functions that are 21: defined in the system-dependent modules, ck?[ft]io.c. 22: 23: The command line parser processes any arguments found on the command line, 24: as passed to main() via argv/argc. The interactive parser uses the facilities 25: of the cmd package (developed for this program, but usable by any program). 26: 27: Any command parser may be substituted for this one. The only requirements 28: for the Kermit command parser are these: 29: 30: 1. Set parameters via global variables like duplex, speed, ttname, etc. 31: See ckmain.c for the declarations and descriptions of these variables. 32: 33: 2. If a command can be executed without the use of Kermit protocol, then 34: execute the command directly and set the variable sstate to 0. Examples 35: include 'set' commands, local directory listings, the 'connect' command. 36: 37: 3. If a command requires the Kermit protocol, set the following variables: 38: 39: sstate string data 40: 'x' (enter server mode) (none) 41: 'r' (send a 'get' command) cmarg, cmarg2 42: 'v' (enter receive mode) cmarg2 43: 'g' (send a generic command) cmarg 44: 's' (send files) nfils, cmarg & cmarg2 OR cmlist 45: 'c' (send a remote host command) cmarg 46: 47: cmlist is an array of pointers to strings. 48: cmarg, cmarg2 are pointers to strings. 49: nfils is an integer. 50: 51: cmarg can be a filename string (possibly wild), or 52: a pointer to a prefabricated generic command string, or 53: a pointer to a host command string. 54: cmarg2 is the name to send a single file under, or 55: the name under which to store an incoming file; must not be wild. 56: cmlist is a list of nonwild filenames, such as passed via argv. 57: nfils is an integer, interpreted as follows: 58: -1: argument string is in cmarg, and should be expanded internally. 59: 0: stdin. 60: >0: number of files to send, from cmlist. 61: 62: The screen() function is used to update the screen during file transfer. 63: The tlog() function maintains a transaction log. 64: The debug() function maintains a debugging log. 65: The intmsg() and chkint() functions provide the user i/o for interrupting 66: file transfers. 67: */ 68: 69: /* Includes */ 70: 71: #include "ckcdeb.h" 72: #include <stdio.h> 73: #include <ctype.h> 74: #include <signal.h> 75: #include "ckcker.h" 76: #include "ckucmd.h" 77: #include "ckuusr.h" 78: 79: #ifdef vax11c 80: #define KERMRC "kermit.ini" 81: #else 82: #define KERMRC ".kermrc" 83: #endif 84: 85: /* External Kermit Variables, see ckmain.c for description. */ 86: 87: extern int size, spsiz, rpsiz, npad, timint, rtimo, speed, local, server, 88: displa, binary, fncnv, delay, parity, deblog, escape, xargc, flow, 89: turn, duplex, cxseen, czseen, nfils, ckxech, pktlog, seslog, tralog, stdouf, 90: turnch, chklen, bctr, bctu, dfloc, mdmtyp, keep, 91: rptflg, rptq, ebqflg, ebq, warn, quiet, cnflg, timef, spsizf, mypadn, tsecs; 92: 93: extern long filcnt, tlci, tlco, ffc, tfc, fsize; 94: 95: extern char *versio, *protv, *ckxv, *ckzv, *fnsv, *connv, *dftty, *cmdv; 96: extern char *dialv, *loginv; 97: extern char *ckxsys, *ckzsys, *cmarg, *cmarg2, **xargv, **cmlist; 98: extern CHAR mystch, stchr, sstate, mypadc, padch, eol, seol, ctlq, filnam[], 99: ttname[]; 100: extern char *DIRCMD, *PWDCMD, cmerrp[]; 101: char *strcpy(), *getenv(); 102: 103: /* Declarations from cmd package */ 104: 105: extern char cmdbuf[]; /* Command buffer */ 106: 107: /* Declarations from ck?fio.c module */ 108: 109: extern char *SPACMD, *zhome(); /* Space command, home directory. */ 110: extern int backgrd; /* Kermit executing in background */ 111: 112: /* The background flag is set by ckutio.c (via conint() ) to note whether */ 113: /* this kermit is executing in background ('&' on shell command line). */ 114: 115: 116: /* Variables and symbols local to this module */ 117: 118: char line[CMDBL+10], *lp; /* Character buffer for anything */ 119: char debfil[50]; /* Debugging log file name */ 120: char pktfil[50]; /* Packet log file name */ 121: char sesfil[50]; /* Session log file name */ 122: char trafil[50]; /* Transaction log file name */ 123: 124: int n, /* General purpose int */ 125: cflg, /* Command-line connect cmd given */ 126: action, /* Action selected on command line*/ 127: repars, /* Reparse needed */ 128: tlevel, /* Take command level */ 129: cwdf = 0; /* CWD has been done */ 130: 131: #define MAXTAKE 20 /* Maximum nesting of TAKE files */ 132: FILE *tfile[MAXTAKE]; /* File pointers for TAKE command */ 133: 134: char *homdir; /* Pointer to home directory string */ 135: char cmdstr[100]; 136: 137: /* C M D L I N -- Get arguments from command line */ 138: /* 139: Simple Unix-style command line parser, conforming with 'A Proposed Command 140: Syntax Standard for Unix Systems', Hemenway & Armitage, Unix/World, Vol.1, 141: No.3, 1984. 142: */ 143: cmdlin() { 144: char x; /* Local general-purpose int */ 145: cmarg = ""; /* Initialize globals */ 146: cmarg2 = ""; 147: action = cflg = 0; 148: 149: while (--xargc > 0) { /* Go through command line words */ 150: xargv++; 151: debug(F111,"xargv",*xargv,xargc); 152: if (**xargv == '-') { /* Got an option (begins with dash) */ 153: x = *(*xargv+1); /* Get the option letter */ 154: x = doarg(x); /* Go handle the option */ 155: if (x < 0) exit(GOOD_EXIT); 156: } else { /* No dash where expected */ 157: usage(); 158: exit(BAD_EXIT); 159: } 160: } 161: debug(F101,"action","",action); 162: if (!local) { 163: if ((action == 'g') || (action == 'r') || 164: (action == 'c') || (cflg != 0)) 165: fatal("-l and -b required"); 166: } 167: if (*cmarg2 != 0) { 168: if ((action != 's') && (action != 'r') && 169: (action != 'v')) 170: fatal("-a without -s, -r, or -g"); 171: } 172: if ((action == 'v') && (stdouf) && (!local)) { 173: if (isatty(1)) 174: fatal("unredirected -k can only be used in local mode"); 175: } 176: if ((action == 's') || (action == 'v') || 177: (action == 'r') || (action == 'x')) { 178: if (local) displa = 1; 179: if (stdouf) displa = 0; 180: } 181: 182: if (quiet) displa = 0; /* No display if quiet requested */ 183: 184: if (cflg) { 185: conect(); /* Connect if requested */ 186: if (action == 0) { 187: if (cnflg) conect(); /* And again if requested */ 188: doexit(GOOD_EXIT); /* Then exit indicating success */ 189: } 190: } 191: if (displa) concb(escape); /* (for console "interrupts") */ 192: return(action); /* Then do any requested protocol */ 193: } 194: 195: /* D O A R G -- Do a command-line argument. */ 196: 197: doarg(x) char x; { 198: int z; char *xp; 199: 200: xp = *xargv+1; /* Pointer for bundled args */ 201: while (x) { 202: switch (x) { 203: 204: case 'x': /* server */ 205: if (action) fatal("conflicting actions"); 206: action = 'x'; 207: break; 208: 209: case 'f': 210: if (action) fatal("conflicting actions"); 211: action = setgen('F',"","",""); 212: break; 213: 214: case 'r': /* receive */ 215: if (action) fatal("conflicting actions"); 216: action = 'v'; 217: break; 218: 219: case 'k': /* receive to stdout */ 220: if (action) fatal("conflicting actions"); 221: stdouf = 1; 222: action = 'v'; 223: break; 224: 225: case 's': /* send */ 226: if (action) fatal("conflicting actions"); 227: if (*(xp+1)) fatal("invalid argument bundling after -s"); 228: z = nfils = 0; /* Initialize file counter, flag */ 229: cmlist = xargv+1; /* Remember this pointer */ 230: while (--xargc > 0) { /* Traverse the list */ 231: *xargv++; 232: if (**xargv == '-') { /* Check for sending stdin */ 233: if (strcmp(*xargv,"-") != 0) break; 234: z++; 235: } 236: nfils++; /* Bump file counter */ 237: } 238: xargc++, *xargv--; /* Adjust argv/argc */ 239: if (nfils < 1) fatal("missing filename for -s"); 240: if (z > 1) fatal("-s: too many -'s"); 241: if (z == 1) { 242: if (nfils == 1) nfils = 0; 243: else fatal("invalid mixture of filenames and '-' in -s"); 244: } 245: if (nfils == 0) { 246: if (isatty(0)) fatal("sending from terminal not allowed"); 247: } 248: debug(F101,*xargv,"",nfils); 249: action = 's'; 250: break; 251: 252: /* cont'd... */ 253: 254: /* ...doarg(), cont'd */ 255: 256: case 'g': /* get */ 257: if (action) fatal("conflicting actions"); 258: if (*(xp+1)) fatal("invalid argument bundling after -g"); 259: *xargv++, xargc--; 260: if ((xargc == 0) || (**xargv == '-')) 261: fatal("missing filename for -g"); 262: cmarg = *xargv; 263: action = 'r'; 264: break; 265: 266: case 'c': /* connect before */ 267: cflg = 1; 268: break; 269: 270: case 'n': /* connect after */ 271: cnflg = 1; 272: break; 273: 274: case 'h': /* help */ 275: usage(); 276: return(-1); 277: 278: case 'a': /* "as" */ 279: if (*(xp+1)) fatal("invalid argument bundling after -a"); 280: *xargv++, xargc--; 281: if ((xargc < 1) || (**xargv == '-')) 282: fatal("missing name in -a"); 283: cmarg2 = *xargv; 284: break; 285: 286: case 'l': /* set line */ 287: if (*(xp+1)) fatal("invalid argument bundling after -l"); 288: *xargv++, xargc--; 289: if ((xargc < 1) || (**xargv == '-')) 290: fatal("communication line device name missing"); 291: strcpy(ttname,*xargv); 292: /* if (strcmp(ttname,dftty) == 0) local = dfloc; else local = 1; */ 293: local = (strcmp(ttname,CTTNAM) != 0); /* (better than old way) */ 294: debug(F101,"local","",local); 295: ttopen(ttname,&local,0); 296: break; 297: 298: case 'b': /* set baud */ 299: if (*(xp+1)) fatal("invalid argument bundling"); 300: *xargv++, xargc--; 301: if ((xargc < 1) || (**xargv == '-')) 302: fatal("missing baud"); 303: z = atoi(*xargv); /* Convert to number */ 304: if (chkspd(z) > -1) speed = z; /* Check it */ 305: else fatal("unsupported baud rate"); 306: break; 307: 308: case 'i': /* Treat files as binary */ 309: binary = 1; 310: break; 311: 312: /* cont'd... */ 313: 314: /* ...doarg(), cont'd */ 315: 316: 317: case 'w': /* File warning */ 318: warn = 1; 319: break; 320: 321: case 'q': /* Quiet */ 322: quiet = 1; 323: break; 324: 325: case 'd': /* debug */ 326: debopn("debug.log"); 327: break; 328: 329: case 'p': /* set parity */ 330: if (*(xp+1)) fatal("invalid argument bundling"); 331: *xargv++, xargc--; 332: if ((xargc < 1) || (**xargv == '-')) 333: fatal("missing parity"); 334: switch(x = **xargv) { 335: case 'e': 336: case 'o': 337: case 'm': 338: case 's': parity = x; break; 339: case 'n': parity = 0; break; 340: default: fatal("invalid parity"); 341: } 342: break; 343: 344: case 't': 345: turn = 1; /* Line turnaround handshake */ 346: turnch = XON; /* XON is turnaround character */ 347: duplex = 1; /* Half duplex */ 348: flow = 0; /* No flow control */ 349: break; 350: 351: default: 352: fatal("invalid argument, type 'kermit -h' for help"); 353: } 354: 355: x = *++xp; /* See if options are bundled */ 356: } 357: return(0); 358: } 359: 360: /* Misc */ 361: 362: fatal(msg) char *msg; { /* Fatal error message */ 363: fprintf(stderr,"\r\nFatal: %s\n",msg); 364: tlog(F110,"Fatal:",msg,0l); 365: doexit(BAD_EXIT); /* Exit indicating failure */ 366: } 367: 368: 369: ermsg(msg) char *msg; { /* Print error message */ 370: if (!quiet) fprintf(stderr,"\r\n%s - %s\n",cmerrp,msg); 371: tlog(F110,"Error -",msg,0l); 372: } 373: 374: /* Interactive command parser */ 375: 376: 377: /* Top-Level Keyword Table */ 378: 379: struct keytab cmdtab[] = { 380: "!", XXSHE, 0, 381: "%", XXCOM, CM_INV, 382: "bye", XXBYE, 0, 383: "c", XXCON, CM_INV, 384: "close", XXCLO, 0, 385: "connect", XXCON, 0, 386: "cwd", XXCWD, 0, 387: "dial", XXDIAL, 0, 388: "directory", XXDIR, 0, 389: "echo", XXECH, 0, 390: "exit", XXEXI, 0, 391: "finish", XXFIN, 0, 392: "get", XXGET, 0, 393: "help", XXHLP, 0, 394: "log", XXLOG, 0, 395: "quit", XXQUI, 0, 396: "r", XXREC, CM_INV, 397: "receive", XXREC, 0, 398: "remote", XXREM, 0, 399: "s", XXSEN, CM_INV, 400: "script", XXLOGI, 0, 401: "send", XXSEN, 0, 402: "server", XXSER, 0, 403: "set", XXSET, 0, 404: "show", XXSHO, 0, 405: "space", XXSPA, 0, 406: "statistics", XXSTA, 0, 407: "take", XXTAK, 0 408: }; 409: int ncmd = (sizeof(cmdtab) / sizeof(struct keytab)); 410: 411: /* Parameter keyword table */ 412: 413: struct keytab prmtab[] = { 414: "baud", XYSPEE, CM_INV, 415: "block-check", XYCHKT, 0, 416: "delay", XYDELA, 0, 417: "duplex", XYDUPL, 0, 418: "end-of-packet", XYEOL, CM_INV, /* moved to send/receive */ 419: "escape-character", XYESC, 0, 420: "file", XYFILE, 0, 421: "flow-control", XYFLOW, 0, 422: "handshake", XYHAND, 0, 423: "incomplete", XYIFD, 0, 424: "line", XYLINE, 0, 425: "modem-dialer", XYMODM, 0, 426: "packet-length", XYLEN, CM_INV, /* moved to send/receive */ 427: "pad-character", XYPADC, CM_INV, /* moved to send/receive */ 428: "padding", XYNPAD, CM_INV, /* moved to send/receive */ 429: "parity", XYPARI, 0, 430: "prompt", XYPROM, 0, 431: "receive", XYRECV, 0, 432: "send", XYSEND, 0, 433: "speed", XYSPEE, 0, 434: "start-of-packet", XYMARK, CM_INV, /* moved to send/receive */ 435: "timeout", XYTIMO, CM_INV /* moved to send/receive */ 436: }; 437: int nprm = (sizeof(prmtab) / sizeof(struct keytab)); /* How many parameters */ 438: 439: 440: /* Remote Command Table */ 441: 442: struct keytab remcmd[] = { 443: "cwd", XZCWD, 0, 444: "delete", XZDEL, 0, 445: "directory", XZDIR, 0, 446: "help", XZHLP, 0, 447: "host", XZHOS, 0, 448: "space", XZSPA, 0, 449: "type", XZTYP, 0, 450: "who", XZWHO, 0 451: }; 452: int nrmt = (sizeof(remcmd) / sizeof(struct keytab)); 453: 454: struct keytab logtab[] = { 455: "debugging", LOGD, 0, 456: "packets", LOGP, 0, 457: "session", LOGS, 0, 458: "transactions", LOGT, 0 459: }; 460: int nlog = (sizeof(logtab) / sizeof(struct keytab)); 461: 462: /* Show command arguments */ 463: 464: #define SHPAR 0 /* Parameters */ 465: #define SHVER 1 /* Versions */ 466: 467: struct keytab shotab[] = { 468: "parameters", SHPAR, 0, 469: "versions", SHVER, 0 470: }; 471: 472: /* C M D I N I -- Initialize the interactive command parser */ 473: 474: cmdini() { 475: 476: printf("%s,%s\nType ? for help\n",versio,ckxsys); 477: cmsetp("C-Kermit>"); /* Set default prompt. */ 478: 479: tlevel = -1; /* Take file level */ 480: 481: /* Look for init file in home or current directory. */ 482: 483: homdir = zhome(); 484: lp = line; 485: lp[0] = '\0'; 486: if (homdir) { 487: strcpy(lp,homdir); 488: if (lp[0] == '/') strcat(lp,"/"); 489: } 490: strcat(lp,KERMRC); 491: if ((tfile[0] = fopen(line,"r")) != NULL) { 492: tlevel = 0; 493: debug(F110,"init file",line,0); 494: } 495: if (homdir && (tlevel < 0)) { 496: strcpy(lp,KERMRC); 497: if ((tfile[0] = fopen(line,"r")) != NULL) { 498: tlevel = 0; 499: debug(F110,"init file",line,0); 500: } else { 501: debug(F100,"no init file","",0); 502: } 503: } 504: 505: congm(); /* Get console tty modes */ 506: } 507: 508: 509: /* T R A P -- Terminal interrupt handler */ 510: 511: trap() { 512: debug(F100,"terminal interrupt...","",0); 513: doexit(GOOD_EXIT); /* Exit indicating success */ 514: } 515: 516: /* P A R S E R -- Top-level interactive command parser. */ 517: 518: parser() { 519: int xx, cbn; 520: char *cbp; 521: 522: concb(escape); /* Put console in cbreak mode. */ 523: conint(trap); /* Turn on console terminal interrupts. */ 524: /* 525: sstate becomes nonzero when a command has been parsed that requires some 526: action from the protocol module. Any non-protocol actions, such as local 527: directory listing or terminal emulation, are invoked directly from below. 528: */ 529: if (local) printf("\n"); /*** Temporary kludge ***/ 530: sstate = 0; /* Start with no start state. */ 531: while (sstate == 0) { /* Parse cmds until action requested */ 532: while ((tlevel > -1) && feof(tfile[tlevel])) { /* If end of take */ 533: fclose(tfile[tlevel]); /* file, close it */ 534: tlevel--; /* and forget about it. */ 535: cmini(ckxech); /* and clear the cmd buffer. */ 536: } 537: if (tlevel > -1) { /* If in take file */ 538: cbp = cmdbuf; /* Get the next line. */ 539: cbn = CMDBL; 540: 541: /* Loop to get next command line and all continuation lines from take file. */ 542: 543: again: if (fgets(line,cbn,tfile[tlevel]) == NULL) continue; 544: lp = line; /* Got one, copy it. */ 545: while (*cbp++ = *lp++) 546: if (--cbn < 1) fatal("Command too long for internal buffer"); 547: if (*(cbp - 3) == '\\') { /* Continued on next line? */ 548: cbp -= 3; /* If so, back up pointer, */ 549: goto again; /* go back, get next line. */ 550: } 551: stripq(cmdbuf); /* Strip any quotes from cmd buffer. */ 552: 553: } else { /* No take file, get typein. */ 554: 555: prompt(); /* Issue interactive prompt. */ 556: cmini(ckxech); 557: } 558: repars = 1; 559: displa = 0; 560: while (repars) { 561: cmres(); /* Reset buffer pointers. */ 562: xx = cmkey(cmdtab,ncmd,"Command",""); 563: debug(F101,"top-level cmkey","",xx); 564: switch (docmd(xx)) { 565: case -4: /* EOF */ 566: doexit(GOOD_EXIT); /* ...exit successfully */ 567: case -1: /* Reparse needed */ 568: repars = 1; 569: continue; 570: case -2: /* Invalid command given */ 571: if (backgrd) /* if in background, terminate */ 572: fatal("Kermit command error in background execution"); 573: if (tlevel > -1) { /* If in take file, quit */ 574: ermsg("Kermit command error: take file terminated."); 575: fclose(tfile[tlevel]); 576: tlevel--; 577: } 578: cmini(ckxech); /* (fall thru) */ 579: case -3: /* Empty command OK at top level */ 580: default: /* Anything else (fall thru) */ 581: repars = 0; /* No reparse, get new command. */ 582: continue; 583: } 584: } 585: } 586: /* Got an action command; disable terminal interrupts and return start state */ 587: 588: if (!local) connoi(); /* Interrupts off only if remote */ 589: return(sstate); 590: } 591: 592: /* D O E X I T -- Exit from the program. */ 593: 594: doexit(exitstat) int exitstat; { 595: 596: ttclos(); /* Close external line, if any */ 597: if (local) { 598: strcpy(ttname,dftty); /* Restore default tty */ 599: local = dfloc; /* And default remote/local status */ 600: } 601: if (!quiet) conres(); /* Restore console terminal. */ 602: if (!quiet) connoi(); /* Turn off console interrupt traps. */ 603: 604: if (deblog) { /* Close any open logs. */ 605: debug(F100,"Debug Log Closed","",0); 606: *debfil = '\0'; 607: deblog = 0; 608: zclose(ZDFILE); 609: } 610: if (pktlog) { 611: *pktfil = '\0'; 612: pktlog = 0; 613: zclose(ZPFILE); 614: } 615: if (seslog) { 616: *sesfil = '\0'; 617: seslog = 0; 618: zclose(ZSFILE); 619: } 620: if (tralog) { 621: tlog(F100,"Transaction Log Closed","",0l); 622: *trafil = '\0'; 623: tralog = 0; 624: zclose(ZTFILE); 625: } 626: exit(exitstat); /* Exit from the program. */ 627: } 628: 629: /* B L D L E N -- Make length-encoded copy of string */ 630: 631: char * 632: bldlen(str,dest) char *str, *dest; { 633: int len; 634: len = strlen(str); 635: *dest = tochar(len); 636: strcpy(dest+1,str); 637: return(dest+len+1); 638: } 639: 640: 641: /* S E T G E N -- Construct a generic command */ 642: 643: setgen(type,arg1,arg2,arg3) char type, *arg1, *arg2, *arg3; { 644: char *upstr, *cp; 645: 646: cp = cmdstr; 647: *cp++ = type; 648: *cp = NUL; 649: if (*arg1 != NUL) { 650: upstr = bldlen(arg1,cp); 651: if (*arg2 != NUL) { 652: upstr = bldlen(arg2,upstr); 653: if (*arg3 != NUL) bldlen(arg3,upstr); 654: } 655: } 656: cmarg = cmdstr; 657: debug(F110,"setgen",cmarg,0); 658: 659: return('g'); 660: } 661: 662: /* D O C M D -- Do a command */ 663: 664: /* 665: Returns: 666: -2: user typed an illegal command 667: -1: reparse needed 668: 0: parse was successful (even tho command may have failed). 669: */ 670: 671: docmd(cx) int cx; { 672: int x, y; 673: char *s; 674: 675: switch (cx) { 676: 677: case -4: /* EOF */ 678: if (!quiet) printf("\r\n"); 679: doexit(GOOD_EXIT); 680: case -3: /* Null command */ 681: return(0); 682: case -2: /* Error */ 683: case -1: /* Reparse needed */ 684: return(cx); 685: 686: case XXBYE: /* bye */ 687: if ((x = cmcfm()) < 0) return(x); 688: if (!local) { 689: printf("You have to 'set line' first\n"); 690: return(0); 691: } 692: sstate = setgen('L',"","",""); 693: return(0); 694: 695: case XXCOM: /* comment */ 696: if ((x = cmtxt("Text of comment line","",&s)) < 0) return(x); 697: return(0); 698: 699: case XXCON: /* connect */ 700: if ((x = cmcfm()) < 0) return(x); 701: return(doconect()); 702: 703: case XXCWD: 704: if (cmtxt("Name of local directory, or carriage return",homdir,&s) < 0) 705: return(-1); 706: if (chdir(s)) perror(s); 707: cwdf = 1; 708: system(PWDCMD); 709: return(0); 710: 711: case XXCLO: 712: x = cmkey(logtab,nlog,"Which log to close",""); 713: if (x == -3) { 714: printf("?You must tell which log\n"); 715: return(-2); 716: } 717: if (x < 0) return(x); 718: if ((y = cmcfm()) < 0) return(y); 719: switch (x) { 720: 721: case LOGD: 722: if (deblog == 0) { 723: printf("?Debugging log wasn't open\n"); 724: return(0); 725: } 726: *debfil = '\0'; 727: deblog = 0; 728: return(zclose(ZDFILE)); 729: 730: case LOGP: 731: if (pktlog == 0) { 732: printf("?Packet log wasn't open\n"); 733: return(0); 734: } 735: *pktfil = '\0'; 736: pktlog = 0; 737: return(zclose(ZPFILE)); 738: 739: case LOGS: 740: if (seslog == 0) { 741: printf("?Session log wasn't open\n"); 742: return(0); 743: } 744: *sesfil = '\0'; 745: seslog = 0; 746: return(zclose(ZSFILE)); 747: 748: case LOGT: 749: if (tralog == 0) { 750: printf("?Transaction log wasn't open\n"); 751: return(0); 752: } 753: *trafil = '\0'; 754: tralog = 0; 755: return(zclose(ZTFILE)); 756: 757: default: 758: printf("\n?Unexpected log designator - %ld\n", x); 759: return(0); 760: } 761: 762: case XXDIAL: /* dial number */ 763: if ((x = cmtxt("Number to be dialed","",&s)) < 0) return(x); 764: return(dial(s)); 765: 766: case XXDIR: /* directory */ 767: if ((x = cmtxt("Directory/file specification",".",&s)) < 0) return(x); 768: lp = line; 769: sprintf(lp,"%s %s",DIRCMD,s); 770: system(line); 771: return(0); 772: 773: 774: case XXECH: /* echo */ 775: if ((x = cmtxt("Material to be echoed","",&s)) < 0) return(x); 776: for ( ; *s; s++) { 777: if ((x = *s) == 0134) { /* Convert octal escapes */ 778: s++; /* up to 3 digits */ 779: for (x = y = 0; *s >= '0' && *s <= '7' && y < 3; s++,y++) { 780: x = x * 8 + (int) *s - 48; 781: } 782: s--; 783: } 784: putchar(x); 785: } 786: printf("\n"); 787: return(0); 788: 789: case XXQUI: /* quit, exit */ 790: case XXEXI: 791: if ((x = cmcfm()) > -1) doexit(GOOD_EXIT); 792: else return(x); 793: 794: case XXFIN: /* finish */ 795: if ((x = cmcfm()) < 0) return(x); 796: if (!local) { 797: printf("You have to 'set line' first\n"); 798: return(0); 799: } 800: sstate = setgen('F',"","",""); 801: return(0); 802: 803: case XXGET: /* get */ 804: if (!local) { 805: printf("\nYou have to 'set line' first\n"); 806: return(0); 807: } 808: x = cmtxt("Name of remote file(s), or carriage return","",&cmarg); 809: if ((x == -2) || (x == -1)) return(x); 810: 811: /* If foreign file name omitted, get foreign and local names separately */ 812: 813: if (*cmarg == NUL) { 814: 815: if (tlevel > -1) { /* Input is from take file */ 816: 817: if (fgets(line,100,tfile[tlevel]) == NULL) 818: fatal("take file ends prematurely in 'get'"); 819: stripq(line); 820: cmarg = line; 821: if (fgets(cmdbuf,CMDBL,tfile[tlevel]) == NULL) 822: fatal("take file ends prematurely in 'get'"); 823: stripq(cmdbuf); 824: if (*cmdbuf == NUL) cmarg2 = line; else cmarg2 = cmdbuf; 825: 826: } else { /* Input is from terminal */ 827: 828: char psave[40]; /* Save old prompt */ 829: cmsavp(psave,40); 830: cmsetp(" Remote file specification: "); /* Make new one */ 831: cmini(ckxech); 832: x = -1; 833: prompt(); 834: while (x == -1) { /* Prompt till they answer */ 835: x = cmtxt("Name of remote file(s)","",&cmarg); 836: debug(F111," cmtxt",cmarg,x); 837: } 838: if (x < 0) { 839: cmsetp(psave); 840: return(x); 841: } 842: if (*cmarg == NUL) { /* If user types a bare CR, */ 843: printf("(cancelled)\n"); /* Forget about this. */ 844: cmsetp(psave); /* Restore old prompt, */ 845: return(0); /* and return. */ 846: } 847: strcpy(line,cmarg); /* Make a safe copy */ 848: cmarg = line; 849: cmsetp(" Local name to store it under: "); /* New prompt */ 850: cmini(ckxech); 851: x = -1; 852: prompt(); /* Prompt */ 853: while (x < 0) { /* Again, parse till answered */ 854: x = cmofi("Local file name","",&cmarg2); 855: if (x == -2) return(x); 856: if (x == -3) { /* If bare CR, */ 857: printf("(cancelled)\n"); /* escape from this... */ 858: cmsetp(psave); /* restore old prompt, */ 859: return(0); /* and return. */ 860: } 861: } 862: cmsetp(psave); /* Restore old prompt. */ 863: if ((x == cmcfm()) < 0) return(-2); 864: } 865: } 866: sstate = 'r'; /* All ok, set start state. */ 867: if (local) displa = 1; 868: return(0); 869: 870: case XXHLP: /* Help */ 871: x = cmkey(cmdtab,ncmd,"C-Kermit command","help"); 872: return(dohlp(x)); 873: 874: case XXLOG: /* Log */ 875: x = cmkey(logtab,nlog,"What to log",""); 876: if (x == -3) { 877: printf("?You must specify what is to be logged\n"); 878: return(-2); 879: } 880: if (x < 0) return(x); 881: return(dolog(x)); 882: 883: case XXLOGI: /* Send script remote system */ 884: if ((x = cmtxt("Text of login script","",&s)) < 0) return(x); 885: return( login(s) ); /* Return 0=completed, -2=failed */ 886: 887: case XXREC: /* Receive */ 888: cmarg2 = ""; 889: x = cmofi("Name under which to store the file, or CR","",&cmarg2); 890: if ((x == -1) || (x == -2)) return(x); 891: debug(F111,"cmofi cmarg2",cmarg2,x); 892: if ((x = cmcfm()) < 0) return(x); 893: sstate = 'v'; 894: if (local) displa = 1; 895: return(0); 896: 897: case XXREM: /* Remote */ 898: if (!local) { 899: printf("\nYou have to 'set line' first\n"); 900: return(-2); 901: } 902: x = cmkey(remcmd,nrmt,"Remote Kermit server command",""); 903: if (x == -3) { 904: printf("?You must specify a command for the remote server\n"); 905: return(-2); 906: } 907: return(dormt(x)); 908: 909: case XXSEN: /* Send */ 910: cmarg = cmarg2 = ""; 911: if ((x = cmifi("File(s) to send","",&s,&y)) < 0) { 912: if (x == -3) { 913: printf("?A file specification is required\n"); 914: return(-2); 915: } 916: return(x); 917: } 918: nfils = -1; /* Files come from internal list. */ 919: strcpy(line,s); /* Save copy of string just parsed. */ 920: debug(F101,"Send: wild","",y); 921: *cmarg2 = '\0'; /* Initialize send-as name */ 922: if (y == 0) { 923: if ((x = cmtxt("Name to send it with","",&cmarg2)) < 0) return(x); 924: } else { 925: if ((x = cmcfm()) < 0) return(x); 926: } 927: cmarg = line; /* File to send */ 928: debug(F110,"Sending:",cmarg,0); 929: if (*cmarg2 != '\0') debug(F110," as:",cmarg2,0); 930: sstate = 's'; /* Set start state */ 931: if (local) displa = 1; 932: return(0); 933: 934: case XXSER: /* Server */ 935: if ((x = cmcfm()) < 0) return(x); 936: sstate = 'x'; 937: if (local) displa = 1; 938: return(0); 939: 940: case XXSET: /* Set */ 941: x = cmkey(prmtab,nprm,"Parameter",""); 942: if (x == -3) { 943: printf("?You must specify a parameter to set\n"); 944: return(-2); 945: } 946: if (x < 0) return(x); 947: return(doprm(x)); 948: 949: /* XXSHE code by H. Fischer; copyright rights assigned to Columbia Univ */ 950: /* 951: Adapted to use getpwuid to find login shell because many systems do not 952: have SHELL in environment, and to use direct calling of shell rather 953: than intermediate system() call. -- H. Fischer 954: */ 955: case XXSHE: /* Local shell command */ 956: { 957: int pid; 958: if (cmtxt("Unix shell command to execute","",&s) < 0) return(-1); 959: conres(); /* Make console normal */ 960: #ifdef MSDOS 961: zxcmd(s); 962: #else 963: #ifdef vax11c 964: 965: system(s); /* Best we can do for VMS? */ 966: 967: #else /* All Unix systems... */ 968: 969: if ((pid = fork()) == 0) { /* Make child */ 970: char *shpath, *shname, *shptr; /* For finding desired shell */ 971: struct passwd *p; 972: extern struct passwd * getpwuid(); 973: extern int getuid(); 974: char *defShel = "/bin/sh"; /* Default */ 975: 976: p = getpwuid( getuid() ); /* Get login data */ 977: if ( p == (struct passwd *) NULL || !*(p->pw_shell) ) 978: shpath = defShel; 979: else 980: shpath = p->pw_shell; 981: shptr = shname = shpath; 982: while (*shptr != '\0') 983: if (*shptr++ == '/') shname = shptr; 984: if (*s == NUL) /* Interactive shell requested? */ 985: execl(shpath,shname,"-i",(char *)0); /* Yes, do that */ 986: else /* Otherwise, */ 987: execl(shpath,shname,"-c",s,(char *)0); /* exec the given command */ 988: exit(GOOD_EXIT); } /* Just punt if it didnt work */ 989: 990: else { /* Parent */ 991: 992: int wstat; /* Kermit must wait for child */ 993: int (*istat)(), (*qstat)(); 994: 995: istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */ 996: qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */ 997: 998: while (((wstat = wait(0)) != pid) && (wstat != -1)) /* Wait for fork */ 999: ; 1000: signal(SIGINT,istat); /* Restore interrupts */ 1001: signal(SIGQUIT,qstat); 1002: } 1003: #endif 1004: #endif 1005: concb(escape); /* Console back in cbreak mode */ 1006: return(0); 1007: } 1008: 1009: case XXSHO: /* Show */ 1010: x = cmkey(shotab,2,"","parameters"); 1011: if (x < 0) return(x); 1012: if (y = (cmcfm()) < 0) return(y); 1013: switch (x) { 1014: 1015: case SHPAR: 1016: shopar(); 1017: break; 1018: 1019: case SHVER: 1020: printf("\nVersions:\n %s\n %s\n",versio,protv); 1021: printf(" %s\n",fnsv); 1022: printf(" %s\n %s\n %s for%s\n",cmdv,userv,ckxv,ckxsys); 1023: printf(" %s for%s\n %s\n",ckzv,ckzsys,connv); 1024: printf(" %s\n %s\n\n",dialv,loginv); 1025: break; 1026: 1027: default: 1028: printf("\nNothing to show...\n"); 1029: break; 1030: } 1031: return(0); 1032: 1033: case XXSPA: /* space */ 1034: if ((x = cmcfm()) < 0) return(x); 1035: system(SPACMD); 1036: return(0); 1037: 1038: case XXSTA: /* statistics */ 1039: if ((x = cmcfm()) < 0) return(x); 1040: printf("\nMost recent transaction --\n"); 1041: printf(" files: %ld\n",filcnt); 1042: printf(" total file characters : %ld\n",tfc); 1043: printf(" communication line in : %ld\n",tlci); 1044: printf(" communication line out : %ld\n",tlco); 1045: printf(" elapsed time : %d sec\n",tsecs); 1046: if (filcnt > 0) { 1047: if (tsecs > 0) { 1048: long lx; 1049: lx = (tfc / tsecs) * 10; 1050: printf(" effective baud rate : %ld\n",lx); 1051: if (speed > 0) { 1052: lx = (lx * 100) / speed; 1053: printf(" efficiency : %ld %%\n",lx); 1054: } 1055: } 1056: printf(" block check type used : %d\n",bctu); 1057: printf(" compression : "); 1058: if (rptflg) printf("yes [%c]\n",rptq); else printf("no\n"); 1059: printf(" 8th bit prefixing : "); 1060: if (ebqflg) printf("yes [%c]\n",ebq); else printf("no\n\n"); 1061: } else printf("\n"); 1062: return(0); 1063: 1064: case XXTAK: /* take */ 1065: if (tlevel > MAXTAKE-1) { 1066: printf("?Take files nested too deeply\n"); 1067: return(-2); 1068: } 1069: if ((y = cmifi("C-Kermit command file","",&s,&x)) < 0) { 1070: if (y == -3) { 1071: printf("?A file specification is required\n"); 1072: return(-2); 1073: } else return(y); 1074: } 1075: if (x != 0) { 1076: printf("?Wildcards not allowed in command file name\n"); 1077: return(-2); 1078: } 1079: strcpy(line,s); /* Make a safe copy of the string */ 1080: if ((y = cmcfm()) < 0) return(y); 1081: if ((tfile[++tlevel] = fopen(line,"r")) == NULL) { 1082: perror(line); 1083: debug(F110,"Failure to open",line,0); 1084: tlevel--; 1085: } 1086: return(0); 1087: 1088: default: 1089: printf("Not available - %s\n",cmdbuf); 1090: return(-2); 1091: } 1092: } 1093: 1094: /* S H O P A R -- Show Parameters */ 1095: 1096: shopar() { 1097: 1098: int i; 1099: extern struct keytab mdmtab[]; extern int nmdm; 1100: 1101: puts("\nCommunications Parameters:"); 1102: printf(" Line: %s, speed: %d, mode: ",ttname,speed); 1103: if (local) printf("local"); else printf("remote"); 1104: 1105: for (i = 0; i < nmdm; i++) { 1106: if (mdmtab[i].val == mdmtyp) { 1107: printf(", modem-dialer: %s",mdmtab[i].kwd); 1108: break; 1109: } 1110: } 1111: printf("\n Parity: "); 1112: switch (parity) { 1113: case 'e': printf("even"); break; 1114: case 'o': printf("odd"); break; 1115: case 'm': printf("mark"); break; 1116: case 's': printf("space"); break; 1117: case 0: printf("none"); break; 1118: default: printf("invalid - %d",parity); break; 1119: } 1120: printf(", duplex: "); 1121: if (duplex) printf("half, "); else printf("full, "); 1122: printf("flow: "); 1123: if (flow == 1) printf("xon/xoff"); 1124: else if (flow == 0) printf("none"); 1125: else printf("%d",flow); 1126: printf(", handshake: "); 1127: if (turn) printf("%d\n",turnch); else printf("none\n"); 1128: 1129: printf("\nProtocol Parameters: Send Receive"); 1130: if (timef || spsizf) printf(" (* = override)"); 1131: printf("\n Timeout: %11d%9d", rtimo, timint); 1132: if (timef) printf("*"); 1133: printf("\n Padding: %11d%9d\n", npad, mypadn); 1134: printf( " Pad Character:%11d%9d\n", padch, mypadc); 1135: printf( " Packet Start: %11d%9d\n", mystch, stchr); 1136: printf( " Packet End: %11d%9d\n", seol, eol); 1137: printf( " Packet Length:%11d", spsiz); 1138: printf( spsizf ? "*" : " " ); printf("%8d\n", rpsiz); 1139: 1140: printf("\nBlock Check Type: %d, Delay: %d\n",bctr,delay); 1141: if (ebqflg) printf("8th-Bit Prefix: '%c'\n",ebq); 1142: if (rptflg) printf("Repeat-Count Prefix: '%c'\n",rptq); 1143: 1144: printf("\nFile parameters:\n File Names: "); 1145: if (fncnv) printf("%-12s","converted"); else printf("%-12s","literal"); 1146: #ifdef DEBUG 1147: printf(" Debugging Log: "); 1148: if (deblog) printf("%s",debfil); else printf("none"); 1149: #endif 1150: printf("\n File Type: "); 1151: if (binary) printf("%-12s","binary"); else printf("%-12s","text"); 1152: printf(" Packet Log: "); 1153: if (pktlog) printf(pktfil); else printf("none"); 1154: printf("\n File Warning: "); 1155: if (warn) printf("%-12s","on"); else printf("%-12s","off"); 1156: printf(" Session Log: "); 1157: if (seslog) printf(sesfil); else printf("none"); 1158: printf("\n File Display: "); 1159: if (quiet) printf("%-12s","off"); else printf("%-12s","on"); 1160: #ifdef TLOG 1161: printf(" Transaction Log: "); 1162: if (tralog) printf(trafil); else printf("none"); 1163: #endif 1164: printf("\n\nIncomplete File Disposition: "); 1165: if (keep) printf("keep"); else printf("discard"); 1166: #ifdef KERMRC 1167: printf(", Init file: %s",KERMRC); 1168: #endif 1169: puts("\n"); 1170: } 1171: 1172: /* D O C O N E C T -- Do the connect command */ 1173: 1174: /* Note, we don't call this directly from dial, because we need to give */ 1175: /* the user a chance to change parameters (e.g. parity) after the */ 1176: /* connection is made. */ 1177: 1178: doconect() { 1179: int x; 1180: conres(); /* Put console back to normal */ 1181: x = conect(); /* Connect */ 1182: concb(escape); /* Put console into cbreak mode, */ 1183: return(x); /* for more command parsing. */ 1184: } 1185: 1186: 1187: /* D O L O G -- Do the log command */ 1188: 1189: dolog(x) int x; { 1190: int y; char *s; 1191: 1192: switch (x) { 1193: 1194: case LOGD: 1195: #ifdef DEBUG 1196: y = cmofi("Name of debugging log file","debug.log",&s); 1197: #else 1198: y = -2; s = ""; 1199: printf("%s","- Sorry, debug log not available\n"); 1200: #endif 1201: break; 1202: 1203: case LOGP: 1204: y = cmofi("Name of packet log file","packet.log",&s); 1205: break; 1206: 1207: case LOGS: 1208: y = cmofi("Name of session log file","session.log",&s); 1209: break; 1210: 1211: case LOGT: 1212: #ifdef TLOG 1213: y = cmofi("Name of transaction log file","transact.log",&s); 1214: #else 1215: y = -2; s = ""; 1216: printf("%s","- Sorry, transaction log not available\n"); 1217: #endif 1218: break; 1219: 1220: default: 1221: printf("\n?Unexpected log designator - %d\n",x); 1222: return(-2); 1223: } 1224: if (y < 0) return(y); 1225: 1226: strcpy(line,s); 1227: s = line; 1228: if ((y = cmcfm()) < 0) return(y); 1229: 1230: /* cont'd... */ 1231: 1232: /* ...dolog, cont'd */ 1233: 1234: 1235: switch (x) { 1236: 1237: case LOGD: 1238: return(deblog = debopn(s)); 1239: 1240: case LOGP: 1241: zclose(ZPFILE); 1242: y = zopeno(ZPFILE,s); 1243: if (y > 0) strcpy(pktfil,s); else *pktfil = '\0'; 1244: return(pktlog = y); 1245: 1246: case LOGS: 1247: zclose(ZSFILE); 1248: y = zopeno(ZSFILE,s); 1249: if (y > 0) strcpy(sesfil,s); else *sesfil = '\0'; 1250: return(seslog = y); 1251: 1252: case LOGT: 1253: zclose(ZTFILE); 1254: tralog = zopeno(ZTFILE,s); 1255: if (tralog > 0) { 1256: strcpy(trafil,s); 1257: tlog(F110,"Transaction Log:",versio,0l); 1258: tlog(F100,ckxsys,"",0); 1259: ztime(&s); 1260: tlog(F100,s,"",0l); 1261: } 1262: else *trafil = '\0'; 1263: return(tralog); 1264: 1265: default: 1266: return(-2); 1267: } 1268: } 1269: 1270: 1271: /* D E B O P N -- Open a debugging file */ 1272: 1273: debopn(s) char *s; { 1274: #ifdef DEBUG 1275: char *tp; 1276: zclose(ZDFILE); 1277: deblog = zopeno(ZDFILE,s); 1278: if (deblog > 0) { 1279: strcpy(debfil,s); 1280: debug(F110,"Debug Log ",versio,0); 1281: debug(F100,ckxsys,"",0); 1282: ztime(&tp); 1283: debug(F100,tp,"",0); 1284: } else *debfil = '\0'; 1285: return(deblog); 1286: #else 1287: return(0); 1288: #endif 1289: }