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