home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 3 Comm
/
03-Comm.zip
/
CKPM5X_S.ZIP
/
CKUUSR.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-03-03
|
57KB
|
1,740 lines
char *userv = "User Interface 5A(067), 1 Mar 90";
/* C K U U S R -- "User Interface" for Unix Kermit (Part 1) */
/*
Author: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET),
Columbia University Center for Computing Activities.
First released January 1985.
Copyright (C) 1985, 1990, Trustees of Columbia University in the City of New
York. Permission is granted to any individual or institution to use, copy, or
redistribute this software so long as it is not sold for profit, provided this
copyright notice is retained.
*/
/*
NOTE: Because of the massive additions in functionality, and therefore
the increase in the number of commands, much code was moved from here to
the two new modules, ckuus4.c and ckuus5.c. This module now contains only
the top-level command keyword table, the SET command keyword table, and
the top-level interactive command parser/dispatcher. ckuus3.c contains the
rest of the SET and REMOTE command parsers; ckuus2.c contains the help
command parser and help text strings, and ckuus4.c and ckuus5.c contain
miscellaneous pieces that logically belong in the ckuusr.c file but had to
be moved because of size problems with some C compilers / linkers.
*/
/*
The ckuus*.c modules depend on the existence of C library features like fopen,
fgets, feof, (f)printf, argv/argc, etc. Other functions that are likely to
vary among Unix implementations -- like setting terminal modes or interrupts
-- are invoked via calls to functions that are defined in the system-
dependent modules, ck?[ft]io.c. The command line parser processes any
arguments found on the command line, as passed to main() via argv/argc. The
interactive parser uses the facilities of the cmd package (developed for this
program, but usable by any program). Any command parser may be substituted
for this one. The only requirements for the Kermit command parser are these:
1. Set parameters via global variables like duplex, speed, ttname, etc. See
ckmain.c for the declarations and descriptions of these variables.
2. If a command can be executed without the use of Kermit protocol, then
execute the command directly and set the variable sstate to 0. Examples
include 'set' commands, local directory listings, the 'connect' command.
3. If a command requires the Kermit protocol, set the following variables:
sstate string data
'x' (enter server mode) (none)
'r' (send a 'get' command) cmarg, cmarg2
'v' (enter receive mode) cmarg2
'g' (send a generic command) cmarg
's' (send files) nfils, cmarg & cmarg2 OR cmlist
'c' (send a remote host command) cmarg
cmlist is an array of pointers to strings.
cmarg, cmarg2 are pointers to strings.
nfils is an integer.
cmarg can be a filename string (possibly wild), or
a pointer to a prefabricated generic command string, or
a pointer to a host command string.
cmarg2 is the name to send a single file under, or
the name under which to store an incoming file; must not be wild.
If it's the name for receiving, a null value means to store the
file under the name it arrives with.
cmlist is a list of nonwild filenames, such as passed via argv.
nfils is an integer, interpreted as follows:
-1: filespec (possibly wild) in cmarg, must be expanded internally.
0: send from stdin (standard input).
>0: number of files to send, from cmlist.
The screen() function is used to update the screen during file transfer.
The tlog() function writes to a transaction log.
The debug() function writes to a debugging log.
The intmsg() and chkint() functions provide the user i/o for interrupting
file transfers.
*/
/* Includes */
#include <stdio.h>
#include <ctype.h>
#ifndef AMIGA
/* Apparently these should be included for OS/2 C-Kermit after all... */
/* #ifndef OS2 */
#include <signal.h>
#include <setjmp.h>
/* #endif */
#endif
#include "ckcdeb.h"
#include "ckcasc.h"
#include "ckcker.h"
#include "ckucmd.h"
#include "ckuusr.h"
#include "ckcxla.h"
#ifdef datageneral
#define fgets(stringbuf,max,fd) dg_fgets(stringbuf,max,fd)
#define fork() vfork()
/* DG version 3.21 of C has bugs in the following routines, since they
* depend on /etc/passwd. In the context where the routines are used,
* we don't need them anyway.
*/
#define getgid() -1
#define getuid() -1
#define geteuid() -1
#endif
/* External Kermit Variables, see ckmain.c for description. */
extern int size, rpsiz, urpsiz, speed, local, rmailf,
server, displa, binary, parity, deblog, escape, xargc, flow,
turn, duplex, nfils, ckxech, pktlog, seslog, tralog, stdouf,
turnch, dfloc, keep, maxrps, warn, quiet, cnflg, tlevel,
mdmtyp, zincnt, cmaskm;
extern int xxstring(); /* Variable expander */
extern long vernum;
extern char *versio, *protv, *ckxv, *ckzv, *fnsv, *connv, *dftty, *cmdv;
extern char *dialv, *loginv;
extern char *ckxsys, *ckzsys, *cmarg, *cmarg2, **xargv, **cmlist;
extern char *DIRCMD, *PWDCMD, *DELCMD, cmerrp[], optbuf[];
extern CHAR sstate, ttname[], filnam[];
extern CHAR *zinptr;
extern int tcharset, fcharset;
extern struct csinfo fcsinfo[], tcsinfo[];
char *strcpy(), *getenv(), *varlook();
#ifdef AMIGA
char *getcwd();
#endif
#ifdef OS2
char *getcwd();
#endif
/* Declarations from cmd package */
extern char cmdbuf[], atmbuf[], savbuf[]; /* Command buffers */
/* Declarations from ck?fio.c module */
extern char *SPACMD, *zhome(); /* Space command, home directory. */
extern int backgrd; /* Kermit executing in background */
#ifdef OS2
extern char *zfindfile();
#endif
/* The background flag is set by ckutio.c (via conint() ) to note whether */
/* this kermit is executing in background ('&' on shell command line). */
/* Variables and symbols local to this module */
extern char line[]; /* Character buffer for anything */
char *lp; /* Pointer to line buffer */
extern char inpbuf[]; /* Buffer for INPUT and REINPUT */
char *inpbp = inpbuf; /* And pointer to same */
extern char vnambuf[]; /* Buffer for variable names */
char *vnp; /* Pointer to same */
extern char lblbuf[]; /* Buffer for labels */
extern char debfil[]; /* Debugging log file name */
extern char pktfil[]; /* Packet log file name */
extern char sesfil[]; /* Session log file name */
extern char trafil[]; /* Transaction log file name */
extern char tmpbuf[]; /* Temporary buffer */
char *tp; /* Temporary pointer */
int n, /* General purpose int */
cflg, /* Command-line connect cmd given */
action, /* Action selected on command line*/
repars, /* Reparse needed */
ifc, /* IF case */
not = 0, /* Flag for IF NOT */
techo = 0, /* Take echo */
terror = 1, /* Take error action, 1 = quit */
tvtflg = 0, /* tty device put in tvt mode */
cwdf = 0; /* CWD has been done */
extern int en_cwd, en_del, en_dir, en_fin, /* Flags for ENABLE/DISABLE */
en_get, en_hos, en_sen, en_set, en_spa, en_typ, en_who;
int /* SET INPUT parameters. */
indef = 5, /* 5 seconds default timeout */
intime = 0, /* 0 = proceed */
incase = 0, /* 0 = ignore */
inecho = 1; /* 1 = echo on */
int cmdsrc = 0; /* Where commands are coming from: */
/* 0 = kb, 1 = take, 2 = macro */
int maclvl = -1; /* Macro to execute */
extern int macx[]; /* Index of current macro */
int mecho = 0; /* Macro echo */
int merror = 0; /* Macro error action */
extern char *macp[]; /* Pointer to macro */
char varnam[6]; /* For variable names */
extern int macargc[]; /* ARGC from macro invocation */
int success; /* "Input" success flag */
extern FILE *tfile[]; /* File pointers for TAKE command */
extern char *m_arg[MACLEVEL][NARGS]; /* Stack of macro arguments */
extern char *g_var[]; /* Global variables %a, %b, etc */
extern struct cmdptr cmdstk[]; /* The command stack itself */
int cmdlvl = 0; /* Current position in command stack */
int count[]; /* For IF COUNT, one for each cmdlvl */
int ifcmd[]; /* Last command was IF */
int iftest[]; /* Last IF was true */
char *homdir; /* Pointer to home directory string */
extern char kermrc[]; /* Name of initialization file */
int rcflag = 0; /* Flag for alternate init file name */
extern char cmdstr[]; /* Place to build generic command */
/* Top-Level Interactive Command Keyword Table */
struct keytab cmdtab[] = {
"!", XXSHE, 0, /* shell escape */
"#", XXCOM, CM_INV, /* comment */
":", XXLBL, CM_INV, /* label */
"ask", XXASK, 0, /* ask */
"askq", XXASKQ,0, /* ask quietly */
"assign", XXASS, 0, /* assign */
"bye", XXBYE, 0, /* bye to remote server */
"c", XXCON, CM_INV, /* invisible synonym for connect */
"cd", XXCWD, 0, /* change directory */
"clear", XXCLE, 0, /* clear input buffer */
"close", XXCLO, 0, /* close a log file */
"comment", XXCOM, 0, /* comment */
"connect", XXCON, 0, /* connect to remote system */
"cwd", XXCWD, CM_INV, /* invisisble synonym for cd */
"decrement", XXDEC, 0, /* decrement a numeric variable */
"define", XXDEF, 0, /* define a macro */
"delete", XXDEL, 0, /* delete a file */
"dial", XXDIAL,0, /* dial a phone number */
"directory", XXDIR, 0, /* directory of files */
"disable", XXDIS, 0, /* disable server function */
"do", XXDO, 0, /* execute a macro */
"echo", XXECH, 0, /* echo argument */
"else", XXELS, CM_INV, /* ELSE part of IF statement */
"enable", XXENA, 0, /* enable a server function */
"end", XXEND, 0, /* end a take file or macro */
"exit", XXEXI, 0, /* exit the program */
"finish", XXFIN, 0, /* shut down a remote server */
"get", XXGET, 0, /* get a file from a server */
"goto", XXGOTO,0, /* goto label in take file or macro */
"hangup", XXHAN, 0, /* hangup dialed phone connection */
"help", XXHLP, 0, /* display help text */
"if", XXIF, 0, /* if (condition) command */
"increment", XXINC, 0, /* increment a numeric variable */
"input", XXINP, 0, /* input string from comm line */
"l", XXLOG, CM_INV, /* invisible synonym for log */
"log", XXLOG, 0, /* open a log file */
"ls", XXDIR, CM_INV, /* invisible synonym for directory */
"mail", XXMAI, 0, /* mail file to user */
"output", XXOUT, 0, /* output string to comm line */
"pause", XXPAU, 0, /* sleep for specified interval */
"pop", XXEND, CM_INV, /* allow POP as synonym for END */
"push", XXSHE, 0, /* PUSH command (like RUN, !) */
"pwd", XXPWD, 0, /* print working directory */
"quit", XXQUI, 0, /* quit from program = exit */
"r", XXREC, CM_INV, /* invisible synonym for receive */
"reinput", XXREI, 0, /* reinput */
"receive", XXREC, 0, /* receive files */
"remote", XXREM, 0, /* send generic command to server */
"replay", XXTYP, 0, /* replay (for now, just type) */
"rm", XXDEL, CM_INV, /* invisible synonym for delete */
"run", XXSHE, 0, /* run a program or command */
"s", XXSEN, CM_INV, /* invisible synonym for send */
"script", XXLOGI,0, /* execute a uucp-style script */
"send", XXSEN, 0, /* send files */
"server", XXSER, 0, /* be a server */
"set", XXSET, 0, /* set parameters */
"show", XXSHO, 0, /* show parameters */
"space", XXSPA, 0, /* show available disk space */
"statistics", XXSTA, 0, /* display file transfer stats */
"stop", XXSTO, 0, /* stop all take files */
"take", XXTAK, 0, /* take commands from file */
"test", XXTES, CM_INV, /* (for testing) */
"translate", XXXLA, 0, /* translate local file char sets */
"transmit", XXTRA, 0, /* raw upload file */
"type", XXTYP, 0, /* display a local file */
"version", XXVER, 0, /* version number display */
"wait", XXWAI, CM_INV /* wait (like pause) */
};
int ncmd = (sizeof(cmdtab) / sizeof(struct keytab));
char toktab[] = {
'!', /* Shell escape */
'#', /* Comment */
';', /* Comment */
'&', /* Echo */
':', /* Label */
'\0' /* End of this string */
};
/* Parameter keyword table */
struct keytab prmtab[] = {
"attributes", XYATTR, 0,
"baud", XYSPEE, CM_INV,
"block-check", XYCHKT, 0,
"count", XYCOUN, 0,
"debug", XYDEBU, CM_INV,
"delay", XYDELA, 0,
"duplex", XYDUPL, 0,
"end-of-packet", XYEOL, CM_INV, /* moved to send/receive */
"escape-character", XYESC, 0,
"file", XYFILE, 0,
"flow-control", XYFLOW, 0,
"handshake", XYHAND, 0,
#ifdef NETCONN
"host", XYNETW, 0,
#endif /* NETCONN */
"incomplete", XYIFD, 0,
"input", XYINPU, 0,
"l", XYLINE, CM_INV,
"language", XYLANG, 0,
"line", XYLINE, 0,
"macro", XYMACR, 0,
"modem-dialer", XYMODM, 0,
#ifdef NETCONN
"network", XYNET, CM_INV,
#endif /* NETCONN */
"packet-length", XYLEN, CM_INV, /* moved to send/receive */
"pad-character", XYPADC, CM_INV, /* moved to send/receive */
"padding", XYNPAD, CM_INV, /* moved to send/receive */
"parity", XYPARI, 0,
"port", XYLINE, CM_INV,
"prompt", XYPROM, 0,
"receive", XYRECV, 0,
"retry", XYRETR, 0,
"send", XYSEND, 0,
"server", XYSERV, 0,
"speed", XYSPEE, 0,
"start-of-packet", XYMARK, CM_INV, /* moved to send/receive */
"take", XYTAKE, 0,
"terminal", XYTERM, 0,
"timeout", XYTIMO, CM_INV, /* moved to send/receive */
"transfer", XYXFER, 0,
"unknown-character-set", XYUNCS, 0,
"window", XYWIND, 0
};
int nprm = (sizeof(prmtab) / sizeof(struct keytab)); /* How many parameters */
/* Table of networks (not used yet) */
#ifdef NETCONN
struct keytab netcmd[] = {
"tcp-ip-socket", 0, 0
};
int nnets = 1; /* How many networks */
#endif /* NETCONN */
/* Remote Command Table */
struct keytab remcmd[] = {
"cd", XZCWD, CM_INV,
"cwd", XZCWD, 0,
"delete", XZDEL, 0,
"directory", XZDIR, 0,
"help", XZHLP, 0,
"host", XZHOS, 0,
"print", XZPRI, 0,
"set", XZSET, 0,
"space", XZSPA, 0,
"type", XZTYP, 0,
"who", XZWHO, 0
};
int nrmt = (sizeof(remcmd) / sizeof(struct keytab));
struct keytab logtab[] = {
"debugging", LOGD, 0,
"packets", LOGP, 0,
"session", LOGS, 0,
"transactions", LOGT, 0
};
int nlog = (sizeof(logtab) / sizeof(struct keytab));
/* Show command arguments */
struct keytab shotab[] = {
"communications", SHCOM, 0,
"count", SHCOU, 0,
"file", SHFIL, 0,
"key", SHKEY, CM_INV,
"languages", SHLNG, 0,
"macros", SHMAC, 0,
"parameters", SHPAR, CM_INV,
"protocol", SHPRO, 0,
"scripts", SHSCR, 0,
"server", SHSER, 0,
"speed", SHSPD, CM_INV,
"status", SHSTA, 0,
"versions", SHVER, 0
};
int nsho = (sizeof(shotab) / sizeof(struct keytab));
struct keytab iftab[] = { /* IF commands */
"<", XXIFLT, 0,
"=", XXIFAE, 0,
">", XXIFGT, 0,
"count", XXIFCO, 0,
"defined", XXIFDE, 0,
"equal", XXIFEQ, 0,
"exist", XXIFEX, 0,
"failure", XXIFFA, 0,
"not", XXIFNO, 0,
"success", XXIFSU, 0
};
int nif = (sizeof(iftab) / sizeof(struct keytab));
struct keytab enatab[] = { /* ENABLE commands */
"all", EN_ALL, 0,
"bye", EN_FIN, 0,
"cd", EN_CWD, 0,
"cwd", EN_CWD, CM_INV,
"directory", EN_DIR, 0,
"finish", EN_FIN, 0,
"get", EN_GET, 0,
"host", EN_HOS, 0,
"send", EN_SEN, 0,
"set", EN_SET, 0,
"space", EN_SPA, 0,
"type", EN_TYP, 0,
"who", EN_WHO, 0
};
int nena = (sizeof(enatab) / sizeof(struct keytab));
struct mtab mactab[MAC_MAX] = { /* Preinitialized macro table */
NULL, NULL, 0
};
int nmac = 0;
struct keytab mackey[MAC_MAX]; /* Macro names as command keywords */
/* D O C M D -- Do a command */
/*
Returns:
-2: user typed an illegal command
-1: reparse needed
0: parse was successful (even tho command may have failed).
*/
docmd(cx) int cx; {
int b, x, y, z;
char *s, *p, *q;
char a;
#ifdef DTILDE
char *tnam, *tilde_expand(); /* May have to expand tildes */
#endif
debug(F101,"docmd entry, cx","",cx);
switch (cx) {
case -4: /* EOF */
#ifdef OSK
if (!quiet && !backgrd) printf("\n");
#else
if (!quiet && !backgrd) printf("\r\n");
#endif /* OSK */
doexit(GOOD_EXIT);
case -3: /* Null command */
return(0);
case -6: /* Special */
case -2: /* Error, maybe */
case -1: /* Reparse needed */
return(cx);
case XXASK: /* ask */
case XXASKQ:
if ((y = cmfld("Variable name","",&s,NULL)) < 0) return(y);
strcpy(line,s);
lp = line;
if (line[0] == CMDQ && line[1] == '%') lp++;
if (*lp == '%') {
if (*(lp+2) != '\0') {
printf("?Only one character after %% in variable name, please\n");
return(-2);
}
if (isdigit(*lp) && maclvl < 0) {
printf("?Macro parameters not allowed at top level\n");
return(-2);
}
} else { /* Actually, we could allow */
printf("?Variables only, please"); /* them to type in macro */
return(-2); /* definitions, but... */
}
if ((y = cmtxt("Prompt","",&p,xxstring)) < 0) return(y);
{ /* Input must be from terminal */
char psave[40]; /* Save old prompt */
cmsavp(psave,40);
cmsetp(p); /* Make new one */
if (cx == XXASK) /* ASK echoes what the user types */
cmini(ckxech);
else /* ASKQ does not echo */
cmini(0);
x = -1; /* This means to reparse. */
if (!backgrd) prompt(); /* Issue prompt. */
while (x == -1) { /* Prompt till they answer */
x = cmtxt("definition for variable","",&s,NULL);
debug(F111," cmtxt",s,x);
}
if (cx == XXASKQ) printf("\r\n"); /* If ASKQ must echo CRLF here */
if (x < 0) {
cmsetp(psave);
return(x);
}
success = 1; /* Here we know command succeeded */
if (*s == NUL) { /* If user types a bare CR, */
cmsetp(psave); /* Restore old prompt, */
delmac(lp); /* delete variable if it exists, */
return(0); /* and return. */
}
y = *(lp + 1); /* Fold case */
if (isupper(y)) *(lp + 1) = tolower(y);
y = addmac(lp,s); /* Add it to the macro table. */
cmsetp(psave); /* Restore old prompt. */
}
return(0);
case XXBYE: /* bye */
if ((x = cmcfm()) < 0) return(x);
sstate = setgen('L',"","","");
return(0);
case XXCLE: /* clear */
if ((x = cmcfm()) < 0) return(x);
if (!local) {
printf("You have to 'set line' first\n");
return(0);
}
y = ttflui(); /* flush input buffer */
for (x = 0; x < INPBUFSIZ; x++) /* and our local copy too */
inpbuf[x] = 0;
inpbp = inpbuf;
success = (y == 0); /* Set SUCCESS/FAILURE */
return(0);
case XXCOM: /* comment */
if ((x = cmtxt("Text of comment line","",&s,NULL)) < 0) return(x);
/* Don't change SUCCESS flag for this one */
return(0);
case XXCON: /* Connect */
if ((x = cmcfm()) < 0)
return(x);
return(success = doconect());
case XXCWD:
#ifdef AMIGA
if ((x = cmtxt("Name of local directory, or carriage return","",&s,
xxstring)) < 0)
return(x);
/* if no name, just print directory name */
if (*s) {
if (chdir(s)) {
cwdf = success = 0;
perror(s);
}
success = cwdf = 1;
}
if (getcwd(line, sizeof(line)) == NULL)
printf("Current directory name not available.\n");
else
if (!backgrd && cmdlvl == 0) printf("%s\n", line);
#else
if ((x = cmdir("Name of local directory, or carriage return",homdir,&s,
xxstring)) < 0 )
return(x);
if (x == 2) {
printf("\n?Wildcards not allowed in directory name\n");
return(-2);
}
#ifdef OS2
if ( s!=NUL ) {
if (strlen(s)>=2 && s[1]==':') { /* Disk specifier */
if (zchdsk(*s)) { /* Change disk successful */
if ( strlen(s)>=3 & ( s[2]==CMDQ || isalnum(s[2]) ) ) {
if (chdir(s)) perror(s);
}
} else {
cwdf = success = 0;
perror(s);
}
} else if (chdir(s)) {
cwdf = success = 0;
perror(s);
}
}
success = cwdf = 1;
concooked();
system(PWDCMD);
conraw();
#else
if (! zchdir(s)) {
cwdf = success = 0;
perror(s);
}
system(PWDCMD); /* assume this works... */
success = cwdf = 1; /* system() doesn't tell */
#endif
#endif
return(0);
case XXCLO:
x = cmkey(logtab,nlog,"Which log to close","",xxstring);
if (x == -3) {
printf("?You must tell which log\n");
return(-2);
}
if (x < 0) return(x);
if ((y = cmcfm()) < 0) return(y);
y = doclslog(x);
success = (y == 1);
return(success);
case XXDEC: /* DECREMENT */
case XXINC: { /* INCREMENT */
char c;
int n;
if ((y = cmfld("Variable name","",&s,NULL)) < 0)
return(y);
strncpy(vnambuf,s,VNAML);
vnp = vnambuf;
if (vnambuf[0] == CMDQ && vnambuf[1] == '%') vnp++;
if (*vnp != '%') {
printf("?Not a variable name - %s\n",s);
return(-2);
}
if (*vnp == '%' && *(vnp+2) != '\0') {
printf("?Only one character after %% in variable name, please\n");
return(-2);
}
if ((x = cmcfm()) < 0) return(x);
p = varlook(vnp); /* Look up variable */
if (p == NULL) {
printf("?Not defined - %s\n",s);
return(success = 0); /* If not found, fail. */
}
if (!chknum(p)) { /* If not numeric, fail. */
printf("?Not numeric - %s = [%s]\n",s,p);
return(success = 0);
}
n = atoi(p); /* Otherwise convert to integer */
if (cx == XXINC) /* And now increment */
n++;
else if (cx == XXDEC) /* or decrement as requested. */
n--;
sprintf(tmpbuf,"%d",n); /* Convert back to numeric string */
addmac(vnp,tmpbuf); /* Replace old variable */
return(success = 1); }
case XXDEF: /* DEFINE */
case XXASS: /* ASSIGN */
if ((y = cmfld("Macro or variable name","",&s,NULL)) < 0) return(y);
strcpy(vnambuf,s);
vnp = vnambuf;
if (vnambuf[0] == CMDQ && vnambuf[1] == '%') vnp++;
if (*vnp == '%') {
#ifdef COMMENT
if (isdigit(*(vnp+1)) && maclvl < 0) {
printf("?Macro parameters not allowed at top level\n");
return(-2);
}
#endif
if ((y = cmtxt("Definition of variable","",&s,NULL)) < 0) return(y);
debug(F110,"xxdef var name",vnp,0);
debug(F110,"xxdef var def",s,0);
} else {
if ((y = cmtxt("Definition of macro","",&s,NULL)) < 0) return(y);
debug(F110,"xxdef macro name",vnp,0);
debug(F110,"xxdef macro def",s,0);
}
if (*s == NUL) { /* No arg given, undefine this macro */
delmac(vnp); /* silently... */
return(success = 1); /* even if it doesn't exist... */
}
/* Defining a new macro or variable */
if (*vnp == '%' && *(vnp+2) != '\0') {
printf("?Only one character after %% in variable name, please\n");
return(-2);
}
y = *(vnp + 1); /* Fold case */
if (isupper(y)) *(vnp + 1) = tolower(y);
if (cx == XXASS) { /* ASSIGN rather than DEFINE? */
lp = line; /* If so, expand its value now */
xxstring(s,&lp);
s = line;
}
debug(F111,"calling addmac",s,strlen(s));
y = addmac(vnp,s); /* Add it to the appropriate table. */
if (y < 0) {
printf("?No more space for macros\n");
return(success = 0);
}
return(0);
case XXDIAL: /* dial phone number */
if ((x = cmtxt("Number to be dialed","",&s,xxstring)) < 0)
return(x);
return(success = ckdial(s));
case XXDEL: /* delete */
if ((x = cmifi("File(s) to delete","",&s,&y,xxstring)) < 0) {
if (x == -3) {
printf("?A file specification is required\n");
return(-2);
}
return(x);
}
strncpy(tmpbuf,s,50); /* Make a safe copy of the name. */
sprintf(line,"%s %s",DELCMD,s); /* Construct the system command. */
if ((y = cmcfm()) < 0) return(y); /* Confirm the user's command. */
system(line); /* Let the system do it. */
z = zchki(tmpbuf);
success = (z == -1);
if (cmdlvl == 0 && !backgrd) {
if (success)
printf("%s - deleted\n",tmpbuf);
else
printf("%s - not deleted\n",tmpbuf);
}
return(success);
case XXDIR: /* directory */
#ifdef vms
if ((x = cmtxt("Directory/file specification","",&s,xxstring)) < 0)
return(x);
/* now do this the same as a shell command - helps with LAT */
conres(); /* make console normal */
lp = line;
sprintf(lp,"%s %s",DIRCMD,s);
debug(F110,"Directory string: ", line, 0);
concb(escape);
/*** So where does it do the command??? ***/
return(success = 0);
#else
#ifdef AMIGA
if ((x = cmtxt("Directory/file specification","",&s,xxstring)) < 0)
return(x);
#else
#ifdef datageneral
if ((x = cmtxt("Directory/file specification","+",&s,xxstring)) < 0)
return(x);
#else
if ((x = cmdir("Directory/file specification","*",&s,xxstring)) < 0)
return(x);
strcpy(tmpbuf,s);
if ((y = cmcfm()) < 0) return(y);
s = tmpbuf;
#endif
#endif
lp = line;
sprintf(lp,"%s %s",DIRCMD,s);
#ifdef OS2
concooked();
system(line);
conraw();
#else
system(line);
#endif
return(success = 1); /* who cares... */
#endif
case XXELS: /* else */
if (!ifcmd[cmdlvl]) {
printf("?ELSE doesn't follow IF\n");
return(-2);
}
ifcmd[cmdlvl] = 0;
if (!iftest[cmdlvl]) { /* If IF was false do ELSE part */
if (maclvl > -1) { /* In macro, */
pushcmd(); /* save rest of command. */
} else if (tlevel > -1) { /* In take file, */
pushcmd(); /* save rest of command. */
} else { /* If interactive, */
cmini(ckxech); /* just start a new command */
printf("\n"); /* (like in MS-DOS Kermit) */
prompt();
}
} else { /* Condition is false */
if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
return(y); /* Gobble up rest of line */
}
return(0);
case XXENA: /* enable */
case XXDIS: /* disable */
if ((x = cmkey(enatab,nena,"Server function to enable","",xxstring)) < 0)
return(x);
if ((y = cmcfm()) < 0)
return(y);
y = ((cx == XXENA) ? 1 : 0);
switch (x) {
case EN_ALL:
en_cwd = en_del = en_dir = en_fin = en_get = y;
en_hos = en_sen = en_set = en_spa = en_typ = en_who = y;
break;
case EN_CWD:
en_cwd = y;
break;
case EN_DIR:
en_dir = y;
break;
case EN_FIN:
en_fin = y;
break;
case EN_GET:
en_get = y;
break;
case EN_HOS:
en_hos = y;
break;
case EN_SEN:
en_sen = y;
break;
case EN_SET:
en_set = y;
break;
case EN_SPA:
en_spa = y;
break;
case EN_TYP:
en_typ = y;
break;
case EN_WHO:
en_who = y;
break;
default:
return(-2);
}
return(0);
case XXEND: /* end */
if ((x = cmcfm()) < 0)
return(x);
popclvl(); /* pop command level */
return(success = 1); /* always succeeds */
case XXDO: /* do (a macro) */
if (nmac == 0) {
printf("\?No macros defined\n");
return(-2);
}
for (y = 0; y < nmac; y++) { /* copy the macro table */
mackey[y].kwd = mactab[y].kwd; /* into a regular keyword table */
mackey[y].val = y; /* with value = pointer to macro tbl */
mackey[y].flgs = mactab[y].flgs;
}
/* parse name as keyword */
if ((x = cmkey(mackey,nmac,"macro","",xxstring)) < 0)
return(x);
if ((y = cmtxt("optional arguments","",&s,xxstring)) < 0) /* get args */
return(y);
if (++maclvl > MACLEVEL) { /* Make sure we have storage */
--maclvl;
printf("Macros nested too deeply\n");
return(success = 0);
}
macp[maclvl] = mactab[x].val; /* Point to the macro body */
debug(F111,"do macro",macp[maclvl],maclvl);
macx[maclvl] = x; /* Remember the macro table index */
cmdlvl++; /* Entering a new command level */
if (cmdlvl > CMDSTKL) { /* Too many macros + TAKE files? */
cmdlvl--;
printf("?TAKE files and DO commands nested too deeply\n");
return(success = 0);
}
ifcmd[cmdlvl] = 0;
iftest[cmdlvl] = 0;
count[cmdlvl] = 0;
cmdstk[cmdlvl].src = CMD_MD; /* Say we're in a macro */
cmdstk[cmdlvl].val = maclvl; /* and remember the macro level */
debug(F111,"do macro",mactab[macx[maclvl]].kwd,macx[maclvl]);
/* Clear old %0..%9 arguments */
addmac("%0",mactab[macx[maclvl]].kwd); /* Define %0 = name of macro */
varnam[0] = '%';
varnam[2] = '\0';
for (y = 1; y < 10; y++) { /* Clear args %1..%9 */
varnam[1] = y + '0';
delmac(varnam);
}
/* Assign the new args one word per arg, allowing braces to group words */
p = s; /* Pointer to beginning of arg */
b = 0; /* Flag for outer brace removal */
x = 0; /* Flag for in-word */
y = 0; /* Brace nesting level */
z = 0; /* Argument counter, 0 thru 9 */
while (1) { /* Go thru argument list */
if (*s == '\0') { /* No more characters? */
if (x != 0) {
if (z == 9) break; /* Only go up to 9. */
z++; /* Count it. */
varnam[1] = z + '0'; /* Assign last argument */
addmac(varnam,p);
break; /* And get out. */
} else break;
}
if (x == 0 && *s == ' ') { /* Eat leading blanks */
s++;
continue;
} else if (*s == '{') { /* An opening brace */
if (x == 0 && y == 0) { /* If leading brace */
p = s+1; /* point past it */
b = 1; /* and flag that we did this */
}
x = 1; /* Flag that we're in a word */
y++; /* Count the brace. */
} else if (*s == '}') { /* A closing brace. */
y--; /* Count it. */
if (y == 0 && b != 0) { /* If it matches the leading brace */
*s = ' '; /* change it to a space */
b = 0; /* and we're not in braces any more */
} else if (y < 0) x = 1; /* otherwise just start a new word. */
} else if (*s != ' ') { /* Nonspace means we're in a word */
if (x == 0) p = s; /* Mark the beginning */
x = 1; /* Set in-word flag */
}
/* If we're not inside a braced quantity, and we are in a word, and */
/* we have hit a space, then we have an argument to assign. */
if ((y < 1) && (x != 0) && (*s == ' ')) {
*s = '\0'; /* terminate the arg with null */
x = 0; /* say we're not in a word any more */
y = 0; /* start braces off clean again */
if (z == 9) break; /* Only go up to 9. */
z++; /* count this arg */
varnam[1] = z + '0'; /* compute its name */
addmac(varnam,p); /* add it to the macro table */
p = s+1;
}
s++; /* Point past this character */
}
if ((z == 0) && (y > 1)) { /* Extra closing brace(s) at end */
z++;
varnam[1] = z + '0'; /* compute its name */
addmac(varnam,p); /* Add rest of line to last arg */
}
macargc[maclvl] = z; /* For ARGC variable */
return(success = 1); /* DO command succeeded */
case XXECH: /* echo */
if ((x = cmtxt("Material to be echoed","",&s,xxstring)) < 0) return(x);
printf("%s\n",s);
return(1); /* Don't bother with success? */
case XXOUT: /* Output */
if ((x = cmtxt("Material to be output","",&s,xxstring)) < 0) return(x);
return(success = dooutput(s));
case XXPAU: /* Pause */
case XXWAI: /* Wait */
/* For now, WAIT is just a synonym for PAUSE. */
/* Both should take not only secs but also hh:mm:ss as argument. */
/* WAIT should wait for modem signals like MS-DOS Kermit */
/* Presently there's no mechanism in ckutio.c for this. */
if (cx == XXWAI)
y = cmnum("seconds to wait","1",10,&x,xxstring);
else y = cmnum("seconds to pause","1",10,&x,xxstring);
if (y < 0) return(y);
if (x < 0) x = 0;
switch (cx) {
case XXPAU:
if ((y = cmcfm()) < 0) return(y);
break;
case XXWAI:
if ((y = cmtxt("Modem Signals","",&s,xxstring)) < 0) return(y);
break;
default:
return(-2);
}
/* Command is entered, now do it. For now, WAIT is just like PAUSE */
while (x--) { /* Sleep loop */
if (y = conchk()) { /* Did they type something? */
while (y--) coninc(0); /* Yes, gobble it up */
break; /* And quit PAUSing or WAITing */
}
sleep(1); /* No interrupt, sleep one second */
}
if (cx == XXWAI) success = 0; /* For now, WAIT always fails. */
else success = (x == -1); /* Set SUCCESS/FAILURE for PAUSE. */
return(0);
case XXPWD: /* PWD */
if ((x = cmcfm()) < 0) return(x);
system(PWDCMD);
return(success = 1); /* blind faith */
case XXQUI: /* quit, exit */
case XXEXI:
if ((x = cmcfm()) > -1) doexit(GOOD_EXIT);
else return(x);
case XXFIN: /* finish */
if ((x = cmcfm()) < 0) return(x);
sstate = setgen('F',"","","");
return(0);
case XXGET: /* get */
x = cmtxt("Name of remote file(s), or carriage return","",&cmarg,xxstring);
if ((x == -2) || (x == -1)) return(x);
/* If foreign file name omitted, get foreign and local names separately */
x = 0; /* For some reason cmtxt returns 1 */
if (*cmarg == NUL) {
if (tlevel > -1) { /* Input is from take file */
if (fgets(line,100,tfile[tlevel]) == NULL)
fatal("take file ends prematurely in 'get'");
debug(F110,"take-get 2nd line",line,0);
/**** stripq(line); ***/
for (x = strlen(line);
x > 0 && (line[x-1] == LF || line[x-1] == CR);
x--)
line[x-1] = '\0';
cmarg = line;
if (fgets(cmdbuf,CMDBL,tfile[tlevel]) == NULL)
fatal("take file ends prematurely in 'get'");
/**** stripq(cmdbuf); ***/
for (x = strlen(cmdbuf);
x > 0 && (cmdbuf[x-1] == LF || cmdbuf[x-1] == CR);
x--)
cmdbuf[x-1] = '\0';
if (*cmdbuf == NUL) cmarg2 = line; else cmarg2 = cmdbuf;
x = 0; /* Return code */
printf("%s",cmarg2);
} else { /* Input is from terminal */
char psave[40]; /* Save old prompt */
cmsavp(psave,40);
cmsetp(" Remote file specification: "); /* Make new one */
cmini(ckxech);
x = -1;
if (!backgrd) prompt();
while (x == -1) { /* Prompt till they answer */
x = cmtxt("Name of remote file(s)","",&cmarg,xxstring);
debug(F111," cmtxt",cmarg,x);
}
if (x < 0) {
cmsetp(psave);
return(x);
}
if (*cmarg == NUL) { /* If user types a bare CR, */
printf("(cancelled)\n"); /* Forget about this. */
cmsetp(psave); /* Restore old prompt, */
return(0); /* and return. */
}
strcpy(line,cmarg); /* Make a safe copy */
cmarg = line;
cmsetp(" Local name to store it under: "); /* New prompt */
cmini(ckxech);
x = -1;
if (!backgrd) prompt();
while (x == -1) { /* Again, parse till answered */
x = cmofi("Local file name","",&cmarg2,xxstring);
}
if (x == -3) { /* If bare CR, */
printf("(cancelled)\n"); /* escape from this... */
cmsetp(psave); /* Restore old prompt, */
return(0); /* and return. */
} else if (x < 0) return(x); /* Handle parse errors. */
x = -1; /* Get confirmation. */
while (x == -1) x = cmcfm();
cmsetp(psave); /* Restore old prompt. */
}
}
if (x == 0) { /* Good return from cmtxt or cmcfm, */
sstate = 'r'; /* set start state. */
if (local) displa = 1;
}
return(x);
case XXHLP: /* Help */
x = cmkey2(cmdtab,ncmd,"C-Kermit command","help",toktab,xxstring);
if (x == -5) {
y = chktok(toktab);
debug(F101,"top-level cmkey token","",y);
ungword();
switch (y) {
case '!': x = XXSHE; break;
case '%': x = XXCOM; break;
case '#': x = XXCOM; break;
case ';': x = XXCOM; break;
case ':': x = XXLBL; break;
case '&': x = XXECH; break;
default:
printf("\n?Invalid - %s\n",cmdbuf);
x = -2;
}
}
return(success = (dohlp(x) > -1));
case XXHAN: /* Hangup */
if ((x = cmcfm()) > -1)
return(success = (tthang() > -1));
case XXGOTO: /* Goto */
/* Note, here we don't set SUCCESS/FAILURE flag */
if ((y = cmfld("label","",&s,xxstring)) < 0) return(y);
strcpy(lblbuf,s);
if ((x = cmcfm()) < 0) return(x);
s = lblbuf;
debug(F110,"goto before conversion",s,0);
if (*s != ':') { /* If the label mentioned */
int i; /* does not begin with a colon, */
y = strlen(s); /* then insert one. */
for (i = y; i > 0; i--)
s[i] = s[i-1];
s[0] = ':';
s[++y] = '\0';
}
debug(F111,"goto after conversion",s,y);
while (cmdlvl > 0) { /* Only works inside macros & files */
if (cmdstk[cmdlvl].src == CMD_MD) { /* GOTO inside macro */
int i, m;
lp = mactab[macx[maclvl]].val; /* point to beginning of macro */
debug(F111,"goto in macro",lp,macx[maclvl]);
m = strlen(lp) - y;
debug(F111,"goto in macro",lp,m);
for (i = 0; i < m; i++,lp++) /* search for label in macro body */
if (!strncmp(s,lp,y))
break;
if (i == m) { /* didn't find the label */
debug(F101,"goto failed at cmdlvl","",cmdlvl);
if (!popclvl()) { /* pop up to next higher level */
printf("?Label '%s' not found\n",s); /* if none */
return(0); /* quit */
} else continue; /* otherwise look again */
}
debug(F110,"goto found macro label",lp,0);
macp[maclvl] = lp; /* set macro buffer pointer */
return(1);
} else if (cmdstk[cmdlvl].src == CMD_TF) {
x = 0; /* GOTO issued in take file */
rewind(tfile[tlevel]); /* Search file from beginning */
while (! feof(tfile[tlevel])) {
if (fgets(line,LINBUFSIZ,tfile[tlevel]) == NULL) /* Get line */
break; /* If no more, done, label not found */
lp = line; /* Got line */
while (*lp == ' ' || *lp == '\t')
lp++; /* Strip leading whitespace */
if (!strncmp(lp,s,y)) { /* Compare result with label */
x = 1; /* Got it */
break; /* done. */
}
}
if (x == 0) { /* If not found, print message */
debug(F101,"goto failed at cmdlvl","",cmdlvl);
if (!popclvl()) { /* pop up to next higher level */
printf("?Label '%s' not found\n",s); /* if none */
return(0); /* quit */
} else continue; /* otherwise look again */
}
return(x); /* Send back return code */
}
}
printf("?Stack problem in GOTO\n",s); /* Shouldn't see this */
return(0);
case XXIF: /* IF command */
not = 0; /* Flag for whether "NOT" was seen */
ifagain:
if ((ifc = cmkey(iftab,nif,"","",xxstring)) < 0) /* If what?... */
return(ifc);
switch (ifc) { /* z = 1 for true, 0 for false */
case XXIFNO: /* IF NOT */
not ^= 1;
goto ifagain;
case XXIFSU: /* IF SUCCESS */
z = ( success != 0 );
debug(F101,"if success","",z);
break;
case XXIFFA: /* IF FAILURE */
z = ( success == 0 );
debug(F101,"if failure","",z);
break;
case XXIFDE: /* IF DEFINED */
if ((x = cmfld("Macro or variable name","",&s,NULL)) < 0)
return(x);
strcpy(line,s); /* Make a copy */
lp = line;
if (line[0] == CMDQ && line[1] == '%') /* Change "\%x" to just "%x" */
lp++; /* Both forms are allowed. */
if (*lp == '%') { /* Is it a variable? */
x = *(lp + 1); /* Fold case */
if (isupper(x)) *(lp + 1) = tolower(x);
if (x >= '0' && x <= '9' && maclvl > -1)
z = ( m_arg[maclvl][x - '0'] != 0 ); /* Digit is macro arg */
else /* Otherwise its a global variable */
z = ( g_var[x] != 0 );
} else { /* Otherwise its a macro name */
z = ( mxlook(mactab,lp,nmac) > -1 ); /* Look for exact match */
}
debug(F111,"if defined",s,z);
break;
case XXIFCO: /* IF COUNT */
z = ( --count[cmdlvl] > 0 );
debug(F101,"if count","",z);
break;
case XXIFEX: /* IF EXIST */
if ((x = cmfld("File","",&s,xxstring)) < 0) return(x);
z = ( zchki(s) > -1L );
debug(F101,"if exist","",z);
break;
case XXIFEQ: /* IF EQUAL (string comparison) */
if ((x = cmfld("first word or variable name","",&s,xxstring)) < 0)
return(x);
lp = line;
strcpy(lp,s);
if ((y = cmfld("second word or variable name","",&s,xxstring)) < 0)
return(y);
x = strlen(lp);
tp = line + x + 2;
strcpy(tp,s);
y = strlen(tp);
if (x + y + 2 > LINBUFSIZ) { /* Have to do something better */
fatal("if equal: strings too long"); /* than this... */
z = 0;
break;
}
if (x != y) { /* Different lengths */
z = 0; /* so not equal */
break;
}
if (!incase) /* Ignoring alphabet case? */
z = !xxstrcmp(tp,lp); /* Yes, special string compare */
else /* No, */
z = !strcmp(tp,lp); /* Exact match required. */
debug(F101,"if equal","",z);
break;
case XXIFAE: /* IF (arithmetically) = */
case XXIFLT: /* IF (arithmetically) < */
case XXIFGT: { /* IF (arithmetically) > */
int n1, n2;
if ((x = cmfld("first number or variable name","",&s,xxstring)) < 0)
return(x);
debug(F101,"xxifgt cmfld","",x);
lp = line;
strcpy(lp,s);
debug(F110,"xxifgt exp1",lp,0);
if (!xxstrcmp(lp,"count")) {
n1 = count[cmdlvl];
} else if (!xxstrcmp(lp,"version")) {
n1 = (int) vernum;
} else if (!xxstrcmp(lp,"argc")) {
n1 = (int) macargc[maclvl];
} else {
if (!chknum(lp)) return(-2);
n1 = atoi(lp);
}
if ((y = cmfld("second number or variable name","",&s,xxstring)) < 0)
return(y);
x = strlen(lp);
tp = line + x + 2;
strcpy(tp,s);
debug(F110,"xxifgt exp2",tp,0);
if (!xxstrcmp(tp,"count")) {
n2 = count[cmdlvl];
} else if (!xxstrcmp(tp,"version")) {
n2 = (int) vernum;
} else if (!xxstrcmp(tp,"argc")) {
n2 = (int) macargc[maclvl];
} else {
if (!chknum(tp)) return(-2);
n2 = atoi(tp);
}
z = ((n1 < n2 && ifc == XXIFLT)
|| (n1 == n2 && ifc == XXIFAE)
|| (n1 > n2 && ifc == XXIFGT));
debug(F101,"xxifft n1","",n1);
debug(F101,"xxifft n2","",n2);
debug(F101,"xxifft z","",z);
break; }
default: /* Shouldn't happen */
return(-2);
}
ifcmd[cmdlvl] = 1; /* We just completed an IF command */
if (not) z = !z; /* Handle NOT here */
if (z) { /* Condition is true */
iftest[cmdlvl] = 1; /* Remember that IF succeeded */
if (maclvl > -1) { /* In macro, */
pushcmd(); /* save rest of command. */
} else if (tlevel > -1) { /* In take file, */
pushcmd(); /* save rest of command. */
} else { /* If interactive, */
cmini(ckxech); /* just start a new command */
printf("\n"); /* (like in MS-DOS Kermit) */
prompt();
}
} else { /* Condition is false */
iftest[cmdlvl] = 0; /* Remember command failed. */
if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
return(y); /* Gobble up rest of line */
}
return(0);
case XXINP: /* INPUT and */
case XXREI: /* REINPUT */
y = cmnum("seconds to wait for input","1",10,&x,xxstring);
if (y < 0) return(y);
if (x <= 0) x = 1;
if ((y = cmtxt("Material to be input","",&s,xxstring)) < 0) return(y);
/*
if (! local) {
printf("You must 'set line' first\n");
return(1);
}
*/
if (cx == XXINP) { /* INPUT */
debug(F110,"xxinp line",s,0);
if (local != 0 && tvtflg == 0) { /* Put line in "ttvt" mode */
y = ttvt(speed,flow); /* if not already. */
if (y < 0) {
printf("?Can't condition line for INPUT\n");
return(0); /* Watch out for failure. */
}
tvtflg = 1; /* On success set this flag */
}
success = doinput(x,s); /* Go try to input the search string */
} else { /* REINPUT */
debug(F110,"xxrei line",s,0);
success = doreinp(x,s);
}
if (intime && !success) { /* TIMEOUT-ACTION = QUIT? */
popclvl(); /* If so, pop command level. */
if (!backgrd && cmdlvl == 0) {
if (cx == XXINP) printf("Input timed out\n");
if (cx == XXREI) printf("Reinput failed\n");
}
}
return(success); /* Return (re)doinput's return code */
case XXLBL: /* Label */
if ((x = cmtxt("Command-file label","",&s,xxstring)) < 0) return(x);
/* should be cmfld, then cmcfm, to prevent multiple words in label? */
return(0);
case XXLOG: /* Log */
x = cmkey(logtab,nlog,"What to log","",xxstring);
if (x == -3) {
printf("?You must specify what is to be logged\n");
return(-2);
}
if (x < 0) return(x);
return(success = (dolog(x) > 0));
case XXLOGI: /* Send script remote system */
if ((x = cmtxt("Text of login script","",&s,xxstring)) < 0) return(x);
return(success = login(s)); /* Return 1=completed, 0=failed */
case XXREC: /* Receive */
cmarg2 = "";
x = cmofi("Name under which to store the file, or CR","",&cmarg2,xxstring);
if ((x == -1) || (x == -2)) return(x);
debug(F111,"cmofi cmarg2",cmarg2,x);
if ((x = cmcfm()) < 0) return(x);
sstate = 'v';
if (local) displa = 1;
return(0);
case XXREM: /* Remote */
x = cmkey(remcmd,nrmt,"Remote Kermit server command","",xxstring);
if (x == -3) {
printf("?You must specify a command for the remote server\n");
return(-2);
}
return(dormt(x));
case XXSEN: /* SEND command and... */
case XXMAI: /* MAIL command */
cmarg = cmarg2 = "";
if ((x = cmifi("File(s) to send","",&s,&y,xxstring)) < 0) {
if (x == -3) {
printf("?A file specification is required\n");
return(-2);
}
return(x);
}
nfils = -1; /* Files come from internal list. */
strcpy(line,s); /* Save copy of string just parsed. */
if (cx == XXSEN) { /* SEND command */
debug(F101,"Send: wild","",y);
if (y == 0) {
if ((x = cmtxt("Name to send it with","",&cmarg2,xxstring)) < 0)
return(x);
} else {
if ((x = cmcfm()) < 0) return(x);
}
cmarg = line; /* File to send */
debug(F110,"Sending:",cmarg,0);
if (*cmarg2 != '\0') debug(F110," as:",cmarg2,0);
} else { /* MAIL */
debug(F101,"Mail: wild","",y);
*optbuf = NUL; /* Wipe out any old options */
if ((x = cmtxt("Address to mail to","",&s,xxstring)) < 0) return(x);
strcpy(optbuf,s);
if (strlen(optbuf) > 94) { /* Ensure legal size */
printf("?Option string too long\n");
return(-2);
}
cmarg = line; /* File to send */
debug(F110,"Mailing:",cmarg,0);
debug(F110,"To:",optbuf,0);
rmailf = 1; /* MAIL modifier flag for SEND */
}
sstate = 's'; /* Set start state to SEND */
if (local) displa = 1;
return(0);
case XXSER: /* Server */
if ((x = cmcfm()) < 0) return(x);
sstate = 'x';
if (local) displa = 1;
#ifdef AMIGA
reqoff(); /* No DOS requestors while server */
#endif
return(0);
case XXSET: /* SET command */
x = cmkey(prmtab,nprm,"Parameter","",xxstring);
if (x == -3) {
printf("?You must specify a parameter to set\n");
return(-2);
}
if (x < 0) return(x);
/* have to set success separately for each item in doprm()... */
/* actually not really, could have just had doprm return 0 or 1 */
/* and set success here... */
return(doprm(x,0));
/* XXSHE code by H. Fischer; copyright rights assigned to Columbia Univ */
/*
Adapted to use getpwuid to find login shell because many systems do not
have SHELL in environment, and to use direct calling of shell rather
than intermediate system() call. -- H. Fischer
*/
case XXSHE: /* Local shell command */
{
int pid;
#ifdef AMIGA
if (cmtxt("Command to execute","",&s,xxstring) < 0) return(-1);
#else
#ifdef OS2
if (cmtxt("OS2 command to execute","",&s,xxstring) < 0) return(-1);
#else
if (cmtxt("Unix shell command to execute","",&s,xxstring) < 0) return(-1);
#endif /* Amiga */
#endif /* OS2 */
conres(); /* Make console normal */
#ifdef OS2
if (*s == '\0') sprintf(s,"%s","CMD"); /* Command processor */
concooked();
system(s);
conraw();
#else
#ifdef OSK
system(s);
#else
#ifdef AMIGA
system(s);
#else
#ifdef MSDOS
zxcmd(s);
#else
#ifdef vms
system(s); /* Best we can do for VMS? */
#else
#ifdef datageneral
if (*s == NUL) /* Interactive shell requested? */
#ifdef mvux
system("/bin/sh ");
#else
system("x :cli prefix Kermit_Baby:");
#endif
else /* Otherwise, */
system(s); /* Best for aos/vs?? */
#else
#ifdef aegis
if ((pid = vfork()) == 0) { /* Make child quickly */
char *shpath, *shname, *shptr; /* For finding desired shell */
if ((shpath = getenv("SHELL")) == NULL) shpath = "/com/sh";
#else /* All Unix systems */
if ((pid = fork()) == 0) { /* Make child */
char *shpath, *shname, *shptr; /* For finding desired shell */
struct passwd *p;
extern struct passwd * getpwuid();
extern int getuid();
char *defShel = "/bin/sh"; /* Default */
p = getpwuid( getuid() ); /* Get login data */
if ( p == (struct passwd *) NULL || !*(p->pw_shell) )
shpath = defShel;
else
shpath = p->pw_shell;
#endif
shptr = shname = shpath;
while (*shptr != '\0')
if (*shptr++ == '/') shname = shptr;
/* Remove following uid calls if they cause trouble */
#ifdef BSD4
#ifndef BSD41
setegid(getgid()); /* Override 4.3BSD csh security */
seteuid(getuid()); /* checks. */
#endif
#endif
if (*s == NUL) /* Interactive shell requested? */
execl(shpath,shname,"-i",NULL); /* Yes, do that */
else /* Otherwise, */
execl(shpath,shname,"-c",s,NULL); /* exec the given command */
exit(BAD_EXIT); } /* Just punt if it didn't work */
else { /* Parent */
int wstat; /* Kermit must wait for child */
SIGTYP (*istat)(), (*qstat)();
istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */
qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
while (((wstat = wait((int *)0)) != pid) && (wstat != -1)) ;
/* Wait for fork */
signal(SIGINT,istat); /* Restore interrupts */
signal(SIGQUIT,qstat);
}
#endif
#endif
#endif
#endif
#endif
#endif
concb(escape); /* Console back in cbreak mode */
return(success = 1); /* Just pretend it worked. */
}
case XXSHO: /* Show */
x = cmkey(shotab,nsho,"","parameters",xxstring);
if (x < 0) return(x);
return(success = doshow(x));
case XXSPA: /* space */
#ifdef datageneral
/* The DG can take an argument after its "space" command. */
if ((x = cmtxt("Confirm, or local directory name","",&s,xxstring)) < 0)
return(x);
if (*s == NUL) system(SPACMD);
else {
char *cp;
cp = alloc(strlen(s) + 7); /* For "space *s" */
strcpy(cp,"space "), strcat(cp,s);
system(cp);
if (cp) free(cp);
}
#else
if ((x = cmcfm()) < 0) return(x);
#ifdef OS2
concooked();
system(SPACMD);
conraw();
#else
system(SPACMD);
#endif
#endif
return(success = 1); /* pretend it worked */
case XXSTA: /* statistics */
if ((x = cmcfm()) < 0) return(x);
return(success = dostat());
case XXSTO: /* stop */
if ((x = cmcfm()) < 0) return(x);
dostop();
success = 1; /* always succeeds */
return(0);
case XXTAK: /* take */
if (tlevel > MAXTAKE-1) {
printf("?Take files nested too deeply\n");
return(-2);
}
if ((y = cmifi("C-Kermit command file","",&s,&x,xxstring)) < 0) {
if (y == -3) {
printf("?A file specification is required\n");
return(-2);
} else return(y);
}
if (x != 0) {
printf("?Wildcards not allowed in command file name\n");
return(-2);
}
strcpy(line,s); /* Make a safe copy of the string */
if ((y = cmcfm()) < 0) return(y);
if ((tfile[++tlevel] = fopen(line,"r")) == NULL) {
perror(line);
debug(F110,"Failure to open",line,0);
success = 0;
tlevel--;
} else {
cmdlvl++; /* Entering a new command level */
if (cmdlvl > CMDSTKL) {
cmdlvl--;
printf("?TAKE files and DO commands nested too deeply\n");
return(success = 0);
}
ifcmd[cmdlvl] = 0;
iftest[cmdlvl] = 0;
count[cmdlvl] = 0;
cmdstk[cmdlvl].src = CMD_TF; /* Say we're in a TAKE file */
cmdstk[cmdlvl].val = tlevel; /* nested at this level */
success = 1;
}
return(success);
case XXTRA: /* transmit */
if ((x = cmifi("File to transmit","",&s,&y,xxstring)) < 0) {
if (x == -3) {
printf("?Name of an existing file\n");
return(-2);
}
return(x);
}
if (y != 0) {
printf("?Only a single file may be transmitted\n");
return(-2);
}
strcpy(line,s); /* Save copy of string just parsed. */
y = cmnum("Decimal ASCII value of line turnaround character","10",10,&x,
xxstring);
if (y < 0) return(y);
if (x < 0 || x > 127) {
printf("?Decimal number between 0 and 127\n");
return(-2);
}
if ((y = cmcfm()) < 0) return(y); /* Confirm the command */
debug(F110,"calling transmit",line,0);
return(success = transmit(line,x)); /* Do the command */
case XXTYP: /* TYPE */
if ((x = cmifi("File to type","",&s,&y,xxstring)) < 0) {
if (x == -3) {
printf("?Name of an existing file\n");
return(-2);
}
return(x);
}
if (y != 0) {
printf("?A single file please\n");
return(-2);
}
strcpy(line,s); /* Save copy of string just parsed. */
if ((y = cmcfm()) < 0) return(y); /* Confirm the command */
debug(F110,"calling transmit",line,0);
return(success = dotype(line)); /* Do the TYPE command */
case XXTES: /* TEST */
/* Fill this in with whatever is being tested... */
if ((y = cmcfm()) < 0) return(y); /* Confirm the command */
printf("cmdlvl = %d, tlevel = %d, maclvl = %d\n",cmdlvl,tlevel,maclvl);
if (maclvl < 0) {
printf("%s\n",
"Call me from inside a macro and I'll dump the argument stack");
return(0);
}
printf("Macro level: %d, ARGC = %d\n ",maclvl,macargc[maclvl]);
for (y = 0; y < 10; y++) printf("%7d",y);
for (x = 0; x <= maclvl; x++) {
printf("\n%2d: ",x);
for (y = 0; y < 10; y++) {
s = m_arg[x][y];
printf("%7s",s ? s : "(none)");
}
}
printf("\n");
return(0);
case XXXLA: /* translate */
if ((x = cmifi("File to translate","",&s,&y,xxstring)) < 0) {
if (x == -3) {
printf("?Name of an existing file\n");
return(-2);
}
return(x);
}
if (y != 0) {
printf("?A single file please\n");
return(-2);
}
strcpy(line,s); /* Save copy of string just parsed. */
if ((x = cmofi("Output file","",&s,&y,xxstring)) < 0) {
if (x != -3) return(x); /* don't ask... */
else s = CTTNAM;
}
if (y != 0) {
printf("?A single file please\n");
return(-2);
}
if ((y = cmcfm()) < 0) return(y); /* Confirm the command */
return(success = xlate(line,s)); /* Do the TRANSLATE command */
case XXVER:
if ((y = cmcfm()) < 0) return(y);
printf("%s,%s\n Numeric: %d\n",versio,ckxsys,vernum);
return(success = 1);
default:
printf("Not available - %s\n",cmdbuf);
return(-2);
}
}