BSD 4_3 development
[unix-history] / usr / contrib / kermit / ckuusr.c
CommitLineData
ee2abe03
C
1char *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\f
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\f
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
87extern 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
93extern long filcnt, tlci, tlco, ffc, tfc, fsize;
94
95extern char *versio, *protv, *ckxv, *ckzv, *fnsv, *connv, *dftty, *cmdv;
96extern char *dialv, *loginv;
97extern char *ckxsys, *ckzsys, *cmarg, *cmarg2, **xargv, **cmlist;
98extern CHAR mystch, stchr, sstate, mypadc, padch, eol, seol, ctlq, filnam[],
99 ttname[];
100extern char *DIRCMD, *PWDCMD, cmerrp[];
101char *strcpy(), *getenv();
102
103/* Declarations from cmd package */
104
105extern char cmdbuf[]; /* Command buffer */
106
107/* Declarations from ck?fio.c module */
108
109extern char *SPACMD, *zhome(); /* Space command, home directory. */
110extern 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
118char line[CMDBL+10], *lp; /* Character buffer for anything */
119char debfil[50]; /* Debugging log file name */
120char pktfil[50]; /* Packet log file name */
121char sesfil[50]; /* Session log file name */
122char trafil[50]; /* Transaction log file name */
123
124int 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 */
132FILE *tfile[MAXTAKE]; /* File pointers for TAKE command */
133
134char *homdir; /* Pointer to home directory string */
135char cmdstr[100];
136\f
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*/
143cmdlin() {
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\f
195/* D O A R G -- Do a command-line argument. */
196
197doarg(x) char x; {
198 int z; char *xp;
199
200 xp = *xargv+1; /* Pointer for bundled args */
201 while (x) {
202 switch (x) {
203
204case 'x': /* server */
205 if (action) fatal("conflicting actions");
206 action = 'x';
207 break;
208
209case 'f':
210 if (action) fatal("conflicting actions");
211 action = setgen('F',"","","");
212 break;
213
214case 'r': /* receive */
215 if (action) fatal("conflicting actions");
216 action = 'v';
217 break;
218
219case 'k': /* receive to stdout */
220 if (action) fatal("conflicting actions");
221 stdouf = 1;
222 action = 'v';
223 break;
224
225case '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\f
254/* ...doarg(), cont'd */
255
256case '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
266case 'c': /* connect before */
267 cflg = 1;
268 break;
269
270case 'n': /* connect after */
271 cnflg = 1;
272 break;
273
274case 'h': /* help */
275 usage();
276 return(-1);
277
278case '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
286case '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
298case '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
308case 'i': /* Treat files as binary */
309 binary = 1;
310 break;
311
312/* cont'd... */
313\f
314/* ...doarg(), cont'd */
315
316
317case 'w': /* File warning */
318 warn = 1;
319 break;
320
321case 'q': /* Quiet */
322 quiet = 1;
323 break;
324
325case 'd': /* debug */
326 debopn("debug.log");
327 break;
328
329case '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
344case '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
351default:
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\f
360/* Misc */
361
362fatal(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
369ermsg(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\f
374/* Interactive command parser */
375
376
377/* Top-Level Keyword Table */
378
379struct 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};
409int ncmd = (sizeof(cmdtab) / sizeof(struct keytab));
410\f
411/* Parameter keyword table */
412
413struct 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};
437int nprm = (sizeof(prmtab) / sizeof(struct keytab)); /* How many parameters */
438
439
440/* Remote Command Table */
441
442struct 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};
452int nrmt = (sizeof(remcmd) / sizeof(struct keytab));
453
454struct keytab logtab[] = {
455 "debugging", LOGD, 0,
456 "packets", LOGP, 0,
457 "session", LOGS, 0,
458 "transactions", LOGT, 0
459};
460int nlog = (sizeof(logtab) / sizeof(struct keytab));
461
462/* Show command arguments */
463
464#define SHPAR 0 /* Parameters */
465#define SHVER 1 /* Versions */
466
467struct keytab shotab[] = {
468 "parameters", SHPAR, 0,
469 "versions", SHVER, 0
470};
471\f
472/* C M D I N I -- Initialize the interactive command parser */
473
474cmdini() {
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
511trap() {
512 debug(F100,"terminal interrupt...","",0);
513 doexit(GOOD_EXIT); /* Exit indicating success */
514}
515\f
516/* P A R S E R -- Top-level interactive command parser. */
517
518parser() {
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
543again: 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\f
592/* D O E X I T -- Exit from the program. */
593
594doexit(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\f
629/* B L D L E N -- Make length-encoded copy of string */
630
631char *
632bldlen(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
643setgen(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\f
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
671docmd(cx) int cx; {
672 int x, y;
673 char *s;
674
675 switch (cx) {
676
677case -4: /* EOF */
678 if (!quiet) printf("\r\n");
679 doexit(GOOD_EXIT);
680case -3: /* Null command */
681 return(0);
682case -2: /* Error */
683case -1: /* Reparse needed */
684 return(cx);
685
686case 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
695case XXCOM: /* comment */
696 if ((x = cmtxt("Text of comment line","",&s)) < 0) return(x);
697 return(0);
698
699case XXCON: /* connect */
700 if ((x = cmcfm()) < 0) return(x);
701 return(doconect());
702
703case 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\f
711case 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\f
762case XXDIAL: /* dial number */
763 if ((x = cmtxt("Number to be dialed","",&s)) < 0) return(x);
764 return(dial(s));
765
766case 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
774case 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
789case XXQUI: /* quit, exit */
790case XXEXI:
791 if ((x = cmcfm()) > -1) doexit(GOOD_EXIT);
792 else return(x);
793
794case 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\f
803case 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\f
870case XXHLP: /* Help */
871 x = cmkey(cmdtab,ncmd,"C-Kermit command","help");
872 return(dohlp(x));
873
874case 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
883case 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
887case 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
897case 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\f
909case 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
934case XXSER: /* Server */
935 if ((x = cmcfm()) < 0) return(x);
936 sstate = 'x';
937 if (local) displa = 1;
938 return(0);
939
940case 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\f
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*/
955case 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\f
1009case 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
1033case XXSPA: /* space */
1034 if ((x = cmcfm()) < 0) return(x);
1035 system(SPACMD);
1036 return(0);
1037
1038case 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\f
1064case 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
1088default:
1089 printf("Not available - %s\n",cmdbuf);
1090 return(-2);
1091 }
1092}
1093\f
1094/* S H O P A R -- Show Parameters */
1095
1096shopar() {
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\f
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
1178doconect() {
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
1189dolog(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\f
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
1273debopn(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}