home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 3 Comm / 03-Comm.zip / CKPM5X_S.ZIP / CKUUSR.C < prev    next >
C/C++ Source or Header  |  1990-03-03  |  57KB  |  1,740 lines

  1. char *userv = "User Interface 5A(067), 1 Mar 90";
  2.  
  3. /*  C K U U S R --  "User Interface" for Unix Kermit (Part 1)  */
  4.  
  5. /*
  6.  Author: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET),
  7.  Columbia University Center for Computing Activities.
  8.  First released January 1985.
  9.  Copyright (C) 1985, 1990, Trustees of Columbia University in the City of New 
  10.  York.  Permission is granted to any individual or institution to use, copy, or
  11.  redistribute this software so long as it is not sold for profit, provided this
  12.  copyright notice is retained. 
  13. */
  14.  
  15. /*
  16.   NOTE: Because of the massive additions in functionality, and therefore
  17.   the increase in the number of commands, much code was moved from here to
  18.   the two new modules, ckuus4.c and ckuus5.c.  This module now contains only
  19.   the top-level command keyword table, the SET command keyword table, and
  20.   the top-level interactive command parser/dispatcher.  ckuus3.c contains the
  21.   rest of the SET and REMOTE command parsers; ckuus2.c contains the help
  22.   command parser and help text strings, and ckuus4.c and ckuus5.c contain
  23.   miscellaneous pieces that logically belong in the ckuusr.c file but had to
  24.   be moved because of size problems with some C compilers / linkers.
  25. */
  26.  
  27. /*
  28.  The ckuus*.c modules depend on the existence of C library features like fopen,
  29.  fgets, feof, (f)printf, argv/argc, etc.  Other functions that are likely to
  30.  vary among Unix implementations -- like setting terminal modes or interrupts
  31.  -- are invoked via calls to functions that are defined in the system-
  32.  dependent modules, ck?[ft]io.c.  The command line parser processes any
  33.  arguments found on the command line, as passed to main() via argv/argc.  The
  34.  interactive parser uses the facilities of the cmd package (developed for this
  35.  program, but usable by any program).  Any command parser may be substituted
  36.  for this one.  The only requirements for the Kermit command parser are these:
  37.  
  38. 1. Set parameters via global variables like duplex, speed, ttname, etc.  See
  39.    ckmain.c for the declarations and descriptions of these variables.
  40.  
  41. 2. If a command can be executed without the use of Kermit protocol, then
  42.    execute the command directly and set the variable sstate to 0. Examples
  43.    include 'set' commands, local directory listings, the 'connect' command.
  44.  
  45. 3. If a command requires the Kermit protocol, set the following variables:
  46.  
  47.     sstate                             string data
  48.       'x' (enter server mode)            (none)
  49.       'r' (send a 'get' command)         cmarg, cmarg2
  50.       'v' (enter receive mode)           cmarg2
  51.       'g' (send a generic command)       cmarg
  52.       's' (send files)                   nfils, cmarg & cmarg2 OR cmlist
  53.       'c' (send a remote host command)   cmarg
  54.  
  55.     cmlist is an array of pointers to strings.
  56.     cmarg, cmarg2 are pointers to strings.
  57.     nfils is an integer.
  58.  
  59.     cmarg can be a filename string (possibly wild), or
  60.        a pointer to a prefabricated generic command string, or
  61.        a pointer to a host command string.
  62.     cmarg2 is the name to send a single file under, or
  63.        the name under which to store an incoming file; must not be wild.
  64.        If it's the name for receiving, a null value means to store the
  65.        file under the name it arrives with.
  66.     cmlist is a list of nonwild filenames, such as passed via argv.
  67.     nfils is an integer, interpreted as follows:
  68.       -1: filespec (possibly wild) in cmarg, must be expanded internally.
  69.        0: send from stdin (standard input).
  70.       >0: number of files to send, from cmlist.
  71.  
  72.  The screen() function is used to update the screen during file transfer.
  73.  The tlog() function writes to a transaction log.
  74.  The debug() function writes to a debugging log.
  75.  The intmsg() and chkint() functions provide the user i/o for interrupting
  76.    file transfers.
  77. */
  78.  
  79. /* Includes */
  80.  
  81. #include <stdio.h>
  82. #include <ctype.h>
  83. #ifndef AMIGA
  84. /* Apparently these should be included for OS/2 C-Kermit after all... */
  85. /* #ifndef OS2 */
  86. #include <signal.h>
  87. #include <setjmp.h>
  88. /* #endif */
  89. #endif
  90.  
  91. #include "ckcdeb.h"
  92. #include "ckcasc.h"
  93. #include "ckcker.h"
  94. #include "ckucmd.h"
  95. #include "ckuusr.h"
  96. #include "ckcxla.h"
  97.  
  98. #ifdef datageneral
  99. #define fgets(stringbuf,max,fd) dg_fgets(stringbuf,max,fd)
  100. #define fork() vfork()
  101. /* DG version 3.21 of C has bugs in the following routines, since they
  102.  * depend on /etc/passwd.  In the context where the routines are used,
  103.  * we don't need them anyway.
  104.  */
  105. #define getgid() -1
  106. #define getuid() -1
  107. #define geteuid() -1
  108. #endif
  109.  
  110. /* External Kermit Variables, see ckmain.c for description. */
  111.  
  112. extern int size, rpsiz, urpsiz, speed, local, rmailf,
  113.   server, displa, binary, parity, deblog, escape, xargc, flow,
  114.   turn, duplex, nfils, ckxech, pktlog, seslog, tralog, stdouf,
  115.   turnch, dfloc, keep, maxrps, warn, quiet, cnflg, tlevel,
  116.   mdmtyp, zincnt, cmaskm;
  117.  
  118. extern int xxstring();            /* Variable expander */
  119.  
  120. extern long vernum;
  121. extern char *versio, *protv, *ckxv, *ckzv, *fnsv, *connv, *dftty, *cmdv;
  122. extern char *dialv, *loginv;
  123. extern char *ckxsys, *ckzsys, *cmarg, *cmarg2, **xargv, **cmlist;
  124. extern char *DIRCMD, *PWDCMD, *DELCMD, cmerrp[], optbuf[];
  125. extern CHAR sstate, ttname[], filnam[];
  126. extern CHAR *zinptr;
  127.  
  128. extern int tcharset, fcharset;
  129. extern struct csinfo fcsinfo[], tcsinfo[];
  130. char *strcpy(), *getenv(), *varlook();
  131. #ifdef AMIGA
  132. char *getcwd();
  133. #endif
  134. #ifdef OS2
  135. char *getcwd();
  136. #endif
  137.  
  138. /* Declarations from cmd package */
  139.  
  140. extern char cmdbuf[], atmbuf[], savbuf[]; /* Command buffers */
  141.  
  142. /* Declarations from ck?fio.c module */
  143.  
  144. extern char *SPACMD, *zhome();        /* Space command, home directory. */
  145. extern int backgrd;            /* Kermit executing in background */
  146. #ifdef OS2
  147. extern char *zfindfile();
  148. #endif
  149.  
  150. /* The background flag is set by ckutio.c (via conint() ) to note whether */
  151. /* this kermit is executing in background ('&' on shell command line).    */
  152.  
  153.  
  154. /* Variables and symbols local to this module */
  155.  
  156. extern char line[];            /* Character buffer for anything */
  157. char *lp;                /* Pointer to line buffer */
  158. extern char inpbuf[];            /* Buffer for INPUT and REINPUT */
  159. char *inpbp = inpbuf;            /* And pointer to same */
  160. extern char vnambuf[];            /* Buffer for variable names */
  161. char *vnp;                /* Pointer to same */
  162. extern char lblbuf[];            /* Buffer for labels */
  163. extern char debfil[];            /* Debugging log file name */
  164. extern char pktfil[];            /* Packet log file name */
  165. extern char sesfil[];            /* Session log file name */
  166. extern char trafil[];            /* Transaction log file name */
  167. extern char tmpbuf[];            /* Temporary buffer */
  168. char *tp;                /* Temporary pointer */
  169.  
  170. int n,                    /* General purpose int */
  171.     cflg,                /* Command-line connect cmd given */
  172.     action,                /* Action selected on command line*/
  173.     repars,                /* Reparse needed */
  174.     ifc,                /* IF case */
  175.     not = 0,                /* Flag for IF NOT */
  176.     techo = 0,                /* Take echo */
  177.     terror = 1,                /* Take error action, 1 = quit */
  178.     tvtflg = 0,                /* tty device put in tvt mode */
  179.     cwdf = 0;                /* CWD has been done */
  180.  
  181. extern int en_cwd, en_del, en_dir, en_fin, /* Flags for ENABLE/DISABLE */
  182.    en_get, en_hos, en_sen, en_set, en_spa, en_typ, en_who;
  183.  
  184. int                    /* SET INPUT parameters. */
  185.   indef = 5,                /* 5 seconds default timeout */
  186.   intime = 0,                /* 0 = proceed */
  187.   incase = 0,                /* 0 = ignore */
  188.   inecho = 1;                /* 1 = echo on */
  189.  
  190. int cmdsrc = 0;                /* Where commands are coming from: */
  191.                     /*  0 = kb, 1 = take, 2 = macro */
  192. int maclvl = -1;            /* Macro to execute */
  193. extern int macx[];            /* Index of current macro */
  194. int mecho = 0;                /* Macro echo */
  195. int merror = 0;                /* Macro error action */
  196. extern char *macp[];            /* Pointer to macro */
  197. char varnam[6];                /* For variable names */
  198. extern int macargc[];            /* ARGC from macro invocation */
  199. int success;                /* "Input" success flag */
  200.  
  201. extern FILE *tfile[];            /* File pointers for TAKE command */
  202.  
  203. extern char *m_arg[MACLEVEL][NARGS];    /* Stack of macro arguments */
  204. extern char *g_var[];            /* Global variables %a, %b, etc */
  205.  
  206. extern struct cmdptr cmdstk[];        /* The command stack itself */
  207. int cmdlvl = 0;                /* Current position in command stack */
  208. int count[];                /* For IF COUNT, one for each cmdlvl */
  209. int ifcmd[];                /* Last command was IF */
  210. int iftest[];                /* Last IF was true */
  211.  
  212. char *homdir;                /* Pointer to home directory string */
  213. extern char kermrc[];            /* Name of initialization file */
  214. int rcflag = 0;                /* Flag for alternate init file name */
  215. extern char cmdstr[];            /* Place to build generic command */
  216.  
  217. /* Top-Level Interactive Command Keyword Table */
  218.  
  219. struct keytab cmdtab[] = {
  220.     "!",       XXSHE, 0,        /* shell escape */
  221.     "#",           XXCOM, CM_INV,    /* comment */
  222.     ":",           XXLBL, CM_INV,    /* label */
  223.     "ask",         XXASK, 0,        /* ask */
  224.     "askq",        XXASKQ,0,            /* ask quietly */
  225.     "assign",      XXASS, 0,            /* assign */
  226.     "bye",         XXBYE, 0,        /* bye to remote server */
  227.     "c",           XXCON, CM_INV,    /* invisible synonym for connect */
  228.     "cd",          XXCWD, 0,        /* change directory */
  229.     "clear",       XXCLE, 0,        /* clear input buffer */
  230.     "close",       XXCLO, 0,        /* close a log file */
  231.     "comment",     XXCOM, 0,        /* comment */
  232.     "connect",     XXCON, 0,        /* connect to remote system */
  233.     "cwd",       XXCWD, CM_INV,    /* invisisble synonym for cd */
  234.     "decrement",   XXDEC, 0,        /* decrement a numeric variable */
  235.     "define",      XXDEF, 0,        /* define a macro */
  236.     "delete",      XXDEL, 0,        /* delete a file */
  237.     "dial",       XXDIAL,0,        /* dial a phone number */
  238.     "directory",   XXDIR, 0,        /* directory of files */
  239.     "disable",     XXDIS, 0,        /* disable server function */
  240.     "do",          XXDO,  0,        /* execute a macro */
  241.     "echo",        XXECH, 0,        /* echo argument */
  242.     "else",        XXELS, CM_INV,    /* ELSE part of IF statement */
  243.     "enable",      XXENA, 0,        /* enable a server function */
  244.     "end",         XXEND, 0,        /* end a take file or macro */
  245.     "exit",       XXEXI, 0,        /* exit the program */
  246.     "finish",       XXFIN, 0,        /* shut down a remote server */
  247.     "get",       XXGET, 0,        /* get a file from a server */
  248.     "goto",        XXGOTO,0,        /* goto label in take file or macro */
  249.     "hangup",      XXHAN, 0,        /* hangup dialed phone connection */
  250.     "help",       XXHLP, 0,        /* display help text */
  251.     "if",          XXIF,  0,        /* if (condition) command */
  252.     "increment",   XXINC, 0,        /* increment a numeric variable */
  253.     "input",       XXINP, 0,        /* input string from comm line */
  254.     "l",           XXLOG, CM_INV,    /* invisible synonym for log */
  255.     "log",         XXLOG, 0,        /* open a log file */
  256.     "ls",          XXDIR, CM_INV,    /* invisible synonym for directory */
  257.     "mail",        XXMAI, 0,        /* mail file to user */
  258.     "output",      XXOUT, 0,        /* output string to comm line */
  259.     "pause",       XXPAU, 0,        /* sleep for specified interval */
  260.     "pop",         XXEND, CM_INV,    /* allow POP as synonym for END */
  261.     "push",        XXSHE, 0,        /* PUSH command (like RUN, !) */
  262.     "pwd",         XXPWD, 0,            /* print working directory */
  263.     "quit",       XXQUI, 0,        /* quit from program = exit */
  264.     "r",           XXREC, CM_INV,    /* invisible synonym for receive */
  265.     "reinput",     XXREI, 0,            /* reinput */
  266.     "receive",       XXREC, 0,        /* receive files */
  267.     "remote",       XXREM, 0,        /* send generic command to server */
  268.     "replay",      XXTYP, 0,        /* replay (for now, just type) */
  269.     "rm",          XXDEL, CM_INV,    /* invisible synonym for delete */
  270.     "run",         XXSHE, 0,        /* run a program or command */
  271.     "s",           XXSEN, CM_INV,    /* invisible synonym for send */
  272.     "script",       XXLOGI,0,        /* execute a uucp-style script */
  273.     "send",       XXSEN, 0,        /* send files */
  274.     "server",       XXSER, 0,        /* be a server */
  275.     "set",       XXSET, 0,        /* set parameters */
  276.     "show",        XXSHO, 0,        /* show parameters */
  277.     "space",       XXSPA, 0,        /* show available disk space */
  278.     "statistics",  XXSTA, 0,        /* display file transfer stats */
  279.     "stop",        XXSTO, 0,        /* stop all take files */
  280.     "take",       XXTAK, 0,        /* take commands from file */
  281.     "test",        XXTES, CM_INV,    /* (for testing) */
  282.     "translate",   XXXLA, 0,        /* translate local file char sets */
  283.     "transmit",    XXTRA, 0,        /* raw upload file */
  284.     "type",        XXTYP, 0,        /* display a local file */
  285.     "version",     XXVER, 0,        /* version number display */
  286.     "wait",        XXWAI, CM_INV    /* wait (like pause) */
  287. };
  288. int ncmd = (sizeof(cmdtab) / sizeof(struct keytab));
  289.  
  290. char toktab[] = {
  291.     '!',                /* Shell escape */
  292.     '#',                /* Comment */
  293.     ';',                /* Comment */
  294.     '&',                /* Echo */
  295.     ':',                /* Label */
  296.     '\0'                /* End of this string */
  297. };
  298.  
  299. /* Parameter keyword table */
  300.  
  301. struct keytab prmtab[] = {
  302.     "attributes",       XYATTR,  0,
  303.     "baud",            XYSPEE,  CM_INV,
  304.     "block-check",      XYCHKT,  0,
  305.     "count",            XYCOUN,  0,
  306.     "debug",            XYDEBU,  CM_INV,
  307.     "delay",            XYDELA,  0,
  308.     "duplex",            XYDUPL,  0,
  309.     "end-of-packet",    XYEOL,   CM_INV,    /* moved to send/receive */
  310.     "escape-character", XYESC,   0,
  311.     "file",           XYFILE,  0,
  312.     "flow-control",     XYFLOW,  0,
  313.     "handshake",        XYHAND,  0,
  314. #ifdef NETCONN
  315.     "host",             XYNETW,  0,
  316. #endif /* NETCONN */
  317.     "incomplete",       XYIFD,   0,
  318.     "input",            XYINPU,  0,
  319.     "l",                XYLINE,  CM_INV,
  320.     "language",         XYLANG,  0,
  321.     "line",             XYLINE,  0,
  322.     "macro",            XYMACR,  0,
  323.     "modem-dialer",    XYMODM,     0,
  324. #ifdef NETCONN
  325.     "network",          XYNET,   CM_INV,
  326. #endif /* NETCONN */
  327.     "packet-length",    XYLEN,   CM_INV,    /* moved to send/receive */
  328.     "pad-character",    XYPADC,  CM_INV,    /* moved to send/receive */
  329.     "padding",          XYNPAD,  CM_INV,    /* moved to send/receive */
  330.     "parity",            XYPARI,  0,
  331.     "port",             XYLINE,  CM_INV,
  332.     "prompt",            XYPROM,  0,
  333.     "receive",          XYRECV,  0,
  334.     "retry",            XYRETR,  0,
  335.     "send",             XYSEND,  0,
  336.     "server",           XYSERV,  0,
  337.     "speed",            XYSPEE,  0,
  338.     "start-of-packet",  XYMARK,  CM_INV,    /* moved to send/receive */
  339.     "take",             XYTAKE,  0,
  340.     "terminal",         XYTERM,  0,
  341.     "timeout",            XYTIMO,  CM_INV,     /* moved to send/receive */
  342.     "transfer",         XYXFER,  0,
  343.     "unknown-character-set", XYUNCS, 0,
  344.     "window",           XYWIND,  0
  345. };
  346. int nprm = (sizeof(prmtab) / sizeof(struct keytab)); /* How many parameters */
  347.  
  348. /* Table of networks (not used yet) */
  349. #ifdef NETCONN
  350. struct keytab netcmd[] = {
  351.     "tcp-ip-socket", 0, 0
  352. };
  353. int nnets = 1;                /* How many networks */
  354. #endif /* NETCONN */
  355.  
  356. /* Remote Command Table */
  357.  
  358. struct keytab remcmd[] = {
  359.     "cd",        XZCWD, CM_INV,
  360.     "cwd",       XZCWD, 0,
  361.     "delete",    XZDEL, 0,
  362.     "directory", XZDIR, 0,
  363.     "help",      XZHLP, 0,
  364.     "host",      XZHOS, 0,
  365.     "print",     XZPRI, 0,
  366.     "set",       XZSET, 0,
  367.     "space",     XZSPA, 0,
  368.     "type",      XZTYP, 0,
  369.     "who",       XZWHO, 0
  370. };
  371. int nrmt = (sizeof(remcmd) / sizeof(struct keytab));
  372.  
  373. struct keytab logtab[] = {
  374.     "debugging",    LOGD, 0,
  375.     "packets",        LOGP, 0,
  376.     "session",      LOGS, 0,
  377.     "transactions", LOGT, 0
  378. };
  379. int nlog = (sizeof(logtab) / sizeof(struct keytab));
  380.  
  381. /* Show command arguments */
  382.  
  383. struct keytab shotab[] = {
  384.     "communications", SHCOM, 0,
  385.     "count", SHCOU, 0,
  386.     "file", SHFIL, 0,
  387.     "key", SHKEY, CM_INV,
  388.     "languages", SHLNG, 0,
  389.     "macros", SHMAC, 0,
  390.     "parameters", SHPAR, CM_INV,
  391.     "protocol", SHPRO, 0,
  392.     "scripts", SHSCR, 0,
  393.     "server", SHSER, 0,
  394.     "speed", SHSPD, CM_INV,
  395.     "status", SHSTA, 0,
  396.     "versions", SHVER, 0
  397. };
  398. int nsho = (sizeof(shotab) / sizeof(struct keytab));
  399.  
  400. struct keytab iftab[] = {        /* IF commands */
  401.     "<",          XXIFLT, 0,
  402.     "=",          XXIFAE, 0,
  403.     ">",          XXIFGT, 0,
  404.     "count",      XXIFCO, 0,
  405.     "defined",    XXIFDE, 0,
  406.     "equal",      XXIFEQ, 0,
  407.     "exist",      XXIFEX, 0,
  408.     "failure",    XXIFFA, 0,
  409.     "not",        XXIFNO, 0,
  410.     "success",    XXIFSU, 0
  411. };
  412. int nif = (sizeof(iftab) / sizeof(struct keytab));
  413.  
  414. struct keytab enatab[] = {        /* ENABLE commands */
  415.     "all",        EN_ALL,  0,
  416.     "bye",        EN_FIN,  0,
  417.     "cd",         EN_CWD,  0,
  418.     "cwd",        EN_CWD,  CM_INV,
  419.     "directory",  EN_DIR,  0,
  420.     "finish",     EN_FIN,  0,
  421.     "get",        EN_GET,  0,
  422.     "host",       EN_HOS,  0,
  423.     "send",       EN_SEN,  0,
  424.     "set",        EN_SET,  0,
  425.     "space",      EN_SPA,  0,
  426.     "type",       EN_TYP,  0,
  427.     "who",        EN_WHO,  0
  428. };
  429. int nena = (sizeof(enatab) / sizeof(struct keytab));
  430.  
  431. struct mtab mactab[MAC_MAX] = {        /* Preinitialized macro table */
  432.     NULL, NULL, 0
  433. };
  434. int nmac = 0;
  435.  
  436. struct keytab mackey[MAC_MAX];        /* Macro names as command keywords */
  437.  
  438. /*  D O C M D  --  Do a command  */
  439.  
  440. /*
  441.  Returns:
  442.    -2: user typed an illegal command
  443.    -1: reparse needed
  444.     0: parse was successful (even tho command may have failed).
  445. */ 
  446.  
  447. docmd(cx) int cx; {
  448.     int b, x, y, z;
  449.     char *s, *p, *q;
  450.     char a;
  451. #ifdef DTILDE
  452.     char *tnam, *tilde_expand();    /* May have to expand tildes */
  453. #endif
  454.  
  455.     debug(F101,"docmd entry, cx","",cx);
  456.  
  457.     switch (cx) {
  458.  
  459. case -4:                /* EOF */
  460. #ifdef OSK
  461.     if (!quiet && !backgrd) printf("\n");
  462. #else
  463.     if (!quiet && !backgrd) printf("\r\n");
  464. #endif /* OSK */
  465.     doexit(GOOD_EXIT);
  466. case -3:                /* Null command */
  467.     return(0);
  468. case -6:                /* Special */
  469. case -2:                /* Error, maybe */
  470. case -1:                /* Reparse needed */
  471.     return(cx);
  472.  
  473. case XXASK:                /* ask */
  474. case XXASKQ:
  475.     if ((y = cmfld("Variable name","",&s,NULL)) < 0) return(y);
  476.     strcpy(line,s);
  477.     lp = line;
  478.     if (line[0] == CMDQ && line[1] == '%') lp++;
  479.     if (*lp == '%') {
  480.         if (*(lp+2) != '\0') {
  481.         printf("?Only one character after %% in variable name, please\n");
  482.         return(-2);
  483.     }
  484.         if (isdigit(*lp) && maclvl < 0) {
  485.         printf("?Macro parameters not allowed at top level\n");
  486.         return(-2);
  487.     }
  488.     } else {                /* Actually, we could allow */
  489.     printf("?Variables only, please"); /* them to type in macro */
  490.     return(-2);            /* definitions, but... */
  491.     }
  492.     if ((y = cmtxt("Prompt","",&p,xxstring)) < 0) return(y);
  493.     {                    /* Input must be from terminal */
  494.     char psave[40];            /* Save old prompt */
  495.     cmsavp(psave,40);
  496.     cmsetp(p);            /* Make new one */
  497.     if (cx == XXASK)        /* ASK echoes what the user types */
  498.       cmini(ckxech);
  499.     else                /* ASKQ does not echo */
  500.       cmini(0);
  501.     x = -1;                /* This means to reparse. */
  502.     if (!backgrd) prompt();        /* Issue prompt. */
  503.     while (x == -1) {        /* Prompt till they answer */
  504.         x = cmtxt("definition for variable","",&s,NULL);
  505.         debug(F111," cmtxt",s,x);
  506.     }
  507.     if (cx == XXASKQ) printf("\r\n"); /* If ASKQ must echo CRLF here */
  508.     if (x < 0) {
  509.         cmsetp(psave);
  510.         return(x);
  511.     }
  512.     success = 1;            /* Here we know command succeeded */
  513.     if (*s == NUL) {        /* If user types a bare CR, */
  514.         cmsetp(psave);        /* Restore old prompt, */
  515.         delmac(lp);            /* delete variable if it exists, */
  516.         return(0);            /* and return. */
  517.     }
  518.     y = *(lp + 1);            /* Fold case */
  519.     if (isupper(y)) *(lp + 1) = tolower(y);
  520.     y = addmac(lp,s);        /* Add it to the macro table. */
  521.     cmsetp(psave);            /* Restore old prompt. */
  522.     }
  523.     return(0);
  524.  
  525. case XXBYE:                /* bye */
  526.     if ((x = cmcfm()) < 0) return(x);
  527.     sstate = setgen('L',"","","");
  528.     return(0);
  529.  
  530. case XXCLE:                /* clear */
  531.     if ((x = cmcfm()) < 0) return(x);
  532.     if (!local) {
  533.     printf("You have to 'set line' first\n");
  534.     return(0);
  535.     }
  536.     y = ttflui();            /* flush input buffer */
  537.     for (x = 0; x < INPBUFSIZ; x++)    /* and our local copy too */
  538.       inpbuf[x] = 0;
  539.     inpbp = inpbuf;
  540.     success = (y == 0);            /* Set SUCCESS/FAILURE */
  541.     return(0);
  542.  
  543. case XXCOM:                /* comment */
  544.     if ((x = cmtxt("Text of comment line","",&s,NULL)) < 0) return(x);
  545.     /* Don't change SUCCESS flag for this one */
  546.     return(0);
  547.  
  548. case XXCON:                         /* Connect */
  549.     if ((x = cmcfm()) < 0)
  550.       return(x);
  551.     return(success = doconect());
  552.  
  553. case XXCWD:
  554. #ifdef AMIGA
  555.     if ((x = cmtxt("Name of local directory, or carriage return","",&s,
  556.            xxstring)) < 0)
  557.         return(x);
  558.     /* if no name, just print directory name */
  559.     if (*s) {
  560.     if (chdir(s)) {
  561.         cwdf = success = 0;
  562.         perror(s);
  563.     }
  564.     success = cwdf = 1;
  565.     }
  566.     if (getcwd(line, sizeof(line)) == NULL)
  567.     printf("Current directory name not available.\n");
  568.     else
  569.     if (!backgrd && cmdlvl == 0) printf("%s\n", line);
  570. #else
  571.     if ((x = cmdir("Name of local directory, or carriage return",homdir,&s,
  572.            xxstring)) < 0 )
  573.       return(x);
  574.     if (x == 2) {
  575.     printf("\n?Wildcards not allowed in directory name\n");
  576.     return(-2);
  577.     }
  578. #ifdef OS2
  579.     if ( s!=NUL ) {
  580.     if (strlen(s)>=2 && s[1]==':') {    /* Disk specifier */
  581.         if (zchdsk(*s)) {            /* Change disk successful */
  582.             if ( strlen(s)>=3 & ( s[2]==CMDQ || isalnum(s[2]) ) ) {
  583.                 if (chdir(s)) perror(s);
  584.             }
  585.         } else {
  586.         cwdf = success = 0;
  587.         perror(s);
  588.         }
  589.     } else if (chdir(s)) {
  590.         cwdf = success = 0;
  591.         perror(s);
  592.     }
  593.     }
  594.     success = cwdf = 1;
  595.     concooked();
  596.     system(PWDCMD);
  597.     conraw();
  598. #else
  599.     if (! zchdir(s)) {
  600.     cwdf = success = 0;
  601.     perror(s);
  602.     }
  603.     system(PWDCMD);            /* assume this works... */
  604.     success = cwdf = 1;            /* system() doesn't tell */
  605. #endif
  606. #endif
  607.     return(0);
  608.  
  609. case XXCLO:
  610.     x = cmkey(logtab,nlog,"Which log to close","",xxstring);
  611.     if (x == -3) {
  612.     printf("?You must tell which log\n");
  613.     return(-2);
  614.     }
  615.     if (x < 0) return(x);
  616.     if ((y = cmcfm()) < 0) return(y);
  617.     y = doclslog(x);
  618.     success = (y == 1);
  619.     return(success);
  620.  
  621. case XXDEC:                 /* DECREMENT */
  622. case XXINC: {                /* INCREMENT */
  623.     char c;
  624.     int n;
  625.     
  626.     if ((y = cmfld("Variable name","",&s,NULL)) < 0)
  627.       return(y);
  628.     strncpy(vnambuf,s,VNAML);
  629.     vnp = vnambuf;
  630.     if (vnambuf[0] == CMDQ && vnambuf[1] == '%') vnp++;
  631.     if (*vnp != '%') {
  632.     printf("?Not a variable name - %s\n",s);
  633.     return(-2);
  634.     }
  635.     if (*vnp == '%' && *(vnp+2) != '\0') {
  636.     printf("?Only one character after %% in variable name, please\n");
  637.     return(-2);
  638.     }
  639.     if ((x = cmcfm()) < 0) return(x);
  640.     p = varlook(vnp);            /* Look up variable */
  641.     if (p == NULL) {
  642.     printf("?Not defined - %s\n",s);      
  643.     return(success = 0);        /* If not found, fail. */
  644.     }
  645.     if (!chknum(p)) {            /* If not numeric, fail. */
  646.     printf("?Not numeric - %s = [%s]\n",s,p);
  647.     return(success = 0);
  648.     }
  649.     n = atoi(p);            /* Otherwise convert to integer */
  650.     if (cx == XXINC)            /* And now increment */
  651.       n++;
  652.     else if (cx == XXDEC)        /* or decrement as requested. */
  653.       n--;
  654.     sprintf(tmpbuf,"%d",n);        /* Convert back to numeric string */
  655.     addmac(vnp,tmpbuf);            /* Replace old variable */
  656.     return(success = 1); }
  657.  
  658. case XXDEF:                /* DEFINE */
  659. case XXASS:                /* ASSIGN */
  660.     if ((y = cmfld("Macro or variable name","",&s,NULL)) < 0) return(y);
  661.     strcpy(vnambuf,s);
  662.     vnp = vnambuf;
  663.     if (vnambuf[0] == CMDQ && vnambuf[1] == '%') vnp++;
  664.     if (*vnp == '%') {
  665. #ifdef COMMENT
  666.     if (isdigit(*(vnp+1)) && maclvl < 0) {
  667.         printf("?Macro parameters not allowed at top level\n");
  668.         return(-2);
  669.     }
  670. #endif
  671.     if ((y = cmtxt("Definition of variable","",&s,NULL)) < 0) return(y);
  672.     debug(F110,"xxdef var name",vnp,0);
  673.     debug(F110,"xxdef var def",s,0);
  674.     } else {
  675.     if ((y = cmtxt("Definition of macro","",&s,NULL)) < 0) return(y);
  676.     debug(F110,"xxdef macro name",vnp,0);
  677.     debug(F110,"xxdef macro def",s,0);
  678.     }
  679.     if (*s == NUL) {            /* No arg given, undefine this macro */
  680.     delmac(vnp);            /* silently... */
  681.     return(success = 1);        /* even if it doesn't exist... */
  682.     } 
  683.  
  684.     /* Defining a new macro or variable */
  685.  
  686.     if (*vnp == '%' && *(vnp+2) != '\0') {
  687.     printf("?Only one character after %% in variable name, please\n");
  688.     return(-2);
  689.     }
  690.     y = *(vnp + 1);            /* Fold case */
  691.     if (isupper(y)) *(vnp + 1) = tolower(y);
  692.  
  693.     if (cx == XXASS) {            /* ASSIGN rather than DEFINE? */
  694.     lp = line;            /* If so, expand its value now */
  695.     xxstring(s,&lp);
  696.     s = line;
  697.     }
  698.     debug(F111,"calling addmac",s,strlen(s));
  699.  
  700.     y = addmac(vnp,s);            /* Add it to the appropriate table. */
  701.     if (y < 0) {
  702.     printf("?No more space for macros\n");
  703.     return(success = 0);
  704.     }
  705.     return(0);
  706.     
  707. case XXDIAL:                /* dial phone number */
  708.     if ((x = cmtxt("Number to be dialed","",&s,xxstring)) < 0)
  709.       return(x);
  710.     return(success = ckdial(s));
  711.  
  712. case XXDEL:                /* delete */
  713.     if ((x = cmifi("File(s) to delete","",&s,&y,xxstring)) < 0) {
  714.     if (x == -3) {
  715.         printf("?A file specification is required\n");
  716.         return(-2);
  717.     }
  718.     return(x);
  719.     }
  720.     strncpy(tmpbuf,s,50);        /* Make a safe copy of the name. */
  721.     sprintf(line,"%s %s",DELCMD,s);    /* Construct the system command. */
  722.     if ((y = cmcfm()) < 0) return(y);    /* Confirm the user's command. */
  723.     system(line);            /* Let the system do it. */
  724.     z = zchki(tmpbuf);
  725.     success = (z == -1);
  726.     if (cmdlvl == 0 && !backgrd) {
  727.     if (success)
  728.       printf("%s - deleted\n",tmpbuf);
  729.     else
  730.       printf("%s - not deleted\n",tmpbuf);
  731.     }
  732.     return(success);
  733.  
  734. case XXDIR:                /* directory */
  735. #ifdef vms
  736.     if ((x = cmtxt("Directory/file specification","",&s,xxstring)) < 0)
  737.       return(x);
  738.     /* now do this the same as a shell command - helps with LAT  */
  739.     conres();                /* make console normal */
  740.     lp = line;
  741.     sprintf(lp,"%s %s",DIRCMD,s);
  742.     debug(F110,"Directory string: ", line, 0);
  743.     concb(escape);
  744. /*** So where does it do the command??? ***/
  745.     return(success = 0);
  746. #else
  747. #ifdef AMIGA
  748.     if ((x = cmtxt("Directory/file specification","",&s,xxstring)) < 0)
  749.       return(x);
  750. #else
  751. #ifdef datageneral
  752.     if ((x = cmtxt("Directory/file specification","+",&s,xxstring)) < 0)
  753.       return(x);
  754. #else
  755.     if ((x = cmdir("Directory/file specification","*",&s,xxstring)) < 0)
  756.       return(x);
  757.     strcpy(tmpbuf,s);
  758.     if ((y = cmcfm()) < 0) return(y);
  759.     s = tmpbuf;
  760. #endif
  761. #endif
  762.     lp = line;
  763.     sprintf(lp,"%s %s",DIRCMD,s);
  764. #ifdef OS2
  765.     concooked();
  766.     system(line);
  767.     conraw();
  768. #else
  769.     system(line);
  770. #endif
  771.     return(success = 1);        /* who cares... */
  772. #endif 
  773.  
  774. case XXELS:                /* else */
  775.     if (!ifcmd[cmdlvl]) {
  776.     printf("?ELSE doesn't follow IF\n");
  777.     return(-2);
  778.     }
  779.     ifcmd[cmdlvl] = 0;
  780.     if (!iftest[cmdlvl]) {        /* If IF was false do ELSE part */
  781.     if (maclvl > -1) {        /* In macro, */
  782.         pushcmd();            /* save rest of command. */
  783.     } else if (tlevel > -1) {    /* In take file, */
  784.         pushcmd();            /* save rest of command. */
  785.     } else {            /* If interactive, */
  786.         cmini(ckxech);        /* just start a new command */
  787.         printf("\n");        /* (like in MS-DOS Kermit) */
  788.         prompt();
  789.     }
  790.     } else {                /* Condition is false */
  791.     if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
  792.       return(y);            /* Gobble up rest of line */
  793.     }
  794.     return(0);
  795.  
  796. case XXENA:                /* enable */
  797. case XXDIS:                /* disable */
  798.     if ((x = cmkey(enatab,nena,"Server function to enable","",xxstring)) < 0)
  799.       return(x);
  800.     if ((y = cmcfm()) < 0)
  801.       return(y);
  802.     y = ((cx == XXENA) ? 1 : 0);
  803.     switch (x) {
  804.       case EN_ALL:
  805.     en_cwd = en_del = en_dir = en_fin = en_get = y;
  806.     en_hos = en_sen = en_set = en_spa = en_typ = en_who = y;
  807.     break;
  808.       case EN_CWD:
  809.     en_cwd = y;
  810.     break;
  811.       case EN_DIR:
  812.     en_dir = y;
  813.     break;
  814.       case EN_FIN:
  815.     en_fin = y;
  816.     break;
  817.       case EN_GET:
  818.     en_get = y;
  819.     break;
  820.       case EN_HOS:
  821.     en_hos = y;
  822.     break;
  823.       case EN_SEN:
  824.     en_sen = y;
  825.     break;
  826.       case EN_SET:
  827.     en_set = y;
  828.     break;
  829.       case EN_SPA:
  830.     en_spa = y;
  831.     break;
  832.       case EN_TYP:
  833.     en_typ = y;
  834.     break;
  835.       case EN_WHO:
  836.     en_who = y;
  837.     break;
  838.       default:
  839.     return(-2);
  840.     }
  841.     return(0);
  842.  
  843. case XXEND:                /* end */
  844.     if ((x = cmcfm()) < 0)
  845.       return(x);
  846.     popclvl();                /* pop command level */
  847.     return(success = 1);        /* always succeeds */
  848.  
  849. case XXDO:                /* do (a macro) */
  850.     if (nmac == 0) {
  851.     printf("\?No macros defined\n");
  852.     return(-2);
  853.     }
  854.     for (y = 0; y < nmac; y++) {    /* copy the macro table */
  855.     mackey[y].kwd = mactab[y].kwd;    /* into a regular keyword table */
  856.     mackey[y].val = y;        /* with value = pointer to macro tbl */
  857.     mackey[y].flgs = mactab[y].flgs;
  858.     }
  859.     /* parse name as keyword */
  860.     if ((x = cmkey(mackey,nmac,"macro","",xxstring)) < 0)
  861.       return(x);
  862.     if ((y = cmtxt("optional arguments","",&s,xxstring)) < 0) /* get args */
  863.       return(y);
  864.     if (++maclvl > MACLEVEL) {        /* Make sure we have storage */
  865.     --maclvl;
  866.     printf("Macros nested too deeply\n");
  867.     return(success = 0);
  868.     }
  869.     macp[maclvl] = mactab[x].val;    /* Point to the macro body */
  870.     debug(F111,"do macro",macp[maclvl],maclvl);
  871.     macx[maclvl] = x;            /* Remember the macro table index */
  872.  
  873.     cmdlvl++;                /* Entering a new command level */
  874.     if (cmdlvl > CMDSTKL) {        /* Too many macros + TAKE files? */
  875.     cmdlvl--;
  876.     printf("?TAKE files and DO commands nested too deeply\n");
  877.     return(success = 0);
  878.     }
  879.     ifcmd[cmdlvl] = 0;
  880.     iftest[cmdlvl] = 0;
  881.     count[cmdlvl] = 0;
  882.     cmdstk[cmdlvl].src = CMD_MD;    /* Say we're in a macro */
  883.     cmdstk[cmdlvl].val = maclvl;    /* and remember the macro level */
  884.  
  885.     debug(F111,"do macro",mactab[macx[maclvl]].kwd,macx[maclvl]);
  886.  
  887. /* Clear old %0..%9 arguments */
  888.  
  889.     addmac("%0",mactab[macx[maclvl]].kwd); /* Define %0 = name of macro */
  890.     varnam[0] = '%';
  891.     varnam[2] = '\0';
  892.     for (y = 1; y < 10; y++) {        /* Clear args %1..%9 */
  893.     varnam[1] = y + '0';
  894.     delmac(varnam);
  895.     }    
  896.  
  897. /* Assign the new args one word per arg, allowing braces to group words */
  898.  
  899.     p = s;                /* Pointer to beginning of arg */
  900.     b = 0;                /* Flag for outer brace removal */
  901.     x = 0;                /* Flag for in-word */
  902.     y = 0;                /* Brace nesting level */
  903.     z = 0;                /* Argument counter, 0 thru 9 */
  904.  
  905.     while (1) {                /* Go thru argument list */
  906.     if (*s == '\0') {        /* No more characters? */
  907.         if (x != 0) {
  908.         if (z == 9) break;    /* Only go up to 9. */
  909.         z++;            /* Count it. */
  910.         varnam[1] = z + '0';    /* Assign last argument */
  911.         addmac(varnam,p);
  912.         break;            /* And get out. */
  913.         } else break;
  914.     } 
  915.     if (x == 0 && *s == ' ') {    /* Eat leading blanks */
  916.         s++;
  917.         continue;
  918.     } else if (*s == '{') {        /* An opening brace */
  919.         if (x == 0 && y == 0) {    /* If leading brace */
  920.         p = s+1;        /* point past it */
  921.         b = 1;            /* and flag that we did this */
  922.         }
  923.         x = 1;            /* Flag that we're in a word */
  924.         y++;            /* Count the brace. */
  925.     } else if (*s == '}') {        /* A closing brace. */
  926.         y--;            /* Count it. */
  927.         if (y == 0 && b != 0) {    /* If it matches the leading brace */
  928.         *s = ' ';        /* change it to a space */
  929.         b = 0;            /* and we're not in braces any more */
  930.         } else if (y < 0) x = 1;    /* otherwise just start a new word. */
  931.     } else if (*s != ' ') {        /* Nonspace means we're in a word */
  932.         if (x == 0) p = s;        /* Mark the beginning */
  933.         x = 1;            /* Set in-word flag */
  934.     }
  935.     /* If we're not inside a braced quantity, and we are in a word, and */
  936.     /* we have hit a space, then we have an argument to assign. */
  937.     if ((y < 1) && (x != 0) && (*s == ' ')) { 
  938.         *s = '\0';            /* terminate the arg with null */
  939.         x = 0;            /* say we're not in a word any more */
  940.         y = 0;            /* start braces off clean again */
  941.         if (z == 9) break;        /* Only go up to 9. */
  942.         z++;            /* count this arg */
  943.         varnam[1] = z + '0';    /* compute its name */
  944.         addmac(varnam,p);        /* add it to the macro table */
  945.         p = s+1;
  946.     }
  947.     s++;                /* Point past this character */
  948.     }
  949.     if ((z == 0) && (y > 1)) {        /* Extra closing brace(s) at end */
  950.     z++;
  951.     varnam[1] = z + '0';        /* compute its name */
  952.     addmac(varnam,p);        /* Add rest of line to last arg */
  953.     }
  954.     macargc[maclvl] = z;        /* For ARGC variable */
  955.     return(success = 1);        /* DO command succeeded */
  956.  
  957. case XXECH:                 /* echo */
  958.     if ((x = cmtxt("Material to be echoed","",&s,xxstring)) < 0) return(x);
  959.     printf("%s\n",s);
  960.     return(1);                /* Don't bother with success? */
  961.  
  962. case XXOUT:                /* Output */
  963.     if ((x = cmtxt("Material to be output","",&s,xxstring)) < 0) return(x);
  964.     return(success = dooutput(s));
  965.  
  966. case XXPAU:                /* Pause */
  967. case XXWAI:                /* Wait */
  968.     /* For now, WAIT is just a synonym for PAUSE. */
  969.     /* Both should take not only secs but also hh:mm:ss as argument. */
  970.     /* WAIT should wait for modem signals like MS-DOS Kermit */
  971.     /* Presently there's no mechanism in ckutio.c for this. */
  972.     if (cx == XXWAI)
  973.       y = cmnum("seconds to wait","1",10,&x,xxstring);
  974.     else y = cmnum("seconds to pause","1",10,&x,xxstring);
  975.     if (y < 0) return(y);
  976.     if (x < 0) x = 0;
  977.     switch (cx) {
  978.       case XXPAU:
  979.     if ((y = cmcfm()) < 0) return(y);
  980.     break;
  981.       case XXWAI:
  982.     if ((y = cmtxt("Modem Signals","",&s,xxstring)) < 0) return(y);
  983.     break;
  984.       default:
  985.     return(-2);
  986.     }
  987.  
  988. /* Command is entered, now do it.  For now, WAIT is just like PAUSE */
  989.  
  990.     while (x--) {            /* Sleep loop */
  991.     if (y = conchk()) {        /* Did they type something? */
  992.         while (y--) coninc(0);    /* Yes, gobble it up */
  993.         break;            /* And quit PAUSing or WAITing */
  994.     }
  995.     sleep(1);            /* No interrupt, sleep one second */
  996.     }
  997.     if (cx == XXWAI) success = 0;    /* For now, WAIT always fails. */
  998.     else success = (x == -1);        /* Set SUCCESS/FAILURE for PAUSE. */
  999.     return(0);
  1000.  
  1001. case XXPWD:                /* PWD */
  1002.     if ((x = cmcfm()) < 0) return(x);
  1003.     system(PWDCMD);
  1004.     return(success = 1);        /* blind faith */
  1005.  
  1006. case XXQUI:                /* quit, exit */
  1007. case XXEXI:
  1008.     if ((x = cmcfm()) > -1) doexit(GOOD_EXIT);
  1009.     else return(x);
  1010.  
  1011. case XXFIN:                /* finish */
  1012.     if ((x = cmcfm()) < 0) return(x);
  1013.     sstate = setgen('F',"","","");
  1014.     return(0);
  1015.  
  1016. case XXGET:                /* get */
  1017.     x = cmtxt("Name of remote file(s), or carriage return","",&cmarg,xxstring);
  1018.     if ((x == -2) || (x == -1)) return(x);
  1019.  
  1020. /* If foreign file name omitted, get foreign and local names separately */
  1021.  
  1022.     x = 0;                /* For some reason cmtxt returns 1 */
  1023.     if (*cmarg == NUL) {
  1024.  
  1025.     if (tlevel > -1) {        /* Input is from take file */
  1026.  
  1027.         if (fgets(line,100,tfile[tlevel]) == NULL)
  1028.             fatal("take file ends prematurely in 'get'");
  1029.         debug(F110,"take-get 2nd line",line,0);
  1030. /****        stripq(line); ***/
  1031.         for (x = strlen(line);
  1032.               x > 0 && (line[x-1] == LF || line[x-1] == CR);
  1033.          x--)
  1034.         line[x-1] = '\0';
  1035.         cmarg = line;
  1036.         if (fgets(cmdbuf,CMDBL,tfile[tlevel]) == NULL)
  1037.             fatal("take file ends prematurely in 'get'");
  1038. /****        stripq(cmdbuf); ***/
  1039.         for (x = strlen(cmdbuf);
  1040.               x > 0 && (cmdbuf[x-1] == LF || cmdbuf[x-1] == CR);
  1041.          x--)
  1042.         cmdbuf[x-1] = '\0';
  1043.         if (*cmdbuf == NUL) cmarg2 = line; else cmarg2 = cmdbuf;
  1044.             x = 0;            /* Return code */
  1045.         printf("%s",cmarg2);
  1046.         } else {            /* Input is from terminal */
  1047.  
  1048.         char psave[40];        /* Save old prompt */
  1049.         cmsavp(psave,40);
  1050.         cmsetp(" Remote file specification: "); /* Make new one */
  1051.         cmini(ckxech);
  1052.         x = -1;
  1053.         if (!backgrd) prompt();
  1054.         while (x == -1) {        /* Prompt till they answer */
  1055.             x = cmtxt("Name of remote file(s)","",&cmarg,xxstring);
  1056.         debug(F111," cmtxt",cmarg,x);
  1057.         }
  1058.         if (x < 0) {
  1059.         cmsetp(psave);
  1060.         return(x);
  1061.         }
  1062.         if (*cmarg == NUL) {     /* If user types a bare CR, */
  1063.         printf("(cancelled)\n"); /* Forget about this. */
  1064.             cmsetp(psave);        /* Restore old prompt, */
  1065.         return(0);        /* and return. */
  1066.         }
  1067.         strcpy(line,cmarg);        /* Make a safe copy */
  1068.         cmarg = line;
  1069.         cmsetp(" Local name to store it under: "); /* New prompt */
  1070.         cmini(ckxech);
  1071.         x = -1;
  1072.         if (!backgrd) prompt();
  1073.         while (x == -1) {        /* Again, parse till answered */
  1074.             x = cmofi("Local file name","",&cmarg2,xxstring);
  1075.         }
  1076.         if (x == -3) {                    /* If bare CR, */
  1077.         printf("(cancelled)\n");    /* escape from this... */
  1078.             cmsetp(psave);                /* Restore old prompt, */
  1079.         return(0);                /* and return. */
  1080.         } else if (x < 0) return(x);        /* Handle parse errors. */
  1081.         
  1082.         x = -1;            /* Get confirmation. */
  1083.         while (x == -1) x = cmcfm();
  1084.         cmsetp(psave);        /* Restore old prompt. */
  1085.         }
  1086.     }
  1087.     if (x == 0) {            /* Good return from cmtxt or cmcfm, */
  1088.     sstate = 'r';            /* set start state. */
  1089.     if (local) displa = 1;
  1090.     }
  1091.     return(x);
  1092.  
  1093. case XXHLP:                /* Help */
  1094.     x = cmkey2(cmdtab,ncmd,"C-Kermit command","help",toktab,xxstring);
  1095.     if (x == -5) {
  1096.     y = chktok(toktab);
  1097.     debug(F101,"top-level cmkey token","",y);
  1098.     ungword();
  1099.     switch (y) {
  1100.       case '!': x = XXSHE; break;
  1101.       case '%': x = XXCOM; break;
  1102.       case '#': x = XXCOM; break;
  1103.       case ';': x = XXCOM; break;
  1104.       case ':': x = XXLBL; break;
  1105.       case '&': x = XXECH; break;
  1106.       default:
  1107.         printf("\n?Invalid - %s\n",cmdbuf);
  1108.         x = -2;
  1109.     }
  1110.     }
  1111.     return(success = (dohlp(x) > -1));
  1112.  
  1113. case XXHAN:                /* Hangup */
  1114.     if ((x = cmcfm()) > -1)
  1115.       return(success = (tthang() > -1));
  1116.  
  1117. case XXGOTO:                /* Goto */
  1118. /* Note, here we don't set SUCCESS/FAILURE flag */
  1119.     if ((y = cmfld("label","",&s,xxstring)) < 0) return(y);
  1120.     strcpy(lblbuf,s);
  1121.     if ((x = cmcfm()) < 0) return(x);
  1122.     s = lblbuf;
  1123.     debug(F110,"goto before conversion",s,0);
  1124.     if (*s != ':') {            /* If the label mentioned */
  1125.     int i;                /* does not begin with a colon, */
  1126.     y = strlen(s);            /* then insert one. */
  1127.     for (i = y; i > 0; i--)
  1128.         s[i] = s[i-1];
  1129.     s[0] = ':';
  1130.     s[++y] = '\0';
  1131.     }
  1132.     debug(F111,"goto after conversion",s,y);
  1133.  
  1134.     while (cmdlvl > 0) {        /* Only works inside macros & files */
  1135.     if (cmdstk[cmdlvl].src == CMD_MD) { /* GOTO inside macro */
  1136.         int i, m;
  1137.         lp = mactab[macx[maclvl]].val; /* point to beginning of macro */
  1138.         debug(F111,"goto in macro",lp,macx[maclvl]);
  1139.         m = strlen(lp) - y;
  1140.         debug(F111,"goto in macro",lp,m);
  1141.         for (i = 0; i < m; i++,lp++) /* search for label in macro body */
  1142.           if (!strncmp(s,lp,y))
  1143.         break;
  1144.         if (i == m) {        /* didn't find the label */
  1145.         debug(F101,"goto failed at cmdlvl","",cmdlvl);
  1146.         if (!popclvl()) {    /* pop up to next higher level */
  1147.             printf("?Label '%s' not found\n",s); /* if none */
  1148.             return(0);        /* quit */
  1149.         } else continue;    /* otherwise look again */
  1150.         }
  1151.         debug(F110,"goto found macro label",lp,0);
  1152.         macp[maclvl] = lp;        /* set macro buffer pointer */
  1153.         return(1);
  1154.     } else if (cmdstk[cmdlvl].src == CMD_TF) {
  1155.         x = 0;            /* GOTO issued in take file */
  1156.         rewind(tfile[tlevel]);    /* Search file from beginning */
  1157.         while (! feof(tfile[tlevel])) {
  1158.         if (fgets(line,LINBUFSIZ,tfile[tlevel]) == NULL) /* Get line */
  1159.           break;        /* If no more, done, label not found */
  1160.         lp = line;        /* Got line */
  1161.         while (*lp == ' ' || *lp == '\t')
  1162.           lp++;            /* Strip leading whitespace */
  1163.         if (!strncmp(lp,s,y)) {    /* Compare result with label */
  1164.             x = 1;        /* Got it */
  1165.             break;        /* done. */
  1166.         }
  1167.         }
  1168.         if (x == 0) {        /* If not found, print message */
  1169.         debug(F101,"goto failed at cmdlvl","",cmdlvl);
  1170.         if (!popclvl()) {    /* pop up to next higher level */
  1171.             printf("?Label '%s' not found\n",s);    /* if none */
  1172.             return(0);        /* quit */
  1173.         } else continue;    /* otherwise look again */
  1174.         }
  1175.         return(x);            /* Send back return code */
  1176.     }
  1177.     }
  1178.     printf("?Stack problem in GOTO\n",s); /* Shouldn't see this */
  1179.     return(0);
  1180.  
  1181. case XXIF:                /* IF command */
  1182.     not = 0;                /* Flag for whether "NOT" was seen */
  1183.  
  1184. ifagain:
  1185.     if ((ifc = cmkey(iftab,nif,"","",xxstring)) < 0) /* If what?... */
  1186.       return(ifc);
  1187.     switch (ifc) {            /* z = 1 for true, 0 for false */
  1188.       case XXIFNO:            /* IF NOT */
  1189.     not ^= 1;
  1190.     goto ifagain;
  1191.       case XXIFSU:            /* IF SUCCESS */
  1192.     z = ( success != 0 );
  1193.     debug(F101,"if success","",z);
  1194.     break;
  1195.       case XXIFFA:            /* IF FAILURE */
  1196.     z = ( success == 0 );
  1197.     debug(F101,"if failure","",z);
  1198.     break;
  1199.       case XXIFDE:            /* IF DEFINED */
  1200.     if ((x = cmfld("Macro or variable name","",&s,NULL)) < 0)
  1201.       return(x);
  1202.     strcpy(line,s);            /* Make a copy */
  1203.     lp = line;
  1204.     if (line[0] == CMDQ && line[1] == '%')    /* Change "\%x" to just "%x" */
  1205.       lp++;                /* Both forms are allowed. */
  1206.     if (*lp == '%')    {        /* Is it a variable? */
  1207.         x = *(lp + 1);        /* Fold case */
  1208.         if (isupper(x)) *(lp + 1) = tolower(x);
  1209.         if (x >= '0' && x <= '9' && maclvl > -1)
  1210.           z = ( m_arg[maclvl][x - '0'] != 0 ); /* Digit is macro arg */
  1211.         else            /* Otherwise its a global variable */
  1212.           z = ( g_var[x] != 0 );
  1213.     } else {            /* Otherwise its a macro name */
  1214.         z = ( mxlook(mactab,lp,nmac) > -1 ); /* Look for exact match */
  1215.     }
  1216.     debug(F111,"if defined",s,z);
  1217.     break;
  1218.       case XXIFCO:            /* IF COUNT */
  1219.     z = ( --count[cmdlvl] > 0 );
  1220.     debug(F101,"if count","",z);
  1221.     break;
  1222.       case XXIFEX:            /* IF EXIST */
  1223.     if ((x = cmfld("File","",&s,xxstring)) < 0) return(x);
  1224.     z = ( zchki(s) > -1L );
  1225.     debug(F101,"if exist","",z);
  1226.     break;
  1227.       case XXIFEQ:             /* IF EQUAL (string comparison) */
  1228.     if ((x = cmfld("first word or variable name","",&s,xxstring)) < 0)
  1229.       return(x);
  1230.     lp = line;
  1231.     strcpy(lp,s);
  1232.     if ((y = cmfld("second word or variable name","",&s,xxstring)) < 0)
  1233.       return(y);
  1234.     x = strlen(lp);
  1235.     tp = line + x + 2;
  1236.     strcpy(tp,s);
  1237.     y = strlen(tp);
  1238.     if (x + y + 2 > LINBUFSIZ) {    /* Have to do something better */
  1239.         fatal("if equal: strings too long"); /* than this... */
  1240.         z = 0;
  1241.         break;
  1242.     }
  1243.     if (x != y) {            /* Different lengths */
  1244.         z = 0;            /* so not equal */
  1245.         break;
  1246.     }
  1247.     if (!incase)            /* Ignoring alphabet case? */
  1248.       z = !xxstrcmp(tp,lp);        /* Yes, special string compare */
  1249.     else                /* No, */
  1250.       z = !strcmp(tp,lp);        /* Exact match required. */
  1251.     debug(F101,"if equal","",z);
  1252.     break;
  1253.  
  1254.       case XXIFAE:            /* IF (arithmetically) = */
  1255.       case XXIFLT:            /* IF (arithmetically) < */
  1256.       case XXIFGT: {            /* IF (arithmetically) > */
  1257.     int n1, n2;
  1258.     if ((x = cmfld("first number or variable name","",&s,xxstring)) < 0)
  1259.       return(x);
  1260.     debug(F101,"xxifgt cmfld","",x);
  1261.     lp = line;
  1262.     strcpy(lp,s);
  1263.     debug(F110,"xxifgt exp1",lp,0);
  1264.     if (!xxstrcmp(lp,"count")) {
  1265.         n1 = count[cmdlvl];
  1266.     } else if (!xxstrcmp(lp,"version")) {
  1267.         n1 = (int) vernum;
  1268.     } else if (!xxstrcmp(lp,"argc")) {
  1269.         n1 = (int) macargc[maclvl];
  1270.     } else {
  1271.         if (!chknum(lp)) return(-2);
  1272.         n1 = atoi(lp);
  1273.     }
  1274.     if ((y = cmfld("second number or variable name","",&s,xxstring)) < 0)
  1275.       return(y);
  1276.     x = strlen(lp);
  1277.     tp = line + x + 2;
  1278.     strcpy(tp,s);
  1279.     debug(F110,"xxifgt exp2",tp,0);
  1280.     if (!xxstrcmp(tp,"count")) {
  1281.         n2 = count[cmdlvl];
  1282.     } else if (!xxstrcmp(tp,"version")) {
  1283.         n2 = (int) vernum;
  1284.     } else if (!xxstrcmp(tp,"argc")) {
  1285.         n2 = (int) macargc[maclvl];
  1286.     } else {
  1287.         if (!chknum(tp)) return(-2);
  1288.         n2 = atoi(tp);
  1289.     }
  1290.     z = ((n1 <  n2 && ifc == XXIFLT)
  1291.       || (n1 == n2 && ifc == XXIFAE)
  1292.       || (n1 >  n2 && ifc == XXIFGT));
  1293.     debug(F101,"xxifft n1","",n1);
  1294.     debug(F101,"xxifft n2","",n2);
  1295.     debug(F101,"xxifft z","",z);
  1296.     break; }
  1297.  
  1298.       default:                /* Shouldn't happen */
  1299.     return(-2);
  1300.     }
  1301.         ifcmd[cmdlvl] = 1;        /* We just completed an IF command */
  1302.     if (not) z = !z;        /* Handle NOT here */
  1303.         if (z) {            /* Condition is true */
  1304.         iftest[cmdlvl] = 1;        /* Remember that IF succeeded */
  1305.         if (maclvl > -1) {        /* In macro, */
  1306.         pushcmd();        /* save rest of command. */
  1307.         } else if (tlevel > -1) {    /* In take file, */
  1308.         pushcmd();        /* save rest of command. */
  1309.         } else {            /* If interactive, */
  1310.         cmini(ckxech);        /* just start a new command */
  1311.         printf("\n");        /* (like in MS-DOS Kermit) */
  1312.         prompt();
  1313.         }
  1314.     } else {            /* Condition is false */
  1315.         iftest[cmdlvl] = 0;        /* Remember command failed. */
  1316.         if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
  1317.           return(y);        /* Gobble up rest of line */
  1318.     }
  1319.     return(0);
  1320.  
  1321. case XXINP:                /* INPUT and */
  1322. case XXREI:                /* REINPUT */
  1323.     y = cmnum("seconds to wait for input","1",10,&x,xxstring);
  1324.     if (y < 0) return(y);
  1325.     if (x <= 0) x = 1;
  1326.     if ((y = cmtxt("Material to be input","",&s,xxstring)) < 0) return(y);
  1327. /*
  1328.     if (! local) {
  1329.     printf("You must 'set line' first\n");
  1330.     return(1);
  1331.     }
  1332. */
  1333.     if (cx == XXINP) {            /* INPUT */
  1334.     debug(F110,"xxinp line",s,0);
  1335.     if (local != 0 && tvtflg == 0) { /* Put line in "ttvt" mode */
  1336.         y = ttvt(speed,flow);    /* if not already. */
  1337.         if (y < 0) {
  1338.         printf("?Can't condition line for INPUT\n");
  1339.         return(0);        /* Watch out for failure. */
  1340.         }
  1341.         tvtflg = 1;            /* On success set this flag */
  1342.     }
  1343.     success = doinput(x,s);        /* Go try to input the search string */
  1344.     } else {                /* REINPUT */
  1345.     debug(F110,"xxrei line",s,0);
  1346.     success = doreinp(x,s);
  1347.     }
  1348.     if (intime && !success) {        /* TIMEOUT-ACTION = QUIT? */
  1349.     popclvl();            /* If so, pop command level. */
  1350.     if (!backgrd && cmdlvl == 0) {
  1351.         if (cx == XXINP) printf("Input timed out\n");
  1352.         if (cx == XXREI) printf("Reinput failed\n");
  1353.         }
  1354.     }
  1355.     return(success);            /* Return (re)doinput's return code */
  1356.  
  1357. case XXLBL:                /* Label */
  1358.     if ((x = cmtxt("Command-file label","",&s,xxstring)) < 0) return(x);
  1359.     /* should be cmfld, then cmcfm, to prevent multiple words in label? */
  1360.     return(0);
  1361.  
  1362. case XXLOG:                /* Log */
  1363.     x = cmkey(logtab,nlog,"What to log","",xxstring);
  1364.     if (x == -3) {
  1365.     printf("?You must specify what is to be logged\n");
  1366.     return(-2);
  1367.     }
  1368.     if (x < 0) return(x);
  1369.     return(success = (dolog(x) > 0));
  1370.  
  1371. case XXLOGI:                /* Send script remote system */
  1372.     if ((x = cmtxt("Text of login script","",&s,xxstring)) < 0) return(x);
  1373.     return(success = login(s));        /* Return 1=completed, 0=failed */
  1374.  
  1375. case XXREC:                /* Receive */
  1376.     cmarg2 = "";
  1377.     x = cmofi("Name under which to store the file, or CR","",&cmarg2,xxstring);
  1378.     if ((x == -1) || (x == -2)) return(x);
  1379.     debug(F111,"cmofi cmarg2",cmarg2,x);
  1380.     if ((x = cmcfm()) < 0) return(x);
  1381.     sstate = 'v';
  1382.     if (local) displa = 1;
  1383.     return(0);
  1384.  
  1385. case XXREM:                /* Remote */
  1386.     x = cmkey(remcmd,nrmt,"Remote Kermit server command","",xxstring);
  1387.     if (x == -3) {
  1388.     printf("?You must specify a command for the remote server\n");
  1389.     return(-2);
  1390.     }
  1391.     return(dormt(x));
  1392.  
  1393.  
  1394. case XXSEN:                /* SEND command and... */
  1395. case XXMAI:                /* MAIL command */
  1396.     cmarg = cmarg2 = "";
  1397.     if ((x = cmifi("File(s) to send","",&s,&y,xxstring)) < 0) {
  1398.     if (x == -3) {
  1399.         printf("?A file specification is required\n");
  1400.         return(-2);
  1401.     }
  1402.     return(x);
  1403.     }
  1404.     nfils = -1;                /* Files come from internal list. */
  1405.     strcpy(line,s);            /* Save copy of string just parsed. */
  1406.     if (cx == XXSEN) {            /* SEND command */
  1407.     debug(F101,"Send: wild","",y);
  1408.     if (y == 0) {
  1409.         if ((x = cmtxt("Name to send it with","",&cmarg2,xxstring)) < 0)
  1410.           return(x);
  1411.     } else {
  1412.         if ((x = cmcfm()) < 0) return(x);
  1413.     }
  1414.     cmarg = line;            /* File to send */
  1415.     debug(F110,"Sending:",cmarg,0);
  1416.     if (*cmarg2 != '\0') debug(F110," as:",cmarg2,0);
  1417.     } else {                /* MAIL */
  1418.     debug(F101,"Mail: wild","",y);
  1419.     *optbuf = NUL;            /* Wipe out any old options */
  1420.     if ((x = cmtxt("Address to mail to","",&s,xxstring)) < 0) return(x);
  1421.     strcpy(optbuf,s);
  1422.     if (strlen(optbuf) > 94) {    /* Ensure legal size */
  1423.         printf("?Option string too long\n");
  1424.         return(-2);
  1425.     }
  1426.     cmarg = line;            /* File to send */
  1427.     debug(F110,"Mailing:",cmarg,0);
  1428.     debug(F110,"To:",optbuf,0);
  1429.     rmailf = 1;            /* MAIL modifier flag for SEND */
  1430.     }
  1431.     sstate = 's';            /* Set start state to SEND */
  1432.     if (local) displa = 1;
  1433.     return(0);
  1434.  
  1435. case XXSER:                /* Server */
  1436.     if ((x = cmcfm()) < 0) return(x);
  1437.     sstate = 'x';
  1438.     if (local) displa = 1;
  1439. #ifdef AMIGA
  1440.     reqoff();                /* No DOS requestors while server */
  1441. #endif
  1442.     return(0);
  1443.  
  1444. case XXSET:                /* SET command */
  1445.     x = cmkey(prmtab,nprm,"Parameter","",xxstring);
  1446.     if (x == -3) {
  1447.     printf("?You must specify a parameter to set\n");
  1448.     return(-2);
  1449.     }
  1450.     if (x < 0) return(x);
  1451.     /* have to set success separately for each item in doprm()... */
  1452.     /* actually not really, could have just had doprm return 0 or 1 */
  1453.     /* and set success here... */
  1454.     return(doprm(x,0));
  1455.     
  1456. /* XXSHE code by H. Fischer; copyright rights assigned to Columbia Univ */
  1457. /*
  1458.  Adapted to use getpwuid to find login shell because many systems do not
  1459.  have SHELL in environment, and to use direct calling of shell rather
  1460.  than intermediate system() call. -- H. Fischer
  1461. */
  1462. case XXSHE:                /* Local shell command */
  1463.     {
  1464.     int pid;
  1465. #ifdef AMIGA
  1466.     if (cmtxt("Command to execute","",&s,xxstring) < 0) return(-1);
  1467. #else
  1468. #ifdef OS2
  1469.     if (cmtxt("OS2 command to execute","",&s,xxstring) < 0) return(-1);
  1470. #else
  1471.     if (cmtxt("Unix shell command to execute","",&s,xxstring) < 0) return(-1);
  1472. #endif /* Amiga */
  1473. #endif /* OS2 */
  1474.  
  1475.     conres();                /* Make console normal  */
  1476.  
  1477. #ifdef OS2
  1478.     if (*s == '\0') sprintf(s,"%s","CMD"); /* Command processor */
  1479.     concooked();
  1480.     system(s);
  1481.     conraw();
  1482. #else
  1483. #ifdef OSK
  1484.     system(s);
  1485. #else
  1486. #ifdef AMIGA
  1487.     system(s);
  1488. #else
  1489. #ifdef MSDOS
  1490.     zxcmd(s);
  1491. #else
  1492. #ifdef vms
  1493.     system(s);                /* Best we can do for VMS? */
  1494. #else
  1495. #ifdef datageneral
  1496.     if (*s == NUL)            /* Interactive shell requested? */
  1497. #ifdef mvux
  1498.     system("/bin/sh ");
  1499. #else
  1500.         system("x :cli prefix Kermit_Baby:");
  1501. #endif
  1502.     else                /* Otherwise, */
  1503.         system(s);            /* Best for aos/vs?? */
  1504.  
  1505. #else
  1506. #ifdef aegis
  1507.     if ((pid = vfork()) == 0) {        /* Make child quickly */
  1508.     char *shpath, *shname, *shptr;    /* For finding desired shell */
  1509.  
  1510.         if ((shpath = getenv("SHELL")) == NULL) shpath = "/com/sh";
  1511.  
  1512. #else                    /* All Unix systems */
  1513.     if ((pid = fork()) == 0) {        /* Make child */
  1514.     char *shpath, *shname, *shptr;    /* For finding desired shell */
  1515.     struct passwd *p;
  1516.     extern struct passwd * getpwuid();
  1517.     extern int getuid();
  1518.     char *defShel = "/bin/sh";    /* Default */
  1519.  
  1520.     p = getpwuid( getuid() );    /* Get login data */
  1521.     if ( p == (struct passwd *) NULL || !*(p->pw_shell) )
  1522.         shpath = defShel;
  1523.     else
  1524.         shpath = p->pw_shell;
  1525. #endif
  1526.     shptr = shname = shpath;
  1527.     while (*shptr != '\0')
  1528.         if (*shptr++ == '/') shname = shptr;
  1529.  
  1530. /* Remove following uid calls if they cause trouble */
  1531. #ifdef BSD4
  1532. #ifndef BSD41
  1533.     setegid(getgid());        /* Override 4.3BSD csh security */
  1534.     seteuid(getuid());        /*  checks. */
  1535. #endif
  1536. #endif
  1537.     if (*s == NUL)            /* Interactive shell requested? */
  1538.         execl(shpath,shname,"-i",NULL);    /* Yes, do that */
  1539.     else                /* Otherwise, */
  1540.         execl(shpath,shname,"-c",s,NULL); /* exec the given command */
  1541.     exit(BAD_EXIT); }        /* Just punt if it didn't work */
  1542.  
  1543.     else {                /* Parent */
  1544.  
  1545.         int wstat;            /* Kermit must wait for child */
  1546.     SIGTYP (*istat)(), (*qstat)();
  1547.  
  1548.     istat = signal(SIGINT,SIG_IGN);    /* Let the fork handle keyboard */
  1549.     qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
  1550.  
  1551.         while (((wstat = wait((int *)0)) != pid) && (wstat != -1)) ;
  1552.                                     /* Wait for fork */
  1553.     signal(SIGINT,istat);        /* Restore interrupts */
  1554.     signal(SIGQUIT,qstat);
  1555.     }
  1556. #endif
  1557. #endif
  1558. #endif
  1559. #endif
  1560. #endif
  1561. #endif
  1562.     concb(escape);            /* Console back in cbreak mode */
  1563.     return(success = 1);        /* Just pretend it worked. */
  1564. }
  1565.  
  1566. case XXSHO:                /* Show */
  1567.     x = cmkey(shotab,nsho,"","parameters",xxstring);
  1568.     if (x < 0) return(x);
  1569.     return(success = doshow(x));
  1570.  
  1571. case XXSPA:                /* space */
  1572. #ifdef datageneral
  1573.     /* The DG can take an argument after its "space" command. */
  1574.     if ((x = cmtxt("Confirm, or local directory name","",&s,xxstring)) < 0)
  1575.       return(x);
  1576.     if (*s == NUL) system(SPACMD);
  1577.     else {
  1578.         char *cp;
  1579.         cp = alloc(strlen(s) + 7);      /* For "space *s" */
  1580.         strcpy(cp,"space "), strcat(cp,s);
  1581.         system(cp);
  1582.         if (cp) free(cp);
  1583.     }
  1584. #else
  1585.     if ((x = cmcfm()) < 0) return(x);
  1586. #ifdef OS2
  1587.     concooked();
  1588.     system(SPACMD);
  1589.     conraw();
  1590. #else
  1591.     system(SPACMD);
  1592. #endif
  1593. #endif
  1594.     return(success = 1);        /* pretend it worked */
  1595.  
  1596. case XXSTA:                /* statistics */
  1597.     if ((x = cmcfm()) < 0) return(x);
  1598.     return(success = dostat());
  1599.  
  1600. case XXSTO:                /* stop */
  1601.     if ((x = cmcfm()) < 0) return(x);
  1602.     dostop();    
  1603.     success = 1;            /* always succeeds */
  1604.     return(0);
  1605.  
  1606. case XXTAK:                /* take */
  1607.     if (tlevel > MAXTAKE-1) {
  1608.     printf("?Take files nested too deeply\n");
  1609.     return(-2);
  1610.     }
  1611.     if ((y = cmifi("C-Kermit command file","",&s,&x,xxstring)) < 0) { 
  1612.     if (y == -3) {
  1613.         printf("?A file specification is required\n");
  1614.         return(-2);
  1615.     } else return(y);
  1616.     }
  1617.     if (x != 0) {
  1618.     printf("?Wildcards not allowed in command file name\n");
  1619.     return(-2);
  1620.     }
  1621.     strcpy(line,s);            /* Make a safe copy of the string */
  1622.     if ((y = cmcfm()) < 0) return(y);
  1623.     if ((tfile[++tlevel] = fopen(line,"r")) == NULL) {
  1624.     perror(line);
  1625.     debug(F110,"Failure to open",line,0);
  1626.     success = 0;
  1627.     tlevel--;
  1628.     } else {
  1629.     cmdlvl++;            /* Entering a new command level */
  1630.     if (cmdlvl > CMDSTKL) {
  1631.         cmdlvl--;
  1632.         printf("?TAKE files and DO commands nested too deeply\n");
  1633.         return(success = 0);
  1634.     }
  1635.     ifcmd[cmdlvl] = 0;
  1636.     iftest[cmdlvl] = 0;
  1637.     count[cmdlvl] = 0;
  1638.     cmdstk[cmdlvl].src = CMD_TF;    /* Say we're in a TAKE file */
  1639.     cmdstk[cmdlvl].val = tlevel;    /* nested at this level */
  1640.     success = 1;
  1641.     }
  1642.     return(success);
  1643.  
  1644. case XXTRA:                /* transmit */
  1645.     if ((x = cmifi("File to transmit","",&s,&y,xxstring)) < 0) {
  1646.     if (x == -3) {
  1647.         printf("?Name of an existing file\n");
  1648.         return(-2);
  1649.     }
  1650.     return(x);
  1651.     }
  1652.     if (y != 0) {
  1653.     printf("?Only a single file may be transmitted\n");
  1654.     return(-2);
  1655.     }
  1656.     strcpy(line,s);            /* Save copy of string just parsed. */
  1657.     y = cmnum("Decimal ASCII value of line turnaround character","10",10,&x,
  1658.           xxstring);
  1659.     if (y < 0) return(y);
  1660.     if (x < 0 || x > 127) {
  1661.     printf("?Decimal number between 0 and 127\n");
  1662.     return(-2);
  1663.     }
  1664.     if ((y = cmcfm()) < 0) return(y);    /* Confirm the command */
  1665.     debug(F110,"calling transmit",line,0);
  1666.     return(success = transmit(line,x));    /* Do the command */
  1667.  
  1668. case XXTYP:                /* TYPE */
  1669.     if ((x = cmifi("File to type","",&s,&y,xxstring)) < 0) {
  1670.     if (x == -3) {
  1671.         printf("?Name of an existing file\n");
  1672.         return(-2);
  1673.     }
  1674.     return(x);
  1675.     }
  1676.     if (y != 0) {
  1677.     printf("?A single file please\n");
  1678.     return(-2);
  1679.     }
  1680.     strcpy(line,s);            /* Save copy of string just parsed. */
  1681.     if ((y = cmcfm()) < 0) return(y);    /* Confirm the command */
  1682.     debug(F110,"calling transmit",line,0);
  1683.     return(success = dotype(line));    /* Do the TYPE command */
  1684.  
  1685. case XXTES:                /* TEST */
  1686.     /* Fill this in with whatever is being tested... */
  1687.     if ((y = cmcfm()) < 0) return(y);    /* Confirm the command */
  1688.     printf("cmdlvl = %d, tlevel = %d, maclvl = %d\n",cmdlvl,tlevel,maclvl);
  1689.     if (maclvl < 0) {
  1690.     printf("%s\n",
  1691.            "Call me from inside a macro and I'll dump the argument stack");
  1692.     return(0);
  1693.     }
  1694.     printf("Macro level: %d, ARGC = %d\n     ",maclvl,macargc[maclvl]);
  1695.     for (y = 0; y < 10; y++) printf("%7d",y);
  1696.     for (x = 0; x <= maclvl; x++) {
  1697.     printf("\n%2d:  ",x);
  1698.     for (y = 0; y < 10; y++) {
  1699.         s = m_arg[x][y];
  1700.         printf("%7s",s ? s : "(none)");
  1701.     }
  1702.     }
  1703.     printf("\n");
  1704.     return(0);
  1705.  
  1706. case XXXLA:                /* translate */
  1707.     if ((x = cmifi("File to translate","",&s,&y,xxstring)) < 0) {
  1708.     if (x == -3) {
  1709.         printf("?Name of an existing file\n");
  1710.         return(-2);
  1711.     }
  1712.     return(x);
  1713.     }
  1714.     if (y != 0) {
  1715.     printf("?A single file please\n");
  1716.     return(-2);
  1717.     }
  1718.     strcpy(line,s);            /* Save copy of string just parsed. */
  1719.     if ((x = cmofi("Output file","",&s,&y,xxstring)) < 0) {
  1720.     if (x != -3) return(x);        /* don't ask... */
  1721.     else s = CTTNAM;
  1722.     }
  1723.     if (y != 0) {
  1724.     printf("?A single file please\n");
  1725.     return(-2);
  1726.     }
  1727.     if ((y = cmcfm()) < 0) return(y);    /* Confirm the command */
  1728.     return(success = xlate(line,s));    /* Do the TRANSLATE command */
  1729.  
  1730. case XXVER:
  1731.     if ((y = cmcfm()) < 0) return(y);
  1732.     printf("%s,%s\n Numeric: %d\n",versio,ckxsys,vernum);
  1733.     return(success = 1);
  1734.  
  1735. default:
  1736.     printf("Not available - %s\n",cmdbuf);
  1737.     return(-2);
  1738.     }
  1739. }
  1740.