home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / cku196.zip / ckuus6.c < prev    next >
C/C++ Source or Header  |  2000-01-02  |  230KB  |  8,340 lines

  1. #include "ckcsym.h"
  2. #ifndef NOICP
  3.  
  4. /*  C K U U S 6 --  "User Interface" for Unix Kermit (Part 6)  */
  5.  
  6. /*
  7.   Author: Frank da Cruz (fdc@columbia.edu),
  8.   Columbia University Academic Information Systems, New York City.
  9.  
  10.   Copyright (C) 1985, 2000,
  11.     Trustees of Columbia University in the City of New York.
  12.     All rights reserved.  See the C-Kermit COPYING.TXT file or the
  13.     copyright text in the ckcmai.c module for disclaimer and permissions.
  14. */
  15.  
  16. /* Includes */
  17.  
  18. #include "ckcdeb.h"
  19. #include "ckcasc.h"
  20. #include "ckcker.h"
  21. #include "ckuusr.h"
  22. /* #include "ckcxla.h" */
  23. #include "ckcnet.h"            /* Network symbols */
  24. #include <signal.h>
  25.  
  26. #ifdef VMS
  27. #ifndef TCPSOCKET
  28. #include <errno.h>
  29. #endif /* TCPSOCKET */
  30. #endif /* VMS */
  31.  
  32. #ifdef datageneral
  33. #define fgets(stringbuf,max,fd) dg_fgets(stringbuf,max,fd)
  34. #endif /* datageneral */
  35.  
  36. /* External Kermit Variables, see ckmain.c for description. */
  37.  
  38. extern xx_strp xxstring;
  39.  
  40. extern int local, xitsta, binary, parity, escape, flow, cmd_rows, turn,
  41.   turnch, duplex, ckxech, seslog, dfloc, cnflg, tlevel, pflag, msgflg, mdmtyp,
  42.   zincnt, quiet, repars, techo, network, nzxopts;
  43.  
  44. extern int xaskmore, tt_rows, tt_cols, cmd_cols, g_matchdot;
  45.  
  46. #ifdef CK_IFRO
  47.   extern int remonly;
  48. #endif /* CK_IFRO */
  49.  
  50. #ifdef OS2
  51. extern int StartedFromDialer ;
  52. extern int vmode;
  53. #ifndef NT
  54. #define INCL_NOPM
  55. #define INCL_VIO            /* Needed for ckocon.h */
  56. #include <os2.h>
  57. #undef COMMENT
  58. #else
  59. #define APIRET ULONG
  60. #include <windows.h>
  61. #include <tapi.h>
  62. #include "ckntap.h"
  63. #endif /* NT */
  64. #include "ckocon.h"
  65. #endif /* OS2 */
  66.  
  67. extern long vernum, speed;
  68. extern char *versio, *protv, *ckxv, *ckzv, *fnsv, *connv, *dftty, *cmdv;
  69. extern char *dialv, *loginv, *for_def[], *whil_def[], *xif_def[], *sw_def[];
  70. extern char *ckxsys, *ckzsys;
  71. #ifndef OS2
  72. extern char *DIRCMD;
  73. #ifndef UNIX
  74. extern char *DELCMD;
  75. #endif /* UNIX */
  76. #endif /* OS2 */
  77. extern char ttname[], filnam[];
  78. extern CHAR sstate;
  79. extern char *zinptr;
  80.  
  81. #ifndef NOXFER
  82. extern int oopts, omode, oname, opath;    /* O-Packet options */
  83.  
  84. extern int stdinf, sndsrc, size, rpsiz, urpsiz, fncnv, fnrpath, displa,
  85.   stdouf, isguest, pktlog, nfils, keep, maxrps, fblksiz, frecl, frecfm,
  86.   atcapr, atdiso, spsizf, spsiz, spsizr, spmax, wslotr, prefixing,
  87.   fncact, fnspath, nprotos, g_proto, g_urpsiz, g_spsizf,
  88.   g_spsiz, g_spsizr, g_spmax, g_wslotr, g_prefixing, g_fncact, g_fncnv,
  89.   g_fnspath, g_fnrpath;
  90.  
  91. extern char *cmarg, *cmarg2;
  92.  
  93. #ifndef NOMSEND                /* Multiple SEND */
  94. extern char *msfiles[];
  95. #endif /* NOMSEND */
  96. extern char fspec[];            /* Most recent filespec */
  97. extern int fspeclen;
  98.  
  99. #ifdef CK_TMPDIR
  100. extern int f_tmpdir;            /* Directory changed temporarily */
  101. extern char savdir[];            /* For saving current directory */
  102. extern char * dldir;
  103. #endif /* CK_TMPDIR */
  104.  
  105. extern struct keytab protos[];    /* File transfer protocols */
  106. extern struct ck_p ptab[NPROTOS];
  107. #endif /* NOXFER */
  108. /* Declarations from cmd package */
  109.  
  110. #ifdef DCMDBUF
  111. extern char *cmdbuf, *atmbuf;        /* Command buffers */
  112. #else
  113. extern char cmdbuf[], atmbuf[];        /* Command buffers */
  114. #endif /* DCMDBUF */
  115.  
  116. extern int nopush;
  117.  
  118. #ifndef NOSPL
  119. int askflag = 0;            /* ASK-class command active */
  120. extern char **a_ptr[];
  121. extern int a_dim[];
  122. extern char **m_xarg[];
  123. extern int n_xarg[];
  124. extern struct mtab *mactab;
  125. extern int nmac;
  126. extern long ck_alarm;
  127. extern char alrm_date[], alrm_time[];
  128. extern int x_ifnum;
  129. #endif /* NOSPL */
  130.  
  131. extern int inserver;            /* I am IKSD */
  132. extern int backgrd;            /* Kermit executing in background */
  133. extern char psave[];            /* For saving & restoring prompt */
  134. extern char *tp;            /* Temporary buffer */
  135.  
  136. int saveask = -1;            /* For saving askmore() status */
  137.  
  138. int readblock = 4096;            /* READ buffer size */
  139. CHAR * readbuf = NULL;            /* Pointer to read buffer */
  140. int readsize = 0;            /* Number of chars actually read */
  141. int getcmd = 0;                /* GET-class command was given */
  142.  
  143. extern int zchkod, zchkid;
  144.  
  145. struct keytab deltab[] = {        /* DELETE Command Options */
  146.     "/after",       DEL_AFT,  CM_ARG,
  147.     "/ask",         DEL_ASK,  0,
  148.     "/before",      DEL_BEF,  CM_ARG,
  149.     "/dotfiles",    DEL_DOT,  0,
  150.     "/except",      DEL_EXC,  CM_ARG,
  151.     "/heading",     DEL_HDG,  0,
  152.     "/l",           DEL_LIS,  CM_INV|CM_ABR,
  153.     "/larger-than", DEL_LAR,  CM_ARG,
  154.     "/list",        DEL_LIS,  0,
  155.     "/log",         DEL_LIS,  CM_INV,
  156.     "/noask",       DEL_NAS,  0,
  157.     "/nodotfiles",  DEL_NOD,  0,
  158.     "/noheading",   DEL_NOH,  0,
  159.     "/nol",         DEL_NOL,  CM_INV|CM_ABR,
  160.     "/nolist",      DEL_NOL,  0,
  161.     "/nolog",       DEL_NOL,  CM_INV,
  162. #ifndef CK_TTGWSIZ
  163.     "/nopage",      DEL_NOP,  0,
  164. #endif /* CK_TTGWSIZ */
  165.     "/not-after",   DEL_NAF,  CM_ARG,
  166.     "/not-before",  DEL_NBF,  CM_ARG,
  167.     "/not-since",   DEL_NAF,  CM_INV|CM_ARG,
  168. #ifndef CK_TTGWSIZ
  169.     "/page",        DEL_PAG,  0,
  170. #endif /* CK_TTGWSIZ */
  171.     "/quiet",       DEL_QUI,  CM_INV,
  172.     "/simulate",    DEL_SIM,  0,
  173.     "/since",       DEL_AFT,  CM_ARG|CM_INV,
  174.     "/smaller-than",DEL_SMA,  CM_ARG,
  175.     "/verbose",     DEL_VRB,  CM_INV
  176. };
  177. int ndeltab = sizeof(deltab)/sizeof(struct keytab);
  178.  
  179. /* /QUIET-/VERBOSE (/LIST-/NOLIST) (/LOG-/NOLOG) table */
  180.  
  181. struct keytab qvswtab[] = {
  182.     "/l",           DEL_LIS,  CM_INV|CM_ABR,
  183.     "/list",        DEL_LIS,  0,
  184.     "/log",         DEL_LIS,  CM_INV,
  185.     "/nol",         DEL_NOL,  CM_INV|CM_ABR,
  186.     "/nolist",      DEL_NOL,  0,
  187.     "/nolog",       DEL_NOL,  CM_INV,
  188.     "/quiet",       DEL_QUI,  CM_INV,
  189.     "/verbose",     DEL_VRB,  CM_INV
  190. };
  191. int nqvswtab = sizeof(qvswtab)/sizeof(struct keytab);
  192.  
  193. struct keytab copytab[] = {
  194.     "/append",      998,      0,
  195. #ifndef NOSPL
  196.     "/fromb64",     997,      0,
  197. #endif /* NOSPL */
  198.     "/l",           DEL_LIS,  CM_INV|CM_ABR,
  199.     "/list",        DEL_LIS,  0,
  200.     "/log",         DEL_LIS,  CM_INV,
  201.     "/nol",         DEL_NOL,  CM_INV|CM_ABR,
  202.     "/nolist",      DEL_NOL,  0,
  203.     "/nolog",       DEL_NOL,  CM_INV,
  204.     "/quiet",       DEL_QUI,  CM_INV,
  205.     "/swap-bytes",  999,      0,
  206. #ifndef NOSPL
  207.     "/tob64",       996,      0,
  208. #endif /* NOSPL */
  209.     "/verbose",     DEL_VRB,  CM_INV
  210. };
  211. int ncopytab = sizeof(copytab)/sizeof(struct keytab);
  212.  
  213. #ifndef NOXFER
  214. static struct keytab gettab[] = {    /* GET options */
  215.     "/as-name",         SND_ASN, CM_ARG,
  216.     "/binary",          SND_BIN, 0,
  217. #ifdef CALIBRATE
  218.     "/calibrate",       SND_CAL, CM_INV,
  219. #endif /* CALIBRATE */
  220. #ifdef PIPESEND
  221.     "/command",         SND_CMD, 0,
  222. #endif /* PIPESEND */
  223.     "/delete",          SND_DEL, 0,
  224.     "/except",          SND_EXC, CM_ARG,
  225.     "/filenames",       SND_NAM, CM_ARG,
  226. #ifdef PIPESEND
  227.     "/filter",          SND_FLT, CM_ARG,
  228. #endif /* PIPESEND */
  229. #ifdef VMS
  230.     "/image",           SND_IMG, 0,
  231.     "/labeled",         SND_LBL, 0,
  232. #else
  233.     "/image",           SND_BIN, CM_INV,
  234. #endif /* VMS */
  235. #ifdef CK_TMPDIR
  236.     "/move-to",         SND_MOV, CM_ARG,
  237. #endif /* CK_TMPDIR */
  238.     "/pathnames",       SND_PTH, CM_ARG,
  239.     "/quiet",           SND_SHH, 0,
  240. #ifdef CK_RESEND
  241.     "/recover",         SND_RES, 0,
  242. #endif /* CK_RESEND */
  243.     "/recursive",       SND_REC, 0,
  244.     "/rename-to",       SND_REN, CM_ARG,
  245. #ifdef COMMENT
  246.     "/smaller-than",    SND_SMA, CM_ARG,
  247.     "/subdirectories",  SND_REC, CM_INV,
  248. #endif /* COMMENT */
  249.     "/text",            SND_TXT, 0
  250. };
  251. #define NGETTAB sizeof(gettab)/sizeof(struct keytab)
  252. static int ngettab = NGETTAB;
  253.  
  254. static struct keytab rcvtab[] = {    /* RECEIVE options */
  255.     "/as-name",         SND_ASN, CM_ARG,
  256.     "/binary",          SND_BIN, 0,
  257. #ifdef CALIBRATE
  258.     "/calibrate",       SND_CAL, CM_INV,
  259. #endif /* CALIBRATE */
  260. #ifdef PIPESEND
  261.     "/command",         SND_CMD, 0,
  262. #endif /* PIPESEND */
  263.     "/except",          SND_EXC, CM_ARG,
  264.     "/filenames",       SND_NAM, CM_ARG,
  265. #ifdef PIPESEND
  266.     "/filter",          SND_FLT, CM_ARG,
  267. #endif /* PIPESEND */
  268. #ifdef VMS
  269.     "/image",           SND_IMG, 0,
  270.     "/labeled",         SND_LBL, 0,
  271. #else
  272.     "/image",           SND_BIN, CM_INV,
  273. #endif /* VMS */
  274. #ifdef CK_TMPDIR
  275.     "/move-to",         SND_MOV, CM_ARG,
  276. #endif /* CK_TMPDIR */
  277.     "/pathnames",       SND_PTH, CM_ARG,
  278. #ifdef CK_XYZ
  279.     "/protocol",        SND_PRO, CM_ARG,
  280. #else
  281.     "/protocol",        SND_PRO, CM_ARG|CM_INV,
  282. #endif /* CK_XYZ */
  283.     "/quiet",           SND_SHH, 0,
  284.     "/recursive",       SND_REC, 0,
  285.     "/rename-to",       SND_REN, CM_ARG,
  286.     "/text",            SND_TXT, 0
  287. };
  288. #define NRCVTAB sizeof(rcvtab)/sizeof(struct keytab)
  289. static int nrcvtab = NRCVTAB;
  290. #endif /* NOXFER */
  291.  
  292. /* WAIT table */
  293.  
  294. #define WAIT_FIL 997
  295. #define WAIT_MDM 998
  296.  
  297. struct keytab waittab[] = {
  298.     "cd",            BM_DCD,   CM_INV,    /* (Carrier Detect) */
  299.     "cts",           BM_CTS,   CM_INV,    /* (Clear To Send)  */
  300.     "dsr",           BM_DSR,   CM_INV,    /* (Data Set Ready) */
  301.     "file",          WAIT_FIL, 0,    /* New category selector keywords */
  302.     "modem-signals", WAIT_MDM, 0,    /* ... */
  303.     "ri",            BM_RNG,   CM_INV    /* (Ring Indicator) */
  304. };
  305. int nwaittab = (sizeof(waittab) / sizeof(struct keytab));
  306.  
  307. /* Modem signal table */
  308.  
  309. struct keytab mstab[] = {
  310. #ifdef COMMENT
  311. /* The forms preceded by backslash are for MS-DOS Kermit compatibility. */
  312. /* But... \dsr doesn't work because \d = decimal constant introducer. */
  313. /* Anyway MS-DOS Kermit 3.14 and later accept the keywords without the */
  314. /* backslash. */
  315.     "\\cd",  BM_DCD, CM_INV,        /* Carrier Detect */
  316.     "\\cts", BM_CTS, CM_INV,        /* Clear To Send  */
  317.     "\\dsr", BM_DSR, CM_INV,        /* Data Set Ready */
  318.     "\\ri",  BM_RNG, CM_INV,        /* Ring Indicator */
  319. #endif /* COMMENT */
  320.     "cd",    BM_DCD, 0,            /* Carrier Detect */
  321.     "cts",   BM_CTS, 0,            /* Clear To Send  */
  322.     "dsr",   BM_DSR, 0,            /* Data Set Ready */
  323.     "ri",    BM_RNG, 0            /* Ring Indicator */
  324. };
  325. int nms = (sizeof(mstab) / sizeof(struct keytab));
  326.  
  327. #define WF_MOD 1
  328. #define WF_DEL 2
  329. #define WF_CRE 3
  330.  
  331. struct keytab wfswi[] = {        /* WAIT FILE switches */
  332.     "creation",     WF_CRE, 0,        /* Wait for file to be created */
  333.     "deletion",     WF_DEL, 0,        /* Wait for file to be deleted */
  334.     "modification", WF_MOD, 0        /* Wait for file to be modified */
  335. };
  336. int nwfswi = (sizeof(wfswi) / sizeof(struct keytab));
  337.  
  338. #ifndef NOSPL
  339. struct keytab asgtab[] = {        /* Assignment operators for "." */
  340.     "=",   0, 0,            /* DEFINE */
  341.     ":=",  1, 0,            /* ASSIGN */
  342.     "::=", 2, 0                /* ASSIGN and EVALUATE */
  343. };
  344. int nasgtab = (sizeof(asgtab) / sizeof(struct keytab));
  345.  
  346. struct keytab opntab[] = {
  347. #ifndef NOPUSH
  348.     "!read",  OPN_PI_R, CM_INV,
  349.     "!write", OPN_PI_W, CM_INV,
  350. #endif /* NOPUSH */
  351.     "append", OPN_FI_A, 0,
  352.     "host",   OPN_NET,  0,
  353. #ifdef OS2
  354.     "line",   OPN_SER,  CM_INV,
  355.     "port",   OPN_SER,  0,
  356. #else
  357.     "line",   OPN_SER,  0,
  358.     "port",   OPN_SER,  CM_INV,
  359. #endif /* OS2 */
  360.     "read",   OPN_FI_R, 0,
  361.     "write",  OPN_FI_W, 0
  362. };
  363. int nopn = (sizeof(opntab) / sizeof(struct keytab));
  364.  
  365. struct keytab iftab[] = {        /* IF commands */
  366.     "!",          XXIFNO, 0,
  367.     "!=",         XXIFNQ, 0,
  368.     "&&",         XXIFAN, 0,
  369.     "(",          XXIFLP, 0,
  370.     ")",          XXIFRP, 0,
  371.     "<",          XXIFLT, 0,
  372.     "<=",         XXIFLE, 0,
  373.     "=",          XXIFAE, 0,
  374.     "==",         XXIFAE, CM_INV,
  375.     ">",          XXIFGT, 0,
  376.     ">=",         XXIFGE, 0,
  377.     "||",         XXIFOR, 0,
  378.     "and",        XXIFAN, 0,
  379.     "asktimeout", XXIFAT, 0,
  380.     "absolute",   XXIFAB, 0,
  381.     "alarm",      XXIFAL, 0,
  382.     "available",  XXIFAV, 0,
  383.     "background", XXIFBG, 0,
  384.     "c-kermit",   XXIFCK, 0,
  385.     "command",    XXIFCM, 0,
  386.     "count",      XXIFCO, 0,
  387.     "defined",    XXIFDE, 0,
  388. #ifdef CK_TMPDIR
  389.     "directory",  XXIFDI, 0,
  390. #endif /* CK_TMPDIR */
  391.     "emulation",  XXIFEM, 0,
  392. #ifdef COMMENT
  393.     "eof",        XXIFEO, 0,
  394. #endif /* COMMENT */
  395.     "equal",      XXIFEQ, 0,
  396.     "error",      XXIFFA, CM_INV,
  397.     "exist",      XXIFEX, 0,
  398.     "failure",    XXIFFA, 0,
  399.     "false",      XXIFNT, 0,
  400.     "flag",       XXIFFL, 0,
  401. #ifdef CKFLOAT
  402.     "float",      XXIFFP, 0,
  403. #endif /* CKFLOAT */
  404.     "foreground", XXIFFG, 0,
  405. #ifdef IKSD
  406.     "iksd",       XXIFIK, 0,
  407. #else
  408.     "iksd",       XXIFIK, CM_INV,
  409. #endif /* IKSD */
  410.     "k-95",       XXIFK9, 0,
  411.     "lgt",        XXIFLG, 0,
  412.     "llt",        XXIFLL, 0,
  413.     "local",      XXIFLO, 0,
  414.     "match",      XXIFMA, 0,
  415.     "ms-kermit",  XXIFMS, CM_INV,
  416. #ifdef ZFCDAT
  417.     "newer",      XXIFNE, 0,
  418. #endif /* ZFCDAT */
  419.     "not",        XXIFNO, 0,
  420.     "numeric",    XXIFNU, 0,
  421.     "ok",         XXIFSU, CM_INV,
  422.     "open",       XXIFOP, 0,
  423.     "or",         XXIFOR, 0,
  424.     "quiet",      XXIFQU, 0,
  425.     "readable",   XXIFRD, 0,
  426.     "remote-only",XXIFRO, 0,
  427.     "started-from-dialer",XXIFSD, CM_INV,
  428.     "success",    XXIFSU, 0,
  429.     "tapi",       XXIFTA, 0,
  430. #ifdef OS2
  431.     "terminal-macro", XXIFTM, CM_INV,
  432. #endif /* OS2 */
  433.     "true",       XXIFTR, 0,
  434.     "wild",       XXIFWI, 0,
  435.     "writeable",  XXIFWR, 0,
  436.     "", 0, 0
  437. };
  438. int nif = (sizeof(iftab) / sizeof(struct keytab)) - 1;
  439.  
  440. struct keytab iotab[] = {        /* Keywords for IF OPEN */
  441.     "!read-file",      ZRFILE, CM_INV,
  442.     "!write-file",     ZWFILE, CM_INV,
  443.     "append-file",     ZWFILE, CM_INV,
  444.     "connection",      8888,   0,
  445. #ifdef CKLOGDIAL
  446.     "cx-log",          7777,   0,
  447. #endif /* CKLOGDIAL */
  448.     "debug-log",       ZDFILE, 0,
  449.     "error",           9999,   0,
  450.     "packet-log",      ZPFILE, 0,
  451.     "read-file",       ZRFILE, 0,
  452.     "screen",          ZSTDIO, 0,
  453.     "session-log",     ZSFILE, 0,
  454.     "transaction-log", ZTFILE, 0,
  455.     "write-file",      ZWFILE, 0
  456. };
  457. int niot = (sizeof(iotab) / sizeof(struct keytab));
  458. #endif /* NOSPL */
  459.  
  460. /* Variables and prototypes */
  461.  
  462. #ifdef NETCONN
  463. extern int nnetdir;            /* How many network directories */
  464. #endif /* NETCONN */
  465. #ifdef CK_AUTHENTICATION
  466. _PROTOTYP(int ck_krb4_is_installed,(void));
  467. _PROTOTYP(int ck_krb5_is_installed,(void));
  468. _PROTOTYP(int ck_ntlm_is_installed,(void));
  469. _PROTOTYP(int ck_srp_is_installed,(void));
  470. _PROTOTYP(int ck_ssleay_is_installed,(void));
  471. _PROTOTYP(int ck_crypt_is_installed,(void));
  472. #else
  473. #define ck_krb4_is_installed() (0)
  474. #define ck_krb5_is_installed() (0)
  475. #define ck_ntlm_is_installed() (0)
  476. #define ck_srp_is_installed() (0)
  477. #define ck_ssleay_is_installed() (0)
  478. #define ck_crypt_is_installed() (0)
  479. #endif /* CK_AUTHENTICATION */
  480.  
  481. #define AV_KRB4   1
  482. #define AV_KRB5   2
  483. #define AV_NTLM   3
  484. #define AV_SRP    4
  485. #define AV_SSL    5
  486. #define AV_CRYPTO 6
  487.  
  488. struct keytab availtab[] = {        /* Available authentication types */
  489.     "crypto",     AV_CRYPTO, CM_INV,    /* and encryption */
  490.     "encryption", AV_CRYPTO, 0,
  491.     "k4",         AV_KRB4,   CM_INV,
  492.     "k5",         AV_KRB5,   CM_INV,
  493.     "kerberos4",  AV_KRB4,   0,
  494.     "kerberos5",  AV_KRB5,   0,
  495.     "krb4",       AV_KRB4,   CM_INV,
  496.     "krb5",       AV_KRB5,   CM_INV,
  497.     "ntlm",       AV_NTLM,   0,
  498.     "srp",        AV_SRP,    0,
  499.     "ssl",        AV_SSL,    0,
  500.     "tls",        AV_SSL,    0,
  501.     "",           0,         0
  502. };
  503. int availtabn = sizeof(availtab)/sizeof(struct keytab)-1;
  504.  
  505. #ifndef NODIAL
  506. _PROTOTYP(static int ddcvt, (char *, FILE *, int) );
  507. _PROTOTYP(static int dncvt, (int, int, int, int) );
  508. _PROTOTYP(char * getdname, (void) );
  509.  
  510. static int partial  = 0;        /* For partial dial */
  511. static char *dscopy = NULL;
  512. int dialtype = -1;
  513.  
  514. char *dialnum = (char *)0;        /* Remember DIAL number for REDIAL */
  515. int dirline = 0;            /* Dial directory line number */
  516. extern char * dialdir[];        /* Dial directory file names */
  517. extern int dialdpy;            /* DIAL DISPLAY on/off */
  518. extern int ndialdir;            /* How many dial directories */
  519. extern int ntollfree;            /* Toll-free call info */
  520. extern int ndialpxx;            /* List of PBX exchanges */
  521. extern char *dialtfc[];
  522. char * matchpxx = NULL;            /* PBX exchange that matched */
  523. extern int nlocalac;            /* Local area-code list */
  524. extern char * diallcac[];
  525. extern int tttapi;
  526. #ifdef CK_TAPI
  527. extern int tapiconv;            /* TAPI Conversions */
  528. extern int tapipass;            /* TAPI Passthrough */
  529. #endif /* CK_TAPI */
  530. extern int dialatmo;
  531. extern char * dialnpr, * dialsfx;
  532. extern char * dialixp, * dialixs, * dialmac;
  533. extern char * dialldp, * diallds, * dialtfp;
  534. extern char * dialpxi, * dialpxo, * diallac;
  535. extern char * diallcp, * diallcs, * diallcc;
  536. extern char * dialpxx[];
  537.  
  538. extern int dialcnf;            /* DIAL CONFIRMATION */
  539. int dialfld = 0;            /* DIAL FORCE-LONG-DISTANCE */
  540. int dialsrt = 1;            /* DIAL SORT ON */
  541. int dialrstr = 6;            /* DIAL RESTRICTION */
  542. int dialtest = 0;            /* DIAL TEST */
  543. int dialcount = 0;            /* \v(dialcount) */
  544.  
  545. extern int dialsta;            /* Dial status */
  546. int dialrtr = -1,            /* Dial retries */
  547.     dialint = 10;            /* Dial retry interval */
  548. extern long dialcapas;            /* Modem capabilities */
  549. extern int dialcvt;            /* DIAL CONVERT-DIRECTORY */
  550. #endif /* NODIAL */
  551.  
  552. #ifndef NOSPL
  553. int ifc,                /* IF case */
  554.     not = 0,                /* Flag for IF NOT */
  555.     ifargs = 0;                /* Count of IF condition words */
  556. char ifcond[100];            /* IF condition text */
  557. char *ifcp;                /* Pointer to IF condition text */
  558. #ifdef DCMDBUF
  559. extern int
  560.  *ifcmd,  *count,  *iftest, *intime,
  561.  *inpcas, *takerr, *merror, *xquiet;
  562. #else
  563. extern int ifcmd[];            /* Last command was IF */
  564. extern int iftest[];            /* Last IF was true */
  565. extern int count[];            /* For IF COUNT, one for each cmdlvl */
  566. extern int intime[];            /* Ditto for other stackables... */
  567. extern int inpcas[];
  568. extern int takerr[];
  569. extern int merror[];
  570. extern int xquiet[];
  571. #endif /* DCMDBUF */
  572. #else
  573. extern int takerr[];
  574. #endif /* NOSPL */
  575.  
  576. #ifdef DCMDBUF
  577. extern char *line;            /* Character buffer for anything */
  578. extern char *tmpbuf;
  579. #else
  580. extern char line[], tmpbuf[];
  581. #endif /* DCMDBUF */
  582. extern char *lp;            /* Pointer to line buffer */
  583.  
  584. int cwdf = 0;                /* CWD has been done */
  585.  
  586. /* Flags for ENABLE/DISABLE */
  587. extern int en_cwd, en_cpy, en_del, en_dir, en_fin,
  588.    en_get, en_hos, en_ren, en_sen, en_set, en_spa, en_typ, en_who, en_bye,
  589.    en_asg, en_que, en_ret, en_mai, en_pri, en_mkd, en_rmd, en_xit, en_ena;
  590.  
  591. extern FILE *tfile[];            /* File pointers for TAKE command */
  592. extern char *tfnam[];            /* Names of TAKE files */
  593. extern int tfline[];            /* TAKE-file line number */
  594.  
  595. extern int success;            /* Command success/failure flag */
  596. extern int cmdlvl;            /* Current position in command stack */
  597.  
  598. #ifndef NOSPL
  599. extern int maclvl;            /* Macro to execute */
  600. extern char *macx[];            /* Index of current macro */
  601. extern char *mrval[];            /* Macro return value */
  602. extern char *macp[];            /* Pointer to macro */
  603. extern int macargc[];            /* ARGC from macro invocation */
  604.  
  605. extern char *m_line[];
  606. extern char *m_arg[MACLEVEL][NARGS];    /* Stack of macro arguments */
  607. extern char *g_var[];            /* Global variables %a, %b, etc */
  608.  
  609. #ifdef DCMDBUF
  610. extern struct cmdptr *cmdstk;        /* The command stack itself */
  611. #else
  612. extern struct cmdptr cmdstk[];        /* The command stack itself */
  613. #endif /* DCMDBUF */
  614. #endif /* NOSPL */
  615.  
  616. #define xsystem(s) zsyscmd(s)
  617.  
  618. static int x, y, z = 0;
  619. static char *s, *p;
  620.  
  621. #ifdef OS2
  622. _PROTOTYP( int os2settitle, (char *, int) );
  623. #endif /* OS2 */
  624.  
  625. extern struct keytab yesno[], onoff[], fntab[];
  626. extern int nyesno, nfntab;
  627.  
  628. #ifndef NOSPL
  629.  
  630. /* Do the ASK, ASKQ, GETOK, and READ commands */
  631.  
  632. int asktimedout = 0;
  633.  
  634. #ifdef OS2
  635. static struct keytab asktab[] = {
  636.     "/popup", 1, 0
  637. };
  638. static int nasktab = 1;
  639. #endif /* OS2 */
  640.  
  641. int
  642. doask(cx) int cx; {
  643.     extern int cmflgs, asktimer, timelimit;
  644. #ifdef CK_RECALL
  645.     int sv_recall;
  646.     extern int on_recall;
  647. #endif /* CK_RECALL */
  648. #ifdef OS2
  649.     int popupflg = 0;
  650. #endif /* OS2 */
  651.  
  652.     char vnambuf[VNAML+1];        /* Buffer for variable names */
  653.     char *vnp = NULL;            /* Pointer to same */
  654. #ifdef OS2
  655.     if (cx == XXASK || cx == XXASKQ) {
  656.     struct FDB sw, fl;
  657.     int getval;
  658.     char c;
  659.     cmfdbi(&sw,            /* First FDB - command switches */
  660.            _CMKEY,            /* fcode */
  661.            "Variable name or switch",
  662.            "",            /* default */
  663.            "",            /* addtl string data */
  664.            nasktab,            /* addtl numeric data 1: tbl size */
  665.            4,            /* addtl numeric data 2: 4 = cmswi */
  666.            xxstring,        /* Processing function */
  667.            asktab,            /* Keyword table */
  668.            &fl            /* Pointer to next FDB */
  669.            );
  670.     cmfdbi(&fl,            /* Anything that doesn't match */
  671.            _CMFLD,            /* fcode */
  672.            "",            /* hlpmsg */
  673.            "",            /* default */
  674.            "",            /* addtl string data */
  675.            0,            /* addtl numeric data 1 */
  676.            0,            /* addtl numeric data 2 */
  677.            NULL,
  678.            NULL,
  679.            NULL
  680.            );
  681.     while (1) {            /* Parse 0 or more switches */
  682.         x = cmfdb(&sw);        /* Parse something */
  683.         if (x < 0)
  684.           return(x);
  685.         if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
  686.           break;
  687.         c = cmgbrk();
  688.         if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
  689.         printf("?This switch does not take an argument\n");
  690.         return(-9);
  691.         }
  692.         if (!getval && (cmgkwflgs() & CM_ARG)) {
  693.         printf("?This switch requires an argument\n");
  694.         return(-9);
  695.         }
  696.         switch (cmresult.nresult) {
  697.           case 1: popupflg = 1; break;
  698.           default: return(-2);
  699.         }
  700.     }
  701.     /* Have variable name, make copy. */
  702.     ckstrncpy(vnambuf,cmresult.sresult,VNAML);
  703.     vnp = vnambuf;
  704.     if (vnambuf[0] == CMDQ &&
  705.         (vnambuf[1] == '%' || vnambuf[1] == '&'))
  706.       vnp++;
  707.     y = 0;
  708.     if (*vnp == '%' || *vnp == '&') {
  709.         if ((y = parsevar(vnp,&x,&z)) < 0)
  710.           return(y);
  711.     }
  712.     } else
  713. #endif /* OS2 */
  714.     if (cx != XXGOK && cx != XXRDBL) {    /* Get variable name */
  715.     if ((y = cmfld("Variable name","",&s,NULL)) < 0) {
  716.         if (y == -3) {
  717.         printf("?Variable name required\n");
  718.         return(-9);
  719.         } else return(y);
  720.     }
  721.     ckstrncpy(vnambuf,s,VNAML);    /* Make a copy. */
  722.     vnp = vnambuf;
  723.     if (vnambuf[0] == CMDQ &&
  724.         (vnambuf[1] == '%' || vnambuf[1] == '&'))
  725.       vnp++;
  726.     y = 0;
  727.     if (*vnp == '%' || *vnp == '&') {
  728.         if ((y = parsevar(vnp,&x,&z)) < 0)
  729.           return(y);
  730.     }
  731.     }
  732.     if (cx == XXREA || cx == XXRDBL) {    /* READ or READBLOCK command */
  733.     if ((y = cmcfm()) < 0)        /* Get confirmation */
  734.       return(y);
  735.     if (chkfn(ZRFILE) < 1) {    /* File open? */
  736.         printf("?Read file not open\n");
  737.         return(success = 0);
  738.     }
  739.     if (!(s = (char *)readbuf)) {        /* Where to read into. */
  740.         printf("?Oops, no READ buffer!\n");
  741.         return(success = 0);
  742.     }
  743.     y = zsinl(ZRFILE, s, readblock); /* Read a line. */
  744.     debug(F111,"read zsinl",s,y);
  745.     if (y < 0) {            /* On EOF or other error, */
  746.         zclose(ZRFILE);        /* close the file, */
  747.         delmac(vnp);        /* delete the variable, */
  748.         return(success = 0);    /* and return failure. */
  749.     } else {            /* Read was OK. */
  750.         readsize = (int) strlen(s);
  751.         success = (addmac(vnp,s) < 0 ? 0 : 1); /* Define variable */
  752.         debug(F111,"read addmac",vnp,success);
  753.         return(success);        /* Return success. */
  754.     }
  755.     }
  756.  
  757.     /* ASK, ASKQ, GETOK, or GETC */
  758.  
  759.     if ((y = cmtxt("Prompt, enclose in { braces } to preserve\n\
  760. leading and trailing spaces, precede question mark with backslash (\\).",
  761.            "",&p,xxstring)) < 0) {
  762.     return(y);
  763.     }
  764.     if (!p) p = "";
  765. #ifdef OS2
  766.     if (popupflg) {            /* Popup requested */
  767.     ckstrncpy(tmpbuf,brstrip(p),TMPBUFSIZ);
  768.     p = tmpbuf;
  769.     if (cx == XXASK || cx == XXASKQ) {
  770.         int rc;
  771.         if (cx == XXASK)
  772.           rc = popup_readtext(vmode,p,line,LINBUFSIZ,asktimer);
  773.         else
  774.           rc = popup_readpass(vmode,p,line,LINBUFSIZ,asktimer);
  775.             asktimedout = ( rc == -1 && asktimer );
  776.     }
  777.     y = addmac(vnp,(char *)line);    /* Add it to the macro table. */
  778.     timelimit = 0;
  779.     return(success = y < 0 ? 0 : 1);
  780.     }
  781. #endif /* OS2 */
  782.  
  783.     concb((char)escape);        /* Enter CBREAK mode */
  784.     cmsavp(psave,PROMPTL);        /* Save old prompt */
  785.     cmsetp(brstrip(p));            /* Make new prompt */
  786. reprompt:
  787.     if (cx == XXASKQ) {            /* For ASKQ, */
  788.     cmini(0);            /* no-echo mode. */
  789.     } else {                /* For others, regular echoing. */
  790.     cmini(ckxech);
  791.     }
  792.     askflag = 1;
  793.     x = -1;                /* This means to reparse. */
  794.     cmflgs = 0;
  795.     if (pflag)
  796.       prompt(xxstring);            /* Issue prompt. */
  797.  
  798.     asktimedout = 0;            /* Handle timed responses. */
  799.     if (asktimer > 0)
  800.       timelimit = asktimer;
  801. reparse:
  802.     cmres();
  803.     if (cx == XXGOK) {            /* GETOK */
  804. #ifdef CK_RECALL
  805.     sv_recall = on_recall;
  806.     on_recall = 0;
  807. #endif /* CK_RECALL */
  808.     x = cmkey(yesno,nyesno,"","",xxstring);    /* GETOK uses keyword table */
  809.     if (x < 0) {            /* Parse error */
  810.         if (x == -10) {
  811.         x = 0;
  812.         printf("?Timed out, assuming \"No\"\n");
  813.         asktimedout = 1;
  814.         goto gokdone;
  815.         } else if (x == -3) {    /* No answer? */
  816.         printf("Please respond Yes or No\n"); /* Make them answer */
  817.         cmini(ckxech);
  818.         goto reprompt;
  819.         } else if (x == -1) {
  820.         goto reparse;
  821.         } else
  822.           goto reprompt;
  823.     }
  824.     if (cmcfm() < 0)        /* Get confirmation */
  825.       goto reparse;
  826.   gokdone:
  827.     askflag = 0;
  828.     cmsetp(psave);            /* Restore prompt */
  829. #ifdef VMS
  830.     if (cmdlvl > 0)            /* In VMS and not at top level, */
  831.       conres();            /*  restore console again. */
  832. #endif /* VMS */
  833. #ifdef CK_RECALL
  834.     on_recall = sv_recall;
  835. #endif /* CK_RECALL */
  836.     timelimit = 0;
  837.     return(x);            /* Return success or failure */
  838.     } else if (cx == XXGETC        /* GETC */
  839. #ifdef OS2
  840.            || cx == XXGETK        /* or GETKEYCODE */
  841. #endif /* OS2 */
  842.            ) { /* GETC */
  843.     char tmp[16];
  844.     conbin((char)escape);        /* Put keyboard in raw mode */
  845. #ifdef OS2
  846.     if (cx == XXGETK) {        /* GETKEYCODE */
  847.         extern int os2gks;
  848.         int t;
  849.         t = os2gks;            /* Turn off kverb recognition */
  850.         os2gks = 0;
  851.         x = congks(timelimit);    /* Read a key event, blocking */
  852.         os2gks = t;            /* Put back kverb recognition */
  853.     } else                 /* GETC */
  854. #endif /* OS2 */
  855.       x = coninc(timelimit);    /* Just read one character */
  856.     concb((char)escape);        /* Put keyboard back in cbreak mode */
  857.     if (x > -1) {
  858.         if (cmdsrc() == 0)
  859.           printf("\r\n");
  860. #ifdef OS2
  861.         if (cx == XXGETK) {        /* GETKEYCODE */
  862.         sprintf(tmp,"%d",x);
  863.         } else {
  864. #endif /* OS2 */
  865.         tmp[0] = (char) (x & 0xff);
  866.         tmp[1] = NUL;
  867. #ifdef OS2
  868.         }
  869. #endif /* OS2 */
  870.         y = addmac(vnp,tmp);    /* Add it to the macro table. */
  871.         debug(F111,"getc/getk addmac",vnp,y);
  872.     } else y = -1;
  873.     cmsetp(psave);            /* Restore old prompt. */
  874.     if (x < -1) {
  875.         asktimedout = 1;
  876.         if (!quiet)
  877.           printf("?Timed out\n");
  878.     }
  879.     timelimit = 0;
  880.     return(success = y < 0 ? 0 : 1);
  881.     } else {                /* ASK or ASKQ */
  882. #ifdef CK_RECALL
  883.     sv_recall = on_recall;
  884.     on_recall = 0;
  885. #endif /* CK_RECALL */
  886.     y = cmdgquo();            /* Get current quoting */
  887.     cmdsquo(0);            /* Turn off quoting */
  888.     while (x == -1) {        /* Prompt till they answer */
  889.         x = cmtxt("Please respond.","",&s,NULL);
  890.         debug(F111,"ASK cmtxt",s,x);
  891.         cmres();
  892.     }
  893.     cmdsquo(y);            /* Restore previous quoting */
  894. #ifdef CK_RECALL
  895.     on_recall = sv_recall;
  896. #endif /* CK_RECALL */
  897.     if (cx == XXASKQ)        /* ASKQ must echo CRLF here */
  898.       printf("\r\n");
  899.     if (x < 0) {            /* If cmtxt parse error, */
  900.         cmsetp(psave);        /* restore original prompt */
  901. #ifdef VMS
  902.         if (cmdlvl > 0)        /* In VMS and not at top level, */
  903.           conres();            /*  restore console again. */
  904. #endif /* VMS */
  905.         if (x == -10) {
  906.         printf("?Timed out\n");
  907.         asktimedout = 1;
  908.         x = -9;
  909.         }
  910.         timelimit = 0;
  911.         return(x);            /* and return cmtxt's error code. */
  912.     }
  913.     if (*s == NUL) {        /* If user typed a bare CR, */
  914.         cmsetp(psave);        /* Restore old prompt, */
  915.         delmac(vnp);        /* delete variable if it exists, */
  916. #ifdef VMS
  917.         if (cmdlvl > 0)        /* In VMS and not at top level, */
  918.           conres();            /*  restore console again. */
  919. #endif /* VMS */
  920.         timelimit = 0;
  921.         return(success = 1);    /* and return. */
  922.     }
  923.     y = addmac(vnp,s);        /* Add it to the macro table. */
  924.     debug(F111,"ask addmac",vnp,y);
  925.     cmsetp(psave);            /* Restore old prompt. */
  926. #ifdef VMS
  927.     if (cmdlvl > 0)            /* In VMS and not at top level, */
  928.       conres();            /*  restore console again. */
  929. #endif /* VMS */
  930.     timelimit = 0;
  931.     return(success = y < 0 ? 0 : 1);
  932.     }
  933. }
  934. #endif /* NOSPL */
  935.  
  936. #ifndef NOSPL
  937. int
  938. doincr(cx) int cx; {            /* INCREMENT, DECREMENT */
  939.     char vnambuf[VNAML+1];        /* Buffer for variable names */
  940.     int eval = 0;
  941.     eval = (cx == XX_DECR || cx == XX_INCR);
  942.  
  943.     if ((y = cmfld("Variable name","",&s, eval ? xxstring : NULL)) < 0) {
  944.     if (y == -3) {
  945.         printf("?Variable name required\n");
  946.         return(-9);
  947.     } else return(y);
  948.     }
  949.     ckstrncpy(vnambuf,s,VNAML);
  950.     if ((y = cmnum("by amount","1",10,&x,xxstring)) < 0)
  951.       return(y);
  952.     if ((y = cmcfm()) < 0)
  953.       return(y);
  954.  
  955.     z = (cx == XX_INCR || cx == XXINC) ? 1 : 0;    /* Increment or decrement? */
  956.  
  957.     if (incvar(vnambuf,x,z) < 0) {
  958.     printf("?Variable %s not defined or not numeric\n",vnambuf);
  959.     return(success = 0);
  960.     }
  961.     return(success = 1);
  962. }
  963. #endif /* NOSPL */
  964.  
  965.  
  966. /* Do the (_)DEFINE, (_)ASSIGN, and UNDEFINE commands */
  967.  
  968. #ifndef NOSPL
  969. int
  970. dodef(cx) int cx; {
  971.     extern int xxdot;
  972.     extern char ppvnambuf[];
  973.     int doeval = 0;
  974.     char vnambuf[VNAML+1];        /* Buffer for variable names */
  975.     char *vnp;                /* Pointer to same */
  976.     int k, mydot;
  977.     mydot = xxdot;            /* Copy */
  978.     xxdot = 0;                /* and reset */
  979. /*
  980.   In case we got here from a command that begins like ".\%a", cmkey() has
  981.   already evaluated \%a, but we don't want that, so we retrieve the variable
  982.   name from a special pre-evaluation buffer in the command module, and we
  983.   undo the "unget word" that would be done because of the token, because if
  984.   the variable was defined, it will unget its value rather than its name.
  985. */
  986.     s = NULL;
  987.     if (mydot && ppvnambuf[0] == '.' && ppvnambuf[1]) {
  988.     s = ppvnambuf+1;
  989.     unungw();
  990.     }
  991.     if (!s) {
  992.     if (cx == XXDFX || cx == XXASX)
  993.       /* Evaluate variable name */
  994.       y = cmfld("Macro or variable name","",&s,xxstring);
  995.     else
  996.       /* Don't evaluate the variable name */
  997.       y = cmfld("Macro or variable name","",&s,NULL);
  998.     if (y < 0) {
  999.         if (y == -3) {
  1000.         printf("?Variable name required\n");
  1001.         return(-9);
  1002.         } else return(y);
  1003.     }
  1004.     }
  1005.     k = strlen(s);
  1006.     if (k > VNAML) {
  1007.     printf("?Name too long: \"%s\"\n",s);
  1008.     return(-9);
  1009.     }
  1010.     strcpy(vnambuf,s);
  1011.     vnambuf[VNAML] = NUL;
  1012.     vnp = vnambuf;
  1013.     if (vnambuf[0] == CMDQ && (vnambuf[1] == '%' || vnambuf[1] == '&')) vnp++;
  1014.     if (*vnp == '%' || *vnp == '&') {
  1015.     if ((y = parsevar(vnp,&x,&z)) < 0) return(y);
  1016.     if (cx == XXUNDEF) {        /* Undefine */
  1017.         if ((y = cmtxt("Text to be ignored","",&s,NULL)) < 0) return(y);
  1018.         delmac(vnp);
  1019.         return(success = 1);
  1020.     }
  1021.     debug(F101,"dodef parsevar x","",x);
  1022.     if (mydot) {
  1023.         if ((doeval = cmkey(asgtab,nasgtab,"operator","=",NULL)) < 0)
  1024.           return(doeval);
  1025.         if (doeval > 0)        /* Type of assignment */
  1026.           cx = XXASS;
  1027.     }
  1028.     if (y == 1) {            /* Simple variable */
  1029.         if ((y = cmtxt("Definition of variable","",&s,NULL)) < 0)
  1030.           return(y);
  1031.         s = brstrip(s);
  1032.         debug(F110,"xxdef var name",vnp,0);
  1033.         debug(F110,"xxdef var def",s,0);
  1034.     } else if (y == 2) {        /* Array element */
  1035.         if ((y = arraynam(vnp,&x,&z)) < 0) return(y);
  1036.         if (x == 96) {
  1037.         printf("?Argument vector array is read-only\n");
  1038.         return(-9);
  1039.         }
  1040.         if (chkarray(x,z) < 0) return(-2);
  1041.         if ((y = cmtxt("Definition of array element","",&s,NULL)) < 0)
  1042.           return(y);
  1043.         debug(F110,"xxdef array ref",vnp,0);
  1044.         debug(F110,"xxdef array def",s,0);
  1045.     }
  1046.     } else {                /* Macro */
  1047.     if (cx == XXUNDEF) {        /* Undefine */
  1048.         if ((y = cmtxt("Text to be ignored","",&s,NULL)) < 0) return(y);
  1049.         delmac(vnp);
  1050.         return(success = 1);
  1051.     }
  1052.     if (mydot) {
  1053.         if ((doeval = cmkey(asgtab,nasgtab,"operator","=",NULL)) < 0)
  1054.           return(doeval);
  1055.         if (doeval > 0)
  1056.           cx = XXASS;
  1057.     }
  1058.     if ((y = cmtxt("Definition of macro","",&s,NULL)) < 0) return(y);
  1059.     debug(F110,"xxdef macro name",vnp,0);
  1060.     debug(F110,"xxdef macro def",s,0);
  1061. #ifdef COMMENT
  1062.     /* This did not require a close bracket */
  1063.     if (*s == '{') {        /* Allow macro def to be bracketed. */
  1064.         s++;            /* If it is, remove the brackets. */
  1065.         y = (int)strlen(s);        /* FOR command depends on this! */
  1066.         if (y > 0 && s[y-1] == '}') s[y-1] = NUL;
  1067.     }
  1068. #else
  1069.     s = brstrip(s);
  1070. #endif /* COMMENT */
  1071.     }
  1072.     if (*s == NUL) {            /* No arg given, undefine */
  1073.     delmac(vnp);            /* silently... */
  1074.     return(success = 1);        /* even if it doesn't exist... */
  1075.     }
  1076.  
  1077.     /* Defining a new macro or variable */
  1078.  
  1079.     if (cx == XXASS || cx == XXASX) {    /* ASSIGN rather than DEFINE? */
  1080.     int t;
  1081.     t = LINBUFSIZ-1;
  1082.     lp = line;            /* If so, expand its value now */
  1083.     zzstring(s,&lp,&t);
  1084.     s = line;
  1085.     }
  1086.     if (doeval == 2) {            /* Arithmetic evaluation wanted too? */
  1087.     strcpy(line,evala(s));
  1088.     line[LINBUFSIZ] = NUL;
  1089.     }
  1090.     debug(F111,"calling addmac",s,(int)strlen(s));
  1091.  
  1092.     y = addmac(vnp,s);            /* Add it to the appropriate table. */
  1093.     if (y < 0) {
  1094.     printf("?%s failed\n",(cx == XXASS || cx == XXASX) ?
  1095.            "ASSIGN" : "DEFINE");
  1096.     return(success = 0);
  1097.     } else if (cx == XXASX || cx == XXDFX) /* For _ASG or _DEF, */
  1098.       return(1);               /* don't change success variable */
  1099.     else
  1100.       return(success = 1);
  1101. }
  1102. #endif /* NOSPL */
  1103.  
  1104.  
  1105. #ifndef NODIAL
  1106. /*
  1107.    L U D I A L  --  Lookup up dialing directory entry.
  1108.  
  1109.    Call with string to look up and file descriptor of open dialing directory
  1110.    file.  On success, returns number of matches found, with numbers stored
  1111.    in an array accessible via getdnum().
  1112. */
  1113. static char *dn_p[MAXDNUMS + 1];    /* Dial Number pointers */
  1114. static char *dn_p2[MAXDNUMS + 1];    /* Converted dial number pointers */
  1115. static int dn_x[MAXDNUMS + 1];        /* Type of call */
  1116. static int dncount = 0;
  1117. char * d_name = NULL;            /* Dial name pointer */
  1118.  
  1119. char *                    /* Get dial directory entry name */
  1120. getdname() {
  1121.     return(d_name ? d_name : "");
  1122. }
  1123.  
  1124. char *
  1125. getdnum(n) int n; {            /* Get dial number n from directory */
  1126.     if (n < 0 || n > dncount || n > MAXDNUMS)
  1127.       return("");
  1128.     else
  1129.       return(dn_p[n]);
  1130. }
  1131.  
  1132. char *            /* Check area code for spurious leading digit */
  1133. chk_ac(i,buf) int i; char buf[]; {
  1134.     char *p;
  1135.     if (!buf)
  1136.       return("");
  1137.     p = (char *) buf;            /* Country we are calling: */
  1138.     if (i ==  44 ||            /* UK */
  1139.     i ==  49 ||            /* Germany */
  1140.     i ==  39 ||            /* Italy */
  1141.     i ==  31 ||            /* Netherlands */
  1142.     i == 351 ||            /* Portugal */
  1143.     i ==  55 ||            /* Brazil */
  1144.     i == 972 ||            /* Israel */
  1145.     i ==  41 ||            /* Switzerland */
  1146.     i ==  43 ||            /* Austria */
  1147.     i ==  42 ||            /* Czech Republic */
  1148.     i ==  36 ||            /* Hungary */
  1149.     i ==  30 ||            /* Greece */
  1150.     i == 352 ||            /* Luxembourg */
  1151.     i ==  48 ||            /* Poland */
  1152.     i ==  27 ||            /* South Africa */
  1153.     i ==  33 ||            /* France (as of 1997) */
  1154.     i ==  358            /* Finland (ditto) */
  1155.     ) {
  1156.     if (buf[0] == '0')
  1157.       p++;
  1158.     }
  1159.     return(p);
  1160. }
  1161.  
  1162. /* Call Is Long Distance -- Expand this to cover 10-digit local dialing etc */
  1163. /*
  1164.    src  = area code of caller
  1165.    dest = area code of callee
  1166.    Returns:
  1167.      0 if call is local
  1168.      1 if call is long distance
  1169.      2 if call is local but area code must be dialed anyway
  1170. */
  1171. static int
  1172. callisld(src, dest) char * src, * dest; {
  1173.     int i;
  1174.     if (dialfld)            /* Force long distance? */
  1175.       return(1);
  1176.     if (!strcmp(src,dest)) {        /* Area codes are the same */
  1177.     for (i = 0; i < nlocalac; i++)    /* Is AC in the lc-area-codes list? */
  1178.       if (!strcmp(src,diallcac[i]))
  1179.         return(2);            /* Yes so must be dialed */
  1180.     return(0);            /* No so don't dial it. */
  1181.     }
  1182.     for (i = 0; i < nlocalac; i++)    /* ACs not the same so look in list */
  1183.       if (!strcmp(dest,diallcac[i]))    /* Match */
  1184.     return(2);            /* So local call with area code */
  1185.     return(1);                /* Not local so long-distance */
  1186. }
  1187.  
  1188. char pdsfx[64] = { NUL, NUL };
  1189.  
  1190. #ifndef NOSPL
  1191. static char *
  1192. xdial(s) char *s; {            /* Run dial string thru macro */
  1193.     int x, m;
  1194.     if (!dialmac)            /* Dial macro name given? */
  1195.       return(NULL);
  1196.     if ((x = mxlook(mactab,dialmac,nmac)) < 0) /* Is the macro defined? */
  1197.       return(NULL);
  1198.     m = maclvl;
  1199.     x = dodo(x,s,0);            /* Set up the macro */
  1200.     if (x > 0) {
  1201.     while (maclvl > m)        /* Execute the parser */
  1202.       parser(1);
  1203.     return(mrval[maclvl+1]);    /* Return the result */
  1204.     }
  1205.     return(NULL);
  1206. }
  1207. #endif /* NOSPL */
  1208.  
  1209. static int
  1210. dncvt(k,cx, prefix, suffix)
  1211.     int k, cx, prefix, suffix; {        /* Dial Number Convert */
  1212.     int i, j, n, what;            /* cx is top-level command index */
  1213.     char *ss;                           /* prefix - add prefixes? */
  1214.     char *p, *p2, *pxo;                 /* suffix - add suffixes? */
  1215.     char *lac;
  1216.     char *npr;
  1217.     char *sfx;
  1218.     /* char *psfx; */
  1219.     char ccbuf[128];
  1220.     int cc;
  1221.     char acbuf[24];
  1222.     char *acptr;
  1223.     char outbuf[256];
  1224. /*
  1225.   First pass for strict (punctuation-based) interpretation.
  1226.   If it fails, we try the looser (length-based) one.
  1227. */
  1228.     dialtype = -1;
  1229.     what = 0;                /* Type of call */
  1230.     s = dn_p[k];            /* Number to be converted. */
  1231.     debug(F111,"dncvt",s,k);
  1232.     if (dn_p2[k]) {
  1233.     free(dn_p2[k]);
  1234.     dn_p2[k] = NULL;
  1235.     }
  1236.     if (!s) {
  1237.     printf("Error - No phone number to convert\n");
  1238.     return(-1);
  1239.     }
  1240.     npr = (prefix && dialnpr) ? dialnpr : "";
  1241.     sfx = (suffix && dialsfx) ? dialsfx : "";
  1242.     /* if (partial) psfx = dialsfx ? dialsfx : ""; */
  1243.     pxo = (prefix && dialpxo) ? dialpxo : "";
  1244.     lac = diallac ? diallac : "";    /* Local area code */
  1245.  
  1246.     outbuf[0] = NUL;            /* Initialize conversion buffer */
  1247.     ss = s;                /* Remember original string */
  1248.  
  1249.     if (*s != '+') {            /* Literal number */
  1250.     dn_x[k] = DN_UNK;        /* Sort key is "unknown". */
  1251.     sprintf(outbuf,            /* Sandwich it between */
  1252.         "%s%s%s%s",        /* DIAL PREFIX and SUFFIX */
  1253.         pxo,npr,s,sfx
  1254.         );
  1255. #ifdef CK_TAPI
  1256.     if (tttapi &&            /* TAPI does its own conversions */
  1257.         !tapipass &&        /* if not in passthru mode */
  1258.         tapiconv == CK_AUTO ||    /* and TAPI conversions are AUTO */
  1259.         tapiconv == CK_ON        /* OR if TAPI conversions are ON */
  1260.         ) {
  1261.         char * p = NULL;
  1262.         dialtype = -2;
  1263.         if (!cktapiConvertPhoneNumber(dn_p[k], &p))
  1264.           return(-1);
  1265.         makestr(&dn_p2[k], p);
  1266.         if (p) free(p);
  1267.         return(0);
  1268.     } else
  1269. #endif /* CK_TAPI */
  1270.       makestr(&dn_p2[k], outbuf);    /* Not TAPI */
  1271.     dialtype = what;
  1272.     return(0);            /* Done. */
  1273.     }
  1274.     i = 0;                /* Portable number */
  1275.     s++;                /* Tiptoe past the plus sign */
  1276.     ccbuf[0] = NUL;            /* Do country code first */
  1277.  
  1278.     if (!diallcc) {            /* Do we know our own? */
  1279.     if (cx != XXLOOK)
  1280.       printf("Error - prior SET DIAL COUNTRY-CODE command required\n");
  1281.     return(-1);
  1282.     }
  1283.  
  1284.     /* Parse the number */
  1285.  
  1286.     while (1) {                /* Get the country code */
  1287.         while (*s == HT || *s == SP)
  1288.       s++;
  1289.     if (!s)                /* Not in standard format */
  1290.       break;
  1291.         if (*s == '(') {        /* Beginning of area code  */
  1292.         s++;            /* Skip past parenthesis   */
  1293.         ccbuf[i] = NUL;        /* End of country code */
  1294.         if (!s) {            /* Check for end of string */
  1295.         printf("Error - phone number ends prematurely: \"%s\"\n",ss);
  1296.         return(-1);
  1297.         }
  1298.         break;
  1299.     } else {            /* Collect country code */
  1300.         if (isdigit(*s))
  1301.           ccbuf[i++] = *s;        /* copy this character */
  1302.         s++;
  1303.         if (!*s || i > 127)        /* watch out for memory leak */
  1304.           break;
  1305.     }
  1306.     }
  1307.     cc = atoi(ccbuf);            /* Numeric version of country code */
  1308.  
  1309.     i = 0;                /* Now get area code */
  1310.     acbuf[0] = NUL;            /* Initialize area-code buffer */
  1311.     acptr = acbuf;            /* and pointer. */
  1312.     while (1) {
  1313.         while (*s == HT || *s == SP)    /* Ignore whitespace */
  1314.       s++;
  1315.     if (!s)                /* String finished */
  1316.       break;
  1317.     if (*s == ')') {        /* End of area code  */
  1318.         s++;            /* Skip past parenthesis   */
  1319.         acbuf[i] = NUL;        /* Terminate area-code buffer */
  1320.         break;
  1321.     } else {            /* Part of area code */
  1322.         if (isdigit(*s))        /* If it's a digit, */
  1323.           acbuf[i++] = *s;        /* copy this character */
  1324.         s++;            /* Point to next */
  1325.         if (!*s || i > 23)        /* Watch out for overflow */
  1326.           break;
  1327.     }
  1328.     }
  1329.  
  1330. /*
  1331.    Here we strip any leading 0 for countries that we know have
  1332.    0 as a long-distance prefix and do not have any area codes that
  1333.    start with 0 (formerly also ditto for "9" in Finland...)
  1334. */
  1335.     i = atoi(ccbuf);
  1336.     acptr = chk_ac(i,acbuf);
  1337.  
  1338.     while (*s == HT || *s == SP)    /* Skip whitespace */
  1339.       s++;
  1340.  
  1341. /* printf("S=[%s], ACPTR=[%s]\n",s,acptr); */
  1342.  
  1343.     if (*s && *acptr) {            /* Area code was delimited */
  1344.  
  1345.     while (*s == '-' || *s == '.')    /* Skip past gratuitious punctuation */
  1346.       s++;
  1347.     if (!*s) s--;            /* But not to end of string */
  1348.  
  1349.     if (strcmp(diallcc,ccbuf)) {    /* Out of country? */
  1350.         if (!dialixp) {        /* Need intl-prefix */
  1351.         if (cx != XXLOOK)
  1352.           printf("Error - No international dialing prefix defined\n");
  1353.         return(-1);
  1354.         }
  1355.         what = dn_x[k] = DN_INTL;
  1356.         p  = (prefix && dialixp) ? dialixp : ""; /* Intl-prefix */
  1357.         p2 = (suffix && dialixs) ? dialixs : ""; /* Intl-suffix */
  1358.         sprintf(pdsfx,"%s%s",p2,sfx);
  1359.         sprintf(outbuf,        /* Form the final phone number */
  1360.             "%s%s%s%s%s%s%s%s",
  1361.             pxo,npr,p,ccbuf,acptr,s,p2,sfx
  1362.             );
  1363.  
  1364.     } else if ((x = callisld(lac,acptr)) >= 1) { /* In-country LD */
  1365.         if (!diallac && cx != XXLOOK) { /* Don't know my own area code */
  1366.         if (cc == 1)
  1367.           printf("WARNING - Prior SET DIAL AREA-CODE needed\n");
  1368.         }
  1369.             if (x == 2) {        /* Local call with area code */
  1370.             what = dn_x[k] = DN_LOCAL;    /* Local-call */
  1371.                 p  = (prefix && diallcp) ? diallcp : ""; /* local-prefix */
  1372.         p2 = (suffix && diallcs) ? diallcs : ""; /* local-suffix */
  1373.             } else {
  1374.             what = dn_x[k] = DN_LONG;    /* Long-distance */
  1375.                 for (i = 0; i < ntollfree; i++) { /* But toll-free too? */
  1376.                     if (!strcmp(acptr,dialtfc[i])) {
  1377.                         what = dn_x[k] = DN_FREE;
  1378.                         break;
  1379.                     }
  1380.                 }
  1381.                 if (what == DN_FREE) {    /* Toll-free call */
  1382.                     p = (prefix && dialtfp) ? dialtfp :
  1383.                         ((prefix && dialldp) ? dialldp : "");
  1384.                     p2 = "";        /* no suffix */
  1385.                 } else {            /* normal long distance */
  1386.                     p  = (prefix && dialldp) ? dialldp : ""; /* ld-prefix */
  1387.                     p2 = (suffix && diallds) ? diallds : ""; /* ld-suffix */
  1388.                 }
  1389.             }
  1390.         sprintf(outbuf,"%s%s%s%s%s%s%s", /* Form the number to be dialed */
  1391.             pxo,npr,p,acptr,s,p2,sfx
  1392.             );
  1393.         sprintf(pdsfx,"%s%s",p2,sfx);
  1394.     } else {            /* Same country, same area code */
  1395.         what = dn_x[k] = DN_LOCAL;    /* So it's a local call. */
  1396.         if (!prefix || !(dialpxo || ndialpxx)) { /* Not dialing from PBX */
  1397.                 p  = (prefix && diallcp) ? diallcp : ""; /* local-prefix */
  1398.                 p2 = (suffix && diallcs) ? diallcs : ""; /* local-suffix */
  1399.         if (x == 2)
  1400.           sprintf(outbuf,"%s%s%s%s%s%s",npr,p,acptr,s,p2,sfx);
  1401.         else
  1402.           sprintf(outbuf,"%s%s%s%s%s",npr,p,s,p2,sfx);
  1403.         sprintf(pdsfx,"%s%s",p2,sfx);
  1404.         } else {            /* Dialing from a PBX and not TAPI */
  1405.         if (ndialpxx) {        /* Is it internal? */
  1406. #ifdef COMMENT
  1407.             i = (int) strlen(dialpxx);
  1408.             j = (int) strlen(s);
  1409.             x = -1;
  1410.             if (j > i)
  1411.               x = ckstrcmp(dialpxx,s,i,0);
  1412. #else
  1413.             int kx;
  1414.             x = -1;
  1415.             j = (int) strlen(s);
  1416.             for (kx = 0; kx < ndialpxx; kx++) {
  1417.             i = (int) strlen(dialpxx[kx]);
  1418.             if (j > i)
  1419.               if (!(x = ckstrcmp(dialpxx[kx],s,i,0)))
  1420.                 break;
  1421.             }
  1422. #endif /* COMMENT */
  1423.             if (!x) {
  1424.             char * icp, buf[32];
  1425.             makestr(&matchpxx,dialpxx[kx]);
  1426.             debug(F111,"dncvt matchpxx",matchpxx,kx);
  1427.             what = dn_x[kx] = DN_INTERN;   /* Internal call. */
  1428.             s += i;
  1429.             /* Internal-call prefix */
  1430.             icp = dialpxi;
  1431. #ifndef NOSPL
  1432.             if (icp) {
  1433.                 if (*icp == '\\') {
  1434.                 char c, *bp;
  1435.                 int n;
  1436.                 c = *(icp+1);
  1437.                 if (isupper(c)) c = tolower(c);
  1438.                 if (c == 'v' || c == 'f') {
  1439.                     n = 32;
  1440.                     bp = buf;
  1441.                     zzstring(icp,&bp,&n);
  1442.                     icp = buf;
  1443.                 }
  1444.                 }
  1445.             }
  1446. #endif /* NOSPL */
  1447.             p = (prefix && icp) ? icp : "";
  1448.             sprintf(outbuf,"%s%s%s%s",
  1449.                 npr,p,s,sfx
  1450.                 );
  1451.             } else {        /* External local call */
  1452.             /* local-prefix */
  1453.                         p  = (prefix && diallcp) ? diallcp : "";
  1454.             /* local-suffix */
  1455.                         p2 = (prefix && diallcs) ? diallcs : "";
  1456.             if (x == 2)
  1457.               sprintf(outbuf,"%s%s%s%s%s%s%s",
  1458.                   dialpxo ? dialpxo : "",
  1459.                   npr,p,acptr,s,p2,sfx);
  1460.             else
  1461.               sprintf(outbuf,
  1462.                   "%s%s%s%s%s%s",
  1463.                   dialpxo ? dialpxo : "",
  1464.                   npr,p,s,p2,sfx
  1465.                   );
  1466.             }
  1467.         }
  1468.         }
  1469.     }
  1470.  
  1471.     } else {                /* Area code was not delimited */
  1472.  
  1473.     char xbuf[256];            /* Comparison based only on length */
  1474.     char ybuf[256];
  1475.     int x, j;
  1476.  
  1477.     s = ss;
  1478.  
  1479.  
  1480.     for (i = 0; i < 255; i++) {
  1481.         if (!*s) break;
  1482.         while (!isdigit(*s)) {    /* Only pay attention to digits */
  1483.         s++;
  1484.         if (!*s) break;
  1485.         }
  1486.         xbuf[i] = *s++;
  1487.     }
  1488.     xbuf[i] = NUL;
  1489.  
  1490.     x = 1;                /* Assume LD */
  1491.     n = 0;
  1492.     if (!dialfld) {            /* If LD not forced */
  1493.         for (j = 0; j < nlocalac; j++) { /* check local AC list? */
  1494.         sprintf(ybuf,"%s%s",diallcc,diallcac[j]);
  1495.         n = (int) strlen(ybuf);
  1496.         if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0)) {
  1497.             x = 2;
  1498.             break;
  1499.         }
  1500.         }
  1501.         if (x == 1) {        /* Or exact match with local CC+AC? */
  1502.         sprintf(ybuf,"%s%s",diallcc,lac);
  1503.         n = (int) strlen(ybuf);
  1504.         if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0))
  1505.           x = 0;
  1506.         }
  1507.     }
  1508.     if (x == 0 || x == 2) {        /* Local call */
  1509.         dn_x[k] = DN_LOCAL;
  1510.         p = (prefix && diallcp) ? diallcp : "";
  1511.         p2 = (suffix && diallcs) ? diallcs : "";
  1512.         s = (char *) (xbuf + ((x == 0) ? n : (int)strlen(diallcc)));
  1513.         sprintf(outbuf,"%s%s%s%s%s%s",pxo,npr,p,s,p2,sfx);
  1514.         sprintf(pdsfx,"%s%s",p2,sfx);
  1515.     } else {            /* Not local */
  1516.         n = ckstrncpy(ybuf,diallcc,256);
  1517.         if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0)) { /* Long distance */
  1518.         dn_x[k] = DN_LONG;
  1519.         p = (prefix && dialldp) ? dialldp : "";
  1520.         p2 = (suffix && diallds) ? diallds : "";
  1521.         s = xbuf + n;
  1522.         while (*s == '-' || *s == '.')
  1523.           s++;
  1524.         sprintf(outbuf,"%s%s%s%s%s%s",pxo,npr,p,s,p2,sfx);
  1525.         sprintf(pdsfx,"%s%s",p2,sfx);
  1526.         } else {
  1527.         dn_x[k] = DN_INTL;    /* International */
  1528.         if (!dialixp) {
  1529.             if (cx != XXLOOK) {
  1530.             printf(
  1531.               "Error - No international dialing prefix defined\n"
  1532.                    );
  1533.             return(-1);
  1534.             }
  1535.         }
  1536.         p = (prefix && dialixp) ? dialixp : "";
  1537.         p2 = (suffix && dialixs) ? dialixs : "";
  1538.         sprintf(outbuf,"%s%s%s%s%s%s",pxo,npr,p,xbuf,p2,sfx);
  1539.         sprintf(pdsfx,"%s%s",p2,sfx);
  1540.         }
  1541.     }
  1542.     }
  1543. #ifdef CK_TAPI
  1544.     if (tttapi &&            /* TAPI performs the conversions */
  1545.     !tapipass &&
  1546.     tapiconv == CK_AUTO ||
  1547.     tapiconv == CK_ON
  1548.     ) {
  1549.     p = NULL;
  1550.     dialtype = -2;
  1551.     if (!cktapiConvertPhoneNumber(dn_p[k],&p))
  1552.       return(-1);
  1553.     makestr(&dn_p2[k], p);
  1554.     if (p) free(p);
  1555.     return(0);
  1556.     } else {
  1557. #endif /* CK_TAPI */
  1558.     makestr(&dn_p2[k], outbuf);
  1559. #ifdef CK_TAPI
  1560.     }
  1561. #endif /* CK_TAPI */
  1562.     dialtype = what;
  1563.     return(0);
  1564. }
  1565.  
  1566. static int
  1567. ddcvt(s, f, n) char * s; FILE * f; int n; { /* Dial Directory Convert */
  1568.     char *line, *s2;            /* buffers */
  1569. #ifdef VMS
  1570.     char * temp;
  1571. #endif /* VMS */
  1572.     char *info[8];            /* Pointers to words from entry */
  1573.     FILE * f2;
  1574.     int x, rc;
  1575.     rc = -1;
  1576.  
  1577.     if (!s || !f)            /* No filename or file */
  1578.       return(-1);
  1579.     if ((int) strlen(s) < 1)
  1580.       return(-1);
  1581.     if (!(line = malloc(1024)))        /* Allocate input buffer */
  1582.       return(-1);
  1583.     f2 = NULL;
  1584.  
  1585.     fclose(f);
  1586.     znewn(s,&s2);            /* s2 = address of static buffer */
  1587. #ifdef VMS
  1588.     temp = s2;                /* Swap - otherwise the new */
  1589.     s2 = s;                /* version has the older version */
  1590.     s = temp;                /* number... */
  1591.     if (temp =  (char *)malloc((int)strlen(s)+1))
  1592.       strcpy(temp,s);
  1593.     if (dialdir[n])            /* Replace filename in list */
  1594.       free(dialdir[n]);
  1595.     dialdir[n] = temp;
  1596.     s = temp;
  1597. #else
  1598.     if (zrename(s,s2) < 0) {        /* Not VMS - rename old file */
  1599.     perror(s2);            /* to new (wierd) name. */
  1600.     goto ddexit;
  1601.     }
  1602. #endif /* VMS */
  1603.     if ((f = fopen(s2,"r")) == NULL) {    /* Reopen old file with wierd name */
  1604.     dirline = 0;            /* (or in VMS, old version) */
  1605.     perror(s2);
  1606.     goto ddexit;
  1607.     }
  1608.     if ((f2 = fopen(s,"w")) == NULL) {    /* Create new file with old name */
  1609.     perror(s);            /* (or in VMS, new version) */
  1610.     goto ddexit;
  1611.     }
  1612.     printf("\nSaving old directory as %s.\nConverting %s...",s2,s);
  1613.     fprintf(f2,"; %s - Kermit dialing directory\n", s);
  1614.     fprintf(f2,"%-16s %-20s ; %5s %-6s ; %s\n",
  1615.            "; Name","Number","Speed","Parity","Comment"
  1616.            );
  1617.  
  1618.     while (1) {
  1619.     line[0] = NUL;            /* Read a line */
  1620.     if (fgets(line,1023,f) == NULL)
  1621.       break;
  1622.     if (!line[0]) {            /* Empty line */
  1623.         fprintf(f2,"\n");
  1624.         continue;
  1625.     }
  1626.     x = (int) strlen(line);        /* Strip line terminator, */
  1627.     while (x-- > 0) {        /* if any. */
  1628.         if (line[x] <= SP)
  1629.           line[x] = NUL;
  1630.         else
  1631.           break;
  1632.     }
  1633.     xwords(line,5,info,1);        /* Parse it the old way */
  1634.     for (x = 1; x < 6; x++)
  1635.       if (!info[x]) info[x] = "";
  1636.     fprintf(f2,"%-16s %-20s ; %5s %-6s %s\n",
  1637.            info[1],info[2],info[3],info[4],info[5]
  1638.            );
  1639.     }
  1640.     printf(" OK\n\n");
  1641.     rc = 0;                /* Success */
  1642.   ddexit:
  1643.     if (f) fclose(f);
  1644.     if (f2) fclose(f2);
  1645.     if (line) free(line);
  1646.     return(rc);
  1647. }
  1648.  
  1649. int                    /* s = name to look up   */
  1650. #ifdef CK_ANSIC                /* cx = index of command */
  1651. ludial(char *s, int cx)            /* (DIAL, LOOKUP, etc)   */
  1652. #else
  1653. ludial(s, cx) char *s; int cx;
  1654. #endif /* CK_ANSIC */
  1655. /* ludial */ {
  1656.  
  1657.     int dd, n1, n2, n3, i, j, t;    /* Workers */
  1658.     int olddir, newdir, oldentry, newentry;
  1659.     int pass = 0;
  1660.     int oldflg = 0;
  1661.     int ambiguous = 0;            /* Flag for lookup was ambiguous */
  1662.     char *info[7];            /* Pointers to words from entry */
  1663.     char *pp;                /* Pointer to element of array */
  1664.     FILE * f;
  1665.     char *line;                /* File input buffer */
  1666.  
  1667. /* #define LUDEBUG */
  1668.  
  1669. #ifdef LUDEBUG
  1670. int zz = 1;
  1671. #endif /* LUDEBUG */
  1672.  
  1673.     if (!s || ndialdir < 1)        /* Validate arguments */
  1674.       return(-1);
  1675.  
  1676.     if ((n1 = (int) strlen(s)) < 1)    /* Length of string to look up */
  1677.       return(-1);
  1678.  
  1679.     if (!(line = malloc(1024)))        /* Allocate input buffer */
  1680.       return(-1);
  1681.  
  1682. #ifdef LUDEBUG
  1683. if (zz) printf("LUDIAL 1 s[%s], n1=%d\n",s,n1);
  1684. #endif /* LUDEBUG */
  1685.  
  1686.     pass = 0;
  1687.   lu_again:
  1688.     f = NULL;                /* Dial directory file descriptor */
  1689.     t = dncount = 0;            /* Dial-number match count */
  1690.     dd = 0;                /* Directory counter */
  1691.     olddir = 0;
  1692.     newdir = 0;
  1693. /*
  1694.   We need to recognize both old- and new-style directories.
  1695.   But we can't allow old-style and new-style entries in the same
  1696.   directory because there is no way to tell for sure the difference between
  1697.   an old-style entry like this:
  1698.  
  1699.     foo  5551212  9600
  1700.  
  1701.   and a new-style literal entry like this:
  1702.  
  1703.     foo  555 9600
  1704.  
  1705.   I.e. is the "9600" a speed, or part of the phone number?
  1706. */
  1707.     while (1) {                /* We make one pass */
  1708.     if (!f) {            /* Directory not open */
  1709.             if (dd >= ndialdir)        /* No directories left? */
  1710.           break;            /* Done. */
  1711.         if ((f = fopen(dialdir[dd],"r")) == NULL) { /* Open it */
  1712.         perror(dialdir[dd]);    /* Can't, print message saying why */
  1713.         if (line) {
  1714.             free(line);
  1715.             line = NULL;
  1716.         }
  1717.         dd++;            /* Go on to next one, if any... */
  1718.         continue;
  1719.         }
  1720.         dirline = 0;        /* Directory file line number */
  1721.         if (dialdpy && !pass)
  1722.           printf("Opening: %s...\n",dialdir[dd]);
  1723.             dd++;
  1724.         if (!oldflg) olddir = 0;
  1725.         newdir = 0;
  1726.     }
  1727.     oldentry = 0;
  1728.     newentry = 0;
  1729.     line[0] = NUL;
  1730.     if (getnct(line,1023,f,1) < 0) { /* Read a line */
  1731.         if (f) {            /* f can be clobbered! */
  1732.         fclose(f);        /* Close the file */
  1733.         f = NULL;        /* Indicate next one needs opening */
  1734.         oldflg = 0;
  1735.         }
  1736.         continue;
  1737.     }
  1738.     if (!line[0])            /* Empty line */
  1739.       continue;
  1740. #ifdef LUDEBUG
  1741. if (zz) printf("LUDIAL 2 s[%s]\n",s);
  1742. #endif /* LUDEBUG */
  1743.  
  1744.     /* Make a copy and parse it the old way */
  1745.     /* A copy is needed because xwords() pokes NULs into the string */
  1746.  
  1747.     if (pp = malloc((int)strlen(line) + 1)) {
  1748.         strcpy(pp,line);
  1749.         xwords(pp,5,info,0);    /* Parse it the old way */
  1750.  
  1751. #ifdef LUDEBUG
  1752. if (zz) printf("LUDIAL 3 s[%s]\n",s);
  1753. #endif /* LUDEBUG */
  1754.  
  1755.         if (!info[1])
  1756.           continue;
  1757.         if (*info[1] == ';') {    /* If full-line comment, */
  1758.         newdir = 1;        /* (only new directories have them) */
  1759.         continue;        /* keep reading. */
  1760.         }
  1761.         if (!info[2])
  1762.           continue;
  1763.         if (*info[2] == '+')
  1764.           newentry = 1;
  1765.         if (info[4]) {
  1766.         if ((*info[4] == '=') ||
  1767.             !ckstrcmp(info[4],"none", 4,0) ||
  1768.             !ckstrcmp(info[4],"even", 4,0) ||
  1769.             !ckstrcmp(info[4],"space",5,0) ||
  1770.             !ckstrcmp(info[4],"mark", 4,0) ||
  1771.             !ckstrcmp(info[4],"odd",  3,0)
  1772.             )
  1773.           oldentry = 1;
  1774.         }
  1775.     }
  1776.     if (pp) {
  1777.         free(pp);
  1778.         pp = NULL;
  1779.     }
  1780.  
  1781.     /* Check consistency */
  1782.  
  1783.     if ((oldentry || olddir) && (newentry || newdir)) {
  1784.         printf(
  1785. "\nERROR: You seem to have old- and new-format entries mixed in your\n");
  1786.         printf(
  1787. "dialing directory.  You'll have to edit it by hand to convert it to the\n");
  1788. #ifndef NOHELP
  1789.         printf("new format.  Type HELP DIAL for further information.\n\n");
  1790. #else
  1791.         printf("new format.\n\n");
  1792. #endif /* NOHELP */
  1793.         if (line) {
  1794.         free(line);
  1795.         line = NULL;
  1796.         }
  1797.         return(-1);
  1798.     }
  1799.     if (!olddir && oldentry) {
  1800.         int convert = 0;
  1801.         olddir = 1;
  1802.         if (dialcvt == 2) {        /* 2 == ASK */
  1803.         printf(
  1804. "\nWARNING: Old-style dialing directory detected:\n%s\n\n", line);
  1805.         convert = getyesno("Shall I convert it for you? ",0);
  1806.         } else
  1807.           convert = dialcvt;
  1808.         if (convert) {
  1809.         if (ddcvt(dialdir[dd-1],f,dd-1) < 0) {
  1810.             oldflg = 1;
  1811.             printf(
  1812. "  Sorry, can't convert.");
  1813.             printf(
  1814. "  Will ignore speed and parity fields, continuing...\n\n");
  1815.         } else {
  1816.             olddir = newdir = 0;
  1817.         }
  1818.         dd--;
  1819.         f = NULL;
  1820.         continue;
  1821.         } else {
  1822.         if (dialcvt == 2)
  1823.           printf(
  1824. "  OK, will ignore speed and parity fields, continuing...\n\n");
  1825.         olddir = 1;
  1826.         }
  1827.     }
  1828.  
  1829. #ifdef LUDEBUG
  1830. if (zz) printf("LUDIAL XX s[%s], n1=%d\n",s,n1);
  1831. #endif /* LUDEBUG */
  1832.  
  1833.     /* Now parse again for real */
  1834.  
  1835.     if (oldentry)            /* Parse it the old way */
  1836.       xwords(line,5,info,0);
  1837.     else                /* Parse it the new way */
  1838.       xwords(line,2,info,1);
  1839.  
  1840. #ifdef LUDEBUG
  1841. if (zz) printf("LUDIAL YY s[%s], n1=%d\n",s,n1);
  1842. if (zz) printf("%s [%s]\n",info[1],info[2]);
  1843. #endif /* LUDEBUG */
  1844.  
  1845.     if (info[1]) {            /* First word is entry name */
  1846.         if ((n3 = (int) strlen(info[1])) < 1) /* Its length */
  1847.           continue;            /* If no first word, keep reading. */
  1848.         if (n3 < n1)        /* Search name is longer */
  1849.           continue;            /* Can't possibly match */
  1850.         if (ambiguous && n3 != n1)
  1851.           continue;
  1852.  
  1853. #ifdef LUDEBUG
  1854. if (zz) printf("MATCHING: [%s] [%s], n1=%d\n",s,info[1],n1);
  1855. #endif /* LUDEBUG */
  1856.  
  1857.         if (ckstrcmp(s,info[1],n1,0)) /* Caseless string comparison */
  1858.           continue;
  1859.  
  1860. #ifdef LUDEBUG
  1861. if (zz) printf("MATCH OK: [%s] [%s], n1=%d\n",s,info[1],n1);
  1862. #endif /* LUDEBUG */
  1863.  
  1864.         if (!info[2])        /* No phone number given */
  1865.           continue;
  1866.         if ((n2 = (int) strlen(info[2])) < 1) /* Length of phone number */
  1867.           continue;            /* Ignore empty phone numbers */
  1868.  
  1869.         /* Got one */
  1870.  
  1871.         if (!(pp = (char *)malloc(n2 + 1))) { /* Allocate storage for it */
  1872.         printf("?internal error - ludial malloc 1\n");
  1873.         if (line) {
  1874.             free(line);
  1875.             line = NULL;
  1876.         }
  1877.         dncount = 0;
  1878.         return(-1);
  1879.         }
  1880.         strcpy(pp,info[2]);        /* Copy number into malloc'd storage */
  1881.  
  1882.         if (dncount > MAXDNUMS) {
  1883.         printf("Warning: %d matches found, %d max\n",
  1884.                dncount,
  1885.                MAXDNUMS
  1886.                );
  1887.         dncount = MAXDNUMS;
  1888.         break;
  1889.         }
  1890.         dn_p[dncount++] = pp;    /* Add pointer to array. */
  1891.         if (dncount == 1) {        /* First one... */
  1892.         if (d_name) free(d_name);
  1893.         if (!(d_name = (char *)malloc(n3 + 1))) { /* Save its name */
  1894.             printf("?internal error - ludial malloc 2\n");
  1895.             if (line) {
  1896.             free(line);
  1897.             line = NULL;
  1898.             }
  1899.             dncount = 0;
  1900.             return(-1);
  1901.         }
  1902.         t = n3;            /* And its length */
  1903.         strcpy(d_name,info[1]);
  1904.         } else {            /* Second or subsequent one */
  1905.  
  1906. #ifdef LUDEBUG
  1907.         if (zz)
  1908.           printf("d_name=[%s],info[1]=%s,t=[%d]\n",d_name,info[1],t);
  1909. #endif /* LUDEBUG */
  1910.  
  1911.         if ((int) strlen(info[1]) == t) /* Lengths compare */
  1912.           if (!ckstrcmp(d_name,info[1],t,0)) /* Caseless compare OK */
  1913.             continue;
  1914.  
  1915.         /* Name given by user matches entries with different names */
  1916.  
  1917.         if (ambiguous)        /* Been here before */
  1918.           break;
  1919.  
  1920.         ambiguous = 1;        /* Now an exact match is required */
  1921.         for (j = 0; j < dncount; j++) { /* Clean out previous list */
  1922.             if (dn_p[j]) {
  1923.             free(dn_p[j]);
  1924.             dn_p[j] = NULL;
  1925.             }
  1926.         }
  1927.         pass++;            /* Second pass... */
  1928.         goto lu_again;        /* Do it all over again. */
  1929.         }
  1930.     }
  1931.     }
  1932.     if (line) free(line);
  1933.     if (dncount == 0 && ambiguous) {
  1934.     printf(" Lookup: \"%s\" - ambiguous%s\n",
  1935.            s,
  1936.            cx == XXLOOK ? "" : " - dialing skipped"
  1937.            );
  1938.     return(-2);
  1939.     }
  1940.     return(dncount);
  1941. }
  1942.  
  1943. char *
  1944. pncvt(s) char *s; {            /* Phone number conversion */
  1945.     char *p = NULL;            /* (just a wrapper for dncvt() */
  1946.     char *q = NULL;
  1947.     static char pnbuf[128];
  1948.     makestr(&p,dn_p[0]);        /* Save these in case they are */
  1949.     makestr(&q,dn_p2[0]);        /* being used */
  1950.     makestr(&dn_p[0],s);        /* Copy the argument string to here */
  1951.     dncvt(0,XXLOOK,1,1);        /* Convert it */
  1952.     if (!dn_p2[0])            /* Put result where can return it */
  1953.       pnbuf[0] = NUL;
  1954.     else
  1955.       ckstrncpy(pnbuf,dn_p2[0],127);
  1956.     makestr(&dn_p[0],p);        /* Restore these */
  1957.     makestr(&dn_p2[0],q);
  1958.     makestr(&p,NULL);            /* Free these */
  1959.     makestr(&q,NULL);
  1960.     return((char *)pnbuf);
  1961. }
  1962.  
  1963. int
  1964. dodial(cx) int cx; {            /* DIAL or REDIAL */
  1965.     int i = 0, x = 0;            /* Workers */
  1966.     int sparity = -1;            /* For saving global parity value */
  1967.     int previous = 0;
  1968.     int len = 0;
  1969.     int literal = 0;
  1970.     int flowsave;
  1971.     int lufound = 0;            /* Did any lookup succeed? */
  1972.     int prefix = 1;
  1973.     int postfix = 1;
  1974.     int wasalpha = 0;
  1975.     int xredial = 0;
  1976.     int braces = 0;
  1977.  
  1978.     char *p = NULL, *s3 = NULL, * sav = NULL;
  1979.     int j = 0, t = 0, n = 0;
  1980.     int xretries, xlcc;
  1981.  
  1982.     extern int what;
  1983.  
  1984.     debug(F101,"dodial cx","",cx);
  1985.     debug(F111,"dodial diallcc",diallcc,diallcc);
  1986.  
  1987.     xretries = dialrtr;            /* If retries not set, */
  1988.     if (diallcc) {            /* choose default based on */
  1989.         xlcc = atoi(diallcc);        /* local country code. */
  1990.     if (xretries < 0) {
  1991.       switch (xlcc) {
  1992.         case 1: xretries = 10; break; /* No restrictions in NANP */
  1993.           /* Add other country codes here */
  1994.           /* that are known to have no restrictions on redialing. */
  1995.         default: xretries = 1;
  1996.       }
  1997.     }
  1998.     }
  1999.     if (cx == XXPDIA) {            /* Shortcut... */
  2000.     cx = XXDIAL;
  2001.     partial = 1;
  2002.     debug(F100,"PDIAL sets partial=1","",0);
  2003.     postfix = 0;                    /* Do not add postfix */
  2004.     } else {
  2005.     partial = 0;
  2006.     debug(F100,"DIAL sets partial=0","",0);
  2007.     }
  2008.     previous = dialsta;            /* Status of previous call, if any */
  2009.     if (previous == DIA_PART) {
  2010.     prefix = 0;            /* do not add prefix */
  2011.     }
  2012.     if (cx != XXLOOK) {            /* Not LOOKUP */
  2013. #ifdef IKSD
  2014.         if (inserver) {
  2015.             printf("Sorry, dialing is disabled.\r\n");
  2016.             return(success = 0);
  2017.         }
  2018. #endif /* IKSD */
  2019. #ifdef CK_TAPI
  2020.     if (tttapi && !tapipass) {
  2021.       ;                 /* Skip the modem test if TAPI */
  2022.     } else
  2023. #endif /* CK_TAPI */
  2024.     if (mdmtyp < 1 && !dialtest) {
  2025.         if (network)
  2026.           printf("Please SET HOST first, and then SET MODEM TYPE\n");
  2027.         else
  2028.           printf("Sorry, you must SET MODEM TYPE first\n");
  2029.         dialsta = DIA_NOMO;
  2030.         return(success = 0);
  2031.     }
  2032.     if (!local && !dialtest) {
  2033.         printf("Sorry, you must SET %s or SET HOST first\n",
  2034. #ifdef OS2
  2035.            "PORT"
  2036. #else
  2037.            "LINE"
  2038. #endif /* OS2 */
  2039.            );
  2040.         dialsta = DIA_NOLI;
  2041.         return(success = 0);
  2042.     }
  2043.     if (!network && !dialtest &&
  2044. #ifdef CK_TAPI
  2045.          !tttapi &&
  2046. #endif /* CK_TAPI */
  2047.         (speed < 0L)
  2048. #ifdef UNIX
  2049.         && (strcmp(ttname,"/dev/null"))
  2050. #else
  2051. #ifdef OSK
  2052.         && (strcmp(ttname,"/nil"))
  2053. #endif /* OSK */
  2054. #endif /* UNIX */
  2055.         ) {
  2056.         printf("\nSorry, you must SET SPEED first\n");
  2057.         dialsta = DIA_NOSP;
  2058.         return(success = 0);
  2059.     }
  2060.     }
  2061.     s = NULL;                /* Initialize user's dial string */
  2062.     if (cx == XXRED) {            /* REDIAL or... */
  2063.     if ((y = cmcfm()) < 0)
  2064.       return(y);
  2065.     } else if (cx == XXANSW) {        /* ANSWER or ... */
  2066.     if ((y = cmnum("timeout (seconds)","0",10,&x,xxstring)) < 0)
  2067.       return(y);
  2068.     dialatmo = x;
  2069.     if ((y = cmcfm()) < 0)
  2070.       return(y);
  2071.     } else {                /* DIAL or LOOKUP */
  2072.     if (ndialdir > 0)
  2073.       s3 = "Number to dial or entry from dial directory";
  2074.     else
  2075.       s3 = "Number to dial";
  2076.     if ((x = cmtxt(s3, dialnum ? dialnum : "",&s,xxstring)) < 0)
  2077.       return(x);
  2078.     if (s) {
  2079.         len = (int) strlen(s);
  2080.         ckstrncpy(tmpbuf,s,TMPBUFSIZ); /* Save literal copy */
  2081.         if (len > 1) {        /* Strip outer braces if given */
  2082.         if (*s == '{') {
  2083.             if (s[len-1] == '}') {
  2084.             s[len-1] = NUL;
  2085.             s++;
  2086.             len -= 2;
  2087.             }
  2088.         }
  2089.         }
  2090.     }
  2091.     }
  2092.     if (cx != XXANSW) {
  2093.     for (j = 0; j < MAXDNUMS; j++) { /* Initialize dial-number list */
  2094.         if (!dialnum) {        /* First time dialing */
  2095.         dn_p[j] = NULL;        /* initialize all pointers. */
  2096.         dn_p2[j] = NULL;
  2097.         } else if (dn_p[j]) {    /* Not the first time, */
  2098.         free(dn_p[j]);        /* free previous, if any, */
  2099.         dn_p[j] = NULL;        /* then set to NULL. */
  2100.         if (dn_p2[j])
  2101.           free(dn_p2[j]);
  2102.         dn_p2[j] = NULL;
  2103.         } else break;        /* Already NULL */
  2104.     }
  2105.     if (len == 0)
  2106.       s = NULL;
  2107.     if (!s)
  2108.       s = dialnum;
  2109.     if (!s) {
  2110.         if (cx == XXLOOK)
  2111.           printf("?Lookup what?\n");
  2112.         else
  2113.           printf("%s\n", (cx == XXRED) ?
  2114.            "?No DIAL command given yet" :
  2115.            "?You must specify a number to dial"
  2116.            );
  2117.         return(-9);
  2118.     }
  2119.  
  2120.     /* Now we have the "raw" dial or lookup string and s is not NULL */
  2121.  
  2122.     makestr(&dscopy,s);        /* Put it in a safe place */
  2123.     s = dscopy;
  2124.     n = 0;
  2125.  
  2126.     debug(F111,"dodial",s,ndialdir);
  2127.  
  2128.     wasalpha = 0;
  2129.     if (isalpha(*s)) {
  2130.         wasalpha = 1;
  2131.         if (ndialdir > 0) {        /* Do we have a dialing directory? */
  2132.         n = ludial(s,cx);    /* Look up what the user typed */
  2133.         if (n == 0)
  2134.           printf(" Lookup: \"%s\" - not found%s\n",
  2135.              s,
  2136.              cx == XXLOOK ? "" : " - dialing as given\n"
  2137.              );
  2138.         }
  2139.         debug(F101,"dodial",s,n);
  2140.         if (n < 0 && cx != XXLOOK) { /* Error out if they wanted to dial */
  2141.         if (n == -1)        /* -2 means ludial already gave msg */
  2142.           printf(" Lookup: fatal error - dialing skipped\n");
  2143.         dialsta = DIA_DIR;
  2144.         return(-9);
  2145.         }
  2146.         if (n > 0)            /* A successful lookup */
  2147.           lufound = 1;
  2148.     } else if (*s == '=') {        /* If number starts with = sign */
  2149.         s++;            /* strip it */
  2150.         literal = 1;        /* remember this */
  2151.         while (*s == SP) s++;    /* and then also any leading spaces */
  2152.     } else if (tmpbuf[0] == '{' && tmpbuf[1] == '{') {
  2153.         makelist(tmpbuf,dn_p,MAXDNUMS);
  2154.         makestr(&dscopy,tmpbuf);
  2155.         s = tmpbuf;
  2156.         for (n = 0; n < MAXDNUMS; n++) /* (have to count how many) */
  2157.           if (!dn_p[n]) break;
  2158.         braces = 1;
  2159.     }
  2160.     if (cx == XXLOOK && !wasalpha && !braces) {
  2161.         /* We've been told to lookup a number or a quoted name */
  2162.         char *p;
  2163.         n = 0;
  2164.         p = literal ? s : pncvt(dscopy);
  2165.         if (!p) p = "";
  2166.         if (*p) {
  2167.         printf("%s  => %s\n", dscopy, p);
  2168.         return(success = 1);
  2169.         } else {
  2170.         printf("?Bad phone number\n");
  2171.         return(success = 0);
  2172.         }
  2173.     }
  2174.     /* Save DIAL or successful LOOKUP string for future DIAL or REDIAL */
  2175.     /* But don't save pieces of partial dial ... */
  2176.  
  2177.     debug(F101,"DIAL save dialnum partial","",partial);
  2178.     debug(F101,"DIAL save dialnum previous","",previous);
  2179.     if ((cx == XXDIAL && partial == 0 && previous != DIA_PART) ||
  2180.         (cx == XXLOOK && n > 0)) {
  2181.         makestr(&dialnum,dscopy);
  2182.         if (!quiet && dscopy && !dialnum)
  2183.           printf("WARNING - memory allocation failure: redial number\n");
  2184.     }
  2185.     if (n > 0) {
  2186.         if (!quiet && !backgrd && !braces /* && dialdpy */ ) {
  2187.         if (!strcmp(d_name,s))
  2188.           printf(" Lookup: \"%s\" - exact match\n",s);
  2189.         else
  2190.           printf(" Lookup: \"%s\" - uniquely matches \"%s\"\n",
  2191.              s,
  2192.              d_name
  2193.              );
  2194.         }
  2195.         if ((cx == XXLOOK) || (n > 1)  &&
  2196.         !quiet && !backgrd /* && dialdpy */ ) {
  2197.         printf(" %d telephone number%sfound for \"%s\"%s\n",
  2198.                n,
  2199.                (n == 1) ? " " : "s ",
  2200.                s,
  2201.                (n > 0) ? ":" : "."
  2202.                );
  2203.         s3 = getdname();
  2204.         }
  2205.         for (i = 0; i < n; i++) {    /* Convert */
  2206.         dn_x[i] = -1;
  2207.         if (dncvt(i,cx,prefix,postfix) < 0) {
  2208.             if (cx != XXLOOK) {
  2209.             dialsta = DIA_DIR;
  2210.             return(-9);
  2211.             }
  2212.         }
  2213.         }
  2214.         if (dialsrt && n > 1) {    /* Sort into optimal order */
  2215.         for (i = 0; i < n-1; i++) {
  2216.             for (j = i+1; j < n; j++) {
  2217.             if (dn_x[j] < dn_x[i]) {
  2218.                 t = dn_x[j];
  2219.                 dn_x[j] = dn_x[i];
  2220.                 dn_x[i] = t;
  2221.                 p = dn_p[j];
  2222.                 dn_p[j] = dn_p[i];
  2223.                 dn_p[i] = p;
  2224.                 p = dn_p2[j];
  2225.                 dn_p2[j] = dn_p2[i];
  2226.                 dn_p2[i] = p;
  2227.             }
  2228.             }
  2229.         }
  2230.         }
  2231.         if ((cx == XXLOOK) || (n > 1)  &&
  2232.         !quiet && !backgrd /* && dialdpy */ ) {
  2233.         int nn = n;
  2234. #ifndef NOSPL
  2235.         char * p;
  2236. #endif /* NOSPL */
  2237.         if (cx != XXLOOK)
  2238.           if (n > 12) nn = 12;
  2239.         for (i = 0; i < nn; i++) {
  2240.             printf("%3d. %-12s  %-20s =>  %-20s  (%d)\n",i+1,
  2241.                s3, dn_p[i],
  2242.                dn_p2[i] ? dn_p2[i] : "(processing failed)",
  2243.                dn_x[i]
  2244.                );
  2245.         }
  2246.         if (cx != XXLOOK && n != nn)
  2247.           printf("And %d more...\n", n - nn);
  2248.         }
  2249.     } else if (n == 0) {        /* Not found in directory */
  2250.         makestr(&(dn_p[0]),literal ? s : dscopy);
  2251.         makestr(&d_name,literal ? s : dscopy);
  2252.         dncount = 1;
  2253.         n = 1;
  2254.         if (dncvt(0,cx,prefix,postfix) < 0) { /* In case they typed a */
  2255.         dialsta = DIA_DIR;    /* portable-format number ... */
  2256.         return(-9);
  2257.         }
  2258.     }
  2259.  
  2260. #ifndef NONET
  2261. #ifdef NETCONN
  2262.     /* It's not good that the networks directory depends on NOT-NODIAL.. */
  2263.     if (cx == XXLOOK && dscopy) {    /* Networks here too... */
  2264.         extern char *nh_p[], *nh_p2[], *n_name;
  2265.         extern char *nh_px[4][MAXDNUMS+1];
  2266.         n = -1;
  2267.         if (nnetdir > 0) {        /* Do we have a network directory? */
  2268.         dirline = 0;
  2269.         n = lunet(dscopy);    /* Look up what the user typed */
  2270.         }
  2271.         if (n > -1) {
  2272.         int k;
  2273.         if (n > 0)        /* A successful lookup */
  2274.           lufound = 1;
  2275.         if (cx == XXLOOK && n == 0)
  2276.           printf(" Lookup: \"%s\" - not found\n",dscopy);
  2277.         else
  2278.           printf("%s %d network entr%s found for \"%s\"%s\n",
  2279.              cx == XXLOOK ? " Lookup:" : "",
  2280.              n,
  2281.              (n == 1) ? "y" : "ies",
  2282.              dscopy,
  2283.              (n > 0) ? ":" : "."
  2284.              );
  2285.  
  2286.         for (i = 0; i < n; i++) {
  2287.  
  2288.             printf("%3d. %-12s => %-9s %s",
  2289.                i+1,n_name,nh_p2[i],nh_p[i]);
  2290.             for (k = 0; k < 4; k++) {
  2291.             if (nh_px[k][i]) {
  2292.                 printf(" %s",nh_px[k][i]);
  2293.             } else
  2294.               break;
  2295.             }
  2296.             printf("\n");
  2297.         }
  2298.         }
  2299.     }
  2300. #endif /* NETCONN */
  2301. #endif /* NONET */
  2302.     if (cx == XXLOOK)
  2303.       return(success = lufound);
  2304.     } /* cx != XXANSW */
  2305.  
  2306. #ifdef VMS
  2307.     conres();            /* So Ctrl-C/Y will work */
  2308. #endif /* VMS */
  2309. /*
  2310.   Some modems do not react well to parity.  Also, if we are dialing through a
  2311.   TCP/IP TELNET modem server, parity can be fatally misinterpreted as TELNET
  2312.   negotiations.
  2313.  
  2314.   This should work even if the user interrupts the DIAL command, because the
  2315.   DIAL module has its own interrupt handler.  BUT... if, for some reason, a
  2316.   dialing device actually *requires* parity (e.g. CCITT V.25bis says that even
  2317.   parity should be used), this might prevent successful dialing.  For that
  2318.   reason, we don't do this for V.25bis modems.
  2319. */
  2320.     sparity = parity;            /* Save current parity */
  2321.     if (dialcapas & CKD_V25 == 0)    /* If not V.25bis...  */
  2322.       parity = 0;            /* Set parity to NONE */
  2323.  
  2324.     flowsave = flow;
  2325. /*
  2326.   These modems use some kind of screwy flow control while in command mode,
  2327.   and do not present CTS as they should.  So if RTS/CTS is set (or even if
  2328.   it isn't) disable flow control during dialing.
  2329. */
  2330. #ifndef MINIDIAL
  2331.     if (mdmtyp == n_ATT1910 || mdmtyp == n_ATT1900) {
  2332.     flow = FLO_NONE;        /* This is not enough */
  2333. #ifdef CK_TTSETFLOW
  2334.         ttsetflow(FLO_NONE);        /* Really turn it off */
  2335. #endif /* CK_TTSETFLOW */
  2336.     }
  2337. #endif /* MINIDIAL */
  2338.     if (!network) {
  2339.     if (flow == FLO_RTSC) {
  2340.         int x;
  2341.         if ((x = ttgmdm()) > -1) {
  2342.         if (!x) {
  2343.             printf(
  2344. "WARNING - No modem signals detected.  Is your modem is turned on?  If not,\n\
  2345. use Ctrl-C to interrupt dialing, turn on your modem, then %s.",
  2346.                cx == XXANSW ?
  2347.                "ANSWER again" :
  2348.                "REDIAL"
  2349.                );
  2350.         }
  2351.         if (!(x & BM_CTS)) {
  2352.             printf(
  2353. "WARNING - SET FLOW RTS/CTS is in effect but modem's CTS signal is off.\n\
  2354. Disabling flow control temporarily %s...\n",
  2355.                cx == XXANSW ?
  2356.                "while waiting for call" :
  2357.                "during dialing"
  2358.                );
  2359.             flow = FLO_NONE;
  2360.         }
  2361.         }
  2362.     }
  2363.     }
  2364.     if (cx == XXANSW) {            /* ANSWER */
  2365.     int x;
  2366.     success = ckdial("",0,0,1,0);
  2367.     goto dialfin;
  2368.     }
  2369.  
  2370. /* Edit 192 adds the ability to dial repeatedly. */
  2371.  
  2372.     i = 0;
  2373.     dialcount = 0;
  2374.     do {
  2375.     if (i > 0) printf("\nDial attempt %d of %d...\n", i+1, xretries);
  2376.     dialcount = i+1;
  2377.     success = 0;
  2378.     /* And the ability to dial alternate numbers. */
  2379.     /* Loop to dial each in a list of numbers for the same name... */
  2380.     for (j = 0; j < n && !success; j++) { /* until one answers. */
  2381.         s = dn_p2[j];        /* Next number in list */
  2382.         if (dn_x[j] >= dialrstr) {    /* Dial restriction */
  2383.         printf("Restricted: %s, skipping...\n",dn_p[j]);
  2384.         continue;
  2385.         }
  2386.         xredial = (i == 0 && j == 0) ? 0 : 1;
  2387.         if (!s) s = dn_p[j];
  2388.  
  2389. #ifndef NOSPL
  2390.         sav = s;
  2391.         p = xdial(s);        /* Apply DIAL macro now */
  2392.         if (p) s = p;
  2393. #endif /* NOSPL */
  2394.  
  2395.         if (i == 0 && dialcnf) {
  2396.         printf("Dialing %s\n",s);
  2397.         x = getyesno(" Is this number correct? ",0);
  2398.         if (!x) {
  2399.             char **p;
  2400. #ifdef CK_RECALL
  2401.             int sv_recall;
  2402.             extern int on_recall;
  2403. #endif /* CK_RECALL */
  2404.             cmsavp(psave,PROMPTL);
  2405.             cmsetp(
  2406. #ifdef OS2
  2407. " Please enter the correct number,\r\n or press Enter to skip: "
  2408. #else
  2409. " Please enter the correct number,\r\n or press Return to skip: "
  2410. #endif /* OS2 */
  2411.                );
  2412.             cmini(ckxech);
  2413.             x = -1;
  2414.             if (pflag) prompt(NULL);
  2415. #ifdef CK_RECALL
  2416.             sv_recall = on_recall;
  2417.             on_recall = 0;
  2418. #endif /* CK_RECALL */
  2419.             y = cmdgquo();
  2420.             cmdsquo(0);
  2421.             while (x < 0) {
  2422.             x = cmtxt("Corrected phone number","",&s,NULL);
  2423.             cmres();
  2424.             }
  2425.             if ((int) strlen(s) < 1) {
  2426.             cmsetp(psave);
  2427.             continue;
  2428.             }
  2429.             makestr(&(dn_p2[j]), s);
  2430.             cmdsquo(y);
  2431. #ifdef CK_RECALL
  2432.             on_recall = sv_recall;
  2433. #endif /* CK_RECALL */
  2434.             cmsetp(psave);
  2435.         }
  2436.         }
  2437.         if (dialtest) {        /* Just testing */
  2438.         if (i + j == 0)
  2439.           printf("\nTESTING...\n");
  2440.         if (dialmac)
  2441.           printf(" Number: \"%s\" => \"%s\"\n",sav,s);
  2442.         else
  2443.           printf(" Number: \"%s\"\n",s);
  2444.         dialsta = DIA_BUSY;
  2445.         success = 0;
  2446.         } else {
  2447.         what |= W_DIALING;
  2448.         success = ckdial(s,i,j,partial ? 3 : 0, xredial); /* Dial it */
  2449.         what &= ~(W_DIALING);
  2450.         if (!success) {
  2451.             if (dialsta < 8 ||    /* Break out if unrecoverable error */
  2452.             dialsta  == DIA_INTR ||
  2453.             dialsta  == DIA_ERR  ||
  2454.             previous == DIA_PART
  2455.             )
  2456.               break;
  2457.         }
  2458.         }
  2459.     }
  2460.     if (success)            /* Succeeded, leave the outer loop */
  2461.       break;
  2462.     if (dialsta < 8 ||        /* Break out if unrecoverable error */
  2463.         dialsta == DIA_INTR ||    /* Interrupted */
  2464.         dialsta == DIA_NODT ||    /* No dialtone */
  2465.         dialsta == DIA_NOAC ||    /* Access forbidden */
  2466.         dialsta == DIA_BLCK ||    /* Blacklisted */
  2467.         dialsta == DIA_DIR  ||    /* Dialing directory error */
  2468.         dialsta == DIA_ERR  ||    /* Modem command error */
  2469.         previous == DIA_PART)
  2470.       break;
  2471.     if (++i >= xretries)        /* Break out if too many tries */
  2472.       break;
  2473.     if (!backgrd && !quiet) {
  2474.         if (dialint > 5)
  2475.           printf(
  2476. "\nWill redial in %d second%s- press any key to redial immediately.\n",
  2477.              dialint,
  2478.              dialint == 1 ? " " : "s "
  2479.              );
  2480.         printf("Ctrl-C to cancel...\n");
  2481.     }
  2482.     x = dialint;            /* Redial interval */
  2483.     while (x-- > 0) {
  2484.         if ((y = conchk()) > 0) {    /* Did they type something? */
  2485.         while (y--) coninc(0);    /* Yes, absorb it */
  2486.         break;            /* And wake up */
  2487.         }
  2488.         sleep(1);            /* No interrupt, sleep a sec */
  2489.     }
  2490.     } while (!success);
  2491.  
  2492.   dialfin:
  2493.  
  2494.     if (cx != XXLOOK) {
  2495.     if (!success)
  2496.       bleep((short) BP_FAIL);
  2497.     else if (!quiet)
  2498.       bleep((short) BP_NOTE);
  2499. #ifdef OS2
  2500.     setint();            /* Fix OS/2 interrupts */
  2501. #endif /* OS2 */
  2502.     if (sparity > -1)
  2503.       parity = sparity;        /* Restore parity if we saved it */
  2504.     flow = flowsave;
  2505. #ifdef OS2
  2506.     ttres();            /* Restore DIAL device */
  2507. #endif /* OS2 */
  2508. #ifdef VMS
  2509.     concb((char)escape);        /* Restore console */
  2510. #endif /* VMS */
  2511. #ifdef OS2
  2512.     {                /* Set session title */
  2513.         char * p, name[72];        /* in window list. */
  2514.         char * q;
  2515.         if (cx == XXANSW) {
  2516.         q = "Incoming call";
  2517.         } else {
  2518.         if (d_name)
  2519.           q = d_name;
  2520.         else if (dialnum)
  2521.           q = dialnum;
  2522.         else if (ttname[0])
  2523.           q = ttname;
  2524.         else q = "";
  2525.         }
  2526.         p = name;
  2527.         if (success) {
  2528.         strncpy(name,q,48);
  2529.         while (*p) {        /* Uppercase it for emphasis. */
  2530.             if (islower(*p))
  2531.               *p = toupper(*p);
  2532.             p++;
  2533.         }
  2534.         } else
  2535.           name[0] = NUL ;
  2536.         os2settitle((char *) name, TRUE);
  2537.     }
  2538. #endif /* OS2 */
  2539.     }
  2540.     return(success);
  2541. }
  2542. #endif /* NODIAL */
  2543.  
  2544. /*  D O T Y P E  --  Type a file with various options...  */
  2545.  
  2546. #ifdef BIGBUFOK
  2547. #define TYPBUFL 16384
  2548. #else
  2549. #define TYPBUFL 256
  2550. #endif /* BIGBUFOK */
  2551.  
  2552. int typ_lines = 0;
  2553. int typ_mtchs = 0;
  2554.  
  2555. int
  2556. dotype(file, paging, first, head, pat, width, prefix)
  2557.     char * file, * pat, * prefix; int paging, first, head, width;
  2558. /* dotype */ {
  2559.     char buf[TYPBUFL+2];
  2560.     char * s = NULL;
  2561.     int rc = 1, lines = 0;
  2562.     char ** tail = NULL;
  2563.     int tailing = 0, counting = 0;
  2564.     int x, c, n, i, j, k = 0;
  2565.     int save, len, pfxlen = 0, evalpfx = 1;
  2566.  
  2567.     saveask = xaskmore;            /* Save more-prompting selection */
  2568.     save = binary;            /* Save file type */
  2569.  
  2570.     if (prefix)
  2571.       pfxlen = strlen(prefix);
  2572.  
  2573.     if (paging < 0) {            /* Count only, don't print */
  2574.     counting = 1;
  2575.     prefix = NULL;
  2576.     width = 0;
  2577.     paging = 0;
  2578.     }
  2579.  
  2580. #ifdef OS2
  2581.     if (*file) {
  2582.         ckstrncpy(buf, file, TYPBUFL);    /* Change / to \. */
  2583.         p = buf;
  2584.         while (*p) {
  2585.             if (*p == '/') *p = '\\';
  2586.             p++;
  2587.         }
  2588.     file = buf;
  2589.     } else {
  2590.     rc = 0;
  2591.     goto xdotype;
  2592.     }
  2593. #endif /* OS2 */
  2594.  
  2595.     if (zchki(file) == -2) {        /* It's a directory */
  2596.     debug(F111,"dotype zchki failure",file,-2);
  2597.     if (cmdsrc() == 0) {
  2598.         printf("?Not a regular file: \"%s\"\n",file);
  2599.         rc = -9;
  2600.     } else
  2601.       rc = 0;
  2602.     goto xdotype;
  2603.     }
  2604.     if (!zopeni(ZIFILE, file)) {    /* Not a directory, open it */
  2605.     debug(F111,"dotype zopeni failure",file,0);
  2606.     if (cmdsrc() == 0) {
  2607.         printf("?Can't open file: \"%s\"\n",file);
  2608.         rc = -9;
  2609.     } else
  2610.       rc = 0;
  2611.     goto xdotype;
  2612.     }
  2613.     xaskmore = paging;            /* This is vulnerable to ^C */
  2614.     binary = 0;                /* (fix later...) */
  2615.  
  2616.     /* mallocs in this routine are also vulnerable to Ctrl-C */
  2617.  
  2618.     if (head < 0) {            /* "tail" was requested */
  2619.     tailing = 1;            /* Set flag */
  2620.     head = 0 - head;        /* Get absolute number of lines */
  2621.     if (!counting) {
  2622.         tail = (char **) malloc(head * sizeof(char *)); /* Allocate list */
  2623.         for (i = 0; i < head; i++)    /* Initialize each pointer in list. */
  2624.           tail[i] = NULL;
  2625.     }
  2626.     }
  2627. #ifdef CK_TTGWSIZ
  2628. #ifdef OS2
  2629.     ttgcwsz();
  2630. #else /* OS2 */
  2631.     /* Check whether window size changed */
  2632.     if (ttgwsiz() > 0) {
  2633.         if (tt_rows > 0 && tt_cols > 0) {
  2634.             cmd_rows = tt_rows;
  2635.             cmd_cols = tt_cols;
  2636.         debug(F101,"dotype cmd_rows","",cmd_rows);
  2637.         debug(F101,"dotype cmd_cols","",cmd_cols);
  2638.         }
  2639.     }
  2640. #endif /* OS2 */
  2641. #endif /* CK_TTGWSIZ */
  2642.     typ_lines = 0;
  2643.     typ_mtchs = 0;
  2644.     for (n = first; zsinl(ZIFILE,(char *)buf,TYPBUFL) > -1; lines++) {
  2645.     typ_lines++;            /* For \v(ty_ln) */
  2646.     len = -1;
  2647.     if (pat)            /* Matching? */
  2648.       if (!ckmatch(pat,buf,1,1))    /* Line matches pattern? */
  2649.         continue;            /* No, skip it */
  2650.     typ_mtchs++;
  2651.  
  2652.     if (head > 0 && !tailing && lines == head) /* Handle /HEAD:n */
  2653.       break;
  2654.  
  2655.     buf[TYPBUFL+1] = NUL;        /* Just in case... */
  2656.     len = strlen(buf);
  2657.     if (prefix) {            /* Add specified prefix to each line */
  2658.         char pbuf[64];
  2659.         char * pp;
  2660.         pp = prefix;
  2661. #ifndef NOSPL
  2662.         if (evalpfx) {        /* Prefix is a variable? */
  2663.         int n = 63;        /* Maybe - evaluate it and see */
  2664.         char * p = pbuf;
  2665.         zzstring(prefix,&p,&n); /* If there is no change */
  2666.         if (!strcmp(prefix,line)) { /* it's not a variable */
  2667.             evalpfx = 0;    /* So don't do this again. */
  2668.         } else {        /* It was a variable */
  2669.             pp = pbuf;        /* So substitute its value */
  2670.             pfxlen = 63 - n;    /* and get its new length */
  2671.         }
  2672.         }
  2673. #endif /* NOSPL */
  2674.         if (len + pfxlen + 2 < TYPBUFL) {
  2675.         ckstrncpy(line,buf,LINBUFSIZ);
  2676.         sprintf(buf,"%s%s",pp,line);
  2677.         len += pfxlen;
  2678.         }
  2679.     }
  2680.     if (width > 0 && width <= TYPBUFL) { /* Truncate at given width. */
  2681.         char * obuf = line;        /* But to do that first we must */
  2682.         int i,k,z;            /* expand tabs; assume every 8 cols. */
  2683.         line[0] = NUL;
  2684.         for (i = 0, k = 0; i < width; k++) { /* Character loop... */
  2685.         if (!buf[k])        /* No more chars in this line, done. */
  2686.           break;
  2687.         if (buf[k] != '\t') {    /* If it's not a tab */
  2688.             if (i >= LINBUFSIZ)    /* Check for overflow */
  2689.               break;
  2690.             obuf[i++] = buf[k];    /* and then deposit it. */
  2691.             obuf[i] = NUL;    /* Keep it null-terminated */
  2692.             continue;
  2693.         }
  2694.         z = 8 - (i % 8);    /* It's a tab, expand it. */
  2695.         if (z == 0) z = 8;
  2696.         for (j = 0; j < z && i < LINBUFSIZ; j++)
  2697.           obuf[i++] = ' ';
  2698.         obuf[i] = NUL;
  2699.         }
  2700.         obuf[width] = NUL;        /* Now truncate at given width. */
  2701.         ckstrncpy(buf,obuf,TYPBUFL); /* and copy it back (again?) */
  2702.         len = (i > width) ? width : i; /* Spare us another strlen()... */
  2703.     }
  2704.     if (tailing) {            /* If /TAIL:n... */
  2705.         k = lines % head;        /* save this line in circular buffer */
  2706.         if (!counting)
  2707.           makestr(&(tail[k]),buf);    /* and go back for more. */
  2708.         continue;
  2709.     }
  2710.     if (counting)            /* If only counting */
  2711.       continue;            /* we're done with this line */
  2712.  
  2713.     if (paging) {            /* Displaying this line... */
  2714.         x = (len / cmd_cols) + 1;    /* Crudely allow for wrap */
  2715.         if (cmd_rows > 0 && cmd_cols > 0)
  2716.           n += x;            /* This assumes terminal will wrap */
  2717.     }
  2718.     printf("%s\n", buf);        /* Print this line */
  2719. #ifdef CK_TTGWSIZ
  2720.     if (paging > 0) {        /* Pause at end of screen */
  2721.         if (cmd_rows > 0 && cmd_cols > 0) {
  2722.         if (n > cmd_rows - 3) {
  2723.             if (!askmore())
  2724.               goto xdotype;
  2725.             else
  2726.               n = 0;
  2727.         }
  2728.         }
  2729.     }
  2730. #endif /* CK_TTGWSIZ */
  2731.     }
  2732.  
  2733.   xdotype:
  2734.     x = zclose(ZIFILE);            /* Done, close the file */
  2735.     if (counting) {
  2736.     printf("%s: %d line%s\n",file,typ_lines,typ_lines == 1 ? "" : "s");
  2737.     if (pat)
  2738.       printf("%s: %d match%s\n",pat,typ_mtchs,typ_mtchs == 1 ? "" : "es");
  2739.     goto xxdotype;
  2740.     }
  2741.     if (tailing && tail) {        /* Typing tail of file? */
  2742.     if (lines < head) {        /* Yes, show the lines we saved */
  2743.         k = 0;            /* Show all lines */
  2744.     } else {            /* More lines than tail number */
  2745.         lines = k;            /* Last line to show */
  2746.         k++;            /* First line to show */
  2747.         if (k >= head)
  2748.           k = 0;
  2749.     }
  2750.     n = first;            /* Output line counter */
  2751.     for (i = k ;; i++) {        /* Loop thru circular buffer */
  2752.         j = i % head;        /* Index of this line */
  2753.         s = tail[j];        /* Point to line to display */
  2754.         if (!s)            /* (shouldn't happen...) */
  2755.           break;
  2756.         if (paging) {        /* Crudely allow for line wrap */
  2757.         x = ((int)strlen(s) / cmd_cols) + 1;
  2758.         if (cmd_rows > 0 && cmd_cols > 0)
  2759.           n += x;
  2760.         }
  2761.         printf("%s\n", s);        /* Display this line */
  2762.         if (paging) {        /* Pause at end of screen */
  2763.         if (cmd_rows > 0 && cmd_cols > 0) {
  2764.             if (n > cmd_rows - 3) {
  2765.             if (!askmore())
  2766.               break;
  2767.             else
  2768.               n = 0;
  2769.             }
  2770.         }
  2771.         }
  2772.         free(s);            /* Free the line */
  2773.         if (i % head == lines)    /* When to stop */
  2774.           break;
  2775.     }
  2776.     free(tail);            /* Free the list */
  2777.     }
  2778.  
  2779.   xxdotype:
  2780.     binary = save;            /* Restore text/binary mode */
  2781.     xaskmore = saveask;            /* Restore more-prompting */
  2782.     saveask = -1;
  2783.     return(rc);
  2784. }
  2785.  
  2786. /* System-independent directory */
  2787.  
  2788. static char ** dirlist = NULL;
  2789. static int ndirlist = 0;
  2790.  
  2791. static VOID
  2792. freedirlist() {
  2793.     if (dirlist) {
  2794.     int i;
  2795.     for (i = 0; i < ndirlist; i++) {
  2796.         if (dirlist[i])
  2797.           free(dirlist[i]);
  2798.     }
  2799.     free(dirlist);
  2800.     dirlist = NULL;
  2801.     }
  2802.     ndirlist = 0;
  2803. }
  2804.  
  2805. static struct keytab dirswtab[] = {    /* DIRECTORY command switches */
  2806.     "/after",       DIR_AFT, CM_ARG,
  2807.     "/all",         DIR_ALL, 0,
  2808. #ifndef NOSPL
  2809.     "/array",       DIR_ARR, CM_ARG,
  2810. #endif /* NOSPL */
  2811.     "/ascending",   DIR_ASC, 0,
  2812.     "/backup",      DIR_BUP, 0,
  2813.     "/before",      DIR_BEF, CM_ARG,
  2814.     "/brief",       DIR_BRF, 0,
  2815.     "/descending",  DIR_DSC, CM_INV,
  2816.     "/directories", DIR_DIR, 0,
  2817.     "/dotfiles",    DIR_DOT, 0,
  2818.     "/englishdate", DIR_DAT, 0,
  2819.     "/except",      DIR_EXC, CM_ARG,
  2820.     "/files",       DIR_FIL, 0,
  2821.     "/heading",     DIR_HDG, 0,
  2822.     "/isodate",     DIR_ISO, 0,
  2823.     "/larger-than", DIR_LAR, CM_ARG,
  2824.     "/message",     DIR_MSG, CM_ARG,
  2825.     "/nobackup",    DIR_NOB, 0,
  2826.     "/nodotfiles",  DIR_NOD, 0,
  2827.     "/noheading",   DIR_NOH, 0,
  2828.     "/nomessage",   DIR_NOM, 0,
  2829. #ifdef CK_TTGWSIZ
  2830.     "/nopage",      DIR_NOP, 0,
  2831. #endif /* CK_TTGWSIZ */
  2832. #ifdef RECURSIVE
  2833.     "/norecursive", DIR_NOR, 0,
  2834. #else
  2835. #ifdef VMS
  2836.     "/norecursive", DIR_NOR, 0,
  2837. #else
  2838. #ifdef datageneral
  2839.     "/norecursive", DIR_NOR, 0,
  2840. #endif /* datageneral */
  2841. #endif /* VMS */
  2842. #endif /* RECURSIVE */
  2843.     "/nosort",      DIR_NOS, 0,
  2844.     "/not-after",   DIR_NAF, CM_ARG,
  2845.     "/not-before",  DIR_NBF, CM_ARG,
  2846.     "/not-since",   DIR_NAF, CM_INV|CM_ARG,
  2847. #ifdef PATTERNS
  2848.     "/noxfermode",  DIR_NOT, 0,
  2849. #endif /* PATTERNS */
  2850. #ifdef CK_TTGWSIZ
  2851.     "/page",        DIR_PAG, 0,
  2852. #endif /* CK_TTGWSIZ */
  2853. #ifdef RECURSIVE
  2854.     "/recursive",   DIR_REC, 0,
  2855. #else
  2856. #ifdef VMS
  2857.     "/recursive",   DIR_REC, 0,
  2858. #else
  2859. #ifdef datageneral
  2860.     "/recursive",   DIR_REC, 0,
  2861. #endif /* datageneral */
  2862. #endif /* VMS */
  2863. #endif /* RECURSIVE */
  2864.     "/reverse",     DIR_DSC, 0,
  2865.     "/since",       DIR_AFT, CM_ARG|CM_INV,
  2866.     "/smaller-than",DIR_SMA, CM_ARG,
  2867.     "/sort",        DIR_SRT, CM_ARG,
  2868. #ifdef PATTERNS
  2869.     "/xfermode",    DIR_TYP, 0,
  2870. #endif /* PATTERNS */
  2871.     "/verbose",     DIR_VRB, 0,
  2872.     "",0,0
  2873. };
  2874. static int ndirswtab = (sizeof(dirswtab) / sizeof(struct keytab)) - 1;
  2875.  
  2876. static struct keytab dirsort[] = {    /* DIRECTORY /SORT: options */
  2877.     "date",         DIRS_DT, 0,
  2878.     "name",         DIRS_NM, 0,
  2879.     "size",         DIRS_SZ, 0
  2880. };
  2881. static int ndirsort = (sizeof(dirsort) / sizeof(struct keytab));
  2882.  
  2883. static int dir_date = -1;        /* Option defaults (-1 means none) */
  2884. static int dir_page = -1;
  2885. static int dir_verb =  1;
  2886. static int dir_msg  = -1;
  2887. #ifdef VMS
  2888. static int dir_sort = -1;        /* Names are already sorted in VMS */
  2889. static int dir_rvrs = -1;
  2890. #else
  2891. static int dir_sort =  1;        /* Sort by default */
  2892. static int dir_rvrs =  0;        /* Not in reverse */
  2893. #endif /* VMS */
  2894. static int dir_skey = DIRS_NM;        /* By name */
  2895. #ifdef RECURSIVE
  2896. static int dir_recu = -1;
  2897. #endif /* RECURSIVE */
  2898. static int dir_mode = -1;
  2899. static int dir_show = -1;        /* Show all files by default */
  2900. int dir_dots =  0;            /* Except dot files */
  2901. int dir_back =  1;
  2902. int dir_head =  0;
  2903. static char * dirmsg = NULL;
  2904. static int dirmsglen = 0;
  2905.  
  2906. #ifndef NOSHOW
  2907. VOID
  2908. showdiropts() {
  2909.     int x = 0;
  2910.     extern int optlines;
  2911.     prtopt(&optlines,"DIRECTORY");
  2912.     if (dir_show > 0) {
  2913.     prtopt(&optlines,(dir_show == 1) ? "/FILES" :
  2914.            ((dir_show == 2) ? "/DIRECTORIES" : "/ALL"));
  2915.     x++;
  2916.     } else {
  2917.     prtopt(&optlines,"/ALL");
  2918.     x++;
  2919.     }
  2920.     if (dir_verb > -1) {
  2921.     prtopt(&optlines,dir_verb ? "/VERBOSE" : "/BRIEF");
  2922.     x++;
  2923.     }
  2924.     if (dir_page > -1) {
  2925.     prtopt(&optlines,dir_page ? "/PAGE" : "/NOPAGE");
  2926.     x++;
  2927.     }
  2928.     if (dir_date > -1) {
  2929.     prtopt(&optlines,dir_date ? "/ENGLISHDATE" : "/ISODATE");
  2930.     x++;
  2931.     }
  2932.     if (dir_dots > -1) {
  2933.     prtopt(&optlines,dir_dots ? "/DOTFILES" : "/NODOTFILES");
  2934.     x++;
  2935.     }
  2936.     if (dir_back > -1) {
  2937.     prtopt(&optlines,dir_back ? "/BACKUP" : "/NOBACKUP");
  2938.     x++;
  2939.     }
  2940.     if (dir_head > -1) {
  2941.     prtopt(&optlines,dir_head ? "/HEADING" : "/NOHEADING");
  2942.     x++;
  2943.     }
  2944. #ifdef RECURSIVE
  2945.     if (dir_recu > -1) {
  2946.     prtopt(&optlines,dir_recu ? "/RECURSIVE" : "/NORECURSIVE");
  2947.     x++;
  2948.     }
  2949. #endif /* RECURSIVE */
  2950.     if (dir_mode > -1) {
  2951.     prtopt(&optlines,dir_mode ? "/XFERMODE" : "/NOXFERMODE");
  2952.     x++;
  2953.     }
  2954.     if (dir_sort == 0) {
  2955.     x++;
  2956.     prtopt(&optlines,"/NOSORT ");
  2957.     } else if (dir_sort > 0) {
  2958.     x++;
  2959.     if (dir_skey == DIRS_NM) s = "/SORT:NAME";
  2960.     else if (dir_skey == DIRS_SZ) s = "/SORT:SIZE";
  2961.     else if (dir_skey == DIRS_DT) s = "/SORT:DATE";
  2962.     prtopt(&optlines,s);
  2963.     }
  2964.     if (dir_rvrs > -1) {
  2965.     prtopt(&optlines,dir_rvrs ? "/REVERSE" : "/ASCENDING");
  2966.     x++;
  2967.     }
  2968.     if (dir_msg > -1) {
  2969.     if (dir_msg == 0) {
  2970.         prtopt(&optlines,"/NOMESSAGE");
  2971.     } else {
  2972.         sprintf(tmpbuf,"/MESSAGE:{%s}", dirmsg);
  2973.         prtopt(&optlines,tmpbuf);
  2974.     }
  2975.     x++;
  2976.     }
  2977.     if (!x) prtopt(&optlines,"(no options set)");
  2978.     prtopt(&optlines,"");
  2979. }
  2980. #endif /* NOSHOW */
  2981.  
  2982. int
  2983. setdiropts() {                /* Set DIRECTORY option defaults */
  2984.     int xb = -1, xv = -1, xp = -1, xd = -1, xh = -1, xf = -1;
  2985.     int xk = -1, xr = -1, xs = -1, xx = -1, xm = -1, xa = -1, xg = -1;
  2986.     int getval;
  2987.     char c;
  2988.     while (1) {
  2989.     if ((y = cmswi(dirswtab,ndirswtab,"Switch","",xxstring)) < 0) {
  2990.         if (y == -3)
  2991.           break;
  2992.         else
  2993.           return(y);
  2994.     }
  2995.     c = cmgbrk();
  2996.     if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
  2997.         printf("?This switch does not take an argument\n");
  2998.         return(-9);
  2999.     }
  3000.     if (!getval && (cmgkwflgs() & CM_ARG)) {
  3001.         printf("?This switch requires an argument\n");
  3002.         return(-9);
  3003.     }
  3004.     switch (y) {
  3005.       case DIR_BRF: xv = 0; break;
  3006.       case DIR_VRB: xv = 1; break;
  3007.       case DIR_PAG: xp = 1; break;
  3008.       case DIR_NOP: xp = 0; break;
  3009.       case DIR_ISO: xd = 0; break;
  3010.       case DIR_DAT: xd = 1; break;
  3011.       case DIR_HDG: xh = 1; break;
  3012.       case DIR_NOH: xh = 0; break;
  3013.       case DIR_DOT: xf = 1; break;
  3014.       case DIR_NOD: xf = 0; break;
  3015.       case DIR_ALL: xa = 3; break;
  3016.       case DIR_DIR: xa = 2; break;
  3017.       case DIR_FIL: xa = 1; break;
  3018.       case DIR_SRT:
  3019.         x = DIRS_NM;
  3020.         if (getval)
  3021.           if ((x = cmkey(dirsort,ndirsort,"Sort key","name",xxstring)) < 0)
  3022.         return(x);
  3023.         xk = x;
  3024.         xs = 1;
  3025.         break;
  3026.       case DIR_NOS: xs = 0; break;
  3027.       case DIR_ASC: xx = 0; break;
  3028.       case DIR_DSC: xx = 1; break;
  3029.       case DIR_REC: xr = 1; break;
  3030.       case DIR_NOR: xr = 0; break;
  3031.       case DIR_TYP: xm = 1; break;
  3032.       case DIR_NOT: xm = 0; break;
  3033.       case DIR_BUP: xb = 1; break;
  3034.       case DIR_NOB: xb = 0; break;
  3035.       case DIR_NOM: xg = 0; break;
  3036.       case DIR_MSG:
  3037.         if (getval)
  3038.           if ((x = cmfld("Message to append to each line",
  3039.                  "",
  3040.                  &s,
  3041.                  xxstring
  3042.                  )) < 0)
  3043.         return(x);
  3044.         xg = 1;
  3045.         ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
  3046.         break;
  3047.       default:
  3048.         printf("?This option can not be set\n");
  3049.         return(-9);
  3050.     }
  3051.     }
  3052.     if ((x = cmcfm()) < 0)        /* Get confirmation */
  3053.       return(x);
  3054.     if (xv > -1) dir_verb = xv;        /* Confirmed, save defaults */
  3055.     if (xp > -1) dir_page = xp;
  3056.     if (xd > -1) dir_date = xd;
  3057.     if (xh > -1) dir_head = xh;
  3058.     if (xs > -1) dir_sort = xs;
  3059.     if (xk > -1) dir_skey = xk;
  3060.     if (xx > -1) dir_rvrs = xx;
  3061.     if (xf > -1) dir_dots = xf;
  3062.     if (xa > -1) dir_show = xa;
  3063.     if (xm > -1) dir_mode = xm;
  3064.     if (xb > -1) dir_back = xb;
  3065. #ifdef RECURSIVE
  3066.     if (xr > -1) dir_recu = xr;
  3067. #endif /* RECURSIVE */
  3068.     if (xg > -1) dir_msg  = xg;
  3069.     if (xg > 0)
  3070.       makestr(&dirmsg,tmpbuf);
  3071.     return(success = 1);
  3072. }
  3073.  
  3074. int
  3075. domydir() {                /* Internal DIRECTORY command */
  3076. #ifdef VMSORUNIX
  3077.     extern int zgfs_dir, zgfs_link;
  3078. #endif /* VMSORUNIX */
  3079.     extern char *months[];
  3080.     extern int diractive;
  3081.     extern int recursive;
  3082. #ifdef VMS
  3083.     _PROTOTYP( char * zrelname, (char *,char *) );
  3084.     char * cdp = NULL;
  3085. #endif /* VMS */
  3086.  
  3087.     char name[CKMAXPATH+1], *p = NULL, c = NUL;
  3088.     char linebuf[CKMAXPATH+64];
  3089.     char * mstr = NULL, * dstr = NULL, * s2 = NULL;
  3090.     long len = 0, ndirs = 0, nfiles = 0, nbytes = 0, nmatches = 0;
  3091.     int verbose = 0, wild = 0, page = 0, n = 0, engdate;
  3092.     int heading = 0, xsort = 0, reverse = 0, sortby = 0, msg = 0;
  3093.     int k, i = 0, x = 0, nx = 0, skey = 0, dlen = 0, itsadir = 0;
  3094.     int show = 3, xfermod = 0, backup = 1, rc = 0, getval = 0;
  3095.     int fs = 0;
  3096.     long minsize = -1L, maxsize = -1L;
  3097.     struct FDB sw, fi, fl;
  3098.     char dbuf[24];
  3099. #ifndef NOSPL
  3100.     char array = NUL;
  3101.     char ** ap = NULL;
  3102. #endif /* NOSPL */
  3103.     char
  3104.       * dir_aft = NULL,
  3105.       * dir_bef = NULL,
  3106.       * dir_naf = NULL,
  3107.       * dir_nbf = NULL,
  3108.       * dir_exc = NULL;
  3109.     char * xlist[8];
  3110.  
  3111.     g_matchdot = matchdot;
  3112.  
  3113.     for (i = 0; i < 8; i++) xlist[i] = NULL;
  3114.  
  3115.     name[0] = NUL;
  3116.     freedirlist();            /* In case not freed last time */
  3117.     saveask   = xaskmore;        /* Save more-prompting selection */
  3118.     page      = dir_page > -1 ? dir_page : xaskmore; /* Set option defaults */
  3119.     engdate   = dir_date > -1 ? dir_date : 0;
  3120.     verbose   = dir_verb > -1 ? dir_verb : 1;
  3121.     heading   = dir_head > -1 ? dir_head : 0;
  3122.     xsort     = dir_sort > -1 ? dir_sort : 0;
  3123.     sortby    = dir_skey > -1 ? dir_skey : 0;
  3124.     reverse   = dir_rvrs > -1 ? dir_rvrs : 0;
  3125.     msg       = dir_msg  > -1 ? dir_msg  : 0;
  3126. #ifdef UNIXOROSK
  3127.     matchdot  = dir_dots > -1 ? dir_dots : 0;
  3128. #endif /* UNIXOROSK */
  3129.     xfermod   = dir_mode > -1 ? dir_mode : 0;
  3130.     backup    = dir_back > -1 ? dir_back : 1;
  3131. #ifdef RECURSIVE
  3132.     recursive = dir_recu > -1 ? dir_recu : 0;
  3133. #endif /* RECURSIVE */
  3134.     show      = dir_show > -1 ? dir_show : 3;
  3135.  
  3136. #ifdef CK_TTGWSIZ
  3137. #ifdef OS2
  3138.     ttgcwsz();                /* Screen length for more-prompting */
  3139. #else /* OS2 */
  3140.     /* Check whether window size changed */
  3141.     if (ttgwsiz() > 0) {
  3142.         if (tt_rows > 0 && tt_cols > 0) {
  3143.             cmd_rows = tt_rows;
  3144.             cmd_cols = tt_cols;
  3145.         }
  3146.     }
  3147. #endif /* OS2 */
  3148. #endif /* CK_TTGWSIZ */
  3149.  
  3150.     diractive = 1;
  3151.  
  3152.     cmfdbi(&sw,                /* First FDB - command switches */
  3153.        _CMKEY,            /* fcode */
  3154.        "File specification;\n or switch",
  3155.        "",                /* default */
  3156.        "",                /* addtl string data */
  3157.        ndirswtab,            /* addtl numeric data 1: tbl size */
  3158.        4,                /* addtl numeric data 2: 4 = cmswi */
  3159.        xxstring,            /* Processing function */
  3160.        dirswtab,            /* Keyword table */
  3161.        &fi                /* Pointer to next FDB */
  3162.        );
  3163.     cmfdbi(&fi,                /* 2nd FDB - file to delete */
  3164.        _CMIFI,            /* fcode */
  3165.        "File specification",    /* hlpmsg */
  3166. #ifdef datageneral
  3167.        "+",                /* Default filespec is wildcard */
  3168. #else                    /* that matches all files... */
  3169. #ifdef VMS
  3170.        "*.*",
  3171. #else
  3172.        "*",
  3173. #endif /* VMS */
  3174. #endif /* datageneral */
  3175.        "",                /* addtl string data */
  3176.        1,                /* 0 = files only; 1 = files or dirs */
  3177.        0,                /* 1 = only dirs; 0 files or dirs */
  3178.        xxstring,
  3179.        NULL,
  3180.        &fl
  3181.        );
  3182.     cmfdbi(&fl,                /* Anything that doesn't match */
  3183.        _CMFLD,            /* fcode */
  3184.        "",                /* hlpmsg */
  3185.        "",                /* default */
  3186.        "",                /* addtl string data */
  3187.        0,                /* addtl numeric data 1 */
  3188.        0,                /* addtl numeric data 2 */
  3189.        xxstring,
  3190.        NULL,
  3191.        NULL
  3192.        );
  3193.     while (1) {                /* Parse 0 or more switches */
  3194.     x = cmfdb(&sw);            /* Parse something */
  3195.     debug(F101,"domydir cmfdb","",x);
  3196.     if (x < 0)
  3197.       return(x);
  3198.     if (cmresult.fcode != _CMKEY)    /* Break out if not a switch */
  3199.       break;
  3200.     c = cmgbrk();
  3201.     if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
  3202.         printf("?This switch does not take an argument\n");
  3203.         return(-9);
  3204.     }
  3205.     if (!getval && (cmgkwflgs() & CM_ARG)) {
  3206.         printf("?This switch requires an argument\n");
  3207.         return(-9);
  3208.     }
  3209.     switch (k = cmresult.nresult) {
  3210.       case DIR_BRF: verbose = 0; break;
  3211.       case DIR_VRB: verbose = 1; break;
  3212. #ifdef CK_TTGWSIZ
  3213.       case DIR_PAG: page = 1;    break;
  3214.       case DIR_NOP: page = 0;    break;
  3215. #endif /* CK_TTGWSIZ */
  3216.           case DIR_ISO: engdate = 0; break;
  3217.       case DIR_DAT: engdate = 1; break;
  3218.       case DIR_HDG: heading = 1; break;
  3219.           case DIR_NOH: heading = 0; break;
  3220. #ifdef UNIXOROSK
  3221.       case DIR_DOT: matchdot = 1; break;
  3222.           case DIR_NOD: matchdot = 0; break;
  3223. #endif /* UNIXOROSK */
  3224.       case DIR_ALL:
  3225.         show = 3;
  3226.         cmfdbi(&fi,
  3227.            _CMIFI,
  3228.            "File specification",
  3229. #ifdef datageneral
  3230.            "+",
  3231. #else
  3232. #ifdef VMS
  3233.            "*.*",
  3234. #else
  3235.            "*",
  3236. #endif /* VMS */
  3237. #endif /* datageneral */
  3238.            "",
  3239.            1,            /* Match files */
  3240.            0,            /* or directories */
  3241.            xxstring,
  3242.            NULL,
  3243.            &fl
  3244.            );
  3245.         break;
  3246.       case DIR_DIR:
  3247.         show = 2;
  3248.         cmfdbi(&fi,
  3249.            _CMIFI,
  3250.            "File specification",
  3251. #ifdef datageneral
  3252.            "+",
  3253. #else
  3254. #ifdef VMS
  3255.            "*.*",
  3256. #else
  3257.            "*",
  3258. #endif /* VMS */
  3259. #endif /* datageneral */
  3260.            "",
  3261.            1,            /* Match only */
  3262.            1,            /* directories */
  3263.            xxstring,
  3264.            NULL,
  3265.            &fl
  3266.            );
  3267.         break;
  3268.       case DIR_FIL:
  3269.         show = 1;
  3270.         cmfdbi(&fi,
  3271.            _CMIFI,
  3272.            "File specification",
  3273. #ifdef datageneral
  3274.            "+",
  3275. #else
  3276. #ifdef VMS
  3277.            "*.*",
  3278. #else
  3279.            "*",
  3280. #endif /* VMS */
  3281. #endif /* datageneral */
  3282.            "",
  3283.            0,            /* Match only */
  3284.            0,            /* files */
  3285.            xxstring,
  3286.            NULL,
  3287.            &fl
  3288.            );
  3289.         break;
  3290.           case DIR_SRT:
  3291.         x = DIRS_NM;
  3292.         if (c == ':' || c == '=')
  3293.           if ((x = cmkey(dirsort,ndirsort,"Sort key","name",xxstring)) < 0)
  3294.         return(x);
  3295.         xsort = 1;
  3296.         sortby = x;
  3297.         break;
  3298.  
  3299.       case DIR_BUP: backup  = 1; fs++;   break;
  3300.       case DIR_NOB: backup  = 0; fs++;   break;
  3301.  
  3302.           case DIR_NOS: xsort = 0;     break;
  3303.       case DIR_ASC: reverse = 0;   break;
  3304.       case DIR_DSC: reverse = 1;   break;
  3305. #ifdef RECURSIVE
  3306.       case DIR_REC: recursive = 1; break;
  3307.       case DIR_NOR: recursive = 0; break;
  3308. #endif /* RECURSIVE */
  3309.       case DIR_TYP: xfermod = 1;   break;
  3310.       case DIR_NOT: xfermod = 0;   break;
  3311.       case DIR_NOM: msg     = 0;   break;
  3312.       case DIR_MSG:
  3313.         if (c == ':' || c == '=')
  3314.           if ((x = cmfld("Message to append to each line",
  3315.                  "",
  3316.                  &s,
  3317.                  xxstring
  3318.                  )) < 0)
  3319.         return(x);
  3320.         msg = 1;
  3321.         ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
  3322.         break;
  3323.  
  3324.       case DIR_SMA:
  3325.       case DIR_LAR:
  3326.         if (!getval) break;
  3327.         if ((x = cmnum("File size in bytes","0",10,&y,xxstring)) < 0)
  3328.           return(x);
  3329.         fs++;
  3330.         show = 1;
  3331.         switch (cmresult.nresult) {
  3332.           case DIR_SMA: minsize = y; break;
  3333.           case DIR_LAR: maxsize = y; break;
  3334.         }
  3335.         break;
  3336.  
  3337. #ifndef NOSPL
  3338.       case DIR_ARR:
  3339.         if (c != ':' && c != '=') {
  3340.         printf("?Array name required\n");
  3341.         return(-9);
  3342.         }
  3343.         if ((x = cmfld("Array name (a single letter will do)",
  3344.                "",
  3345.                &s,
  3346.                NULL
  3347.                )) < 0) {
  3348.         if (x == -3) {
  3349.             printf("?Array name required\n");
  3350.             return(-9);
  3351.         } else
  3352.           return(x);
  3353.         }
  3354.         if (!*s) {
  3355.         printf("?Array name required\n");
  3356.         return(-9);
  3357.         }
  3358.         s2 = s;
  3359.         if (*s == CMDQ) s++;
  3360.         if (*s == '&') s++;
  3361.         if (!isalpha(*s)) {
  3362.         printf("?Bad array name - \"%s\"\n",s2);
  3363.         return(-9);
  3364.         }
  3365.         array = *s++;
  3366.         if (isupper(array)) array = tolower(array);
  3367.         if (*s && (*s != '[' || *(s+1) != ']')) {
  3368.         printf("?Bad array name - \"%s\"\n",s2);
  3369.         return(-9);
  3370.         }
  3371.         break;
  3372. #endif /* NOSPL */
  3373.       case DIR_AFT:
  3374.       case DIR_BEF:
  3375.       case DIR_NAF:
  3376.       case DIR_NBF:
  3377.         if (!getval) break;
  3378.         if ((x = cmdate("File-time","",&s,0,xxstring)) < 0) {
  3379.         if (x == -3) {
  3380.             printf("?Date-time required\n");
  3381.             rc = -9;
  3382.         } else
  3383.           rc = x;
  3384.         goto xdomydir;
  3385.         }
  3386.         fs++;
  3387.         switch (k) {
  3388.           case DIR_AFT: makestr(&dir_aft,s); break;
  3389.           case DIR_BEF: makestr(&dir_bef,s); break;
  3390.           case DIR_NAF: makestr(&dir_naf,s); break;
  3391.           case DIR_NBF: makestr(&dir_nbf,s); break;
  3392.         }
  3393.         break;
  3394.       case DIR_EXC:
  3395.         if (!getval) break;
  3396.         if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
  3397.         if (x == -3) {
  3398.             printf("?Pattern required\n");
  3399.             rc = -9;
  3400.         } else
  3401.           rc = x;
  3402.         goto xdomydir;
  3403.         }
  3404.         fs++;
  3405.         makestr(&dir_exc,s);
  3406.         break;
  3407.  
  3408.       default:
  3409.         printf("?Sorry, not implemented yet - \"%s\"\n", atmbuf);
  3410.         goto xdomydir;
  3411.     }
  3412.     }
  3413.     ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Safe copy of filespec */
  3414.     s = line;
  3415.     if ((x = cmcfm()) < 0)        /* Get confirmation */
  3416.       return(x);
  3417.     if (cmresult.fcode != _CMIFI) {    /* Nothing matched */
  3418.     char * m;
  3419.     if (*s == '/')
  3420. #ifdef UNIXOROSK
  3421.       m = "does not match switch or name of accessible file";
  3422. #else
  3423. #ifdef OS2
  3424.       m = "does not match switch or name of accessible file";
  3425. #else
  3426.       m = "no switches match";
  3427. #endif /* OS2 */
  3428. #endif /* UNIXOROSX */
  3429.     else
  3430.       m = "not found or not accessible";
  3431.     printf("\"%s\" - %s\n",s,m);
  3432.     rc = -9;
  3433.     goto xdomydir;
  3434.     }
  3435.     wild = cmresult.nresult;        /* Wildcard was given? */
  3436.     debug(F111,"domydir cmifi2",s,wild);
  3437.  
  3438. #ifdef OS2
  3439.     if (!wild) {
  3440.     if (zchki(s) == -2) {        /* Found a directory */
  3441.         p = s + (int)strlen(s) - 1;    /* Yes */
  3442.         if (*p == '\\' || *p == '/')
  3443.           strcat(s, "*");
  3444.         else if (*p == ':')
  3445.           strcat(s, "./*");
  3446.         else
  3447.           strcat(s, "/*");
  3448.         wild = 1;            /* Now it's wild */
  3449.     }
  3450.     }
  3451. #else
  3452.     if (!wild) if (isdir(s)) {        /* Is it a directory? */
  3453.     p = s + (int)strlen(s) - 1;    /* Yes */
  3454. #ifdef VMS
  3455.     {
  3456.         /* Convert from FOO.DIR;1 to [x.FOO] if necessary */
  3457.         char buf[CKMAXPATH+1];
  3458.         debug(F000,"domydir directory 0",s,*p);
  3459.         if (cvtdir(s,buf) > 0)
  3460.           ckstrncpy(line,buf,LINBUFSIZ);
  3461.     }
  3462. #endif /* VMS */
  3463.     debug(F000,"domydir directory 1",s,*p);
  3464. #ifdef VMS
  3465.     if (*p == ']' || *p == '>' || *p == ':')
  3466.       strcat(s, "*.*");
  3467. #else
  3468. #ifdef datageneral
  3469.     if (*p == ':')
  3470.       strcat(s, "+");
  3471.     else
  3472.       strcat(s, ":+");
  3473. #else
  3474. #ifdef VOS
  3475.     if (*p == '>')
  3476.       strcat(s, "*");
  3477.     else
  3478.       strcat(s, ">*");
  3479. #endif /* VOS */
  3480. #endif /* datageneral */
  3481. #endif /* VMS */
  3482.     wild = 1;            /* Now it's wild */
  3483.     debug(F000,"domydir directory 2",s,*p);
  3484.     }
  3485. #endif /* OS2 */
  3486.  
  3487. #ifdef ZXREWIND
  3488. /* cmifi() already called nzxpand so we can just re-use the same list. */
  3489.     x = zxrewind();            /* Rewind the list */
  3490.     debug(F111,"domydir zxrewind",s,x);
  3491. #else
  3492.     nzxopts = (show == ZX_DIRONLY) ? ZX_DIRONLY :
  3493.       (show == ZX_FILONLY ? ZX_FILONLY : 0);
  3494.     if (matchdot)  nzxopts |= ZX_MATCHDOT;
  3495.     if (recursive) nzxopts |= ZX_RECURSE;
  3496.     x = nzxpand(s,nzxopts);        /* Expand file list */
  3497.     debug(F111,"domydir nzxpand",s,x);
  3498. #endif /* ZXREWIND */
  3499. #ifndef NOSPL
  3500.     if (array) {
  3501.     int n, xx;
  3502.     n = (x < 0) ? 0 : x;
  3503.     if ((xx = dclarray(array,n)) < 0) {
  3504.         printf("?Array declaration failure\n");
  3505.         rc = -9;
  3506.         goto xdomydir;
  3507.     }
  3508.     array = xx;
  3509.     ap = a_ptr[array];
  3510.     if (n < 1) {
  3511.         rc = 0;
  3512.         goto xdomydir;
  3513.     }
  3514.     } else
  3515. #endif /* NOSPL */
  3516.       if (x < 1) {
  3517.     if (x == 0 && isdir(s))
  3518.       printf("?Empty directory - \"%s\"\n", s);
  3519.     else
  3520.       printf("?%s %s match - \"%s\"\n",
  3521.          (x == 0) ? "No" : "Too many",
  3522.          (show == 2) ? "directories" : "files",
  3523.          s
  3524.          );
  3525.     rc = -9;
  3526.     goto xdomydir;
  3527.     }
  3528.     nx = x;                /* Remember how many files */
  3529.  
  3530.     if (msg) {
  3531.     makestr(&dirmsg,tmpbuf);
  3532.     dirmsglen = strlen(tmpbuf);
  3533.     }
  3534.  
  3535. #ifdef VMS
  3536.     cdp = zgtdir();            /* Get current directory */
  3537.     debug(F110,"domydir VMS zgtdir",cdp,0);
  3538. #endif /* VMS */
  3539.  
  3540.     if (xsort && verbose) {        /* If sorting, allocate space */
  3541.     if (!(dirlist = (char **) malloc((x + 1) * sizeof(char **)))) {
  3542.         if (!quiet) {
  3543.         printf("* Warning: Failure to allocate memory for sorting.\n");
  3544.         printf("* Will proceed without sorting...\n");
  3545.         }
  3546.         xsort = 0;
  3547.     }
  3548.     debug(F101,"domydir sort malloc","",xsort);
  3549.     }
  3550.  
  3551.     /* Display the listing */
  3552.  
  3553. #ifndef NOSPL
  3554.     if (array)                /* Storing instead of printing */
  3555.       heading = 0;
  3556. #endif /* NOSPL */
  3557.  
  3558.     if (heading) {            /* If /HEADING print heading */
  3559.     zfnqfp(s,TMPBUFSIZ,tmpbuf);
  3560.     printf("\nDirectory of %s\n\n",tmpbuf);
  3561.     n += 3;
  3562.     }
  3563.     if (!verbose) {            /* /BRIEF */
  3564.     xaskmore = page;
  3565.     rc = filhelp(x,"","",n,0);
  3566.     xaskmore = saveask;
  3567.     if (rc < 0)
  3568.       goto xdomydir;
  3569.     if (heading && rc > 0)
  3570.       printf("Files: %d\n\n",x);    /* (This might scroll a line or 2) */
  3571.     rc = 1;
  3572.     goto xdomydir;
  3573.     }
  3574.     ndirs = nfiles = nbytes = 0L;    /* Initialize counters */
  3575.  
  3576.     if (dir_exc)            /* Have exception list? */
  3577.       makelist(dir_exc,xlist,8);    /* Yes, convert to array */
  3578.  
  3579.     diractive = 1;
  3580.     znext(name);            /* Get next file */
  3581.     while (name[0]) {            /* Loop for each file */
  3582.     if (fs) if (fileselect(name,
  3583.                dir_aft,dir_bef,dir_naf,dir_nbf,
  3584.                minsize,maxsize,!backup,8,xlist) < 1) {
  3585.         znext(name);
  3586.         continue;
  3587.     }
  3588.     len = zgetfs(name);        /* Get file length */
  3589.     debug(F111,"domydir zgetfs",name,len);
  3590. #ifdef VMSORUNIX
  3591.     itsadir = zgfs_dir;        /* See if it's a directory */
  3592. #else
  3593.     itsadir = (len == -2 || isdir(name));
  3594. #endif /* VMSOUNIX */
  3595.     debug(F111,"domydir itsadir",name,itsadir);
  3596.     if ((itsadir && (show == 1)) || (!itsadir && (show == 2))) {
  3597.         znext(name);
  3598.         continue;
  3599.     }
  3600.     /* Get here when we know we have selected this file */
  3601.  
  3602.     nmatches ++;
  3603.     if (itsadir) {            /* Accumulate totals for summary */
  3604.         ndirs++;
  3605.     } else {
  3606.         nfiles++;
  3607.         nbytes += len;
  3608.     }
  3609. #ifndef NOSPL
  3610.     if (array) {
  3611.         debug(F111,"domydir array",name,nfiles);
  3612.         if (ap)
  3613.           makestr(&(ap[nmatches]),name);
  3614.         znext(name);
  3615.         continue;
  3616.     }
  3617. #endif /* NOSPL */
  3618.     dstr = zfcdat(name);        /* Get modification date/time */
  3619.     debug(F111,"domydir zcfdat",dstr,0);
  3620.     if (!dstr) dstr = "";
  3621.     if (!*dstr) {
  3622.         dstr = "0000-00-00 00:00:00";
  3623.     } else if (engdate) {        /* English date requested? */
  3624.         short month, day, year, hour, minute, seconds;
  3625.         month = (dstr[4]-48)*10 + (dstr[5]-48);
  3626.         mstr  = (month > 0 && month <= 12) ? months[month-1] : "xxx";
  3627.         day   = (dstr[6]-48)*10 + (dstr[7]-48);
  3628.         year  = (((dstr[0]-48)*10 +
  3629.               (dstr[1]-48))*10 +
  3630.               (dstr[2]-48))*10 +
  3631.               (dstr[3]-48);
  3632.         hour  = (dstr[9]-48)*10 + (dstr[10]-48);
  3633.         minute = (dstr[12]-48)*10 + (dstr[13]-48);
  3634.         seconds = (dstr[15]-48)*10 + (dstr[16]-48);
  3635.         sprintf(dbuf,
  3636.             "%2d-%s-%4d %02d:%02d:%02d",
  3637.             day,mstr,year,hour,minute,seconds
  3638.             );
  3639.         dstr = dbuf;
  3640.     } else {            /* ISO date */
  3641.         dbuf[0] = dstr[0];        /* yyyy */
  3642.         dbuf[1] = dstr[1];
  3643.         dbuf[2] = dstr[2];
  3644.         dbuf[3] = dstr[3];
  3645.         dbuf[4] = '-';
  3646.         dbuf[5] = dstr[4];        /* mm (numeric) */
  3647.         dbuf[6] = dstr[5];
  3648.         dbuf[7] = '-';
  3649.         dbuf[8] = dstr[6];        /* dd */
  3650.         dbuf[9] = dstr[7];
  3651.         strcpy(dbuf+10,dstr+8);    /* hh:mm:ss */
  3652.         dstr = dbuf;
  3653.     }
  3654.     dlen = strlen(dbuf);        /* Length of date */
  3655.     name[CKMAXPATH] = NUL;
  3656. #ifdef CK_PERMS
  3657. #ifdef VMSORUNIX
  3658.     p = ziperm(name);        /* Get permissions */
  3659.     debug(F110,"ziperm perms",p,0);
  3660. #else
  3661.     p = zgperm(name);
  3662.     debug(F110,"zgperm perms",p,0);
  3663. #endif /* VMSORUNIX */
  3664. #else
  3665.     p = NULL;
  3666.     debug(F110,"NULL perms",p,0);
  3667. #endif /* CK_PERMS */
  3668.  
  3669. #ifdef VMS
  3670.     /* Get relative name to save space -- VMS fullnames are long... */
  3671.     ckstrncpy(name,zrelname(name,cdp),CKMAXPATH);
  3672. #endif /* VMS */
  3673.  
  3674.     if (itsadir && len < 0) {    /* Directory */
  3675. #ifdef VMS
  3676.         sprintf(linebuf,"%-22s%-10s  %s  %s",p,"<DIR>",dstr,name);
  3677. #else
  3678.         if (p)
  3679.           sprintf(linebuf,"%10s%-10s  %s  %s",p,"<DIR>",dstr,name);
  3680.         else
  3681.           sprintf(linebuf,"%-10s  %s  %s", "<DIR>", dstr, name);
  3682. #endif /* VMS */
  3683.     } else {            /* Regular file */
  3684. #ifdef VMS
  3685.         sprintf(linebuf,"%-22s%10ld  %s  %s", p, len, dstr, name);
  3686. #else
  3687.         if (p)
  3688.           sprintf(linebuf,"%10s%10ld  %s  %s", p, len, dstr, name);
  3689.         else
  3690.           sprintf(linebuf,"%10ld  %s  %s", len, dstr, name);
  3691. #endif /* VMS */
  3692.     }
  3693. #ifdef UNIX
  3694. #ifdef CKSYMLINK
  3695.     if (zgfs_link) {
  3696.         int n, m;
  3697.         extern char linkname[];
  3698.         n = strlen(linebuf);
  3699.         m = strlen(linkname) + n;
  3700.         if (m < CKMAXPATH + 58)
  3701.           strcpy(linebuf+n, " -> ");
  3702.         if (m + 4 < CKMAXPATH - 58)
  3703.           strcpy(linebuf+n+4, linkname);
  3704.     } else
  3705. #endif /* CKSYMLINK */
  3706. #endif /* UNIX */
  3707. #ifdef PATTERNS
  3708.     if (xfermod) {            /* Show transfer mode */
  3709.         int i;
  3710.         char * s = "";
  3711.         extern char *txtpatterns[], *binpatterns[];;
  3712.  
  3713.         for (i = 0; i < FTPATTERNS && txtpatterns[i]; i++) {
  3714.         if (ckmatch(txtpatterns[i],name,filecase,1)) {
  3715.             s = " (T)";
  3716.             break;
  3717.         }
  3718.         }
  3719.         for (i = 0; i < FTPATTERNS && binpatterns[i]; i++) {
  3720.         if (ckmatch(binpatterns[i],name,filecase,1)) {
  3721.             s = " (B)";
  3722.             break;
  3723.         }
  3724.         }
  3725.         if (*s) {
  3726.         int n;
  3727.         n = strlen(linebuf);
  3728.         if (n + 4 < CKMAXPATH - 58)
  3729.           strcpy(linebuf+n, s);
  3730.         }
  3731.     }
  3732. #endif /* PATTERNS */
  3733.  
  3734.     if (msg && dirmsg) {
  3735.         int n;
  3736.         n = strlen(linebuf);
  3737.         if (n + dirmsglen + 2 < CKMAXPATH)
  3738.           sprintf((char *)(linebuf+n)," %s", dirmsg);
  3739.     }
  3740.     if (xsort) {            /* Sorting - save line */
  3741.         i = strlen(linebuf);
  3742.         if ((ndirlist >= nx) ||
  3743.         !(dirlist[ndirlist] = (char *)malloc(i+1))) {
  3744.         printf("?Memory allocation error - try /NOSORT\n");
  3745.         rc = -9;
  3746.         goto xdomydir;
  3747.         }
  3748.         strcpy(dirlist[ndirlist],linebuf);
  3749.         ndirlist++;
  3750.     }
  3751.     znext(name);            /* Peek ahead to next file */
  3752.  
  3753.     if (!xsort) {
  3754.         printf("%s\n",linebuf);
  3755.         if (page && (name[0] || heading)) {    /* If /PAGE */
  3756.         if (cmd_cols > 0) {
  3757.             int x = strlen(linebuf);
  3758.             int y;
  3759.             y = (x % cmd_cols) ? 1 : 0;
  3760.             n += x / cmd_cols + y;
  3761.         } else {
  3762.             n++;
  3763.         }
  3764. #ifdef CK_TTGWSIZ
  3765.         if (n > (cmd_rows - 3)) { /* Do more-prompting */
  3766.             if (!askmore()) {
  3767.             rc = 0;
  3768.             goto xdomydir;
  3769.             } else
  3770.               n = 0;
  3771.         }
  3772. #endif /* CK_TTGWSIZ */
  3773.         }
  3774.     }
  3775.     }
  3776. #ifndef NOSPL
  3777.     if (array) {
  3778.     if (ap)
  3779.       makestr(&(ap[0]),ckitoa(nmatches));
  3780.     rc = 1;
  3781.     goto xdomydir;
  3782.     }
  3783. #endif /* NOSPL */
  3784.     if (xsort) {
  3785.     skey = 0;
  3786. #ifdef VMS
  3787.     switch (sortby) {
  3788.       case DIRS_NM: skey = dlen + 35; break;
  3789.       case DIRS_DT: skey = 33; break;
  3790.       case DIRS_SZ: skey = 21;
  3791.     }
  3792. #else
  3793.     if (p) {
  3794.         switch (sortby) {
  3795.           case DIRS_NM: skey = dlen + 24; break;
  3796.           case DIRS_DT: skey = 22; break;
  3797.           case DIRS_SZ: skey = 10;
  3798.         }
  3799.     } else {
  3800.         switch (sortby) {
  3801.           case DIRS_NM: skey = dlen + 14; break;
  3802.           case DIRS_DT: skey = 12; break;
  3803.           case DIRS_SZ: skey = 0;
  3804.         }
  3805.     }
  3806. #endif /* VMS */
  3807.     sh_sort(dirlist,NULL,ndirlist,skey,reverse,filecase);
  3808.     for (i = 0; i < ndirlist; i++) {
  3809.         printf("%s\n",dirlist[i]);
  3810.         if (page && (i < ndirlist -1 || heading)) {    /* If /PAGE */
  3811.         if (cmd_cols > 0) {
  3812.             int x = strlen(dirlist[i]);
  3813.             int y;
  3814.             y = (x % cmd_cols) ? 1 : 0;
  3815.             n += ((int)strlen(dirlist[i]) / cmd_cols) + y;
  3816.         } else {
  3817.             n++;
  3818.         }
  3819. #ifdef CK_TTGWSIZ
  3820.         if (n > (cmd_rows - 3)) { /* Do more-prompting */
  3821.             if (!askmore()) {
  3822.             rc = 0;
  3823.             goto xdomydir;
  3824.             } else
  3825.               n = 0;
  3826.         }
  3827. #endif /* CK_TTGWSIZ */
  3828.         }
  3829.     }
  3830.     }
  3831.     if (heading) {
  3832. #ifdef CKFLOAT
  3833.     CKFLOAT gm;
  3834. #endif /* CKFLOAT */
  3835.     printf("\n%ld director%s, %ld file%s, %ld byte%s",
  3836.            ndirs,
  3837.            (ndirs == 1) ? "y" : "ies",
  3838.            nfiles,
  3839.            (nfiles == 1) ? "" : "s",
  3840.            nbytes,
  3841.            (nbytes == 1) ? "" : "s"
  3842.            );
  3843. #ifdef CKFLOAT
  3844.     gm = ((CKFLOAT) nbytes ) / 1000000.0;
  3845.     if (gm > 1000.0)
  3846.       printf(" (%0.2fGB)",(gm / 1000.0));
  3847.     else if (gm >= 0.01)
  3848.       printf(" (%0.2fMB)",gm);
  3849. #endif /* CKFLOAD */
  3850.     printf("\n\n");
  3851.     }
  3852.   xdomydir:
  3853.     if (g_matchdot > -1) {
  3854.     matchdot = g_matchdot;        /* Restore these... */
  3855.     g_matchdot = -1;
  3856.     }
  3857.     if (saveask > -1) {
  3858.     xaskmore = saveask;
  3859.     saveask = -1;
  3860.     }
  3861.     freedirlist();
  3862.     if (rc > 0)
  3863.       success = 1;
  3864.     return(rc);
  3865. }
  3866.  
  3867. int
  3868. dodir(cx) int cx; {            /* Do the DIRECTORY command */
  3869.     char *dc , *msg;
  3870.  
  3871. #ifdef OS2
  3872.     return(domydir());
  3873. #else /* OS2 */
  3874.     if (nopush
  3875. #ifdef DOMYDIR                /* Systems that domydir() by default */
  3876.     || cx == XXDIR
  3877. #endif /* DOMYDIR */
  3878.     )
  3879.       return(domydir());        /* Built-in directory command */
  3880.  
  3881.     /* Use the system's directory command. */
  3882.  
  3883.     msg = (cx == XXLS) ?
  3884.       "Arguments for ls" :
  3885.     "Directory and/or file specification";
  3886.     if ((x = cmtxt(msg,"",&s,xxstring)) < 0)
  3887.       return(x);
  3888.  
  3889.     ckstrncpy(tmpbuf,s,TMPBUFSIZ);    /* Copy the filespec */
  3890.     s = tmpbuf;
  3891.  
  3892.     if ((y = cmcfm()) < 0) return(y);
  3893.  
  3894.     lp = line;
  3895.     if (!(dc = getenv("CK_DIR")))
  3896.       dc = DIRCMD;
  3897.     sprintf(lp,"%s %s",dc,s);
  3898.     debug(F110,"DIR",line,0);
  3899. #ifdef VMS
  3900.     conres();
  3901. #endif /* VMS */
  3902.     x = zshcmd(line);
  3903. #ifdef VMS
  3904.     concb((char)escape);
  3905. #endif /* VMS */
  3906.     return(success = (x < 1) ? 0 : 1);
  3907. #endif /* OS2 */
  3908. }
  3909.  
  3910. #ifndef NOSERVER
  3911. #ifndef NOFRILLS
  3912. /* Do the ENABLE and DISABLE commands */
  3913.  
  3914. int
  3915. doenable(y,x) int y, x; {
  3916.     switch (x) {
  3917.       case EN_ALL:
  3918.     en_cwd = en_cpy = en_del = en_dir = en_fin = en_get = y;
  3919.     en_ren = en_sen = en_set = en_spa = en_typ = en_ret = y;
  3920.         if (!inserver)
  3921.       en_who = en_mai = en_pri = y;
  3922.     en_mkd = en_rmd = y;
  3923.     en_xit = y;
  3924. #ifndef datageneral
  3925.         en_bye = y;
  3926. #endif /* datageneral */
  3927. #ifndef NOPUSH
  3928.     if (!nopush && !inserver)
  3929.       en_hos = y;
  3930. #endif /* NOPUSH */
  3931. #ifndef NOSPL
  3932.     en_asg = en_que = y;
  3933. #endif /* NOSPL */
  3934.     break;
  3935.  
  3936.       case EN_BYE:
  3937. #ifndef datageneral
  3938. /*
  3939.   In Data General AOS/VS Kermit can't log out its superior process.
  3940. */
  3941.         en_bye = y;
  3942. #endif /* datageneral */
  3943.     break;
  3944.       case EN_CPY:
  3945.         en_cpy = y;
  3946.         break;
  3947.       case EN_CWD:
  3948.     en_cwd = y;
  3949. #ifdef IKSD
  3950.     if (inserver && y == 0) {
  3951.         fnrpath = PATH_OFF;
  3952.         fnspath = PATH_OFF;
  3953.     }
  3954. #endif /* IKSD */
  3955.     break;
  3956.       case EN_DEL:            /* Deleting of files */
  3957.     en_del = y;
  3958.     break;
  3959.       case EN_DIR:
  3960.     en_dir = y;
  3961.     break;
  3962.       case EN_FIN:
  3963.     en_fin = y;
  3964.     break;
  3965.       case EN_GET:
  3966.     en_get = y;
  3967.     break;
  3968. #ifndef NOPUSH
  3969.       case EN_HOS:
  3970.     if (!nopush)
  3971.          en_hos = y;
  3972.     break;
  3973. #endif /* NOPUSH */
  3974.       case EN_REN:
  3975.         en_ren = y;
  3976.         break;
  3977.       case EN_SEN:
  3978.     en_sen = y;
  3979.     break;
  3980.       case EN_SET:
  3981.     en_set = y;
  3982.     break;
  3983.       case EN_SPA:
  3984.     en_spa = y;
  3985.     break;
  3986.       case EN_TYP:
  3987.     en_typ = y;
  3988.     break;
  3989.       case EN_WHO:
  3990.     en_who = y;
  3991.     break;
  3992. #ifndef NOSPL
  3993.       case EN_ASG:
  3994.     en_asg = y;
  3995.     break;
  3996.       case EN_QUE:
  3997.     en_que = y;
  3998.     break;
  3999. #endif /* NOSPL */
  4000.       case EN_RET:
  4001.     en_del = y;
  4002.     break;
  4003.       case EN_MAI:
  4004. #ifdef CK_LOGIN
  4005.     if (isguest && y) {
  4006.         printf("?Sorry, not valid for guests\n");
  4007.         return(-9);
  4008.     }
  4009. #endif /* CK_LOGIN */
  4010.     en_mai = y;
  4011.     break;
  4012.       case EN_PRI:
  4013. #ifdef CK_LOGIN
  4014.     if (isguest && y) {
  4015.         printf("?Sorry, not valid for guests\n");
  4016.         return(-9);
  4017.     }
  4018. #endif /* CK_LOGIN */
  4019.     en_pri = y;
  4020.     break;
  4021.       case EN_MKD:
  4022.     en_mkd = y;
  4023.     break;
  4024.       case EN_RMD:
  4025.     en_rmd = y;
  4026.     break;
  4027.       case EN_XIT:
  4028.     en_xit = y;
  4029.     break;
  4030.       case EN_ENA:
  4031.     if (((y & 1) && !(en_ena & 1)) ||
  4032.         ((y & 2) && !(en_ena & 2))) {
  4033.         printf("?Sorry, DISABLE ENABLE can not be undone\n");
  4034.         return(-9);
  4035.     } else {
  4036.         en_ena = y;
  4037.         break;
  4038.     }
  4039.       default:
  4040.     return(-2);
  4041.     }
  4042.     return(1);
  4043. }
  4044. #endif /* NOFRILLS */
  4045. #endif /* NOSERVER */
  4046.  
  4047. #ifndef NOFRILLS
  4048.  
  4049. static int del_lis = 0;
  4050. static int del_dot = 0;
  4051. static int del_hdg = 0;
  4052. #ifndef CK_TTGWSIZ
  4053. static int del_pag = -1;
  4054. #else
  4055. static int del_pag = 0;
  4056. #endif /* CK_TTGWSIZ */
  4057. static int del_ask = 0;
  4058.  
  4059. #ifndef NOSHOW
  4060. VOID
  4061. showdelopts() {
  4062.     int x = 0;
  4063.     extern int optlines;
  4064.     prtopt(&optlines,"");
  4065.     prtopt(&optlines,"DELETE");
  4066.     if (del_ask > -1) {
  4067.     prtopt(&optlines, del_ask ? "/ASK" : "/NOASK");
  4068.     x++;
  4069.     }
  4070. #ifdef UNIXOROSK
  4071.     if (del_dot > -1) {
  4072.     prtopt(&optlines, del_dot ? "/DOTFILES" : "/NODOTFILES");
  4073.     x++;
  4074.     }
  4075. #endif /* UNIXOROSK */
  4076.     if (del_lis > -1) {
  4077.     prtopt(&optlines, del_lis ? "/LIST" : "/NOLIST");
  4078.     x++;
  4079.     }
  4080.     if (del_hdg > -1) {
  4081.     prtopt(&optlines, del_hdg ? "/HEADING" : "/NOHEADING");
  4082.     x++;
  4083.     }
  4084. #ifndef CK_TTGWSIZ
  4085.     if (del_pag > -1) {
  4086.     prtopt(&optlines, del_pag ? "/PAGE" : "/NOPAGE");
  4087.     x++;
  4088.     }
  4089. #endif /* CK_TTGWSIZ */
  4090.     if (!x) prtopt(&optlines,"(no options set)");
  4091.     prtopt(&optlines,"");
  4092. }
  4093. #endif /* NOSHOW */
  4094.  
  4095.  
  4096. int
  4097. setdelopts() {
  4098.     int x_lis = -1, x_pag = -1, x_dot = -1, x_hdg = -1, x_ask = -1;
  4099.     int getval = 0;
  4100.     char c;
  4101.     while (1) {
  4102.     if ((y = cmswi(deltab,ndeltab,"Switch","",xxstring)) < 0) {
  4103.         if (y == -3)
  4104.           break;
  4105.         else
  4106.           return(y);
  4107.     }
  4108.     c = cmgbrk();
  4109.     if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
  4110.         printf("?This switch does not take an argument\n");
  4111.         return(-9);
  4112.     }
  4113.     if (!getval && (cmgkwflgs() & CM_ARG)) {
  4114.         printf("?This switch requires an argument\n");
  4115.         return(-9);
  4116.     }
  4117.     switch (y) {
  4118.       case DEL_DOT:
  4119.         x_dot = 1;
  4120.         break;
  4121.       case DEL_NOD:
  4122.         x_dot = 0;
  4123.         break;
  4124.       case DEL_HDG:
  4125.         x_hdg = 1;
  4126.         break;
  4127.       case DEL_LIS:
  4128.         x_lis = 1;
  4129.         break;
  4130.       case DEL_NOL:
  4131.         x_lis = 0;
  4132.         break;
  4133. #ifndef CK_TTGWSIZ
  4134.       case DEL_PAG:
  4135.         x_pag = 1;
  4136.         break;
  4137.       case DEL_NOP:
  4138.         x_pag = 0;
  4139.         break;
  4140. #endif /* CK_TTGWSIZ */
  4141.       case DEL_QUI:
  4142.         x_lis = 0;
  4143.         break;
  4144.       case DEL_VRB:
  4145.         x_lis = 1;
  4146.         break;
  4147.       case DEL_ASK:
  4148.         x_ask = 1;
  4149.         break;
  4150.       case DEL_NAS:
  4151.         x_ask = 0;
  4152.         break;
  4153.       default:
  4154.         printf("?Sorry, this option can not be set\n");
  4155.         return(-9);
  4156.     }
  4157.     }
  4158.     if ((x = cmcfm()) < 0)        /* Get confirmation */
  4159.       return(x);
  4160.     if (x_pag > -1) del_pag = x_pag;
  4161.     if (x_dot > -1) del_dot = x_dot;
  4162.     if (x_hdg > -1) del_hdg = x_hdg;
  4163.     if (x_lis > -1) del_lis = x_lis;
  4164.     if (x_ask > -1) del_ask = x_ask;
  4165.     return(success = 1);
  4166. }
  4167.  
  4168. int
  4169. dodel() {                /* DELETE */
  4170. #ifdef UNIX
  4171.     extern char ** mtchs;
  4172. #endif /* UNIX */
  4173.     int i, j, k, x;
  4174.     int fs = 0;                /* Need to call fileselect() */
  4175.     int getval = 0, asking = 0;
  4176.     int simulate = 0, rc = 0;
  4177.     long minsize = -1L, maxsize = -1L;
  4178.     int havename = 0, confirmed = 0;
  4179.     int qflag = 0;
  4180.     char c;
  4181.     struct FDB sw, fi, fl;
  4182.     char
  4183.       * del_aft = NULL,
  4184.       * del_bef = NULL,
  4185.       * del_naf = NULL,
  4186.       * del_nbf = NULL,
  4187.       * del_exc = NULL;
  4188.     int
  4189.       x_lis = -1,
  4190.       /* x_dot = -1, */
  4191.       x_hdg = -1;
  4192.  
  4193.     char * dxlist[8];
  4194.  
  4195.     for (i = 0; i < 8; i++) dxlist[i] = NULL;
  4196.  
  4197.     g_matchdot = matchdot;
  4198.     saveask = xaskmore;
  4199.  
  4200.     if (del_lis > -1) x_lis    = del_lis;
  4201.     if (del_dot > -1) matchdot = del_dot;
  4202.     if (del_hdg > -1) x_hdg    = del_hdg;
  4203.     if (del_pag > -1) xaskmore = del_pag;
  4204.     if (del_ask > -1) asking   = del_ask;
  4205.  
  4206.     cmfdbi(&sw,                /* First FDB - command switches */
  4207.        _CMKEY,            /* fcode */
  4208.        "File specification;\n or switch",
  4209.        "",                /* default */
  4210.        "",                /* addtl string data */
  4211.        ndeltab,            /* addtl numeric data 1: tbl size */
  4212.        4,                /* addtl numeric data 2: 4 = cmswi */
  4213.        xxstring,            /* Processing function */
  4214.        deltab,            /* Keyword table */
  4215.        &fi                /* Pointer to next FDB */
  4216.        );
  4217.     cmfdbi(&fi,                /* 2nd FDB - file to delete */
  4218.        _CMIFI,            /* fcode */
  4219.        "File(s) to delete",        /* hlpmsg */
  4220.        "",                /* default */
  4221.        "",                /* addtl string data */
  4222.        0,                /* addtl numeric data 1 */
  4223.        0,                /* addtl numeric data 2 */
  4224.        xxstring,
  4225.        NULL,
  4226.        &fl
  4227.        );
  4228.     cmfdbi(&fl,                /* Anything that doesn't match */
  4229.        _CMFLD,            /* fcode */
  4230.        "",                /* hlpmsg */
  4231.        "",                /* default */
  4232.        "",                /* addtl string data */
  4233.        0,                /* addtl numeric data 1 */
  4234.        0,                /* addtl numeric data 2 */
  4235.        xxstring,
  4236.        NULL,
  4237.        NULL
  4238.        );
  4239.     while (!havename && !confirmed) {
  4240.     x = cmfdb(&sw);            /* Parse something */
  4241.     if (x < 0) {            /* Error */
  4242.         if (x == -3)
  4243.           break;
  4244.         if (x == -2 || x == -9)
  4245.           printf("?Does not match switch or filename: \"%s\"\n",atmbuf);
  4246.         return(x);
  4247.     }
  4248.     if (cmresult.fcode != _CMKEY)    /* Break out if not a switch */
  4249.       break;
  4250.     c = cmgbrk();            /* Get break character */
  4251.     if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
  4252.         printf("?This switch does not take an argument\n");
  4253.         rc = -9;
  4254.         goto xdelete;
  4255.     }
  4256.     if (!getval && (cmgkwflgs() & CM_ARG)) {
  4257.         printf("?This switch requires an argument\n");
  4258.         rc = -9;
  4259.         goto xdelete;
  4260.     }
  4261.     switch (k = cmresult.nresult) {
  4262.       case DEL_AFT:
  4263.       case DEL_BEF:
  4264.       case DEL_NAF:
  4265.       case DEL_NBF:
  4266.         if (!getval) break;
  4267.         if ((x = cmdate("File-time","",&s,0,xxstring)) < 0) {
  4268.         if (x == -3) {
  4269.             printf("?Date-time required\n");
  4270.             x = -9;
  4271.         } else
  4272.           rc = x;
  4273.         goto xdelete;
  4274.         }
  4275.         fs++;
  4276.         switch (k) {
  4277.           case DEL_AFT: makestr(&del_aft,s); break;
  4278.           case DEL_BEF: makestr(&del_bef,s); break;
  4279.           case DEL_NAF: makestr(&del_naf,s); break;
  4280.           case DEL_NBF: makestr(&del_nbf,s); break;
  4281.         }
  4282.         break;
  4283.       case DEL_DOT:
  4284.         matchdot = 1;
  4285.         break;
  4286.       case DEL_NOD:
  4287.         matchdot = 0;
  4288.         break;
  4289.       case DEL_EXC:
  4290.         if (!getval) break;
  4291.         if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
  4292.         if (x == -3) {
  4293.             printf("?Pattern required\n");
  4294.             x = -9;
  4295.         } else
  4296.           rc = x;
  4297.         goto xdelete;
  4298.         }
  4299.         fs++;
  4300.         makestr(&del_exc,s);
  4301.         break;
  4302.       case DEL_HDG:
  4303.         x_hdg = 1;
  4304.         break;
  4305.       case DEL_LIS:
  4306.         x_lis = 1;
  4307.         break;
  4308.       case DEL_NOL:
  4309.         x_lis = 0;
  4310.         break;
  4311. #ifndef CK_TTGWSIZ
  4312.       case DEL_PAG:
  4313.         xaskmore = 1;
  4314.         break;
  4315.       case DEL_NOP:
  4316.         xaskmore = 0;
  4317.         break;
  4318. #endif /* CK_TTGWSIZ */
  4319.       case DEL_QUI:
  4320.         qflag = 1;
  4321.         x_lis = 0;
  4322.         break;
  4323.       case DEL_VRB:
  4324.         x_lis = 1;
  4325.         break;
  4326.  
  4327.       case DEL_SMA:
  4328.       case DEL_LAR:
  4329.         if (!getval) break;
  4330.         if ((x = cmnum("File size in bytes","0",10,&y,xxstring)) < 0)
  4331.           return(x);
  4332.         fs++;
  4333.         switch (cmresult.nresult) {
  4334.           case DEL_SMA: minsize = y; break;
  4335.           case DEL_LAR: maxsize = y; break;
  4336.         }
  4337.         break;
  4338.  
  4339.       case DEL_SIM:
  4340.         simulate = 1;
  4341.         x_lis = 1;
  4342.         break;
  4343.       case DEL_ASK:
  4344.         asking = 1;
  4345.         break;
  4346.       case DEL_NAS:
  4347.         asking = 0;
  4348.         break;
  4349.       default:
  4350.         printf("?Not implemented yet - \"%s\"\n",atmbuf);
  4351.         return(-9);
  4352.     }
  4353.     }
  4354.     if (qflag && (cmresult.fcode == _CMFLD)) {
  4355.     if ((x = cmcfm()) < 0)
  4356.       return(x);
  4357.     else
  4358.       return(success = 0);
  4359.     }
  4360.     if (cmresult.fcode != _CMIFI) {
  4361.     if (*atmbuf)
  4362.       printf("?Not a deletable file: %s\n",atmbuf);
  4363.     else
  4364.       printf("?A file specification is required\n");
  4365.     return(-9);
  4366.     }
  4367.     ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ); /* Safe copy of filespec */
  4368.     if ((x = cmcfm()) < 0)
  4369.       return(x);
  4370.  
  4371. #ifdef IKSD
  4372. #ifdef CK_LOGIN
  4373.     if (inserver && isguest) {
  4374.     printf("?Sorry, DELETE unavailable to guests\n");
  4375.     return(-9);
  4376.     }
  4377. #endif /* CK_LOGIN */
  4378. #endif /* IKSD */
  4379.  
  4380. #ifndef OS2ORUNIX
  4381.     if (simulate) {
  4382.     printf("?Sorry, /SIMULATE not implemented on this platform\n");
  4383.     return(-9);
  4384.     }
  4385. #endif /* OS2ORUNIX */
  4386.  
  4387. #ifdef COMMENT
  4388.     /* (not needed) */
  4389.     if (!iswild(tmpbuf)) {
  4390.     char *m;
  4391.     x = zchki(tmpbuf);
  4392.     if (x < 0) {
  4393.         switch (x) {
  4394.           case -2: m = "Not a regular file"; break;
  4395.           case -1: m = "File not found or not accessible"; break;
  4396.           default: m = "Can't delete";
  4397.         }
  4398.         printf("?%s: \"%s\"\n",m,tmpbuf);
  4399.         return(-9);
  4400.     }
  4401.     }
  4402. #endif /* COMMENT */
  4403.  
  4404.     makelist(del_exc,dxlist,8);
  4405.  
  4406. /* tmpbuf[] has the name - now do any needed conversions on it */
  4407.  
  4408. #ifdef OS2
  4409.     {   /* Lower level functions change / to \, not good for CMD.EXE. */
  4410.     char *p = tmpbuf;
  4411.     while (*p) {            /* Change them back to \ */
  4412.         if (*p == '/') *p = '\\';
  4413.         p++;
  4414.     }
  4415.     }
  4416. #endif /* OS2 */
  4417.  
  4418. #ifdef VMS
  4419.     if (iswild(tmpbuf)) {
  4420. #ifdef COMMENT
  4421.     /* Does not handle '.' as version separator */
  4422.     char *p = tmpbuf;
  4423.     x = 0;
  4424.     while (*p) {
  4425.         if (*p == ';') {
  4426.         x = 1;
  4427.         break;
  4428.         } else
  4429.           p++;
  4430.     }
  4431.     if (!x) strcat(tmpbuf,";*");
  4432. #else
  4433.         j = 0; x = 0;            /* for end_dot and number of dots */
  4434.         i = strlen(tmpbuf);
  4435.         if (tmpbuf[i] == ';') {
  4436.             strcat(tmpbuf,"0");
  4437.         } else {
  4438.             if (tmpbuf[i--] == '.')
  4439.               j++;
  4440.             for (; i >= 0; i--) {
  4441.                 if (tmpbuf[i] == ';' || tmpbuf[i] == ':' ||
  4442.                     tmpbuf[i] == ']' || tmpbuf[i] == '>')
  4443.                   break;
  4444.                 else if (tmpbuf[i] == '.')
  4445.                   x++;
  4446.             }
  4447.             if (tmpbuf[i] != ';') {    /* dot may have been used */
  4448.                 if (j) {        /* last char is dot */
  4449.                   if (x)
  4450.                     strcat(tmpbuf,"0");    /* second is version separator */
  4451.                   else
  4452.                     strcat(tmpbuf,";0"); /* 'foo.' */
  4453.                 } else if (x == 1)    /* lacking a version separator */
  4454.           strcat(tmpbuf,";0");
  4455.         else if (x == 0)    /* x == 2 has a version */
  4456.           strcat(tmpbuf,".*;0");
  4457.             }
  4458.         }
  4459. #endif /* COMMENT */
  4460.     }
  4461. #endif /* VMS */
  4462.  
  4463.     debug(F110,"dodel tmpbuf",tmpbuf,0); /* Filename */
  4464.  
  4465. #ifndef OS2ORUNIX            /* No built-in DELETE code... */
  4466.     sprintf(line,"%s %s",DELCMD,tmpbuf); /* Construct the system command. */
  4467.  
  4468. #ifdef VMS
  4469.     if (asking) {            /* Maybe overwrite in VMS */
  4470.     if (x_lis)            /* if options are needed... */
  4471.       sprintf(line,"%s /confirm/log %s",DELCMD,tmpbuf);
  4472.     else
  4473.       sprintf(line,"%s /confirm %s",DELCMD,tmpbuf);
  4474.     } else if (x_lis)
  4475.       sprintf(line,"%s /log %s",DELCMD,tmpbuf);
  4476.     conres();
  4477. #endif /* VMS */
  4478.  
  4479.     debug(F110,"dodel line",line,0);
  4480. #endif /* OS2ORUNIX */
  4481.  
  4482. #ifdef MAC
  4483.     success = (zdelet(tmpbuf) == 0);
  4484.  
  4485. #else
  4486. #ifdef COMMENT
  4487.     nzxopts = ZX_FILONLY;        /* Files only for now */
  4488.     if (matchdot)  nzxopts |= ZX_MATCHDOT;
  4489.     /* Note: No recursive -- recursive deleting not supported yet */
  4490.     z = nzxpand(s,nzxopts);        /* Expand file list */
  4491. #endif /* COMMENT */
  4492.  
  4493. #ifdef OS2ORUNIX
  4494.     {
  4495.         int filespace = 0;
  4496.         int len = 0;
  4497.         int count = 0;
  4498.     int lines = 0;
  4499.     int n = 0;
  4500.  
  4501.         s = tmpbuf;
  4502.  
  4503.     if (x_hdg > 0) {
  4504.         printf("Deleting %s...%s\n", s, simulate ? " (SIMULATION)" : "");
  4505.         n += 2;
  4506.     }
  4507. #ifdef ZXREWIND
  4508.     z = zxrewind();            /* Rewind file list */
  4509. #else
  4510.     nzxopts = ZX_FILONLY;        /* Files only for now */
  4511.     if (matchdot)  nzxopts |= ZX_MATCHDOT;
  4512.     /* Note: No recursive -- recursive deleting not supported yet */
  4513.     z = nzxpand(s,nzxopts);        /* Expand file list */
  4514. #endif /* ZXREWIND */
  4515. #ifdef UNIX
  4516.     sh_sort(mtchs,NULL,z,0,0,filecase);
  4517. #endif /* UNIX */
  4518.         if (z > 0) {
  4519.             int i;
  4520.             success = 1;
  4521.             if (x_hdg > 0)
  4522.               printf("\n");
  4523.         while (1) {
  4524.         znext(tmpbuf);
  4525.         if (!*tmpbuf)
  4526.           break;
  4527.         if (fs) if (fileselect(tmpbuf,
  4528.                 del_aft,del_bef,del_naf,del_nbf,
  4529.                 minsize,maxsize,0,8,dxlist) < 1) {
  4530.             if (x_lis > 0) {
  4531.             lines++;
  4532.             printf(" %s (SKIPPED)\n",tmpbuf);
  4533. #ifdef CK_TTGWSIZ
  4534.             if (++n > cmd_rows - 3)
  4535.               if (!askmore()) goto xdelete; else n = 0;
  4536. #endif /* CK_TTGWSIZ */
  4537.             }
  4538.             continue;
  4539.         }
  4540.         if (asking) {
  4541.             int x;
  4542.             sprintf(line," Delete %s? ",tmpbuf);
  4543.             x = getyesno(line,1);
  4544.             switch (x) {
  4545.               case 0: continue;
  4546.               case 1: break;
  4547.               case 2: goto xdelete;
  4548.             }
  4549.         }
  4550.         len = zchki(tmpbuf);
  4551.         if (simulate) {
  4552.             filespace += len;
  4553.             count++;
  4554.             if (x_lis > 0) {
  4555.             lines++;
  4556.             printf(" %s (SELECTED)\n",tmpbuf);
  4557.             if (++n > cmd_rows - 3)
  4558.               if (!askmore()) goto xdelete; else n = 0;
  4559.             }
  4560.         } else if (len >= 0) {
  4561.             zdelet(tmpbuf);
  4562.             if (zchki(tmpbuf) < 0) {
  4563.             filespace += len;
  4564.             count++;
  4565.             if (x_lis > 0) {
  4566.                 lines++;
  4567.                 printf(" %s (OK)\n",tmpbuf);
  4568.                 if (++n > cmd_rows - 3)
  4569.                   if (!askmore()) goto xdelete; else n = 0;
  4570.             }
  4571.             } else {
  4572.             success = 0;
  4573.             if (x_lis > 0) {
  4574.                 lines++;
  4575.                 printf(" %s (FAILED)\n",tmpbuf);
  4576.                 if (++n > cmd_rows - 3)
  4577.                   if (!askmore()) goto xdelete; else n = 0;
  4578.             }
  4579.             }
  4580.         } else if (x_lis > 0) {
  4581.             lines++;
  4582.             if (isdir(tmpbuf))
  4583.               printf(" %s (FAILED: directory)\n",tmpbuf);
  4584.             else
  4585.               printf(" %s (FAILED: not regular file)\n",tmpbuf);
  4586.             if (++n > cmd_rows - 3)
  4587.               if (!askmore()) goto xdelete; else n = 0;
  4588.         }
  4589.             }
  4590.         if (x_hdg > 0) {
  4591.         if (lines > 0)
  4592.           printf("\n");
  4593.         if (++n > cmd_rows - 3)
  4594.           if (!askmore()) goto xdelete; else n = 0;
  4595.         printf("%d file%s %sdeleted, %d byte%s %sfreed%s\n",
  4596.                count,
  4597.                count != 1 ? "s" : "",
  4598.                simulate ? "would be " : "",
  4599.                filespace,
  4600.                filespace != 1 ? "s" : "",
  4601.                simulate ? "would be " : "",
  4602.                simulate ? " (maybe)" : ""
  4603.                );
  4604.         }
  4605.         } else if (x_lis > 0)
  4606.       printf("?Can't delete: %s\n",tmpbuf);
  4607.     }
  4608. #else /* OS2ORUNIX */
  4609. #ifndef VMS                /* Others - let the system do it. */
  4610.     xsystem(line);
  4611.     x = nzxpand(tmpbuf,nzxopts);
  4612.     success = (x > 0) ? 0 : 1;
  4613.     if (x_hdg > 0)
  4614.       printf("%s - %sdeleted\n", tmpbuf, success ? "" : "not ");
  4615. #else
  4616.     if (asking)
  4617.       printf("\n");
  4618.     x = xsystem(line);                  /* zshcmd returns 1 for success */
  4619.     success = (x > 0) ? 1 : 0;
  4620.     if (x_hdg > 0 && !asking)
  4621.       printf("%s - %sdeleted\n", tmpbuf, success ? "" : "not ");
  4622.     concb((char)escape);
  4623. #endif /* VMS */
  4624. #endif /* OS2ORUNIX */
  4625. #endif /* MAC */
  4626.   xdelete:
  4627.     if (g_matchdot > -1) {
  4628.     matchdot = g_matchdot;        /* Restore these... */
  4629.     g_matchdot = -1;
  4630.     }
  4631.     if (saveask > -1) {
  4632.     xaskmore = saveask;
  4633.     saveask = -1;
  4634.     }
  4635.     return((rc < 0) ? rc : success);
  4636. }
  4637. #endif /* NOFRILLS */
  4638.  
  4639. #ifndef NOSPL                /* The ELSE command */
  4640. _PROTOTYP( VOID pushqcmd, (char *) );
  4641.  
  4642. int
  4643. doelse() {
  4644.     if (!ifcmd[cmdlvl]) {
  4645.     printf("?ELSE doesn't follow IF\n");
  4646.     return(-2);
  4647.     }
  4648. #ifdef COMMENT
  4649. /*
  4650.   Wrong.  This prevents IF..ELSE IF...ELSE IF...ELSE IF...ELSE...
  4651.   from working.
  4652. */
  4653.     ifcmd[cmdlvl] = 0;
  4654. #endif /* COMMENT */
  4655.     if (!iftest[cmdlvl]) {        /* If IF was false do ELSE part */
  4656.     if (maclvl > -1 || tlevel > -1) { /* In macro or command file */
  4657.         debug(F100,"doelse pushing","",0);
  4658. #ifdef COMMENT
  4659.         pushcmd(NULL);        /* save rest of command. */
  4660. #else
  4661.         /* This fixes certain obscure problems */
  4662.         /* but breaks many other constructions that must work. */
  4663.         pushqcmd(NULL);
  4664. #endif /* COMMENT */
  4665.     } else {            /* If interactive, */
  4666.         cmini(ckxech);        /* just start a new command */
  4667.         printf("\n");        /* (like in MS-DOS Kermit) */
  4668.         if (pflag) prompt(xxstring);
  4669.     }
  4670.     } else {                /* Condition is false */
  4671.     if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
  4672.       return(y);            /* Gobble up rest of line */
  4673.     }
  4674.     return(0);
  4675. }
  4676. #endif /* NOSPL */
  4677.  
  4678. #ifndef NOSPL
  4679. int
  4680. doswitch() {
  4681.     char *lp, *ap;            /* Macro argument pointer */
  4682.     int x, y, pp = 0;
  4683.  
  4684.     /* Get variable name */
  4685.     if ((y = cmfld("Variable name","",&s,xxstring)) < 0)
  4686.       return(y);
  4687.     if (!strcmp(s,"(")) {
  4688.     pp++;
  4689.     if ((y = cmfld("Variable name","",&s,xxstring)) < 0)
  4690.       return(y);
  4691.     s = tmpbuf;
  4692.     }
  4693.     if (*s == CMDQ) {
  4694.     if (chkvar(s) < 1) {
  4695.         printf("?Variable name required\n");
  4696.         return(-9);
  4697.     }
  4698.     }
  4699.     ckstrncpy(tmpbuf,atmbuf,TMPBUFSIZ);
  4700.     if (pp > 0) {            /* If open paren given parse closing */
  4701.     if ((y = cmfld("Closing parenthesis","",&s,NULL)) < 0)
  4702.       return(y);
  4703.     if (strcmp(atmbuf,")")) {
  4704.         printf("?Closing parenthesis required\n");
  4705.         return(-9);
  4706.     }
  4707.     }
  4708.     lp = line;
  4709.     strcpy(lp,"_switx ");        /* _switx + space */
  4710.     x = strlen(line);
  4711.     lp += x;
  4712.     ap = lp;
  4713.     debug(F110,"SWITCH",tmpbuf,0);
  4714.     ckstrncpy(lp,tmpbuf,LINBUFSIZ-x);    /* + variable name */
  4715.     x = strlen(tmpbuf);
  4716.     lp += x;
  4717.     strcat(lp," ");            /* + space */
  4718.     lp++;
  4719.     debug(F110,"SWITCH 2",line,0);
  4720.  
  4721.     /* Get body */
  4722.  
  4723.     if ((y = cmtxt("series of cases","",&s,NULL)) < 0) return(y);
  4724.     if ((y = (int)strlen(s)) < 1) return(-2);
  4725.     if (s[0] != '{' && s[y-1] != '}') {    /* Supply braces if missing */
  4726.     sprintf(tmpbuf,"{ %s }",s);
  4727.     s = tmpbuf;
  4728.     }
  4729.     if (litcmd(&s,&lp,(LINBUFSIZ - (lp - (char *)line) - 2)) < 0) {
  4730.     printf("?Unbalanced braces\n");
  4731.     return(0);
  4732.     }
  4733.     debug(F110,"SWITCH 3",line,0);
  4734.  
  4735.     x = mlook(mactab,"_switx",nmac);    /* Look up SWITCH macro definition */
  4736.     if (x < 0) {            /* Not there? */
  4737.     addmmac("_switx",sw_def);    /* Put it back. */
  4738.     if ((x = mlook(mactab,"_switx",nmac)) < 0) { /* Look it up again. */
  4739.         printf("?SWITCH macro definition gone!\n"); /* Shouldn't happen. */
  4740.         return(success = 0);
  4741.     }
  4742.     }
  4743.     debug(F110,"SWITCH command",line,0); /* Execute the SWITCH macro. */
  4744.     return(success = dodo(x,ap,cmdstk[cmdlvl].ccflgs | CF_IMAC));
  4745. }
  4746.  
  4747. int
  4748. dofor() {                /* The FOR command. */
  4749.     int i, fx, fy, fz;            /* loop variables */
  4750.     char *ap, *di;            /* macro argument pointer */
  4751.     int pp = 0;                /* Paren level */
  4752.  
  4753.     for (i = 0; i < 2; i++) {
  4754.     if ((y = cmfld("Variable name","",&s,NULL)) < 0) {
  4755.         if (y == -3) {
  4756.         printf("?Variable name required\n");
  4757.         return(-9);
  4758.         } else
  4759.           return(y);
  4760.     }
  4761.     if (strcmp(s,"("))
  4762.       break;
  4763.     pp++;
  4764.     }
  4765.     if ((y = parsevar(s,&x,&z)) < 0)    /* Check variable. */
  4766.       return(y);
  4767.  
  4768.     lp = line;                /* Build a copy of the command */
  4769.     strcpy(lp,"_forx ");
  4770.     lp += (int)strlen(line);        /* "_for" macro. */
  4771.     ap = lp;                /* Save pointer to macro args. */
  4772.  
  4773.     if (*s == CMDQ) s++;        /* Skip past backslash if any. */
  4774.     while (*lp++ = *s++) ;        /* copy it */
  4775.     lp--; *lp++ = SP;            /* add a space */
  4776.  
  4777.     if ((y = cmnum("initial value","",10,&fx,xxstring)) < 0) {
  4778.     if (y == -3) return(-2);
  4779.     else return(y);
  4780.     }
  4781.     debug(F101,"dofor fx","",fx);
  4782.     s = atmbuf;                /* Copy the atom buffer */
  4783.  
  4784.     if ((int)strlen(s) < 1) goto badfor;
  4785. /*
  4786.   In edit 192, we change the loop variables to be evaluated at loop entry,
  4787.   not each time through the loop.  This was required in order to allow
  4788.   \v(argc) to be used as a loop variable, or in a loop-variable expression.
  4789.   Thus, we can't have FOR loops that modify their own exit conditions by
  4790.   changing the final value or the increment.  The problem with \v(argc) was
  4791.   that it is on the macro stack; after entry into the _forx macro, it is at
  4792.   the wrong place.
  4793. */
  4794.     sprintf(tmpbuf,"%d",fx);        /* Substitute actual value */
  4795.     s = tmpbuf;
  4796.     while (*lp++ = *s++) ;        /* (what they actually typed) */
  4797.     lp--; *lp++ = SP;
  4798.  
  4799.     if ((y = cmnum("final value","",10,&fy,xxstring)) < 0) {
  4800.     if (y == -3) return(-2);
  4801.     else return(y);
  4802.     }
  4803.     debug(F101,"dofor fy","",fy);
  4804.     s = atmbuf;                /* Same deal */
  4805.     if ((int)strlen(s) < 1)
  4806.       goto badfor;
  4807.  
  4808.     sprintf(tmpbuf,"%d",fy);
  4809.     s = tmpbuf;
  4810.     while (*lp++ = *s++) ;
  4811.     lp--;
  4812.     *lp++ = SP;
  4813.  
  4814.     x_ifnum = 1;            /* Increment or parenthesis */
  4815.     di = (fx < fy) ? "1" : "-1";    /* Default increment */
  4816.     if ((y = cmnum("increment",di,10,&fz,xxstring)) < 0) {
  4817.     debug(F111,"dofor increment",atmbuf,y);
  4818.     x_ifnum = 0;
  4819.     if (y == -3) {            /* Premature termination */
  4820.         return(-2);
  4821.     } else if (y == -2) {        /* Maybe closing paren */
  4822.         if (!strcmp(atmbuf,")")) {
  4823.         pp--;            /* Count it */
  4824.         s = di;            /* supply default interval */
  4825.         fz = atoi(s);
  4826.         } else            /* Not closing paren, invalid */
  4827.           return(y);
  4828.     } else                /* Other error */
  4829.       return(y);
  4830.     } else {                /* Number */
  4831.     x_ifnum = 0;
  4832.     debug(F101,"dofor fz","",fz);
  4833.     s = atmbuf;            /* Use it */
  4834.     }
  4835.     if ((int)strlen(s) < 1)
  4836.       goto badfor;
  4837.  
  4838.     sprintf(tmpbuf,"%d",fz);        /* Same deal */
  4839.     s = tmpbuf;
  4840.     while (*lp++ = *s++) ;
  4841.     lp--; *lp++ = SP;
  4842.  
  4843.     /* Insert the appropriate comparison operator */
  4844.     if (fz < 0)
  4845.       *lp++ = '<';
  4846.     else
  4847.       *lp++ = '>';
  4848.     *lp++ = SP;
  4849.  
  4850.     if (pp > 0) {            /* If open paren given parse closing */
  4851.     if ((y = cmfld("Closing parenthesis","",&s,NULL)) < 0)
  4852.       return(y);
  4853.     if (strcmp(atmbuf,")")) {
  4854.         printf("?Closing parenthesis required\n");
  4855.         return(-9);
  4856.     }
  4857.     }
  4858.     if ((y = cmtxt("Command to execute","",&s,NULL)) < 0) return(y);
  4859.     if ((y = (int)strlen(s)) < 1) return(-2);
  4860.     if (s[0] != '{' && s[y-1] != '}') {    /* Supply braces if missing */
  4861.     sprintf(tmpbuf,"{ %s }",s);
  4862.     s = tmpbuf;
  4863.     }
  4864.     if (litcmd(&s,&lp,(LINBUFSIZ - (lp - (char *)line) - 2)) < 0) {
  4865.     printf("?Unbalanced braces\n");
  4866.     return(0);
  4867.     }
  4868. #ifdef COMMENT
  4869. /* Too strict */
  4870.     if (fz == 0) {
  4871.     printf("?Zero increment not allowed\n");
  4872.     return(0);
  4873.     }
  4874. #endif /* COMMENT */
  4875.     x = mlook(mactab,"_forx",nmac);    /* Look up FOR macro definition */
  4876.     if (x < 0) {            /* Not there? */
  4877.     addmmac("_forx",for_def);    /* Put it back. */
  4878.     if ((x = mlook(mactab,"_forx",nmac)) < 0) { /* Look it up again. */
  4879.         printf("?FOR macro definition gone!\n"); /* Shouldn't happen. */
  4880.         return(success = 0);
  4881.     }
  4882.     }
  4883.     debug(F110,"FOR command",line,0);    /* Execute the FOR macro. */
  4884.     return(success = dodo(x,ap,cmdstk[cmdlvl].ccflgs | CF_IMAC));
  4885.  
  4886. badfor: printf("?Incomplete FOR command\n");
  4887.     return(-2);
  4888. }
  4889. #endif /* NOSPL */
  4890.  
  4891. #ifndef NOFRILLS
  4892. /* Do the BUG command */
  4893.  
  4894. int
  4895. dobug() {
  4896.     int n;
  4897.     char * s = "";
  4898.     extern char * k_info_dir;
  4899.  
  4900.     if (k_info_dir)
  4901.       s = k_info_dir;
  4902.  
  4903. #ifdef COMMENT
  4904.     printf("\n%s,%s\n Numeric: %ld",versio,ckxsys,vernum);
  4905. #endif /* COMMENT */
  4906.     printf(
  4907. "\nBefore requesting technical support from Columbia U., please consult:\n\n"
  4908.        );
  4909.     n = 7;
  4910. #ifdef OS2
  4911.     printf(" . Your \"Kermit 95\" user manual (use the MANUAL command).\n");
  4912.     printf(" . The technical reference manual, \"Using C-Kermit\".\n");
  4913.     printf(" . The README.TXT file in Kermit 95's directory on your disk.\n");
  4914.     printf(" . The BUGS.TXT file in Kermit 95's directory on your disk.\n");
  4915.     n += 5;
  4916. #else
  4917.     printf(" . The book \"Using C-Kermit\" (type HELP for more info).\n");
  4918.     n += 1;
  4919. #ifdef UNIX
  4920.     printf(" . The %sckermit2.txt and %sckcbwr.txt files.\n",s,s);
  4921.     printf(" . The %sckubwr.txt and %sckuins.txt files.\n",s,s);
  4922.     n += 2;
  4923. #else
  4924. #ifdef VMS
  4925.     printf(" . The CKERMIT2.TXT and CKCBWR.TXT files.\n");
  4926.     printf(" . The CKVBWR.TXT and CKVINS.TXT files.\n");
  4927.     n += 2;
  4928. #else
  4929. #ifdef datageneral
  4930.     printf(" . The ckermit2.txt and ckcbwr.txt files.\n");
  4931.     printf(" . The ckdbwr.txt file.\n");
  4932.     n += 2;
  4933. #else
  4934. #ifdef STRATUS
  4935.     printf(" . The ckermit2.txt and ckcbwr.txt files.\n");
  4936.     printf(" . The cklbwr.txt file\n");
  4937.     n += 2;
  4938. #else
  4939. #ifdef AMIGA
  4940.     printf(" . The ckermit2.txt and ckcbwr.txt files.\n");
  4941.     printf(" . The ckibwr.txt file\n");
  4942.     n += 2;
  4943. #else
  4944. #ifdef GEMDOS
  4945.     printf(" . The CKERMIT2.TXT and CKCBWR.TXT files.\n");
  4946.     printf(" . The CKSBWR.TXT file\n");
  4947.     n += 2;
  4948. #else
  4949. #ifdef MAC
  4950.     printf(" . The ckermit2.txt and ckcbwr.txt files.\n");
  4951.     printf(" . The ckmbwr.txt file\n");
  4952.     n += 2;
  4953. #else
  4954. #ifdef OSK
  4955.     printf(" . The ckermit2.txt and ckcbwr.txt files.\n");
  4956.     printf(" . The ck9bwr.txt file\n");
  4957.     n += 2;
  4958. #else
  4959.     printf(" . The CKERMIT2.TXT and CKCBWR.TXT files.\n");
  4960.     printf(" . The appropriate system-dependent CK?BWR.TXT file.\n");
  4961.     n += 2;
  4962. #endif
  4963. #endif
  4964. #endif
  4965. #endif
  4966. #endif
  4967. #endif
  4968. #endif
  4969. #endif
  4970. #endif /* OS2 */
  4971.  
  4972.     printf(" . Your own organization's support staff, if any.\n");
  4973.     printf(
  4974. " . The comp.protocols.kermit.misc newsgroup.\n");
  4975.     printf(
  4976. " . The Kermit support website, http://www.columbia.edu/kermit/support.html.\n"
  4977.        );
  4978.     printf(
  4979. " . The Kermit FAQ, http://www.columbia.edu/kermit/faq.html.\n");
  4980.     printf(
  4981. " . The C-Kermit FAQ, http://www.columbia.edu/kermit/ckfaq.html.\n");
  4982.     n += 4;
  4983.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4984.     printf("\n\
  4985. If you still need help or have a bug to report after consulting these sources,"
  4986.        );
  4987.     printf("\nsend e-mail to:\n\n");
  4988.     n += 2;
  4989.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4990.     printf("  kermit-support@columbia.edu\n\n");
  4991.     n += 1;
  4992.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4993.     printf("Or contact us by post:\n\n");
  4994.     printf(
  4995. "  Kermit, Columbia University, 612 W 115 Street, New York NY  10025, USA\n\n"
  4996.        );
  4997.     n += 1;
  4998.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4999.     printf("Or by fax at +1 (212) 663-8202.\n\n");
  5000.     n += 1;
  5001.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5002.     printf("Telephone support is available too:\n\n");
  5003.     n += 1;
  5004.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5005.     printf("  +1 (900) 555-5595, USA only, $2.50 per minute\n");
  5006.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5007.     printf(
  5008.     "  +1 (212) 854-5126, from anywhere, $25.00 USD per call, MC/Visa\n\n");
  5009.     n += 1;
  5010.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5011. #ifndef NOSHOW
  5012. #ifndef NOFRILLS
  5013.     printf(
  5014. "Before reporting problems, please use the SHOW VERSION and SHOW FEATURES\n");
  5015.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5016.     printf(
  5017. "commands to get detailed program version and configuration information.\n\n");
  5018. #endif /* NOFRILLS */
  5019. #endif /* NOSHOW */
  5020.     return(1);
  5021. }
  5022. #endif /* NOFRILLS */
  5023.  
  5024. #ifndef NOSPL
  5025.  
  5026. /*  T O D 2 S E C  --  Convert time of day as hh:mm:ss to secs since midnite */
  5027. /*
  5028.   Call with a string hh:mm or hh:mm:ss.
  5029.   Returns a 0 to 86400 on success, or a negative number on failure.
  5030. */
  5031. long
  5032. tod2sec(t) char * t; {
  5033.     long t2;
  5034.     long hh = 0L, mm = 0L, ss = 0L;
  5035.  
  5036.     if (!t) t = "";
  5037.     if (!*t)
  5038.       return(-3);
  5039.     debug(F110,"tod2sec",t,0);
  5040.  
  5041.     if (isdigit(*t))            /* Get hours from argument */
  5042.       hh = *t++ - '0';
  5043.     else
  5044.       return(-1L);
  5045.     if (isdigit(*t))
  5046.       hh = hh * 10 + *t++ - '0';
  5047. #ifdef COMMENT
  5048.     if (hh > 24L)
  5049.       return(-1L);
  5050. #endif /* COMMENT */
  5051.     if (*t == ':')
  5052.       t++;
  5053.     else if (!*t)
  5054.       goto xtod2sec;
  5055.     else
  5056.       return(-1L);
  5057.  
  5058.     if (isdigit(*t))            /* Minutes */
  5059.       mm = *t++ - '0';
  5060.     else
  5061.       return(-1L);
  5062.     if (isdigit(*t))
  5063.       mm = mm * 10 + *t++ - '0';
  5064.     if (mm > 60L)
  5065.       return(-1L);
  5066.     if (*t == ':')
  5067.       t++;
  5068.     else if (!*t)
  5069.       goto xtod2sec;
  5070.     else
  5071.       return(-1L);
  5072.  
  5073.     if (isdigit(*t))            /* Seconds */
  5074.       ss = *t++ - '0';
  5075.     else
  5076.       return(-1L);
  5077.     if (isdigit(*t))
  5078.       ss = ss * 10 + *t++ - '0';
  5079.     if (ss > 60L)
  5080.       return(-1L);
  5081.  
  5082.     if (*t > 32)            /* No trailing junk allowed */
  5083.       return(-1L);
  5084.  
  5085.   xtod2sec:
  5086.  
  5087.     t2 = hh * 3600L + mm * 60L + ss;    /* Seconds since midnight from arg */
  5088.     debug(F101,"tod2sec t2","",t2);
  5089.  
  5090.     return(t2);
  5091. }
  5092.  
  5093. int waitinterval = 1;
  5094.  
  5095. #ifdef OLDWAIT
  5096. #undef OLDWAIT
  5097. #endif /* OLDWAIT */
  5098.  
  5099. int kbchar = NUL;
  5100.  
  5101. int
  5102. dopaus(cx) int cx; {
  5103.     long zz;
  5104.     extern int sleepcan;
  5105.  
  5106. #ifdef OLDWAIT
  5107.     zz = -1L;
  5108.     x_ifnum = 1;            /* Turn off internal complaints */
  5109.     if (cx == XXWAI)
  5110.       y = cmnum("seconds to wait, or time of day hh:mm:ss","1",10,&x,xxstring);
  5111.     else if (cx == XXPAU)
  5112.       y = cmnum("seconds to pause, or time of day hh:mm:ss",
  5113.         "1",10,&x,xxstring);
  5114.     else
  5115.       y = cmnum("milliseconds to sleep, or time of day hh:mm:ss",
  5116.         "100",10,&x,xxstring);
  5117.     x_ifnum = 0;
  5118.     if (y < 0) {
  5119.     if (y == -2) {            /* Invalid number or expression */
  5120.         char *p = tmpbuf;        /* Retrieve string from atmbuf */
  5121.         int n = TMPBUFSIZ;
  5122.         *p = NUL;
  5123.         zzstring(atmbuf,&p,&n);    /* Evaluate in case it's a variable */
  5124.         zz = tod2sec(tmpbuf);    /* Convert to secs since midnight */
  5125.         if (zz < 0L) {
  5126.         printf("?Number, expression, or time of day required\n");
  5127.         return(-9);
  5128.         } else {
  5129.         char now[32];        /* Current time */
  5130.         char *p;
  5131.         long tnow;
  5132.         p = now;
  5133.         ztime(&p);
  5134.         tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
  5135.         if (zz < tnow)        /* User's time before now */
  5136.           zz += 86400L;        /* So make it tomorrow */
  5137.         zz -= tnow;        /* Seconds from now. */
  5138.         }
  5139.     } else
  5140.       return(y);
  5141.     }
  5142.     if (x < 0) x = 0;
  5143.     switch (cx) {
  5144.       case XXPAU:            /* PAUSE */
  5145.       case XXMSL:            /* MSLEEP */
  5146.     if ((y = cmcfm()) < 0) return(y);
  5147.     break;
  5148.       case XXWAI:            /* WAIT */
  5149.     z = 0;                /* Modem signal mask */
  5150.     while (1) {            /* Read zero or more signal names */
  5151.         y = cmkey(mstab,nms,"modem signal","",xxstring);
  5152.         if (y == -3) break;        /* -3 means they typed CR */
  5153.         if (y < 0) return(y);    /* Other negatives are errors */
  5154.         z |= y;            /* OR the bit into the signal mask */
  5155.     }
  5156.     if ((y = cmcfm()) < 0) return(y);
  5157.     break;
  5158.  
  5159.       default:                /* Shouldn't happen */
  5160.     return(-2);
  5161.     }
  5162.  
  5163. /* Command is entered, now do it. */
  5164.  
  5165.     if (zz > -1L) {            /* Time of day given? */
  5166.     x = zz;
  5167.     if (zz != (long) x) {
  5168.         printf(
  5169. "Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n"
  5170.            );
  5171.         return(-9);
  5172.     }
  5173.     }
  5174.     if (cx == XXMSL) {            /* Millisecond sleep */
  5175.     msleep(zz < 0 ? x : x * 1000);
  5176.     return(success = 1);
  5177.     }
  5178.     if (cx == XXPAU && !sleepcan) {    /* SLEEP CANCELLATION is OFF */
  5179.     sleep(x);
  5180.     return(success = 1);
  5181.     }
  5182.  
  5183.     /* WAIT, or else SLEEP with cancellation allowed... */
  5184.  
  5185.     do {                /* Sleep loop */
  5186.     int mdmsig;
  5187.     if (sleepcan) {            /* Keyboard cancellation allowed? */
  5188.         if (y = conchk()) {        /* Did they type something? */
  5189. #ifdef COMMENT
  5190.         while (y--) coninc(0);    /* Yes, gobble it all up */
  5191. #else
  5192.         /* There is a debate over whether PAUSE should absorb    */
  5193.         /* its cancelling character(s).  There are several       */
  5194.         /* reasons why it should gobble at least one character:  */
  5195.         /* (1) MS-DOS Kermit does it                             */
  5196.         /* (2) if not, subsequent PAUSE commands will terminate  */
  5197.         /*     immediately                                       */
  5198.         /* (3) if not, subsequent ASK commands will use it as    */
  5199.         /*     valid input.  If \13, then it will get no input   */
  5200.         /* (4) if not, then the character appears on the command */
  5201.         /*     line after all enclosing macros are complete.     */
  5202.         kbchar = coninc(0);    /* Gobble one up */
  5203. #endif /* COMMENT */
  5204.         break;            /* And quit PAUSing or WAITing */
  5205.         }
  5206.     }
  5207.     if (cx == XXWAI) {        /* WAIT (z == modem signal mask) */
  5208.         debug(F101,"WAIT x","",x);
  5209.         if (z > 0) {        /* Looking for any modem signals? */
  5210.         mdmsig = ttgmdm();    /* Yes, get them */
  5211.         if (mdmsig < 0)        /* Failed */
  5212.           return(success = 0);
  5213.         if ((mdmsig & z) == z)    /* Got what we wanted? */
  5214.           return(success = 1);    /* Succeed */
  5215.         }
  5216.         if (x == 0)            /* WAIT 0 and didn't get our signals */
  5217.           break;
  5218.     }
  5219.     sleep(1);            /* No interrupt, sleep one second */
  5220.     } while (--x > 0);
  5221.  
  5222.     if (cx == XXWAI)            /* If WAIT and loop exhausted */
  5223.       success = (z == 0);        /* Fail. */
  5224.     else                /*  */
  5225.       success = (x == 0);        /* Set SUCCESS/FAILURE for PAUSE. */
  5226.     return(success);
  5227.  
  5228. #else  /* New code uses chained FDBs and allows FILE waits... */
  5229.  
  5230.     char * m = "";            /* Help message */
  5231.     struct FDB nu, fl, kw;        /* Parse function descriptor blocks */
  5232.     int filewait = 0;
  5233.     int mdmsig = 0, fs = 0;
  5234.     char filedate[32];
  5235.  
  5236.     kbchar = 0;
  5237.  
  5238.     switch (cx) {
  5239.       case XXWAI: m = "seconds to wait, or time of day hh:mm:ss"; break;
  5240.       case XXPAU: m = "seconds to pause, or time of day hh:mm:ss"; break;
  5241.       case XXMSL: m = "milliseconds to sleep, or time of day hh:mm:ss"; break;
  5242.     }
  5243.     zz = -1L;
  5244.     cmfdbi(&nu,
  5245.        _CMNUM,            /* Number */
  5246.        m,                /* Help message */
  5247.        (cx == XXMSL) ? "100" : "1",    /* Default */
  5248.        "",                /* N/A */
  5249.        0,                /* N/A */
  5250.        0,                /* N/A */
  5251.        xxstring,            /* Processing function */
  5252.        NULL,            /* N/A */
  5253.        &fl                /* Next */
  5254.        );
  5255.     cmfdbi(&fl,                /* Time of day */
  5256.        _CMFLD,            /* Field */
  5257.        "",                /* hlpmsg */
  5258.        "",                /* default */
  5259.        "",                /* addtl string data */
  5260.        0,                /* addtl numeric data 1 */
  5261.        0,                /* addtl numeric data 2 */
  5262.        xxstring,            /* processing func */
  5263.        NULL,            /* N/A */
  5264.        NULL                /* No next */
  5265.        );
  5266.     x = cmfdb(&nu);            /* Parse a number or a field */
  5267.     if (x < 0) {
  5268.     if (x == -3)
  5269.       x = -2;
  5270.     return(x);
  5271.     }
  5272.     switch (cmresult.fcode) {
  5273.       case _CMNUM:            /* Number */
  5274.     x = cmresult.nresult;
  5275.     break;
  5276.       case _CMFLD:            /* Field */
  5277.     zz = tod2sec(cmresult.sresult);    /* Convert to secs since midnight */
  5278.     if (zz < 0L) {
  5279.         printf("?Number, expression, or time of day required\n");
  5280.         return(-9);
  5281.     } else {
  5282.         char now[32];        /* Current time */
  5283.         char *p;
  5284.         long tnow;
  5285.         p = now;
  5286.         ztime(&p);
  5287.         tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
  5288.         if (zz < tnow)        /* User's time before now */
  5289.           zz += 86400L;        /* So make it tomorrow */
  5290.         zz -= tnow;        /* Seconds from now. */
  5291.     }
  5292.     }
  5293.     debug(F101,"PAUSE/WAIT/MSLEEP zz","",zz);
  5294.     switch (cx) {
  5295.       case XXPAU:            /* PAUSE */
  5296.       case XXMSL:            /* MSLEEP */
  5297.     if ((y = cmcfm()) < 0) return(y);
  5298.     break;
  5299.       case XXWAI:            /* WAIT */
  5300.     z = 0;                /* Modem signal mask */
  5301.     y = cmkey(waittab,nwaittab,"","",xxstring);
  5302.     if (y < 0) {
  5303.         if (y == -3) {
  5304.         if ((y = cmcfm()) < 0)
  5305.           return(y);
  5306.         break;
  5307.         } else
  5308.           return(y);
  5309.     }
  5310.     if (y == WAIT_FIL) {        /* FILE */
  5311.         int wild = 0;
  5312.         if ((z = cmkey(wfswi,nwfswi,"event","",xxstring)) < 0)
  5313.           return(z);
  5314.         filewait = z;
  5315.         if (filewait == WF_MOD || filewait == WF_DEL)
  5316.           z = cmifi("Filename","",&s,&wild,xxstring);
  5317.         else
  5318.           z = cmfld("Filename","",&s,xxstring);
  5319.         if (z < 0)
  5320.           return(z);
  5321.         if (wild || (filewait == WF_CRE) && iswild(s)) {
  5322.         printf("?Wildcards not valid here\n");
  5323.         return(-9);
  5324.         }
  5325.         strcpy(tmpbuf,s);
  5326.         if ((z = cmcfm()) < 0)
  5327.           return(z);
  5328.         break;
  5329.     } else if (y != WAIT_MDM) {    /* A modem signal */
  5330.         z |= y;            /* OR the bit into the signal mask */
  5331.     }
  5332.     if (!filewait) {        /* Modem signals... */
  5333.         while (1) {            /* Get zero or more signal names */
  5334.         y = cmkey(mstab,nms,"modem signal","",xxstring);
  5335.         if (y == -3) break;    /* -3 means they typed CR */
  5336.         if (y < 0) return(y);    /* Other negatives are errors */
  5337.         z |= y;            /* OR the bit into the signal mask */
  5338.         }
  5339.         if ((y = cmcfm()) < 0) return(y);
  5340.         break;
  5341.     }
  5342.  
  5343.       default:                /* Shouldn't happen */
  5344.     return(-2);
  5345.     } /* switch (cx) */
  5346.  
  5347. /* Command is entered, now do it. */
  5348.  
  5349.     if (zz > -1L) {            /* Time of day given? */
  5350.     x = zz;
  5351.     if (zz != (long) x) {
  5352.         printf(
  5353. "Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n"
  5354.            );
  5355.         return(-9);
  5356.     }
  5357.     }
  5358.     if (sleepcan)
  5359.       concb((char)escape);        /* Ensure single-char wakeup */
  5360.  
  5361.     if (cx == XXMSL) {            /* Millisecond sleep */
  5362.     msleep(zz < 0 ? x : x * 1000);
  5363.     return(success = 1);
  5364.     }
  5365.     if (cx == XXPAU && !sleepcan) {    /* SLEEP CANCELLATION is OFF */
  5366.     sleep(x);
  5367.     return(success = 1);
  5368.     }
  5369.     if (filewait) {            /* FILE... */
  5370.     fs = zchki(tmpbuf);        /* Check if file exists */
  5371.     switch (filewait) {
  5372.       case WF_DEL:
  5373.         if (fs == -1)
  5374.           return(success = 1);
  5375.         break;
  5376.       case WF_MOD:
  5377.         if (fs == -1) {
  5378.         printf("?File does not exit: %s\n",tmpbuf);
  5379.         return(-9);
  5380.         }
  5381.         s = zfcdat(tmpbuf);        /* Get current modification date */
  5382.         if (!s) s = "";
  5383.         if (ckstrncpy(filedate,s,32) != 17) {
  5384.         printf("?Can't get modification time: %s\n",tmpbuf);
  5385.         return(-9);
  5386.         }
  5387.         break;
  5388.       case WF_CRE:
  5389.         if (fs > -1)
  5390.           return(success = 1);
  5391.         break;
  5392.     }
  5393.     }
  5394.     do {                /* Polling loop */
  5395.     if (sleepcan) {            /* Keyboard cancellation allowed? */
  5396.         if ((y = conchk()) > 0) {    /* Did they type something? */
  5397.         kbchar = coninc(0);    /* Yes, get first char they typed */
  5398.         debug(F000,"WAIT kbchar","",kbchar);
  5399. #ifdef COMMENT
  5400.         while (--y > 0)        /* Gobble the rest up */
  5401.           coninc(0);
  5402. #endif /* COMMENT */
  5403.         return(success = 0);    /* And quit PAUSing or WAITing */
  5404.         }
  5405.     }
  5406.     if (filewait == 0) {
  5407.         if (cx == XXWAI) {        /* WAIT for modem signals */
  5408.         if (z != 0) {
  5409.             mdmsig = ttgmdm();    /* Get them. */
  5410.             debug(F101,"WAIT ttgmdm","",mdmsig);
  5411.             if (mdmsig < 0)    /* Failure to get them? */
  5412.               return(success = 0); /* Fail. */
  5413.             if ((mdmsig & z) == z) /* Got desired ones? */
  5414.               return(success = 1); /* Succeed. */
  5415.         } else if (x == 0)
  5416.           return(success = 0);
  5417.         }
  5418.     } else {            /* FILE... */
  5419.         fs = zchki(tmpbuf);        /* Get file status */
  5420.         if (filewait == WF_MOD) {    /* Wait for modification */
  5421.         if (fs == -1)        /* Failure to get status */
  5422.           return(success = 0);    /* so WAIT fails. */
  5423.         s = zfcdat(tmpbuf);    /* Get current modification time */
  5424.         if (!s) s = "";        /* And compare with the time */
  5425.         if (strcmp(s,filedate))    /* when the WAIT started */
  5426.           return(success = 1);
  5427.         } else if (filewait == WF_DEL) { /* Wait for deletion */
  5428.         if (fs == -1)        /* If file doesn't exist, */
  5429.           return(success = 1);    /* succeed. */
  5430.         } else if (filewait == WF_CRE) { /* Wait for creation */
  5431.         if (fs != -1)        /* If file exists */
  5432.           return(success = 1);    /* succeed. */
  5433.         }
  5434.     }
  5435.     if (x < 1)            /* SLEEP/WAIT/PAUSE 0 */
  5436.       break;
  5437.     sleep(waitinterval);        /* No interrupt, sleep */
  5438.     x -= waitinterval;        /* Deduct sleep time */
  5439.     } while (x > 0);
  5440.  
  5441.     if (cx == XXWAI)            /* WAIT time expired */
  5442.       success = (z == 0);        /* Succeed if no modem signals */
  5443.     else                /* For SLEEP or PAUSE, success */
  5444.       success = (x == 0);        /* depends on whether it was */
  5445.     return(success);            /* interrupted from the keyboard. */
  5446. #endif /* OLDWAIT */
  5447. }
  5448. #endif /* NOSPL */
  5449.  
  5450.  
  5451. #ifndef NOFRILLS
  5452. #ifdef ZCOPY
  5453. int
  5454. docopy() {
  5455.     int i, x, listing = 0, havename = 0;
  5456.     struct FDB sw, fi;
  5457.     int swapping = 0;
  5458.     int appending = 0;
  5459.     int fromb64 = 0;
  5460.     int tob64 = 0;
  5461.  
  5462.     cmfdbi(&sw,                /* 2nd FDB - optional /PAGE switch */
  5463.        _CMKEY,            /* fcode */
  5464.        "Filename or switch",    /* hlpmsg */
  5465.        "",                /* default */
  5466.        "",                /* addtl string data */
  5467.        ncopytab,            /* addtl numeric data 1: tbl size */
  5468.        4,                /* addtl numeric data 2: 4 = cmswi */
  5469.        xxstring,            /* Processing function */
  5470.        copytab,            /* Keyword table */
  5471.        &fi                /* Pointer to next FDB */
  5472.        );
  5473.     cmfdbi(&fi,                /* 1st FDB - file to type */
  5474.        _CMIFI,            /* fcode */
  5475.        "",                /* hlpmsg */
  5476.        "",                /* default */
  5477.        "",                /* addtl string data */
  5478.        0,                /* addtl numeric data 1 */
  5479.        0,                /* addtl numeric data 2 */
  5480.        xxstring,
  5481.        NULL,
  5482.        NULL
  5483.        );
  5484.  
  5485.     while (!havename) {
  5486.     x = cmfdb(&sw);            /* Parse something */
  5487.     if (x < 0)            /* Error */
  5488.       return(x);
  5489.     switch (cmresult.fcode) {
  5490.       case _CMKEY:
  5491.         switch (cmresult.nresult) {
  5492.           case DEL_LIS:
  5493.           case DEL_VRB:
  5494.         listing = 1;
  5495.         break;
  5496.           case DEL_NOL:
  5497.           case DEL_QUI:
  5498.         listing = 0;
  5499.         break;
  5500.           case 999:
  5501.         swapping = 1;
  5502.         break;
  5503.           case 998:
  5504.         appending = 1;
  5505.         break;
  5506. #ifndef NOSPL
  5507.           case 997:
  5508.         fromb64 = 1;
  5509.         break;
  5510.           case 996:
  5511.         tob64 = 1;
  5512.         break;
  5513. #endif /* NOSPL */
  5514.         }
  5515.         break;
  5516.       case _CMIFI:
  5517.         s = cmresult.sresult;
  5518.         havename = 1;
  5519.         break;
  5520.       default:
  5521.         return(-2);
  5522.     }
  5523.     }
  5524.     if (cmresult.nresult > 0) {        /* No wildcards allowed */
  5525.     printf(
  5526.        "\n?Multiple files not allowed - please specify a single file.\n");
  5527.     return(-9);
  5528.     }
  5529.     ckstrncpy(line,s,LINBUFSIZ);    /* Make a safe copy of source name */
  5530.     p = line + (int)strlen(line) + 2;    /* Place for destination name */
  5531.  
  5532.     if ((x = cmofi("destination name and/or directory",
  5533. #ifdef UNIX
  5534.            "."
  5535. #else
  5536.            ""
  5537. #endif /* UNIX */
  5538.            ,&s,xxstring)) < 0) {
  5539.         /* Get destination name */
  5540.     if (x == -3) {
  5541.         printf("?Name for destination file required\n");
  5542.         return(-9);
  5543.     } else return(x);
  5544.     }
  5545.     ckstrncpy(p,s,LINBUFSIZ-(p-line));    /* Safe copy of destination name */
  5546.     if ((y = cmcfm()) < 0) return(y);
  5547.     if (appending && swapping) {
  5548.     printf("?Sorry, /APPEND and /SWAP conflict\n");
  5549.     return(-9);
  5550.     }
  5551. #ifdef VMS
  5552.     conres();                /* Let Ctrl-C work. */
  5553. #endif /* VMS */
  5554.     debug(F110,"docopy line",line,0);
  5555.     debug(F110,"docopy p",p,0);
  5556.     if (iswild(line)) {
  5557.     printf("?Wildcards not allowed\n");
  5558.     return(-9);
  5559.     }
  5560. #ifdef IKSD
  5561.     if (zchki(p) > -1) {        /* Destination file exists? */
  5562.     if (inserver && (!ENABLED(en_del)
  5563. #ifdef CK_LOGIN
  5564.              || isguest
  5565. #endif /* CK_LOGIN */
  5566.              )) {
  5567.         printf("?Sorry, changing existing files is disabled\n");
  5568.         return(-9);
  5569.     }
  5570.     }
  5571. #endif /* IKSD */
  5572.     if (listing) printf("%s => %s ",line,p);
  5573.  
  5574.     if (tob64 && fromb64) {        /* To and from B64 = no conversion */
  5575.     tob64 = 0;
  5576.     fromb64 = 0;
  5577.     }
  5578.     if (!swapping && !appending && !fromb64 && !tob64) { /* Straight copy */
  5579.     if ((x = zcopy(line,p)) < 0) {    /* Let zcopy() do it. */
  5580.         switch (x) {
  5581.           case -2:
  5582.         printf("?Not a regular file - \"%s\"\n", line);
  5583.         break;
  5584.           case -3:
  5585.         printf("?Not found or not accessible - \"%s\"\n", line);
  5586.         break;
  5587.           case -4:
  5588.         printf("?Permission denied\n");
  5589.         break;
  5590.           case -5:
  5591.         printf("?Source and destination are the same file\n");
  5592.         break;
  5593.           case -6:
  5594.         printf("?Input/Output error\n");
  5595.         break;
  5596.           case -7:
  5597.         printf("?Error opening output file - \"%s\"\n", p);
  5598.         break;
  5599.           default:
  5600.         printf("?Can't copy %s to %s\n",line,p);
  5601.         }
  5602. #ifdef VMSORUNIX
  5603.         concb((char)escape);
  5604. #endif /* VMSORUNIX */
  5605.         return(-9);
  5606.     } else {
  5607. #ifdef VMSORUNIX
  5608.         concb((char)escape);
  5609. #endif /* VMSORUNIX */
  5610.         if (listing) printf("(OK)\n");
  5611.         return(success = 1);
  5612.     }
  5613.     } else {                /* Special options */
  5614.  
  5615.     int prev, y, x = 0;        /* Variables needed for them */
  5616.     int rc = 0, i, t;
  5617.     char ibuf[100];
  5618.     char obuf[200];
  5619.     FILE * in = NULL;
  5620.     FILE * out = NULL;
  5621.     errno = 0;            /* Reset errno */
  5622.  
  5623.     if ((in = fopen(line,"r")) == NULL) { /* Open input file */
  5624.         perror(line);
  5625.         return(-9);
  5626.     }
  5627.     if ((out = fopen(p, (appending ? "a" : "w"))) == NULL) {
  5628.         fclose(in);
  5629.         perror(p);
  5630.         return(-9);
  5631.     }
  5632. #ifndef NOSPL
  5633.     if (tob64) {            /* Converting to Base-64 */
  5634.         while (1) {
  5635.         prev = x;
  5636.         if ((x = fread(ibuf,1,54,in)) < 1) {
  5637.             rc = 1;
  5638.             break;
  5639.         }
  5640.         if (prev % 3) {
  5641.             printf("?Phase error: %d\n", prev);
  5642.             rc = -9;
  5643.             break;
  5644.         }
  5645.         if (swapping) {
  5646.             if (x & 1) {
  5647.             printf("?Swap error\n");
  5648.             rc = -9;
  5649.             break;
  5650.             }
  5651.             for (i = 0; i < x; i+=2) {
  5652.             t = ibuf[i];
  5653.             ibuf[i] = ibuf[i+1];
  5654.             ibuf[i+1] = t;
  5655.             }
  5656.         }
  5657.         if ((y = b8tob64(ibuf,x,obuf,180)) < 0) {
  5658.             printf("?Encoding error\n");
  5659.             rc = -9;
  5660.             break;
  5661.         }
  5662.         fprintf(out,"%s\n",obuf);
  5663.         }
  5664.  
  5665.     } else if (fromb64) {        /* Converting from Base 64 */
  5666.  
  5667.         if ((out = fopen(p,appending ? "a" : "w")) == NULL) {
  5668.         fclose(in);
  5669.         perror(p);
  5670.         return(-9);
  5671.         }
  5672.         x = 1;
  5673.         while (x) {
  5674.         x = fread(ibuf,1,80,in);
  5675.         if ((y = b64tob8(ibuf,x,obuf,80)) < 0) {
  5676.             printf("?Decoding error\n");
  5677.             rc = -9;
  5678.             break;
  5679.         }
  5680.         if (swapping) {
  5681.             if (x & 1) {
  5682.             printf("?Swap error\n");
  5683.             rc = -9;
  5684.             break;
  5685.             }
  5686.             for (i = 0; i < y; i+=2) {
  5687.             t = obuf[i];
  5688.             obuf[i] = obuf[i+1];
  5689.             obuf[i+1] = t;
  5690.             }
  5691.         }
  5692.         if (y > 0) {
  5693.             if (fwrite(obuf,1,y,out) < 1) {
  5694.             perror(p);
  5695.             rc = -9;
  5696.             break;
  5697.             }
  5698.         }
  5699.         }
  5700.  
  5701.     } else
  5702. #endif /* NOSPL */
  5703.  
  5704.     if (swapping) {            /* Swapping bytes */
  5705.  
  5706.         char c[3];
  5707.         c[2] = NUL;
  5708.  
  5709.         while (1) {
  5710.         x = fread((char *)c,1,2,in);
  5711.         if (x < 1) {
  5712.             rc = 1;
  5713.             break;
  5714.         } else if (x == 1) {
  5715.             c[1] = c[0];
  5716.             c[0] = NUL;
  5717.             printf(
  5718.              "?WARNING: source file contains odd number of bytes\n");
  5719.         }
  5720.         if (fprintf(out,"%c%c",c[1],c[0]) == EOF) {
  5721.             perror(p);
  5722.             rc = -9;
  5723.             break;
  5724.         }
  5725.         }
  5726.  
  5727.     } else if (appending) {        /* Appending to target file */
  5728.  
  5729.         char c;
  5730.         while (1) {
  5731.         x = fread(&c,1,1,in);
  5732.         if (x < 1) {
  5733.             rc = 1;
  5734.             break;
  5735.         }
  5736.         if (fwrite(&c,1,1,out) < 1) {
  5737.             perror(p);
  5738.             rc = -9;
  5739.             break;
  5740.         }
  5741.         }
  5742.     }
  5743.     if (out) fclose(out);
  5744.     if (in) fclose(in);
  5745.     if (rc > -1) success = rc;
  5746.     return(rc);
  5747.     }
  5748. }
  5749. #endif /* ZCOPY */
  5750. #endif /* NOFRILLS */
  5751.  
  5752. #ifndef NORENAME
  5753. #ifndef NOFRILLS
  5754. #ifdef ZRENAME
  5755. int
  5756. dorenam() {
  5757.     /* Parse a file or a directory name */
  5758.     int i, x, listing = 0, havename = 0;
  5759.     struct FDB sw, fi;
  5760.  
  5761.     cmfdbi(&sw,                /* 2nd FDB - optional /PAGE switch */
  5762.        _CMKEY,            /* fcode */
  5763.        "Filename or switch",    /* hlpmsg */
  5764.        "",                /* default */
  5765.        "",                /* addtl string data */
  5766.        nqvswtab,            /* addtl numeric data 1: tbl size */
  5767.        4,                /* addtl numeric data 2: 4 = cmswi */
  5768.        xxstring,            /* Processing function */
  5769.        qvswtab,            /* Keyword table */
  5770.        &fi                /* Pointer to next FDB */
  5771.        );
  5772.  
  5773.     cmfdbi(&fi,                /* 1st FDB - file to type */
  5774.        _CMIFI,            /* fcode */
  5775.        "",                /* hlpmsg */
  5776.        "",                /* default */
  5777.        "",                /* addtl string data */
  5778.        0,                /* addtl numeric data 1 */
  5779.        0,                /* addtl numeric data 2 */
  5780.        xxstring,
  5781.        NULL,
  5782.        NULL
  5783.        );
  5784.  
  5785.     while (!havename) {
  5786.     x = cmfdb(&sw);            /* Parse something */
  5787.     if (x < 0)            /* Error */
  5788.       return(x);
  5789.     switch (cmresult.fcode) {
  5790.       case _CMKEY:
  5791.         switch (cmresult.nresult) {
  5792.           case DEL_LIS:
  5793.           case DEL_VRB:
  5794.         listing = 1;
  5795.         break;
  5796.           case DEL_NOL:
  5797.           case DEL_QUI:
  5798.         listing = 0;
  5799.         break;
  5800.         }
  5801.         break;
  5802.       case _CMIFI:
  5803.         s = cmresult.sresult;
  5804.         havename = 1;
  5805.         break;
  5806.       default:
  5807.         return(-2);
  5808.     }
  5809.     }
  5810.     if (cmresult.nresult > 0) {        /* No wildcards allowed */
  5811.     printf(
  5812.        "\n?Multiple files not allowed - please specify a single file.\n");
  5813.     return(-9);
  5814.     }
  5815.     ckstrncpy(line,s,LINBUFSIZ);    /* Make a safe copy of the old name */
  5816.     p = line + (int)strlen(line) + 2;    /* Place for new name */
  5817.     if ((x = cmofi("New name","",&s,xxstring)) < 0) { /* Get new name */
  5818.     if (x == -3) {
  5819.         printf("?New name for file required\n");
  5820.         return(-9);
  5821.     } else return(x);
  5822.     }
  5823.     ckstrncpy(p,s,LINBUFSIZ-(p-line));    /* Make a safe copy of the new name */
  5824.     if ((y = cmcfm()) < 0) return(y);
  5825. #ifdef VMS
  5826.     conres();                /* Let Ctrl-C work. */
  5827. #endif /* VMS */
  5828.     debug(F110,"dorename line",line,0);
  5829.     debug(F110,"dorename p",p,0);
  5830.     if (listing) printf("%s => %s ",line,p);
  5831.     if (zrename(line,p) < 0) {
  5832.     printf("?Can't rename %s to %s\n",line,p);
  5833. #ifdef VMS
  5834.     concb((char)escape);
  5835. #endif /* VMS */
  5836.     return(-9);
  5837.     } else {
  5838. #ifdef VMS
  5839.     concb((char)escape);
  5840. #endif /* VMS */
  5841.     if (listing) printf("(OK)\n");
  5842.     return(success = 1);
  5843.     }
  5844. }
  5845. #endif /* ZRENAME */
  5846. #endif /* NOFRILLS */
  5847. #endif /* NORENAME */
  5848.  
  5849. #ifndef NOSPL
  5850.  
  5851. /* Do the RETURN command */
  5852.  
  5853. int
  5854. doreturn(s) char *s; {
  5855.     int x; char *p;
  5856.     extern int tra_asg;
  5857.     if (maclvl < 0) {
  5858.     printf("\n?Can't return from level %d\n",maclvl);
  5859.     return(success = 0);
  5860.     }
  5861.     lp = line;                /* Expand return value now */
  5862.     x = LINBUFSIZ-1;
  5863.     if (!s) s = "";
  5864.     if (zzstring(s,&lp,&x) > -1) {
  5865.     s = line;
  5866.     debug(F110,"RETURN parse",s,0);
  5867.     }
  5868.  
  5869.     /* Pop from all FOR/WHILE/SWITCH/XIFs */
  5870.     while ((maclvl > 0) &&
  5871.        (m_arg[maclvl-1][0]) &&
  5872.        (cmdstk[cmdlvl].src == CMD_MD) &&
  5873.        (!strncmp(m_arg[maclvl-1][0],"_xif",4) ||
  5874.         !strncmp(m_arg[maclvl-1][0],"_for",4) ||
  5875.         !strncmp(m_arg[maclvl-1][0],"_swi",4) ||
  5876.         !strncmp(m_arg[maclvl-1][0],"_whi",4))) {
  5877.     debug(F110,"RETURN popping",m_arg[maclvl-1][0],0);
  5878.     dogta(XXPTA);            /* Put args back */
  5879.     popclvl();            /* Pop up two levels */
  5880.     popclvl();
  5881.     debug(F101,"RETURN maclvl 2","",maclvl);
  5882.     }
  5883.     if (tra_asg) {            /* If tracing show return value */
  5884.     if (*s)
  5885.       printf("<<< %s: \"%s\"\n", m_arg[maclvl][0], s);
  5886.     else
  5887.       printf("<<< %s: (null)\n", m_arg[maclvl][0]);
  5888.     }
  5889.     popclvl();                /* Pop from enclosing TAKE or macro */
  5890.     debug(F101,"RETURN maclvl 3","",maclvl);
  5891.  
  5892.     x = (int)strlen(s);            /* Length of return value */
  5893.     if (x > 0) {            /* Have return value? */
  5894.     p = malloc(x+2);        /* Allocate a place to keep it */
  5895.     if (mrval[maclvl+1]) {        /* Free old one, if any */
  5896.         free(mrval[maclvl+1]);
  5897.         mrval[maclvl+1] = NULL;
  5898.     }
  5899.     if (p) {            /* Did we get a place? */
  5900.         strcpy(p, s);        /* Yes, copy the string into it. */
  5901.         mrval[maclvl+1] = p;    /* Make return value point to it. */
  5902.         debug(F110,"RETURN copy",mrval[maclvl],0);
  5903.     } else {            /* No, could not get space. */
  5904.         mrval[maclvl+1] = NULL;    /* Return null pointer. */
  5905.         x = 0;            /* Set failure return code. */
  5906.     }
  5907.     } else if (mrval[maclvl+1]) {
  5908.     makestr(&(mrval[maclvl+1]),NULL); /* Blank return code */
  5909.     }
  5910. #ifdef COMMENT
  5911.     /* What the heck is this? */
  5912.     return(success = x ? 1 : 0);    /* Return status code */
  5913. #else
  5914.     /* RETURN should not affect SUCCESS/FAILURE */
  5915.     return(0);
  5916. #endif /* COMMENT */
  5917. }
  5918. #endif /* NOSPL */
  5919.  
  5920. #ifndef NOSPL
  5921. /* Do the OPEN command */
  5922.  
  5923. int
  5924. doopen()  {                /* OPEN { append, read, write } */
  5925.     int x, y, z = 0; char *s;
  5926.     static struct filinfo fcb;        /* (must be static) */
  5927.     if ((x = cmkey(opntab,nopn,"mode","",xxstring)) < 0) {
  5928.     if (x == -3) {
  5929.         printf("?Mode required\n");
  5930.         return(-9);
  5931.     } else return(x);
  5932.     }
  5933.     switch (x) {
  5934.       case OPN_FI_R:            /* Old file (READ) */
  5935.     if (chkfn(ZRFILE) > 0) {
  5936.         printf("?Read file already open\n");
  5937.         return(-2);
  5938.     }
  5939.     if ((z = cmifi("File to read","",&s,&y,xxstring)) < 0) {
  5940.         if (z == -3) {
  5941.         printf("?Input filename required\n");
  5942.         return(-9);
  5943.         } else return(z);
  5944.     }
  5945.     if (y) {                /* No wildcards allowed */
  5946.         printf("\n?Please specify a single file\n");
  5947.         return(-2);
  5948.     }
  5949.     ckstrncpy(line,s,LINBUFSIZ);
  5950.     if ((int)strlen(line) < 1) return(-2);
  5951.     if ((z = cmnum("buffer size","4096",10,&y,xxstring)) < 0)
  5952.       return(z);
  5953.     if (y < 1) {
  5954.         printf("?Positive number required\n");
  5955.         return(-9);
  5956.     }
  5957.     if ((z = cmcfm()) < 0) return(z);
  5958.         readblock = y;
  5959.     if (readbuf)
  5960.       free(readbuf);
  5961.     if (!(readbuf = (CHAR *) malloc(readblock+1))) {
  5962.         printf("?Can't allocate read buffer\n");
  5963.         return(-9);
  5964.     }
  5965.     return(success = zopeni(ZRFILE,line));
  5966.  
  5967. #ifndef MAC
  5968. #ifndef NOPUSH
  5969.       case OPN_PI_R:            /* Pipe/Process (!READ) */
  5970.     if (nopush) {
  5971.         printf("?Read from pipe disabled\n");
  5972.         return(success=0);
  5973.     }
  5974.     if (chkfn(ZRFILE) > 0) {
  5975.         printf("?Read file already open\n");
  5976.         return(-2);
  5977.     }
  5978.         if ((y = cmtxt("System command to read from","",&s,xxstring)) < 0) {
  5979.         if (y == -3) {
  5980.         printf("?Command name required\n");
  5981.         return(-9);
  5982.         } else return(y);
  5983.     }
  5984.     ckstrncpy(line,s,LINBUFSIZ);
  5985.     if ((int)strlen(line) < 1) return(-2);
  5986.     if ((y = cmcfm()) < 0) return(y);
  5987.     if (!readbuf) {
  5988.         if (!(readbuf = (CHAR *) malloc(readblock+1))) {
  5989.         printf("?Can't allocate read buffer\n");
  5990.         return(-9);
  5991.         }
  5992.     }
  5993.     return(success = zxcmd(ZRFILE,line));
  5994.  
  5995.       case OPN_PI_W:            /* Write to pipe */
  5996.     if (nopush) {
  5997.         printf("?Write to pipe disabled\n");
  5998.         return(success=0);
  5999.     }
  6000.     if (chkfn(ZWFILE) > 0) {
  6001.         printf("?Write file already open\n");
  6002.         return(-2);
  6003.     }
  6004.         if ((y = cmtxt("System command to write to","",&s,xxstring)) < 0) {
  6005.         if (y == -3) {
  6006.         printf("?Command name required\n");
  6007.         return(-9);
  6008.         } else return(y);
  6009.     }
  6010.     ckstrncpy(line,s,LINBUFSIZ);
  6011.     if ((int)strlen(line) < 1) return(-2);
  6012.     if ((y = cmcfm()) < 0) return(y);
  6013.     success = zxcmd(ZWFILE,line);
  6014.     if (!success && msgflg)
  6015.       printf("Can't open process for writing: %s\n",line);
  6016.     return(success);
  6017. #endif /* NOPUSH */
  6018. #endif /* MAC */
  6019.  
  6020.       case OPN_FI_W:            /* New file (WRITE) */
  6021.       case OPN_FI_A:            /* (APPEND) */
  6022.     if ((z = cmofi("Name of local file to create","",&s,xxstring)) < 0) {
  6023.         if (z == -3) {
  6024.         printf("?Filename required\n");
  6025.         return(-9);
  6026.         } else return(z);
  6027.     }
  6028.     if (z == 2) {
  6029.         printf("?Sorry, %s is a directory name\n",s);
  6030.         return(-9);
  6031.     }
  6032.     if (chkfn(ZWFILE) > 0) {
  6033.         printf("?Write/Append file already open\n");
  6034.         return(-2);
  6035.     }
  6036.         fcb.bs = fcb.cs = fcb.rl = fcb.fmt = fcb.org = fcb.cc = fcb.typ = 0;
  6037.     fcb.lblopts = 0;
  6038.     fcb.dsp = (x == OPN_FI_W) ? XYFZ_N : XYFZ_A; /* Create or Append */
  6039.     ckstrncpy(line,s,LINBUFSIZ);
  6040.     if ((int)strlen(line) < 1) return(-2);
  6041.     if ((y = cmcfm()) < 0) return(y);
  6042.     return(success = zopeno(ZWFILE,line,NULL,&fcb));
  6043.  
  6044. #ifndef NOLOCAL
  6045.       case OPN_SER:            /* OPEN PORT or LINE */
  6046.       case OPN_NET: {            /* OPEN HOST */
  6047.       extern int didsetlin, ttnproto;
  6048.       if (x == OPN_NET) {
  6049.           z = ttnproto;
  6050.           ttnproto = NP_NONE;
  6051.       }
  6052.       if ((y = setlin((x == OPN_SER) ? XYLINE : XYHOST, 1, 0)) < 0) {
  6053.           if (x == OPN_NET)
  6054.         ttnproto = z;
  6055.           success = 0;
  6056.       }
  6057.       didsetlin++;
  6058.       return(y);
  6059.       }
  6060. #endif /* NOLOCAL */
  6061.  
  6062.       default:
  6063.     printf("?Not implemented");
  6064.     return(-2);
  6065.     }
  6066. }
  6067. #endif /* NOSPL */
  6068.  
  6069. #ifndef NOXFER
  6070. /*  D O X G E T  --  GET command parser with switches  */
  6071.  
  6072. #ifdef CK_LABELED
  6073. int g_lf_opts = -1;
  6074. extern int lf_opts;
  6075. #endif /* CK_LABELED */
  6076.  
  6077. int
  6078. doxget(cx) int cx; {
  6079.     extern int                /* External variables we need */
  6080. #ifdef RECURSIVE
  6081.       recursive,
  6082. #endif /* RECURSIVE */
  6083.       xfermode, fdispla, protocol,
  6084.       g_binary, g_xfermode, g_displa, g_rpath;
  6085.     extern char * rcv_move;        /* Directory to move new files to */
  6086.     extern char * rcv_rename;        /* What to rename new files to */
  6087.     extern char * g_rcv_move;
  6088.     extern char * g_rcv_rename;
  6089.     extern char * rcvexcept[];        /* RECEIVE / GET exception list */
  6090.     int opkt  =  0;            /* Flag for O-Packet needed */
  6091.  
  6092. #ifdef PIPESEND
  6093.     extern int pipesend;
  6094.     extern char * rcvfilter, * g_rfilter;
  6095. #endif /* PIPESEND */
  6096.     extern struct keytab rpathtab[];
  6097.     extern int nrpathtab;
  6098.     extern long calibrate;
  6099.     int asname = 0;            /* Flag for have as-name */
  6100.     int konly = 0;            /* Kermit-only function */
  6101.     int c, i, n, confirmed = 0;        /* Workers */
  6102.     int getval = 0;            /* Whether to get switch value */
  6103.     int rcvcmd = 0;            /* Whether it is the RECEIVE command */
  6104.     int mget = 0;            /* Whether it is the MGET command */
  6105.     struct stringint {            /* Temporary array for switch values */
  6106.     char * sval;
  6107.     int ival;
  6108.     } pv[SND_MAX+1];
  6109.     struct FDB sw, fl, cm;        /* FDBs for each parse function */
  6110.     char * cmdstr = "this command";
  6111.  
  6112.     debug(F101,"xget cx","",cx);
  6113.  
  6114.     oopts = -1;
  6115.     omode = -1;
  6116.  
  6117.     for (i = 0; i <= SND_MAX; i++) {    /* Initialize switch values */
  6118.     pv[i].sval = NULL;
  6119.     pv[i].ival = -1;
  6120.     }
  6121.     /* Preset switch values based on top-level command that called us */
  6122.  
  6123.     switch (cx) {
  6124.       case XXREC:            /* RECEIVE */
  6125.     cmdstr = "RECEIVE";
  6126.     rcvcmd = 1; break;
  6127.       case XXGET:            /* GET */
  6128.     cmdstr = "GET";
  6129.     konly = 1;
  6130.     break;
  6131. #ifdef CK_RESEND
  6132.       case XXREGET:            /* REGET */
  6133.     cmdstr = "REGET";
  6134.     konly = 1;
  6135.     pv[SND_BIN].ival = 1;        /* Implies /BINARY */
  6136.     pv[SND_RES].ival = 1; break;
  6137. #endif /* CK_RESEND */
  6138.       case XXRETR:            /* RETRIEVE */
  6139.     cmdstr = "RETRIEVE";
  6140.     konly = 1;
  6141.     pv[SND_DEL].ival = 1; break;
  6142. #ifdef PIPESEND
  6143.       case XXCREC:            /* CRECEIVE */
  6144.     cmdstr = "CRECEIVE";
  6145.     konly = 1;
  6146.     rcvcmd = 1;
  6147.     pv[SND_CMD].ival = 1; break;
  6148.       case XXCGET:            /* CGET */
  6149.     cmdstr = "CGET";
  6150.     konly = 1;
  6151.     pv[SND_CMD].ival = 1; break;
  6152. #endif /* PIPESEND */
  6153. #ifndef NOMGET
  6154.       case XXMGET:            /* MGET */
  6155.     cmdstr = "MGET";
  6156.     konly = 1;
  6157.     mget = 1; break;
  6158. #endif /* NOMGET */
  6159.     }
  6160.     debug(F111,"xget rcvcmd",cmdstr,rcvcmd);
  6161.     debug(F101,"xget konly","",konly);
  6162.  
  6163. #ifdef CK_XYZ
  6164.     if (!rcvcmd && protocol != PROTO_K) {
  6165.     printf("?Sorry, %s works only with Kermit protocol\n",cmdstr);
  6166.     return(-9);
  6167.     }
  6168. #endif /* CK_XYZ */
  6169.  
  6170.     /* Set up chained parse functions... */
  6171.  
  6172.     cmfdbi(&sw,                /* First FDB - command switches */
  6173.        _CMKEY,            /* fcode */
  6174.        rcvcmd ?
  6175.        "Optional name/template to store incoming files under, or switch" :
  6176.        "Remote filename, or switch", /* hlpmsg */
  6177.        "",                /* default */
  6178.        "",                /* addtl string data */
  6179.        rcvcmd ? nrcvtab : ngettab,    /* addtl numeric data 1: tbl size */
  6180.        4,                /* addtl numeric data 2: 4 = cmswi */
  6181.        xxstring,            /* Processing function */
  6182.        rcvcmd ? rcvtab : gettab,    /* Keyword table */
  6183.        &fl                /* Pointer to next FDB */
  6184.        );
  6185.     if (rcvcmd || mget)            /* RECEIVE or MGET */
  6186.       cmfdbi(&fl,
  6187.        _CMTXT,            /* fcode */
  6188.        rcvcmd ?            /* hlpmsg */
  6189.          "Output filename or Command" : /* Output filename */
  6190.          "File(s) to GET",            /* Files we are asking for */
  6191.        "",                /* default */
  6192.        "",                /* addtl string data */
  6193.        0,                /* addtl numeric data 1 */
  6194.        0,                /* addtl numeric data 2 */
  6195. #ifdef CK_XYZ
  6196.        (protocol == PROTO_X || protocol == PROTO_XC) ?
  6197.          xxstring :
  6198.          (rcvcmd ? (xx_strp)0  : xxstring)
  6199. #else
  6200.        rcvcmd ? (xx_strp)0  : xxstring /* Processing function */
  6201. #endif /* CK_XYZ */
  6202.          ,
  6203.        NULL,
  6204.        &cm
  6205.        );
  6206.     else
  6207.       cmfdbi(&fl,            /* Remote filename or command */
  6208.        _CMFLD,            /* fcode */
  6209.        "Remote filename",        /* hlpmsg */
  6210.        "",                /* default */
  6211.        "",                /* addtl string data */
  6212.        0,                /* addtl numeric data 1 */
  6213.        0,                /* addtl numeric data 2 */
  6214.        xxstring,
  6215.        NULL,
  6216.        &cm
  6217.        );
  6218.     cmfdbi(&cm,                /* Confirmation */
  6219.        _CMCFM,            /* fcode */
  6220.        "",                /* hlpmsg */
  6221.        "",                /* default */
  6222.        "",                /* addtl string data */
  6223.        0,                /* addtl numeric data 1 */
  6224.        0,                /* addtl numeric data 2 */
  6225.        NULL,
  6226.        NULL,
  6227.        NULL
  6228.        );
  6229.  
  6230.     /* (See doxsend() for fuller commentary) */
  6231.  
  6232.     while (1) {                /* Parse 0 or more switches */
  6233.     x = cmfdb(&sw);            /* Parse something */
  6234.     debug(F101,"xget cmfdb","",x);
  6235.     if (x < 0)            /* Error */
  6236.       goto xgetx;            /* or reparse needed */
  6237.     if (cmresult.fcode != _CMKEY)    /* Break out if not a switch */
  6238.       break;
  6239.     c = cmgbrk();            /* Get break character */
  6240.     if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
  6241.         printf("?This switch does not take an argument\n");
  6242.         x = -9;
  6243.         goto xgetx;
  6244.     }
  6245.     if (!getval && (cmgkwflgs() & CM_ARG)) {
  6246.         printf("?This switch requires an argument\n");
  6247.         x = -9;
  6248.         goto xgetx;
  6249.     }
  6250.     n = cmresult.nresult;        /* Numeric result = switch value */
  6251.     debug(F101,"xget switch","",n);
  6252.  
  6253.     switch (n) {            /* Process the switch */
  6254. #ifdef PIPESEND
  6255.       case SND_CMD:            /* These take no args */
  6256.         if (nopush) {
  6257.         printf("?Sorry, system command access is disabled\n");
  6258.         x = -9;
  6259.         goto xgetx;
  6260.         } else if (rcvfilter) {
  6261.         printf(
  6262. "?Sorry, no GET /COMMAND when RECEIVE FILTER selected\n");
  6263.         x = -9;
  6264.         goto xgetx;
  6265.         }
  6266.         if (rcvcmd)
  6267.           sw.hlpmsg = "Command, or switch"; /* Change help message */
  6268.         /* Fall thru... */
  6269. #endif /* PIPESEND */
  6270.  
  6271.       case SND_REC:            /* /RECURSIVE */
  6272.         pv[SND_PTH].ival = PATH_REL; /* Implies relative pathnames */
  6273.         pv[n].ival = 1;        /* Set the recursive flag */
  6274.         break;
  6275.  
  6276.       case SND_RES:            /* /RECOVER */
  6277.         pv[SND_BIN].ival = 1;    /* Implies /BINARY */
  6278.         pv[n].ival = 1;        /* Set the resend flag */
  6279.         break;
  6280.  
  6281.       case SND_DEL:            /* /DELETE */
  6282.       case SND_SHH:            /* /QUIET */
  6283.           case SND_CAL:            /* /CALIBRATE */
  6284.         pv[n].ival = 1;        /* Just set the appropriate flag */
  6285.         break;
  6286.  
  6287.       /* File transfer modes - each undoes the others */
  6288.  
  6289.       case SND_BIN:            /* Binary */
  6290.       case SND_TXT:            /* Text */
  6291.       case SND_IMG:            /* Image */
  6292.       case SND_LBL:            /* Labeled */
  6293.         pv[SND_BIN].ival = 0;    /* Unset all */
  6294.         pv[SND_TXT].ival = 0;
  6295.         pv[SND_IMG].ival = 0;
  6296.         pv[SND_LBL].ival = 0;
  6297.         pv[n].ival = 1;        /* Set the requested one */
  6298.         break;
  6299.  
  6300.       case SND_EXC:            /* Excludes */
  6301.         if (!getval) break;
  6302.         if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
  6303.         if (x == -3) {
  6304.             printf("?Pattern required\n");
  6305.             x = -9;
  6306.         }
  6307.         goto xgetx;
  6308.         }
  6309.         if (pv[n].sval) free(pv[n].sval);
  6310.         y = strlen(s);
  6311.         if (y > 256) {
  6312.         printf("?Pattern too long - 256 max\n");
  6313.         x = -9;
  6314.         goto xgetx;
  6315.         }
  6316.         pv[n].sval = malloc(y+1);
  6317.         if (pv[n].sval) {
  6318.         strcpy(pv[n].sval,s);
  6319.         pv[n].ival = 1;
  6320.         }
  6321.         break;
  6322.  
  6323. #ifdef COMMENT
  6324.       /* Not implemented */
  6325.       case SND_PRI:            /* GET to printer */
  6326.         pv[n].ival = 1;
  6327.         if (!getval) break;
  6328.         if ((x = cmfld("Print options","",&s,xxstring)) < 0)
  6329.           goto xgetx;
  6330.         pv[n].sval = malloc((int)strlen(s)+1);
  6331.         if (pv[n].sval)
  6332.           strcpy(pv[n].sval,s);
  6333.         break;
  6334. #endif /* COMMENT */
  6335.  
  6336.       case SND_MOV:            /* MOVE after */
  6337.       case SND_REN:            /* RENAME after */
  6338.         if (!getval) break;
  6339.         if ((x = cmfld(n == SND_MOV ?
  6340.        "device and/or directory for source file after sending" :
  6341.        "new name for source file after sending",
  6342.                "",
  6343.                &s,
  6344.                n == SND_MOV ? xxstring : NULL
  6345.                )) < 0) {
  6346.         if (x == -3) {
  6347.             printf("%s\n", n == SND_MOV ?
  6348.                "?Destination required" :
  6349.                "?New name required"
  6350.                );
  6351.             x = -9;
  6352.         }
  6353.         goto xgetx;
  6354.         }
  6355.         if (pv[n].sval) {
  6356.         free(pv[n].sval);
  6357.         pv[n].sval = NULL;
  6358.         }
  6359.         s = brstrip(s);
  6360.         y = strlen(s);
  6361.         if (y > 0) {
  6362.         pv[n].sval = malloc(y+1);
  6363.         if (pv[n].sval) {
  6364.             strcpy(pv[n].sval,s);
  6365.             pv[n].ival = 1;
  6366.         }
  6367.         }
  6368.         break;
  6369.  
  6370.       case SND_ASN:            /* As-name */
  6371.         if (!getval) break;
  6372.         if (mget) {
  6373.         printf("?Sorry, as-name not allowed with MGET\n");
  6374.         x = -9;
  6375.         goto xgetx;
  6376.         }
  6377.         if ((x = cmfld("Name to store it under","",&s,NULL)) < 0)
  6378.           goto xgetx;
  6379.         s = brstrip(s);
  6380.         if ((y = strlen(s)) > 0) {
  6381.         if (pv[n].sval) free(pv[n].sval);
  6382.         pv[n].sval = malloc(y+1);
  6383.         if (pv[n].sval) {
  6384.             strcpy(pv[n].sval,s);
  6385.             pv[n].ival = 1;
  6386.         }
  6387.         }
  6388.         break;
  6389.  
  6390. #ifdef PIPESEND
  6391.       case SND_FLT:            /* Filter */
  6392.         debug(F101,"xget /filter getval","",getval);
  6393.         if (!getval) break;
  6394.         if ((x = cmfld("Filter program to receive through",
  6395.                "",&s,NULL)) < 0) {
  6396.         if (x == -3)
  6397.           s = "";
  6398.         else
  6399.           goto xgetx;
  6400.         }
  6401.         s = brstrip(s);
  6402.         y = strlen(s);
  6403.         for (x = 0; x < y; x++) {    /* Make sure they included "\v(...)" */
  6404.         if (s[x] != '\\') continue;
  6405.         if (s[x+1] == 'v') break;
  6406.         }
  6407.         if (x == y) {
  6408.         printf(
  6409.         "?Filter must contain a replacement variable for filename.\n"
  6410.                );
  6411.         x = -9;
  6412.         goto xgetx;
  6413.         }
  6414.         pv[n].ival = 1;
  6415.         if (pv[n].sval) {
  6416.         free(pv[n].sval);
  6417.         pv[n].sval = NULL;
  6418.         }
  6419.         if ((y = strlen(s)) > 0) {
  6420.         if (pv[n].sval = malloc(y+1))
  6421.           strcpy(pv[n].sval,s);
  6422.         }
  6423.         break;
  6424. #endif /* PIPESEND */
  6425.  
  6426.       case SND_PTH:            /* Pathnames */
  6427.         if (!getval) {
  6428.         pv[n].ival = PATH_REL;
  6429.         break;
  6430.         }
  6431.         if ((x = cmkey(rpathtab,nrpathtab,"","on",xxstring)) < 0)
  6432.           goto xgetx;
  6433.         pv[n].ival = x;        /* Ditto */
  6434.         break;
  6435.  
  6436.       case SND_NAM:            /* Filenames */
  6437.         if (!getval) break;
  6438.         if ((x = cmkey(fntab,nfntab,"","converted",xxstring)) < 0)
  6439.           goto xgetx;
  6440.         pv[n].ival = x;
  6441.         break;
  6442.  
  6443.       case SND_PRO:            /* Protocol to use */
  6444.         if (!getval) break;
  6445.         if ((x = cmkey(protos,nprotos,"File-transfer protocol","",
  6446.                xxstring)) < 0) {
  6447.         if (x == -3)
  6448.           x = 0;
  6449.         else
  6450.           goto xgetx;
  6451.         }
  6452.         debug(F111,"xget /proto",atmbuf,x);
  6453.         pv[n].ival = x;
  6454.         if (konly && x != PROTO_K) {
  6455.         printf(
  6456. "?Sorry, this command works only with Kermit protocol\n"
  6457.                );
  6458.         x = -9;
  6459.         goto xgetx;
  6460.         }
  6461.         break;
  6462.  
  6463.       default:
  6464.         printf("?Unexpected switch value - %d\n",cmresult.nresult);
  6465.         x = -9;
  6466.         goto xgetx;
  6467.     }
  6468.     }
  6469.     debug(F101,"xget cmresult fcode","",cmresult.fcode);
  6470.  
  6471.     cmarg = line;            /* Initialize string pointers */
  6472.     cmarg2 = tmpbuf;
  6473.     asname = 0;
  6474.     line[0] = NUL;            /* and buffers. */
  6475.     tmpbuf[0] = NUL;
  6476.  
  6477.     switch (cmresult.fcode) {        /* How did we get out of switch loop */
  6478.       case _CMFLD:            /* Remote filespec */
  6479.     ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
  6480.     break;
  6481.       case _CMTXT:            /* As-name */
  6482.     if (rcvcmd) {
  6483.         ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ);
  6484.         if ((int)strlen(tmpbuf) > 0)
  6485.           asname = 1;
  6486.     } else {
  6487.         ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
  6488.     }
  6489.       case _CMCFM:            /* Confirmation */
  6490.     confirmed = 1;
  6491.     break;
  6492.       default:
  6493.     printf("?Unexpected function code: %d\n",cmresult.fcode);
  6494.     x = -9;
  6495.     goto xgetx;
  6496.     }
  6497.     debug(F110,"xget string",cmarg,0);
  6498.     debug(F101,"xget confirmed","",confirmed);
  6499.  
  6500.     cmarg = brstrip(cmarg);        /* Strip any braces */
  6501.  
  6502.     if (!confirmed) {            /* CR not typed yet, get more fields */
  6503.     if (pv[SND_CMD].ival > 0) {
  6504.         debug(F100,"xget calling cmtxt","",0);
  6505.         x = cmtxt("Local command to pipe into","",&s,NULL);
  6506.         if (x < 0 && x != -3) goto xgetx;
  6507.         if (x != -3) {
  6508.         ckstrncpy(tmpbuf,s,TMPBUFSIZ);
  6509.         asname = 1;
  6510.         }
  6511.     } else if (!rcvcmd) {
  6512. #ifdef VMS
  6513.         /* cmofi() fails if you give it a directory name */
  6514.         x = cmfld("Name or directory for incoming file","",&s,NULL);
  6515.         debug(F111,"xget cmfld",s,x);
  6516. #else
  6517.         x = cmofi("Name or directory for incoming file","",&s,NULL);
  6518.         debug(F111,"xget cmofi",s,x);
  6519. #endif /* VMS */
  6520.         if (x < 0 && x != -3) goto xgetx;
  6521.         if (x != -3) {
  6522.         ckstrncpy(tmpbuf,s,TMPBUFSIZ);
  6523.         if ((x = cmcfm()) < 0) goto xgetx;
  6524.         asname = 1;
  6525.         }
  6526.     }
  6527.     }
  6528.     /* Arrive here with cmarg and cmarg2 all set */
  6529.  
  6530.     debug(F111,"xget asname",cmarg2,asname);
  6531.     if (!asname) {
  6532.     if (pv[SND_ASN].sval)
  6533.       ckstrncpy(tmpbuf,pv[SND_ASN].sval,TMPBUFSIZ);
  6534.     else
  6535.       tmpbuf[0] = NUL;
  6536.     }
  6537.     cmarg2 = brstrip(cmarg2);        /* Strip outer braces if any. */
  6538.     debug(F110,"xget cmarg",cmarg,0);
  6539.     debug(F110,"xget cmarg2",cmarg2,0);
  6540.  
  6541.     if (!*cmarg &&
  6542.     (cx == XXGET || cx == XXREGET || cx == XXCGET || cx == XXMGET)) {
  6543.     printf("?A remote file specification is required\n");
  6544.     x = -9;
  6545.     goto xgetx;
  6546.     }
  6547. #ifdef PIPESEND
  6548.     if (pv[SND_CMD].ival > 0) {        /* /COMMAND sets pipesend flag */
  6549.     x = -9;
  6550.     if (!*cmarg2) {
  6551.         printf("?Command required\n");
  6552.         goto xgetx;
  6553.     } else if (nopush) {
  6554.         printf("?Sorry, system command access is disabled\n");
  6555.         goto xgetx;
  6556.     } else if (rcvfilter) {
  6557.         printf("?Sorry, no GET /COMMAND while RECEIVE FILTER selected\n");
  6558.         goto xgetx;
  6559.     } else
  6560.       pipesend = 1;
  6561.     }
  6562.     debug(F101,"xget /COMMAND pipesend","",pipesend);
  6563. #endif /* PIPESEND */
  6564.  
  6565. #ifdef CK_RESEND
  6566.     if (pv[SND_RES].ival > 0) {        /* REGET or GET /RECOVER */
  6567. #ifdef RECURSIVE
  6568.     if (pv[SND_REC].ival > 0) {    /* RECURSIVE */
  6569. #ifdef COMMENT
  6570.         printf("?Unsupported option combination: /RECOVER /RECURSIVE\n");
  6571.         x = -9;
  6572.         goto xgetx;
  6573. #else
  6574.         opkt = 1;
  6575. #endif /* COMMENT */
  6576.     }
  6577. #endif /* RECURSIVE */
  6578.     if (pv[SND_DEL].ival > 0) {    /* /DELETE */
  6579. #ifdef COMMENT
  6580.         printf("?Unsupported option combination: /RECOVER /DELETE\n");
  6581.         x = -9;
  6582.         goto xgetx;
  6583. #else
  6584.         opkt = 1;
  6585. #endif /* COMMENT */
  6586.     }
  6587.     }
  6588. #endif /* CK_RESEND */
  6589.  
  6590.     if (pv[SND_EXC].ival > 0)        /* /EXCEPT */
  6591.       makelist(pv[SND_EXC].sval,rcvexcept,8);
  6592.  
  6593. #ifdef IKS_OPTION
  6594.     if (!rcvcmd) {
  6595.         if (!iks_wait(KERMIT_REQ_START,1)) {
  6596.         printf(
  6597.           "?A Kermit Server is unavailable to process this command\n");
  6598.         x = -9;            /* correct the return code */
  6599.         goto xgetx;
  6600.         }
  6601.     }
  6602. #endif /* IKS_OPTION */
  6603.  
  6604. #ifdef CK_XYZ
  6605.     if ((pv[SND_PRO].ival < 0 &&
  6606.          (protocol == PROTO_X || protocol == PROTO_XC) ||
  6607.          pv[SND_PRO].ival > -1 &&
  6608.          (pv[SND_PRO].ival == PROTO_X || pv[SND_PRO].ival == PROTO_XC)) &&
  6609.     rcvcmd && !*cmarg2) {
  6610.     printf(
  6611. "Sorry, you must specify a name when receiving a file with XMODEM protocol\n"
  6612.            );
  6613.     x = -9;
  6614.     goto xgetx;
  6615.     }
  6616. #endif /* CK_XYZ */
  6617.  
  6618. #ifdef RECURSIVE
  6619.     if (pv[SND_REC].ival > 0) {        /* RECURSIVE */
  6620.     recursive = 1;
  6621.     pv[SND_PTH].ival = PATH_REL;    /* Implies relative pathnames too */
  6622.     }
  6623. #endif /* RECURSIVE */
  6624.  
  6625.     /* Save global protocol parameters */
  6626.  
  6627.     g_proto = protocol;
  6628. #ifdef CK_LABELED
  6629.     g_lf_opts = lf_opts;        /* Save labeled transfer options */
  6630. #endif /* CK_LABELED */
  6631.     g_urpsiz = urpsiz;            /* Receive packet length */
  6632.     g_spsizf = spsizf;            /* Send packet length flag */
  6633.     g_spsiz = spsiz;            /* Send packet length */
  6634.     g_spsizr = spsizr;            /* etc etc */
  6635.     g_spmax = spmax;
  6636.     g_wslotr = wslotr;
  6637.     g_prefixing = prefixing;
  6638.     g_fncact = fncact;
  6639.     g_fncnv = fncnv;
  6640.     g_fnspath = fnspath;
  6641.     g_fnrpath = fnrpath;
  6642.  
  6643.     if (pv[SND_PRO].ival > -1) {    /* Change according to switch */
  6644.     protocol = pv[SND_PRO].ival;
  6645.         if (ptab[protocol].rpktlen > -1)   /* copied from initproto() */
  6646.             urpsiz = ptab[protocol].rpktlen;
  6647.         if (ptab[protocol].spktflg > -1)
  6648.             spsizf = ptab[protocol].spktflg;
  6649.         if (ptab[protocol].spktlen > -1) {
  6650.             spsiz = ptab[protocol].spktlen;
  6651.             if (spsizf)
  6652.                 spsizr = spmax = spsiz;
  6653.         }
  6654.         if (ptab[protocol].winsize > -1)
  6655.             wslotr = ptab[protocol].winsize;
  6656.         if (ptab[protocol].prefix > -1)
  6657.             prefixing = ptab[protocol].prefix;
  6658.         if (ptab[protocol].fnca > -1)
  6659.             fncact  = ptab[protocol].fnca;
  6660.         if (ptab[protocol].fncn > -1)
  6661.             fncnv   = ptab[protocol].fncn;
  6662.         if (ptab[protocol].fnsp > -1)
  6663.             fnspath = ptab[protocol].fnsp;
  6664.         if (ptab[protocol].fnrp > -1)
  6665.             fnrpath = ptab[protocol].fnrp;
  6666.     }
  6667.     debug(F101,"xget protocol","",protocol);
  6668.     debug(F111,"xget cmarg2",cmarg2,xfermode);
  6669.  
  6670.     g_xfermode = xfermode;
  6671.     g_binary = binary;
  6672.     if (pv[SND_BIN].ival > 0) {        /* Change according to switch */
  6673.     xfermode = XMODE_M;
  6674.     binary = XYFT_B;        /* FILE TYPE BINARY */
  6675.     omode = GMOD_BIN;        /* O-Packet mode */
  6676.     debug(F101,"doxget /BINARY xfermode","",xfermode);
  6677.     } else if (pv[SND_TXT].ival > 0) {    /* Ditto for /TEXT */
  6678.     xfermode = XMODE_M;
  6679.     binary = XYFT_T;
  6680.     omode = GMOD_TXT;
  6681.     debug(F101,"doxget /TEXT xfermode","",xfermode);
  6682.     } else if (pv[SND_IMG].ival > 0) {
  6683.     xfermode = XMODE_M;
  6684. #ifdef VMS
  6685.     binary = XYFT_I;
  6686. #else
  6687.     binary = XYFT_B;
  6688. #endif /* VMS */
  6689.     omode = GMOD_TXT;
  6690.     debug(F101,"doxget /IMAGE xfermode","",xfermode);
  6691.     }
  6692. #ifdef CK_LABELED
  6693.     else if (pv[SND_LBL].ival > 0) {
  6694.     xfermode = XMODE_M;
  6695.     binary = XYFT_L;
  6696.     omode = GMOD_LBL;
  6697.     debug(F101,"doxget /LABELED xfermode","",xfermode);
  6698.     }
  6699. #endif /* CK_LABELED */
  6700.     debug(F101,"xget binary","",binary);
  6701.     debug(F101,"xget omode","",omode);
  6702.  
  6703. #ifdef PIPESEND
  6704.     if (pv[SND_FLT].ival > 0) {
  6705.     g_rfilter = rcvfilter;
  6706.     if (!pv[SND_FLT].sval) {
  6707.         rcvfilter = NULL;
  6708.     } else {
  6709.         rcvfilter = (char *) malloc((int) strlen(pv[SND_FLT].sval) + 1);
  6710.         if (rcvfilter) strcpy(rcvfilter,pv[SND_FLT].sval);
  6711.     }
  6712.     }
  6713. #endif /* PIPESEND */
  6714.  
  6715. #ifdef CK_TMPDIR
  6716.     if (pv[SND_MOV].ival > 0) {
  6717.     int len;
  6718.     char * p = pv[SND_MOV].sval;
  6719. #ifdef CK_LOGIN
  6720.     if (isguest) {
  6721.         printf("?Sorry, /MOVE-TO not available to guests\n");
  6722.         x = -9;
  6723.         goto xgetx;
  6724.     }
  6725. #endif /* CK_LOGIN */
  6726.     len = strlen(p);
  6727.     if (!isdir(p)) {        /* Check directory */
  6728. #ifdef CK_MKDIR
  6729.         char * s = NULL;
  6730.         s = (char *)malloc(len + 4);
  6731.         if (s) {
  6732.         strcpy(s,p);
  6733. #ifdef datageneral
  6734.         if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
  6735. #else
  6736.         if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
  6737. #endif /* datageneral */
  6738.         s[len++] = 'X';
  6739.         s[len] = NUL;
  6740.         x = zmkdir(s);
  6741.         free(s);
  6742.         if (x < 0) {
  6743.             printf("?Can't create \"%s\"\n",p);
  6744.             x = -9;
  6745.             goto xgetx;
  6746.         }
  6747.         }
  6748. #else
  6749.         printf("?Directory \"%s\" not found\n",p);
  6750.         x = -9;
  6751.         goto xgetx;
  6752. #endif /* CK_MKDIR */
  6753.     }
  6754.     makestr(&rcv_move,p);
  6755.     }
  6756. #endif /* CK_TMPDIR */
  6757.  
  6758.     if (pv[SND_REN].ival > 0) {        /* /RENAME-TO:name */
  6759.     char * p = pv[SND_REN].sval;
  6760. #ifdef CK_LOGIN
  6761.     if (isguest) {
  6762.         printf("?Sorry, /RENAME-TO not available to guests\n");
  6763.         x = -9;
  6764.         goto xgetx;
  6765.     }
  6766. #endif /* CK_LOGIN */
  6767.     if (!p) p = "";
  6768.     if (!*p) {
  6769.         printf("?New name required for /RENAME\n");
  6770.         x = -9;
  6771.         goto xgetx;
  6772.     }
  6773.     p = brstrip(p);
  6774.     makestr(&rcv_rename,p);
  6775.     debug(F110,"xget rcv_rename","",0);
  6776.     }
  6777.  
  6778. #ifdef CALIBRATE
  6779.     if (pv[SND_CAL].ival > 0)
  6780.       calibrate = 1L;
  6781. #endif /* CALIBRATE */
  6782.     g_displa = fdispla;
  6783.     if (pv[SND_SHH].ival > 0)
  6784.       fdispla = 0;
  6785.     debug(F101,"xget display","",fdispla);
  6786.  
  6787.     if (pv[SND_NAM].ival > -1) {    /* /FILENAMES */
  6788.     g_fncnv = fncnv;        /* Save global value */
  6789.     fncnv = pv[SND_NAM].ival;
  6790.     debug(F101,"xsend fncnv","",fncnv);
  6791.     /* We should also handle O packet filename option here */
  6792.     /* but we don't really need to since WHATAMI already handles it */
  6793.     }
  6794.     if (pv[SND_PTH].ival > -1) {    /* PATHNAMES */
  6795.     g_rpath = fnrpath;        /* Save global values */
  6796.     fnrpath = pv[SND_PTH].ival;
  6797.     debug(F101,"xsend fnrpath","",fnrpath);
  6798. #ifndef NZLTOR
  6799.     if (fnrpath != PATH_OFF) {
  6800.         g_fncnv = fncnv;
  6801.         fncnv = XYFN_L;
  6802.         debug(F101,"xsend fncnv","",fncnv);
  6803.     }
  6804.     /* We should also handle O packet pathname option here */
  6805.     /* but we don't really need to since WHATAMI already handles it */
  6806. #endif /* NZLTOR */
  6807.     }
  6808.  
  6809.     /* Set protocol start state */
  6810.  
  6811.     if (opkt) {                /* Extended GET Options*/
  6812.     sstate = (CHAR) 'o';
  6813.     oopts = 0;
  6814.     if (pv[SND_DEL].ival > 0) oopts |= GOPT_DEL; /* GET /DELETE */
  6815.     if (pv[SND_RES].ival > 0) oopts |= GOPT_RES; /* GET /RECOVER */
  6816.     if (pv[SND_REC].ival > 0) oopts |= GOPT_REC; /* GET /RECURSIVE */
  6817.     } else if (rcvcmd)
  6818.       sstate = (CHAR) 'v';        /* RECEIVE or CRECEIVE */
  6819.     else if (pv[SND_DEL].ival > 0)
  6820.       sstate = (CHAR) 'h';        /* GET /DELETE (= RETRIEVE) */
  6821.     else if (pv[SND_RES].ival > 0)
  6822.       sstate = (CHAR) 'j';        /* GET /RECOVER (= REGET) */
  6823.     else
  6824.       sstate = (CHAR) 'r';        /* Regular GET */
  6825.     getcmd = 1;
  6826.     debug(F000,"xget sstate","",sstate);
  6827. #ifdef MAC
  6828.     what = W_RECV;
  6829.     scrcreate();
  6830. #endif /* MAC */
  6831.     if (local) {
  6832.     if (pv[SND_SHH].ival != 0)
  6833.       displa = 1;
  6834.     ttflui();
  6835.     }
  6836.     x = 0;
  6837. #ifdef PIPESEND
  6838.     if (pipesend)
  6839.       goto xgetx;
  6840. #endif /* PIPESEND */
  6841.  
  6842. #ifdef CK_TMPDIR
  6843. /*
  6844.   cmarg2 is also allowed to be a device or directory name;
  6845.   even the name of a directory that doesn't exist.
  6846. */
  6847.     y = strlen(cmarg2);
  6848.     debug(F111,"xget strlen(cmarg2)",cmarg2,y);
  6849.     if ((y > 0) &&
  6850. #ifdef OS2
  6851.     ((isalpha(cmarg2[0]) &&
  6852.      cmarg2[1] == ':' &&
  6853.      cmarg2[2] == NUL) ||
  6854.     (cmarg[y-1] == '/' || cmarg[y-1] == '\\') ||
  6855.     isdir(cmarg2))
  6856. #else
  6857. #ifdef UNIXOROSK
  6858.     (cmarg2[y-1] == '/' || isdir(cmarg2))
  6859. #else
  6860. #ifdef VMS
  6861.     (cmarg2[y-1] == ']' || cmarg2[y-1] == '>' || isdir(cmarg2))
  6862. #else
  6863. #ifdef STRATUS
  6864.     (cmarg2[y-1] == '>' || isdir(cmarg2))
  6865. #else
  6866. #ifdef datageneral
  6867.     (cmarg2[y-1] == ':' || cmarg[0] == ':' || isdir(cmarg2))
  6868. #else
  6869.     isdir(cmarg2)
  6870. #endif /* datageneral */
  6871. #endif /* STRATUS */
  6872. #endif /* VMS */
  6873. #endif /* UNIXOROSK */
  6874. #endif /* OS2 */
  6875.     ) {
  6876.     debug(F110,"doxget RECEIVE cmarg2 disk or dir",cmarg2,0);
  6877.     if (!f_tmpdir) {
  6878.         int x;
  6879.         s = zgtdir();
  6880.         if (s) {
  6881.         ckstrncpy(savdir,s,TMPDIRLEN); /* remember old disk/dir */
  6882.         f_tmpdir = 1;    /* and that we did this */
  6883.         } else {
  6884.         printf("?Can't get current directory\n");
  6885.         cmarg2 = "";
  6886.         f_tmpdir = 0;
  6887.         x = -9;
  6888.         goto xgetx;
  6889.         }
  6890. #ifdef CK_MKDIR
  6891.         x = zchki(cmarg2);        /* Does as-name exist? */
  6892.         if (x == -1) {        /* Doesn't exist */
  6893.         char * p = NULL;    /* Try to create it */
  6894.         x = strlen(cmarg2);
  6895.         if (p = (char *)malloc(x+4)) {
  6896.             sprintf(p,"%s%s",cmarg2,"x.x");
  6897.             x = zmkdir(p);
  6898.             free(p);
  6899.             if (x < 0) {
  6900.             printf("?Can't create %s\n",cmarg2);
  6901.             x = -9;
  6902.             goto xgetx;
  6903.             }
  6904.         }
  6905.         }
  6906. #endif /* CK_MKDIR */
  6907.         if (!zchdir(cmarg2)) {    /* change to given disk/directory, */
  6908.         printf("?Can't access %s\n",cmarg2);
  6909.         x = -9;
  6910.         goto xgetx;
  6911.         }
  6912.         cmarg2 = "";
  6913.     }
  6914.     }
  6915. #endif /* CK_TMPDIR */
  6916.  
  6917.     ckstrncpy(fspec,cmarg,CKMAXPATH);    /* Note - this is a REMOTE filespec */
  6918.     debug(F111,"xget fspec",fspec,fspeclen);
  6919.     debug(F110,"xget cmarg2",cmarg2,0);
  6920.  
  6921.   xgetx:
  6922.     for (i = 0; i < SND_MAX; i++)
  6923.       if (pv[i].sval)
  6924.     free(pv[i].sval);
  6925.     return(x);
  6926. }
  6927. #endif /* NOXFER */
  6928.  
  6929. #ifndef NOSPL
  6930.  
  6931. /*
  6932.   D O G T A  --  Do _GETARGS or _PUTARGS Command.
  6933.  
  6934.   Used by XIF, FOR, WHILE, and SWITCH, each of which are implemented as
  6935.   2-level macros; the first level defines the macro, the second runs it.
  6936.   This routine hides the fact that they are macros by importing the
  6937.   macro arguments (if any) from two levels up, to make them available
  6938.   in the IF, FOR, SWITCH, and WHILE commands themselves; for example as
  6939.   loop indices, etc, and within the IF/FOR/WHILE/SWITCH body itself.
  6940. */
  6941. int
  6942. dogta(cx) int cx; {
  6943.     int i, n; char c; char mbuf[4]; char *p;
  6944.     extern int topargc, cmdint;
  6945.     extern char ** topxarg;
  6946.  
  6947.     if ((y = cmcfm()) < 0)
  6948.       return(y);
  6949.     if (cx == XXGTA)
  6950.       debug(F101,"dogta _GETARGS maclvl","",maclvl);
  6951.     else if (cx == XXPTA)
  6952.       debug(F101,"dogta _PUTARGS maclvl","",maclvl);
  6953.     else
  6954.       return(-2);
  6955.     if (maclvl < 1)
  6956.       return(success = 0);
  6957.  
  6958.     /* Make new copies of macro arguments /%0..9 */
  6959.  
  6960.     mbuf[0] = '%'; mbuf[1] = '0'; mbuf[2] = NUL; /* Argument name buf */
  6961.     for (i = 0; i < 10; i++) {        /* For all args */
  6962.     c = (char) (i + '0');        /* Make name */
  6963.     mbuf[1] = (char) c;        /* Insert digit */
  6964.     if (cx == XXGTA) {        /* Get arg from level-minus-2 */
  6965.         if (maclvl == 1) p = g_var[c]; /* If at level 1 use globals 0..9 */
  6966.         else p = m_arg[maclvl-2][i]; /* Otherwise they're on the stack */
  6967.         addmac(mbuf,p);
  6968.         if (maclvl > 1)
  6969.           makestr(&(m_line[maclvl]),m_line[maclvl-2]);
  6970.     } else if (cx == XXPTA) {    /* Put args level+2 */
  6971.         if (cmdint)
  6972.           connoi();            /* Turn off interrupts. */
  6973.         maclvl -= 2;        /* This is gross.. */
  6974.         p = m_arg[maclvl+2][i];
  6975.         addmac(mbuf,m_arg[maclvl+2][i]);
  6976.         maclvl += 2;
  6977.         if (cmdint)
  6978.           conint(trap,stptrap);    /* Restore interrupts */
  6979.         count[cmdlvl - 2]  = count[cmdlvl];
  6980.         intime[cmdlvl - 2] = intime[cmdlvl];
  6981.         inpcas[cmdlvl - 2] = inpcas[cmdlvl];
  6982.         takerr[cmdlvl - 2] = takerr[cmdlvl];
  6983.         merror[cmdlvl - 2] = merror[cmdlvl];
  6984.         xquiet[cmdlvl - 2] = xquiet[cmdlvl];
  6985.     } else return(success = 0);    /* Bad call to this routine */
  6986.     }
  6987.     /* Now take care of the argument vector array \&_[] and \v(return) */
  6988.     /* Here we just copy the pointers */
  6989.  
  6990.     if (cx == XXGTA) {            /* GETARGS from 2 levels up */
  6991.     if (maclvl == 1) {
  6992.         a_ptr[0] = topxarg;        /* \&_[] array */
  6993.         a_dim[0] = topargc - 1;    /* Dimension doesn't include [0] */
  6994.         m_xarg[maclvl] = topxarg;
  6995.         n_xarg[maclvl] = topargc;    /* But \v(argc) does include \%0 */
  6996.         macargc[maclvl] = topargc;
  6997.             makestr(&(mrval[maclvl+1]),mrval[0]); /* (see vnlook()) */
  6998.     } else {
  6999.         a_ptr[0] = m_xarg[maclvl-2];
  7000.         a_dim[0] = n_xarg[maclvl-2];
  7001.         m_xarg[maclvl] = m_xarg[maclvl-2];
  7002.         n_xarg[maclvl] = n_xarg[maclvl-2];
  7003.         macargc[maclvl] = n_xarg[maclvl-2];
  7004.             makestr(&(mrval[maclvl+1]),mrval[maclvl-1]); /* (see vnlook()) */
  7005.     }
  7006.     } else {                /* PUTARGS 2 levels down */
  7007.     if (maclvl+2 >= MACLEVEL)
  7008.       return(success = 0);
  7009.     a_ptr[0] = m_xarg[maclvl+2];
  7010.         m_xarg[maclvl] = m_xarg[maclvl+2];
  7011.     a_dim[0] = n_xarg[maclvl+2];
  7012.     n_xarg[maclvl] = n_xarg[maclvl+2];
  7013.     macargc[maclvl] = n_xarg[maclvl+2];
  7014.     }
  7015.     return(1);            /* Internal command - don't change success */
  7016. }
  7017. #endif /* NOSPL */
  7018.  
  7019. #ifndef NOSPL
  7020. /*
  7021.   Do the GOTO and [_]FORWARD commands.
  7022.   s = Label to search for, cx = function code: XXGOTO, XXFWD, or XXXFWD.
  7023. */
  7024. #ifdef BIGBUFOK
  7025. #define LBLMAXLEN 255            /* Max label length */
  7026. #else
  7027. #define LBLMAXLEN 63
  7028. #endif /* BIGBUFOK */
  7029.  
  7030. int
  7031. dogoto(s, cx) char *s; int cx; {
  7032.     int i, j, x, y, z, bc;
  7033.     int stopflg = 0;
  7034.     char * cmd;                /* Name of this command */
  7035.     char tmplbl[LBLMAXLEN+1], *lp;    /* Current label from command stream */
  7036.     char tmp2[LBLMAXLEN+1];        /* SWITCH label conversion buffer */
  7037.     char tmp3[LBLMAXLEN+1];        /* Target label */
  7038.  
  7039.     stopflg = (cx == XXXFWD);        /* _FORWARD (used in SWITCH) */
  7040.     bc = 0;                /* Brace counter */
  7041.  
  7042.     cmd = (cx == XXGOTO) ? "GOTO" : ((cx == XXFWD) ? "FORWARD" : "_FORWARD");
  7043.  
  7044. #ifdef DEBUG
  7045.     if (deblog) {
  7046.     debug(F111,"GOTO command",cmd,cx);
  7047.     debug(F101,"GOTO cmdlvl","",cmdlvl);
  7048.     debug(F101,"GOTO maclvl","",maclvl);
  7049.     debug(F101,"GOTO tlevel","",tlevel);
  7050.     }
  7051. #endif /* DEBUG */
  7052.     debug(F110,cmd,s,0);
  7053.     ckstrncpy(tmp3+1,s,LBLMAXLEN-1);
  7054.     s = tmp3+1;
  7055.     if (*s != ':') {            /* Make copy of label */
  7056.     tmp3[0] = ':';            /* guaranteed to start with ":" */
  7057.     s--;
  7058.     }
  7059.     if (s[1] == '.' || s[1] == SP || s[1] == NUL) {
  7060.     printf("?Bad label syntax - '%s'\n",s);
  7061.     return(success = 0);
  7062.     }
  7063.     if (cmdlvl == 0) {
  7064.     printf("?Sorry, %s only works in a command file or macro\n",cmd);
  7065.     return(success = 0);
  7066.     }
  7067.     y = strlen(s);            /* y = length of target label */
  7068.     debug(F111,cmd,s,y);
  7069.  
  7070.     while (cmdlvl > 0) {        /* As long as not at top level... */
  7071.     if (cmdstk[cmdlvl].src == CMD_MD) { /* GOTO inside macro */
  7072.         int i, m, flag;
  7073.         char *xp, *tp;
  7074.  
  7075.         /* GOTO: rewind the macro; FORWARD: start at current position */
  7076.  
  7077.         lp = (cx == XXGOTO) ? macx[maclvl] : macp[maclvl];
  7078.         m = (int)strlen(lp) - y + 1;
  7079.         debug(F111,"GOTO in macro",lp,m);
  7080.  
  7081.         flag = 1;            /* flag for valid label position */
  7082.         for (i = 0; i < m; i++,lp++) { /* search for label in macro body */
  7083.         if (*lp == '{')        /* But only at this level */
  7084.           bc++;            /* Anything inside braces is off */
  7085.         else if (*lp == '}')    /* limits. */
  7086.           bc--;
  7087.         if (stopflg && bc > 0)    /* This is good for SWITCH */
  7088.           continue;        /* but interferes with WHILE, etc. */
  7089.         if (*lp == ',') {
  7090.             flag = 1;
  7091.             continue;
  7092.         }
  7093.         if (flag) {        /* If in valid label position */
  7094.             if (*lp == SP)    /* eat leading spaces */
  7095.               continue;
  7096.             if (*lp != ':') {    /* Look for label introducer */
  7097.             flag = 0;    /* this isn't it */
  7098.             continue;    /* keep looking */
  7099.             }
  7100.         }
  7101.         if (!flag)        /* We don't have a label */
  7102.           continue;        /*  so keep looking... */
  7103.         xp = lp; tp = tmplbl;    /* Copy the label from the macro */
  7104.         j = 0;            /* to make it null-terminated */
  7105.         while (*tp = *xp) {
  7106.             if (j++ > LBLMAXLEN) /* j = length of word from macro */
  7107.               break;
  7108.             if (*tp < 33 || *tp == ',')    /* Look for end of word */
  7109.               break;
  7110.             else tp++, xp++;    /* Next character */
  7111.         }
  7112.         *tp = NUL;        /* In case we stopped early */
  7113.         /* Now do caseless string comparison, using longest length */
  7114.         debug(F111,"macro GOTO label",s,y);
  7115.         debug(F111,"macro target label",tmplbl,j);
  7116.         if (stopflg) {        /* Allow variables as SWITCH labels */
  7117.             int n = LBLMAXLEN - 1;
  7118.             char * p = tmp2;
  7119.             zzstring(tmplbl,&p,&n);
  7120.             ckstrncpy(tmplbl,tmp2,LBLMAXLEN);
  7121.             tmp2[49] = NUL;
  7122.         }
  7123.         debug(F111,"GOTO s",s,y);
  7124.         debug(F111,"GOTO tmplbl",tmplbl,j);
  7125.  
  7126.         if (stopflg) {
  7127.             z = ckmatch(tmplbl,s,inpcas[cmdlvl],1) ? 0 : 1;
  7128.         } else {
  7129.             z = (stopflg && inpcas[cmdlvl]) ?
  7130.               strcmp(s,tmplbl) :
  7131.             ckstrcmp(s,tmplbl,(y > j) ? y : j, 0);
  7132.         }
  7133.         if (!z)
  7134.           break;
  7135.         else if (stopflg &&
  7136.              !ckstrcmp(":default",tmplbl,(8 > j) ? 8 : j, 0))
  7137.           break;
  7138.         else
  7139.           flag = 0;
  7140.         }
  7141.         debug(F111,"GOTO macro i",cmd,i);
  7142.         debug(F111,"GOTO macro m",cmd,m);
  7143.         if (i >= m) {        /* Didn't find the label */
  7144.         debug(F101,"GOTO failed cmdlvl","",cmdlvl);
  7145.         if (stopflg)
  7146.           return(0);
  7147.         if ((maclvl > 0) &&
  7148.                (m_arg[maclvl-1][0]) &&
  7149.                (cmdstk[cmdlvl].src == CMD_MD) &&
  7150.                (!strncmp(m_arg[maclvl-1][0],"_xif",4) ||
  7151.             !strncmp(m_arg[maclvl-1][0],"_for",4) ||
  7152.             !strncmp(m_arg[maclvl-1][0],"_swi",4) ||
  7153.             !strncmp(m_arg[maclvl-1][0],"_whi",4))) {
  7154.             dogta(XXPTA);    /* Restore args */
  7155.             debug(F101,"GOTO in XIF/FOR/WHI/SWI popping","",cmdlvl);
  7156.             popclvl();        /* Pop an extra level */
  7157.         }
  7158.         debug(F101,"GOTO popping","",cmdlvl);
  7159.         if (!popclvl()) {    /* pop up to next higher level */
  7160.             printf("?Label '%s' not found\n",s); /* if none */
  7161.             return(0);        /* quit */
  7162.         } else continue;    /* otherwise look again */
  7163.         }
  7164.         debug(F110,"GOTO found macro label",tmplbl,0);
  7165.         macp[maclvl] = lp;        /* set macro buffer pointer */
  7166.         return(1);
  7167.     } else if (cmdstk[cmdlvl].src == CMD_TF) {
  7168.         x = 0;            /* GOTO issued in take file */
  7169.         debug(F111,"GOTO in TAKE file",cmd,cx);
  7170.         if (cx == XXGOTO) {        /* If GOTO, but not FORWARD, */
  7171.         rewind(tfile[tlevel]);    /* search file from beginning */
  7172.         tfline[tlevel] = 0;
  7173.         }
  7174.         while (! feof(tfile[tlevel])) {
  7175.         if (fgets(line,LINBUFSIZ,tfile[tlevel]) == NULL) /* Get line */
  7176.           break;        /* If no more, done, label not found */
  7177.         tfline[tlevel]++;
  7178.         lp = line;        /* Got line */
  7179.         while (*lp == SP || *lp == HT)
  7180.           lp++;            /* Strip leading whitespace */
  7181.         if (*lp != ':') continue; /* Check for label introducer */
  7182.         tp = lp;        /* Get end of word */
  7183.         j = 0;
  7184.         while (*tp) {        /* And null-terminate it */
  7185.             if (*tp < 33) {
  7186.             *tp = NUL;
  7187.             break;
  7188.             } else tp++, j++;
  7189.         }
  7190.         if (!ckstrcmp(lp,s,(y > j) ? y : j,0)) { /* Caseless compare */
  7191.             x = 1;        /* Got it */
  7192.             break;        /* done. */
  7193.         } else if (stopflg &&
  7194.                !ckstrcmp(":default",tmplbl,(8 > j) ? 8 : j,0)) {
  7195.             x = 1;
  7196.             break;
  7197.         }
  7198.         }
  7199.         if (x == 0) {        /* If not found, print message */
  7200.         debug(F101,"GOTO failed at cmdlvl","",cmdlvl);
  7201.         if (stopflg)
  7202.           return(0);
  7203.         if (!popclvl()) {    /* pop up to next higher level */
  7204.             printf("?Label '%s' not found\n",s); /* if none */
  7205.             return(0);        /* quit */
  7206.         } else continue;    /* otherwise look again */
  7207.         }
  7208.         return(x);            /* Send back return code */
  7209.     }
  7210.     }
  7211.     printf("?Stack problem in GOTO %s\n",s); /* Shouldn't see this */
  7212.     return(0);
  7213. }
  7214. #endif /* NOSPL */
  7215.  
  7216. /* Finish parsing and do the IF, XIF, and WHILE commands */
  7217.  
  7218. #ifndef NOSPL
  7219.  
  7220. /*  C H K V A R  --  Check (if it's a) Variable  */
  7221.  
  7222.  
  7223. #ifdef OLDCHKVAR
  7224. /*
  7225.   Crude and disgusting, but needed for OS/2, DOS, and Windows, where filenames
  7226.   have backslashes in them.  How do we know if a backslash in a filename is a
  7227.   directory separator, or if it's a Kermit backslash?  This routine does a
  7228.   rough syntax check of the next few characters and if it looks like it MIGHT
  7229.   be a variable, then it tries to evaluate it, and if the result is not empty,
  7230.   we say it's a variable, although sometimes it might not be -- some cases are
  7231.   truly ambiguous.  For example there might a DOS directory called \%a, and
  7232.   we also have a variable with the same name.  This is all for the sake of not
  7233.   having to tell PC users that they have to double all backslashes in file
  7234.   and directory names.
  7235. */
  7236. #else
  7237. /*
  7238.   Somewhat less crude & disgusting.  The previous method was nondeterministic
  7239.   and (worse) it interfered with macro argument passing.  So now we only
  7240.   check the syntax of backslash-items to see if they are variables, but we
  7241.   do NOT check their values.
  7242. */
  7243. #endif /* OLDCHKVAR */
  7244. /*
  7245.   Call with a string pointer pointing at the backslash of the purported
  7246.   variable.  Returns 1 if it has the syntax of a variable, 0 if not.
  7247. */
  7248. int
  7249. chkvar(s) char *s; {
  7250.     int z = 0;                /* Return code - assume failure. */
  7251.     if (!s) s = "";            /* Watch our for null pointers. */
  7252.     if (!*s) return(0);            /* Empty arg so not a variable. */
  7253.     if (*s == CMDQ) {            /* Object begins with backslash. */
  7254.     char c;
  7255.     c = s[1];            /* Character following backslash. */
  7256.     if (c) {
  7257.         int t = 0;
  7258.         if (c == CMDQ)        /* Quoted backslash */
  7259.           return(1);
  7260.         c = (char) (islower(c) ? toupper(c) : c); /* Otherwise... */
  7261.         if (c == '%') {        /* Simple variable */
  7262. #ifdef OLDCHKVAR
  7263.         t = 1;
  7264. #else
  7265.         return(1);
  7266. #endif /* OLDCHKVAR */
  7267.         } else if (c == '&') {    /* Array */
  7268.         if (s[3] == '[')
  7269.           t = ckindex("]",s,4,0,1);
  7270. #ifndef OLDCHKVAR
  7271.         return((t > 0) ? 1 : 0);
  7272. #endif /* OLDCHKVAR */
  7273.         } else if (c == '$' ||    /* Environment variable */
  7274.                c == 'V' ||    /* Built-in variable */
  7275.                c == 'M') {    /* Macro name */
  7276.             t = (s[2] == '(');
  7277. #ifndef OLDCHKVAR
  7278.         return((t > 0) ? 1 : 0);
  7279. #endif /* OLDCHKVAR */
  7280.         } else if (c == 'F') {    /* Function reference */
  7281.         /* Don't actually call it - it might have side effects */
  7282.         int x;
  7283.         if (x = ckindex("(",s,3,0,1)) /* Just check syntax */
  7284.           if (x = ckindex(")",s,x,0,1))
  7285.             z = 1;
  7286.         /* Insert a better syntax check here if necessary */
  7287.         }
  7288. #ifdef OLDCHKVAR
  7289.         if (t) {
  7290.         t = 255;        /* This lets us test \v(xxx) */
  7291.         lp = line;        /* and even \f...(xxx) */
  7292.         zzstring(s,&lp,&t);    /* Evaluate it, whatever it is. */
  7293.         t = strlen(line);    /* Get its length. */
  7294.         debug(F111,"chkvar",line,t);
  7295.         z = t > 0;        /* If length > 0, it's defined */
  7296.         }
  7297. #endif /* OLDCHKVAR */
  7298.     }
  7299.     }
  7300.     return(z);
  7301. }
  7302.  
  7303. /*  B O O L E X P  --  Evaluate a Boolean expression  */
  7304.  
  7305. #define BOOLLEN 1024
  7306. static char boolval[BOOLLEN];
  7307.  
  7308. int
  7309. boolexp(cx) int cx; {
  7310.     int x, y, z; char *s, *p;
  7311.     int parens = 0, pcount = 0, ecount = 0;
  7312.     extern int cmfldflgs;
  7313.     char *q, *bx;
  7314.     struct FDB kw, nu, fl;
  7315. #ifdef FNFLOAT
  7316.     CKFLOAT f1 = 0.0, f2 = 0.0;
  7317.     int f1flag = 0, f2flag = 0;
  7318. #endif /* FNFLOAT */
  7319. #ifdef OS2
  7320.     extern int keymac;
  7321. #endif /* OS2 */
  7322.  
  7323.     not = 0;                /* Flag for whether "NOT" was seen */
  7324.     z = 0;                /* Initial IF condition */
  7325.     ifargs = 0;                /* Count of IF condition words */
  7326.     bx = boolval;            /* Initialize boolean value */
  7327.     *bx = NUL;
  7328.  
  7329.   ifagain:
  7330.     cmfdbi(&kw,                /* First FDB - command switches */
  7331.        _CMKEY,            /* fcode */
  7332.        "Number, numeric-valued variable, Boolean expression, or keyword",
  7333.        "",                /* default */
  7334.        "",                /* addtl string data */
  7335.        nif,                /* addtl numeric data 1: tbl size */
  7336.        0,                /* addtl numeric data 2: 4 = silent */
  7337.        xxstring,            /* Processing function */
  7338.        iftab,            /* Keyword table */
  7339.        &nu                /* Pointer to next FDB */
  7340.        );
  7341.     cmfdbi(&nu,                /* 2nd FDB - An integer */
  7342.        _CMNUM,            /* fcode */
  7343.        "",                /* hlpmsg */
  7344.        "",                /* Default */
  7345.        "",                /* addtl string data */
  7346.        0,
  7347.        0,
  7348.        xxstring,
  7349.        NULL,
  7350. #ifndef FNFLOAT
  7351.        &fl
  7352. #else
  7353.        NULL
  7354. #endif /* FNFLOAT */
  7355.        );
  7356. #ifndef FNFLOAT
  7357.     cmfdbi(&fl,                /* A floating-point number */
  7358.        _CMFLD,            /* fcode */
  7359.        "",                /* hlpmsg */
  7360.        "",                /* default */
  7361.        "",                /* addtl string data */
  7362.        0,                /* addtl numeric data 1 */
  7363.        0,                /* addtl numeric data 2 */
  7364.        xxstring,
  7365.        NULL,
  7366.        NULL
  7367.        );
  7368. #endif /* FNFLOAT */
  7369.     x = cmfdb(&kw);            /* Parse a keyword or a number */
  7370.     if (x < 0) {
  7371.     if (x == -3)
  7372.       x = -2;
  7373.     return(x);
  7374.     }
  7375.     debug(F111,"boolval switch","",cmresult.fcode);
  7376.     switch (cmresult.fcode) {        /* What did we get? */
  7377. #ifdef FNFLOAT
  7378.       case _CMFLD:            /* A "field" */
  7379.     if (isfloat(cmresult.sresult,0)) { /* A floating-point number? */
  7380.         f1 = floatval;        /* Yes, get its value */
  7381.         f1flag = 1;            /* remember we did this */
  7382.         ifc = 9999;            /* Set special "if-code" */
  7383.     } else
  7384.       return(-2);
  7385. #endif /* FNFLOAT */
  7386.       case _CMNUM:            /* A number... */
  7387.     ifc = 9999;            /* Set special "if-code" */
  7388.     break;
  7389.       case _CMKEY:            /* A keyword */
  7390.     ifc = cmresult.nresult;        /* Get if-code */
  7391.     break;
  7392.       default:
  7393.     return(-2);
  7394.     }
  7395.     switch (ifc) {            /* set z = 1 for true, 0 for false */
  7396.       case 9999:            /* Number */
  7397. #ifdef FNFLOAT
  7398.     if (f1flag) {
  7399.         z = (f1 == 0.0) ? 0 : 1;
  7400.     } else
  7401. #endif /* FNFLOAT */
  7402.     z = (cmresult.nresult == 0) ? 0 : 1;
  7403.     break;
  7404.       case XXIFLP:            /* Left paren */
  7405.     if (pcount == 0 && ifargs > 0)
  7406.       return(-2);
  7407.     parens = 1;
  7408.     pcount++;
  7409.     ifargs++;
  7410.     *bx++ = '(';
  7411.     goto ifagain;
  7412.       case XXIFRP:            /* Right paren */
  7413.     if (!parens)
  7414.       return(-2);
  7415.     if (--pcount < 0)
  7416.       return(-2);
  7417.     ifargs++;
  7418.     *bx++ = ')';
  7419.     *bx = NUL;
  7420.     if (pcount == 0)
  7421.       goto ifend;
  7422.     goto ifagain;
  7423.       case XXIFAN:            /* AND (&&) */
  7424.     ifargs++;
  7425.     if (!ecount)
  7426.       return(-2);
  7427.     *bx++ = '&';
  7428.     goto ifagain;
  7429.       case XXIFOR:            /* OR (||) */
  7430.     ifargs++;
  7431.     if (!ecount)
  7432.       return(-2);
  7433.     *bx++ = '|';
  7434.     goto ifagain;
  7435.       case XXIFNO:            /* IF NOT [ NOT [ NOT ... ] ] */
  7436.     if (bx > boolval) {        /* evala() doesn't like cascaded */
  7437.         if (*(bx-1) == '!') {    /* unary operators... */
  7438.         *(bx-1) = NUL;        /* So here, two wrongs make a right. */
  7439.         bx--;
  7440.         } else {
  7441.         *bx++ = '!';
  7442.         }
  7443.     } else {
  7444.         *bx++ = '!';
  7445.     }
  7446.     ifargs++;
  7447.     goto ifagain;
  7448.       case XXIFTR:            /* IF TRUE */
  7449.     z = 1;
  7450.     debug(F101,"if true","",z);
  7451.     ifargs += 1;
  7452.     break;
  7453.       case XXIFNT:            /* IF FALSE */
  7454.     z = 0;
  7455.     debug(F101,"if true","",z);
  7456.     ifargs += 1;
  7457.     break;
  7458.       case XXIFSU:            /* IF SUCCESS */
  7459.     z = ( success != 0 ) ? 1 : 0;
  7460.     debug(F101,"if success","",z);
  7461.     ifargs += 1;
  7462.     break;
  7463.       case XXIFFA:            /* IF FAILURE */
  7464.     z = ( success == 0 ) ? 1 : 0;
  7465.     debug(F101,"if failure","",z);
  7466.     ifargs += 1;
  7467.     break;
  7468.       case XXIFDE:            /* IF DEFINED */
  7469.     if ((x = cmfld("Macro or variable name","",&s,NULL)) < 0) {
  7470.         if (x == -3) return(-2);
  7471.         else return(x);
  7472.     }
  7473.     if (*s == CMDQ) {
  7474.         z = chkvar(s);        /* Starts with backslash */
  7475.         if (z > 0) {        /* Yes... */
  7476.         int t, x;        /* Get its value into a local buffer */
  7477.         char * lp;
  7478.         char line[256];        /* Note that value might be longer */
  7479.         t = 255;        /* than buffer so if zzstring fails  */
  7480.         lp = line;        /* check for that -- overflow means */
  7481.         line[0] = NUL;        /* the quantity is defined. */
  7482.         x = zzstring(s,&lp,&t);
  7483.         if ((x < 0 && t != 255) || !line[0])
  7484.           z = 0;
  7485.         debug(F111,"if defined zzstring",line,z);
  7486.         debug(F101,"if defined zzstring t","",t);
  7487.         }
  7488.     } else {
  7489.         z = (mxlook(mactab,s,nmac) > -1); /* Look for exact match */
  7490.     }
  7491.     debug(F111,"if defined final",s,z);
  7492.     ifargs += 2;
  7493.     break;
  7494.  
  7495.       case XXIFBG:            /* IF BACKGROUND */
  7496.       case XXIFFG:            /* IF FOREGROUND */
  7497.     bgchk();            /* Check background status */
  7498.     if (ifc == XXIFFG)        /* Foreground */
  7499.       z = pflag ? 1 : 0;
  7500.         else z = pflag ? 0 : 1;        /* Background */
  7501.     ifargs += 1;
  7502.     break;
  7503.  
  7504.       case XXIFCO:            /* IF COUNT */
  7505.     z = ( --count[cmdlvl] > 0 );
  7506.     if (cx == XXWHI) count[cmdlvl] += 2; /* Don't ask... */
  7507.     debug(F101,"if count","",z);
  7508.     ifargs += 1;
  7509.     break;
  7510.  
  7511.       case XXIFEX:            /* IF EXIST */
  7512. #ifdef CK_TMPDIR
  7513.       case XXIFDI:            /* IF DIRECTORY */
  7514. #endif /* CK_TMPDIR */
  7515.       case XXIFAB:            /* IF ABSOLUTE */
  7516.     if ((x = cmfld(
  7517.                ((ifc == XXIFDI) ? "Directory name" : "File"),
  7518.                "",&s,
  7519. #ifdef OS2
  7520.                NULL        /* This allows \'s in filenames */
  7521. #else
  7522.                xxstring
  7523. #endif /* OS2 */
  7524.                )) < 0) {
  7525.         if (x == -3) {
  7526.         extern int cmflgs;
  7527.         if (cmflgs == 1) {
  7528.             printf("?File or directory name required\n");
  7529.             return(-9);
  7530.         }
  7531.         } else return(x);
  7532.     }
  7533.     s = brstrip(s);
  7534.     if (ifc == XXIFAB) {
  7535.         z = isabsolute(s);
  7536.     } else if (ifc == XXIFEX) {
  7537.         z = (zchki(s) > -1L);
  7538.         debug(F101,"if exist 1","",z);
  7539. #ifdef OS2
  7540.         if (!z) {            /* File not found. */
  7541.         int t;            /* Try expanding variables */
  7542.         t = LINBUFSIZ-1;    /* and looking again. */
  7543.         lp = line;
  7544.         zzstring(s,&lp,&t);
  7545.         s = line;
  7546.         z = ( zchki(s) > -1L );
  7547.         debug(F101,"if exist 2","",z);
  7548.         }
  7549. #endif /* OS2 */
  7550. #ifdef CK_TMPDIR
  7551.     } else {
  7552. #ifdef VMS
  7553.         z = (zchki(s) == -2)
  7554. #else
  7555. /* Because this doesn't catch $DISK1:[FOO]BLAH.DIR;1 */
  7556.         z = isdir(s)
  7557. #ifdef OS2
  7558.           || (isalpha(s[0]) && s[1] == ':' && s[2] == NUL)
  7559. #endif /* OS2 */
  7560. #endif /* VMS */
  7561.           ;
  7562.         debug(F101,"if directory 1","",z);
  7563.  
  7564.         if (!z) {            /* File not found. */
  7565.         int t;            /* Try expanding variables */
  7566.         t = LINBUFSIZ-1;    /* and looking again. */
  7567.         lp = line;
  7568.         zzstring(s,&lp,&t);
  7569.         s = line;
  7570.         z = isdir(s)
  7571. #ifdef OS2
  7572.           || (isalpha(s[0]) && s[1] == ':' && s[2] == NUL)
  7573. #endif /* OS2 */
  7574.             ;
  7575.         debug(F101,"if directory 2","",z);
  7576.         }
  7577. #endif /* CK_TMPDIR */
  7578.     }
  7579.     ifargs += 2;
  7580.     break;
  7581.  
  7582.       case XXIFEQ:             /* IF EQUAL (string comparison) */
  7583.       case XXIFLL:            /* IF Lexically Less Than */
  7584.       case XXIFLG:            /* If Lexically Greater Than */
  7585.     if ((x = cmfld("first word or variable name","",&s,xxstring)) < 0) {
  7586.         if (x == -3) {
  7587.         printf("?Text required\n");
  7588.         return(-9);
  7589.         } else return(x);
  7590.     }
  7591.     s = brstrip(s);            /* Strip braces */
  7592.     x = (int)strlen(s);
  7593.     if (x > LINBUFSIZ-1) {
  7594.         printf("?IF: strings too long\n");
  7595.         return(-2);
  7596.     }
  7597.     lp = line;            /* lp points to first string */
  7598.         ckstrncpy(line,s,LINBUFSIZ);
  7599.     if ((y = cmfld("second word or variable name","",&s,xxstring)) < 0) {
  7600.         if (y == -3) {
  7601.         printf("?Text required\n");
  7602.         return(-9);
  7603.         } else return(y);
  7604.     }
  7605.     s = brstrip(s);
  7606.     y = (int)strlen(s);
  7607.     if (x + y + 2 > LINBUFSIZ) {
  7608.         printf("?IF: strings too long\n");
  7609.         return(-2);
  7610.     }
  7611.     tp = lp + x + 2;        /* tp points to second string */
  7612.     strcpy(tp,s);
  7613.     x = ckstrcmp(lp,tp,-1,inpcas[cmdlvl]); /* Use longest length */
  7614.     switch (ifc) {
  7615.       case XXIFEQ:             /* IF EQUAL (string comparison) */
  7616.         z = (x == 0);
  7617.         break;
  7618.       case XXIFLL:            /* IF Lexically Less Than */
  7619.         z = (x < 0);
  7620.         break;
  7621.       case XXIFLG:            /* If Lexically Greater Than */
  7622.         z = (x > 0);
  7623.         break;
  7624.     }
  7625.     debug(F101,"IF EQ result","",z);
  7626.     ifargs += 3;
  7627.     break;
  7628.  
  7629.       case XXIFAE:            /* IF (arithmetically) = */
  7630.       case XXIFNQ:            /* IF != (not arithmetically equal) */
  7631.       case XXIFLT:            /* IF <  */
  7632.       case XXIFLE:            /* IF <= */
  7633.       case XXIFGE:            /* IF >= */
  7634.       case XXIFGT: {            /* IF >  */
  7635.  
  7636.     /* Really should use longs here... */
  7637.     /* But cmnum parses ints. */
  7638.     int n1 = 0, n2 = 0;
  7639.     x = cmfld("first number or variable name","",&s,xxstring);
  7640.     if (x == -3) {
  7641.         printf("?Quantity required\n");
  7642.         return(-9);
  7643.     }
  7644.     if (x < 0) return(x);
  7645.     debug(F101,"xxifgt cmfld","",x);
  7646.     lp = line;
  7647.         ckstrncpy(line,s,LINBUFSIZ);
  7648.     debug(F110,"xxifgt exp1",lp,0);
  7649.  
  7650. /* The following bit is for compatibility with old versions of MS-DOS Kermit */
  7651.  
  7652.     if (!ckstrcmp(lp,"count",5,0)) {
  7653.         n1 = count[cmdlvl];
  7654.     } else if (!ckstrcmp(lp,"version",7,0)) {
  7655.         n1 = (int) vernum;
  7656.     } else if (!ckstrcmp(lp,"argc",4,0)) {
  7657.         n1 = (int) macargc[maclvl];
  7658.     } else {
  7659.  
  7660. /* End of compatibility bit */
  7661.  
  7662. #ifdef FNFLOAT
  7663.         /* Allow floating-point comparisons. */
  7664.         /* ckstrchr() test is used in addition to isfloat() since */
  7665.         /* isfloat() succeeds also for integers and we don't want to */
  7666.         /* do floating-point comparisons unless we have to. */
  7667.         if (ckstrchr(lp,'.') && isfloat(lp,0)) {
  7668.         f1 = floatval;
  7669.         f1flag = 1;
  7670.         } else
  7671. #endif /* FNFLOAT */
  7672.         if (chknum(lp)) {
  7673.         n1 = atoi(lp);
  7674.         } else {            /* Check for arithmetic expression */
  7675.         q = evala(lp);        /* cmnum() does this but ... */
  7676.         if (chknum(q))        /* we're not using cmnum(). */
  7677.           n1 = atoi(q);
  7678.         else
  7679.           return(-2);
  7680.         }
  7681.     }
  7682.     y = cmfld("second number or variable name","",&s,xxstring);
  7683.     if (y == -3) {
  7684.         printf("?Quantity required\n");
  7685.         return(-9);
  7686.     }
  7687.     if (y < 0) return(y);
  7688.         if ((int)strlen(s) < 1) return(-2);
  7689.     x = (int)strlen(lp);
  7690.     tp = line + x + 2;
  7691.     strcpy(tp,s);
  7692.     debug(F110,"xxifgt exp2",tp,0);
  7693.     if (!ckstrcmp(tp,"count",5,0)) {
  7694.         n2 = count[cmdlvl];
  7695.     } else if (!ckstrcmp(tp,"version",7,0)) {
  7696.         n2 = (int) vernum;
  7697.     } else if (!ckstrcmp(tp,"argc",4,0)) {
  7698.         n2 = (int) macargc[maclvl];
  7699.     } else {
  7700. #ifdef FNFLOAT
  7701.         if (ckstrchr(lp,'.') && isfloat(tp,0)) {
  7702.         f2 = floatval;
  7703.         f2flag = 1;
  7704.         } else
  7705. #endif /* FNFLOAT */
  7706.         if (chknum(tp)) {
  7707.         n2 = atoi(tp);
  7708.         } else {
  7709.         q = evala(tp);
  7710.         if (chknum(q))
  7711.           n2 = atoi(q);
  7712.         else
  7713.           return(-2);
  7714.         }
  7715.     }
  7716.     debug(F101,"xxifft ifc","",ifc);
  7717. #ifdef FNFLOAT
  7718.     if (f1flag && !f2flag) {
  7719.         f2 = (CKFLOAT)n2;
  7720.         f2flag = 1;
  7721.     }
  7722.     if (f2flag && !f1flag)
  7723.       f1 = (CKFLOAT)n1;
  7724.     if (f1flag)
  7725.       z = ((f1 <  f2 && ifc == XXIFLT)
  7726.            || (f1 != f2 && ifc == XXIFNQ)
  7727.            || (f1 <= f2 && ifc == XXIFLE)
  7728.            || (f1 == f2 && ifc == XXIFAE)
  7729.            || (f1 >= f2 && ifc == XXIFGE)
  7730.            || (f1 >  f2 && ifc == XXIFGT));
  7731.     else
  7732. #endif /* FNFLOAT */
  7733.       z = ((n1 <  n2 && ifc == XXIFLT)
  7734.            || (n1 != n2 && ifc == XXIFNQ)
  7735.            || (n1 <= n2 && ifc == XXIFLE)
  7736.            || (n1 == n2 && ifc == XXIFAE)
  7737.            || (n1 >= n2 && ifc == XXIFGE)
  7738.            || (n1 >  n2 && ifc == XXIFGT));
  7739.     debug(F101,"xxifft z","",z);
  7740.     ifargs += 3;
  7741.     break; }
  7742.  
  7743.       case XXIFNU:            /* IF NUMERIC */
  7744.     x = cmfld("variable name or constant","",&s,NULL);
  7745.     if (x == -3) {
  7746.         extern int cmflgs;
  7747.         if (cmflgs == 1) {
  7748.         printf("?Quantity required\n");
  7749.         return(-9);
  7750.         }
  7751.     } else if (x < 0)
  7752.       return(x);
  7753.     x = LINBUFSIZ-1;
  7754.     lp = line;
  7755.     zzstring(s,&lp,&x);
  7756.     lp = line;
  7757.     debug(F110,"xxifnu quantity",lp,0);
  7758.         z = chknum(lp);
  7759. #ifdef COMMENT
  7760. /*
  7761.   This works, but it's not wise -- IF NUMERIC is mostly used to see if a
  7762.   string really does contain only numeric characters.  If they want to force
  7763.   evaluation, they can use \feval() on the argument string.
  7764. */
  7765.     if (!z) {            /* Not a number */
  7766.         x_ifnum = 1;        /* Avoid "eval" error messages */
  7767.         q = evala(lp);        /* Maybe it's an expression */
  7768.         z = chknum(q);        /* that evaluates to a number */
  7769.         x_ifnum = 0;        /* Put eval messages back to normal */
  7770.         if (z) debug(F110,"xxifnu exp",lp,0);
  7771.     }
  7772. #endif /* COMMENT */
  7773.         debug(F101,"xxifnu chknum","",z);
  7774.     ifargs += 2;
  7775.     break;
  7776.  
  7777. #ifdef ZFCDAT
  7778.       case XXIFNE: {            /* IF NEWER */
  7779.     char d1[20], * d2;        /* Buffers for 2 dates */
  7780.     if ((z = cmifi("First file","",&s,&y,xxstring)) < 0)
  7781.       return(z);
  7782.     strcpy(d1,zfcdat(s));
  7783.     if ((z = cmifi("Second file","",&s,&y,xxstring)) < 0)
  7784.       return(z);
  7785.     d2 = zfcdat(s);
  7786.     if ((int)strlen(d1) != 17 || (int)strlen(d2) != 17) {
  7787.         printf("?Failure to get file date\n");
  7788.         return(-9);
  7789.     }
  7790.     debug(F110,"xxifnewer d1",d1,0);
  7791.     debug(F110,"xxifnewer d2",d2,0);
  7792.     z = (strcmp(d1,d2) > 0) ? 1 : 0;
  7793.         debug(F101,"xxifnewer","",z);
  7794.     ifargs += 2;
  7795.     break;
  7796.       }
  7797. #endif /* ZFCDAT */
  7798.  
  7799. #ifdef CK_IFRO
  7800.       case XXIFRO:            /* REMOTE-ONLY advisory */
  7801.     ifargs++;
  7802. #ifdef NOLOCAL
  7803.     z = 1;
  7804. #else
  7805.     z = remonly;
  7806. #endif /* NOLOCAL */
  7807.     break;
  7808. #endif /* CK_IFRO */
  7809.  
  7810.       case XXIFAL:            /* ALARM */
  7811.     ifargs++;
  7812.     debug(F101,"IF ALARM ck_alarm","",ck_alarm);
  7813.     debug(F110,"IF ALARM alrm_date",alrm_date,0);
  7814.     debug(F110,"IF ALARM alrm_time",alrm_time,0);
  7815.  
  7816.     if (ck_alarm < 1L || alrm_date[0] < '0' || alrm_time[0] < '0') {
  7817.         z = 0;            /* ALARM not SET */
  7818.         break;            /* so IF ALARM fails */
  7819.     }
  7820.     strcpy(tmpbuf,ckcvtdate("",1));    /* Get current date and time */
  7821.     s = tmpbuf;
  7822.     s[8] = NUL;
  7823.     z = (int) strncmp(tmpbuf,alrm_date,8); /* Compare dates */
  7824.     debug(F101,"IF ALARM date z","",z);
  7825.     if (z == 0) {            /* Dates are the same */
  7826.         /* Compare times */
  7827.         z = (tod2sec(tmpbuf+9) >= atol(alrm_time)) ? 1 : -1;
  7828.         debug(F101,"IF ALARM time z","",z);
  7829.     }
  7830.     tmpbuf[0] = NUL;        /* z >= 0 if alarm is passed */
  7831.     z = ((z >= 0) ? 1 : 0);        /* z <  0 otherwise */
  7832.     debug(F101,"IF ALARM final z","",z);
  7833.     break;
  7834.  
  7835.       case XXIFOP:            /* IF OPEN */
  7836.     if ((x = cmkey(iotab,niot,"file or log","",xxstring)) < 0)
  7837.       return(x);
  7838.     if (x == 9999 || x == ZSTDIO) {
  7839.         bgchk();            /* Check background status */
  7840.         z = pflag ? 1 : 0;
  7841.     } else if (x == 8888) {
  7842.         z = local ? ttchk() > -1 : 0;
  7843. #ifdef CKLOGDIAL
  7844.         } else if (x == 7777) {
  7845.         extern int dialog;
  7846.         z = dialog ? 1 : 0;
  7847. #endif /* CKLOGDIAL */
  7848.     } else
  7849.       z = (chkfn(x) > 0) ? 1 : 0;
  7850.     ifargs += 1;
  7851.     break;
  7852.  
  7853. #ifdef OS2
  7854.       case XXIFSD:            /* Started-From-Dialer */
  7855.     ifargs++;
  7856.     z = StartedFromDialer;
  7857.     break;
  7858.  
  7859.       case XXIFTM:            /* Terminal-Macro */
  7860.     ifargs++;
  7861.     z = cmdstk[cmdlvl].ccflgs & CF_KMAC;
  7862.     break;
  7863. #endif /* OS2 */
  7864.  
  7865.       case XXIFEM:            /* Emulation is active */
  7866. #ifdef OS2
  7867.     z = 1;
  7868. #else
  7869.     z = 0;
  7870. #endif /* OS2 */
  7871.     break;
  7872.  
  7873.       case XXIFIK:                      /* Running as IKSD? */
  7874.         z = inserver;
  7875.         break;
  7876.  
  7877.       case XXIFTA:            /* Connection is TAPI */
  7878.     z = 0;
  7879. #ifdef NT
  7880.     if (local && !network && tttapi)
  7881.       z = 1;
  7882. #endif /* NT */
  7883.     break;
  7884.  
  7885.       case XXIFMA:            /* IF MATCH */
  7886.     x = cmfld("String or variable","",&s,xxstring);
  7887.     if (x == -3) {
  7888.         extern int cmflgs;
  7889.         if (cmflgs == 1) {
  7890.         printf("?String required\n");
  7891.         return(-9);
  7892.         }
  7893.     } else if (x < 0)
  7894.       return(x);
  7895.     ckstrncpy(line,s,LINBUFSIZ);
  7896.     s = brstrip(line);
  7897.     debug(F110,"xxifma string",line,0);
  7898.     x = cmfld("Pattern","",&p,xxstring);
  7899.     if (x == -3) {
  7900.         extern int cmflgs;
  7901.         if (cmflgs == 1) {
  7902.         printf("?Pattern required\n");
  7903.         return(-9);
  7904.         }
  7905.     } else if (x < 0)
  7906.       return(x);
  7907.     ckstrncpy(tmpbuf,p,TMPBUFSIZ);
  7908.     p = brstrip(tmpbuf);
  7909.     debug(F110,"xxifma pattern",tmpbuf,0);
  7910.     z = ckmatch(p,s,inpcas[cmdlvl],1);
  7911.     break;
  7912.  
  7913.       case XXIFFL: {            /* IF FLAG */
  7914.       extern int ooflag;
  7915.       z = ooflag;
  7916.       break;
  7917.       }
  7918.       case XXIFAV: {            /* IF AVAILABLE */
  7919.       if ((x = cmkey(availtab,availtabn,"","",xxstring)) < 0)
  7920.         return(x);
  7921.       switch (x) {
  7922.         case AV_KRB4:
  7923.               z = ck_krb4_is_installed();
  7924.               break;
  7925.         case AV_KRB5:
  7926.               z = ck_krb5_is_installed();
  7927.               break;
  7928.             case AV_SRP:
  7929.               z = ck_srp_is_installed();
  7930.               break;
  7931.             case AV_SSL:
  7932.               z = ck_ssleay_is_installed();
  7933.           break;
  7934.             case AV_NTLM:
  7935.               z = ck_ntlm_is_installed();
  7936.           break;
  7937.             case AV_CRYPTO:
  7938.           z = ck_crypt_is_installed();
  7939.           break;
  7940.         default:
  7941.               z = 0;
  7942.       }
  7943.       break;
  7944.       }
  7945.       case XXIFAT:            /* IF ASKTIMEOUT */
  7946.     z = asktimedout;
  7947.     break;
  7948.  
  7949.       case XXIFRD:            /* IF READABLE */
  7950.       case XXIFWR:            /* IF WRITEABLE */
  7951.     if ((x = cmfld("File or directory name",
  7952.                "",
  7953.                &s,
  7954. #ifdef OS2
  7955.                NULL        /* This allows \'s in filenames */
  7956. #else
  7957.                xxstring
  7958. #endif /* OS2 */
  7959.                )) < 0) {
  7960.         if (x == -3) {
  7961.         extern int cmflgs;
  7962.         if (cmflgs == 1) {
  7963.             printf("?File or directory name required\n");
  7964.             return(-9);
  7965.         }
  7966.         } else return(x);
  7967.     }
  7968.     s = brstrip(s);
  7969. /*
  7970.   zchk[io]() do not do what we want here for directories, so we set
  7971.   a global flag telling it to behave specially in this case.  Othewise
  7972.   we'd have to change the API and change all ck?fio.c modules accordingly.
  7973. */
  7974.     y = 0;                /* Try-again control */
  7975. #ifdef OS2
  7976.   ifrdagain:
  7977. #endif /* OS2 */
  7978.     if (ifc == XXIFRD) {        /* IF READABLE */
  7979.         zchkid = 1;
  7980.         z = zchki(s) > -1;
  7981.         zchkid = 0;
  7982.     } else if (ifc == XXIFWR) {    /* IF WRITEABLE */
  7983.         zchkod = 1;
  7984.         z = zchko(s) > -1;
  7985.         zchkod = 0;
  7986.     }
  7987. #ifdef OS2
  7988.     if (!z && !y) {            /* File not found. */
  7989.         int t;            /* Try expanding variables */
  7990.         t = LINBUFSIZ-1;        /* and looking again. */
  7991.         lp = line;
  7992.         zzstring(s,&lp,&t);
  7993.         s = line;
  7994.         z = zchko(s) > -1;
  7995.         y++;
  7996.         goto ifrdagain;
  7997.     }
  7998. #endif /* OS2 */
  7999.     ifargs += 2;
  8000.     break;
  8001.       case XXIFQU:            /* IF QUIET */
  8002.     z = quiet ? 1 : 0;
  8003.     debug(F101,"if quiet","",z);
  8004.     ifargs += 1;
  8005.     break;
  8006.  
  8007.       case XXIFWI:            /* WILD */
  8008.     if ((x = cmfld("File specification","",&s,xxstring)) < 0) return(x);
  8009.     z = iswild(s);
  8010.     break;
  8011.  
  8012.       case XXIFCK:            /* C-KERMIT */
  8013. #ifdef OS2
  8014.         z = 0;
  8015. #else
  8016.         z = 1;
  8017. #endif /* OS2 */
  8018.         break;
  8019.  
  8020.       case XXIFK9:            /* K-95 */
  8021. #ifdef OS2
  8022.         z = 1;
  8023. #else
  8024.         z = 0;
  8025. #endif /* OS2 */
  8026.         break;
  8027.  
  8028.       case XXIFMS:            /* MS-KERMIT */
  8029.         z = 0;
  8030.         break;
  8031.  
  8032.       case XXIFLO:            /* IF LOCAL */
  8033.     z = local ? 1 : 0;
  8034.         break;
  8035.  
  8036.       case XXIFCM: {            /* IF COMMAND */
  8037.       extern struct keytab cmdtab[];
  8038.       extern int ncmd;
  8039.       if ((x = cmfld("Word","",&s,xxstring)) < 0)
  8040.         return(x);
  8041.       z = lookup(cmdtab,s,ncmd,&y);
  8042.       z = (z == -2 || z > -1) ? 1 : 0;
  8043.       break;
  8044.       }
  8045. #ifdef CKFLOAT
  8046.       case XXIFFP:            /* IF FLOAT */
  8047.     if ((x = cmfld("Number","",&s,xxstring)) < 0)
  8048.       if (x != -3)            /* e.g. empty variable */
  8049.         return(x);
  8050.     z = isfloat(s,0);
  8051.     break;
  8052. #endif /* CKFLOAT */
  8053.  
  8054.       default:                /* Shouldn't happen */
  8055.     return(-2);
  8056.     } /* end of switch */
  8057.  
  8058.     if (z)
  8059.       *bx++ = '1';
  8060.     else
  8061.       *bx++ = '0';
  8062.     *bx = NUL;
  8063.     if (bx > boolval + BOOLLEN - 2) {
  8064.     printf("?Boolean expression too long");
  8065.     return(-9);
  8066.     }
  8067.     ecount++;                /* Expression counter */
  8068.     debug(F101,"boolexp parens","",parens);
  8069.     debug(F101,"boolexp pcount","",pcount);
  8070.     if (parens && pcount > 0)
  8071.       goto ifagain;
  8072.  
  8073.   ifend:                /* No more - done */
  8074.     *bx = NUL;
  8075.     z = atoi(evalx(boolval));
  8076.     debug(F111,"boolexp boolval",boolval,z);
  8077.     return(z);
  8078. }
  8079.  
  8080. /*  D O I F  --  Do the IF command  */
  8081.  
  8082. int
  8083. doif(cx) int cx; {
  8084.     int x, y, z; char *s, *p;
  8085.     char *q;
  8086. #ifdef OS2
  8087.     extern int keymac;
  8088. #endif /* OS2 */
  8089.  
  8090.     debug(F101,"doif cx","",cx);
  8091.  
  8092.     z = boolexp(cx);            /* Evaluate the condition(s) */
  8093.     debug(F101,"doif boolexp","",z);
  8094.     if (z < 0)
  8095.       return(z);
  8096.  
  8097.     if (cx == XXIF) {            /* Allow IF to have XIF semantics. */
  8098.     char * p;
  8099.     p = cmpeek();
  8100.     if (!p) p = "";
  8101.     while (*p) {
  8102.         if (*p == SP || *p == HT)
  8103.           p++;
  8104.         else
  8105.           break;
  8106.     }
  8107.     if (*p == '{')
  8108.       cx = XXIFX;
  8109.     }
  8110.     switch (cx) {            /* Separate handling for IF and XIF */
  8111.  
  8112.       case XXASSER:            /* And ASSERT */
  8113.     if ((x = cmcfm()) < 0)
  8114.       return(x);
  8115.     return(success = z);
  8116.  
  8117.       case XXIF:            /* This is IF... */
  8118.     ifcmd[cmdlvl] = 1;        /* We just completed an IF command */
  8119.         debug(F101,"doif condition","",z);
  8120.     if (z) {            /* Condition is true */
  8121.         iftest[cmdlvl] = 1;        /* Remember that IF succeeded */
  8122.         if (maclvl > -1) {        /* In macro, */
  8123.         pushcmd(NULL);        /* save rest of command. */
  8124.         } else if (tlevel > -1) {    /* In take file, */
  8125.         debug(F100, "doif: pushing command", "", 0);
  8126.         pushcmd(NULL);        /* save rest of command. */
  8127.         } else {            /* If interactive, */
  8128.         cmini(ckxech);        /* just start a new command */
  8129.         printf("\n");        /* (like in MS-DOS Kermit) */
  8130.         if (pflag) prompt(xxstring);
  8131.         }
  8132.     } else {            /* Condition is false */
  8133.         iftest[cmdlvl] = 0;        /* Remember command failed. */
  8134.         if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
  8135.           return(y);        /* Gobble up rest of line */
  8136.     }
  8137.     return(0);
  8138.  
  8139.       case XXIFX: {            /* This is XIF (Extended IF) */
  8140.       char *p;
  8141.       char e[5];
  8142.       int i;
  8143.       if ((y = cmtxt("Object command","",&s,NULL)) < 0)
  8144.         return(y);            /* Get object command. */
  8145.       p = s;
  8146.       lp = line;
  8147.       debug(F111,"doif THEN part 1",s,z);
  8148.       if (litcmd(&p,&lp,LINBUFSIZ - 1) < 0) { /* Quote THEN-part */
  8149.           return(-2);
  8150.       }
  8151.       debug(F111,"doif THEN part 2",line,z);
  8152.  
  8153.       while (*p == SP) p++;        /* Strip trailing spaces */
  8154.       ifcmd[cmdlvl] = 0;        /* Assume ELSE part in same line */
  8155.       iftest[cmdlvl] = z ? 1 : 0;
  8156.       if (*p) {            /* At end? */
  8157.           if (!z) {            /* No, use ELSE-part, if any */
  8158.           for (i = 0; i < 4; i++) e[i] = *p++;
  8159.           if (ckstrcmp(e,"else",4,0)) /* See if we have an ELSE */
  8160.             return(-2);        /* Something else - error. */
  8161.           debug(F110,"doif ELSE line 1",p,0);
  8162.           while (*p == SP) p++;    /* Skip spaces */
  8163.           if (*p != '{') {    /* Brace ELSE part if necessary */
  8164.               sprintf(tmpbuf,"{ %s }",p);
  8165.                       p = tmpbuf;
  8166.               debug(F110,"doif ELSE line 2",p,0);
  8167.           }
  8168.           lp = line;        /* Write over THEN part... */
  8169.           *lp = NUL;        /* with ELSE part. */
  8170.           if (litcmd(&p,&lp,LINBUFSIZ - 2) < 0) {
  8171.               return(-2);
  8172.           }
  8173.           while (*p == SP) p++;    /* Strip trailing spaces */
  8174.           if (*p) return(-2);    /* Should be nothing here. */
  8175.           debug(F110,"doif ELSE line 3",line,0);
  8176.           }
  8177.       } else {            /* At end, treat like an IF command */
  8178.           if (!z) line[0] = NUL;    /* Condition not true and no ELSE */
  8179.           ifcmd[cmdlvl] = 1;    /* Allow ELSE on next line */
  8180.           debug(F101,"IF condition","",z);
  8181.       }
  8182.       if (line[0]) {
  8183.           x = mlook(mactab,"_xif",nmac); /* Get index of "_xif" macro. */
  8184.           if (x < 0) {            /* Not there? */
  8185.           addmmac("_xif",xif_def);    /* Put it back. */
  8186.           if (mlook(mactab,"_xif",nmac) < 0) { /* Look it up again. */
  8187.               printf("?XIF macro gone!\n");
  8188.               return(success = 0);
  8189.           }
  8190.           }
  8191.           dodo(x,line,cmdstk[cmdlvl].ccflgs | CF_IMAC);
  8192.       }
  8193.       return(0);
  8194.       }
  8195.       case XXWHI: {            /* WHILE Command */
  8196.       p = cmdbuf;            /* Capture IF condition */
  8197.       ifcond[0] = NUL;        /* from command buffer */
  8198.       while (*p == SP) p++;
  8199.       while (*p != SP) p++;
  8200.       ifcp = ifcond;
  8201.       strcpy(ifcp,"{ \\flit(if ( not ");
  8202.       ifcp += (int)strlen(ifcp);
  8203. #ifdef COMMENT
  8204. /*
  8205.   This doesn't work because it breaks on the first left brace, which does
  8206.   not necessarily start the command list, e.g. "while equal \%a {\35}".
  8207. */
  8208.       while (*p != '{' && *p != NUL) *ifcp++ = *p++;
  8209.       p = " ) goto _..bot) } ";
  8210.       while (*ifcp++ = *p++) ;
  8211. #else
  8212. /*
  8213.   The command parser sets cmbptr to the spot where it left off parsing in
  8214.   the command buffer.
  8215. */
  8216.       {
  8217.           extern char * cmbptr;
  8218.           if (cmbptr) {
  8219.           while (p < cmbptr && *p != NUL)
  8220.             *ifcp++ = *p++;
  8221.           p = " ) goto _..bot) } ";
  8222.           while (*ifcp++ = *p++) ;
  8223.           } else {
  8224.           printf("?Internal error parsing WHILE condition\n");
  8225.           return(-9);
  8226.           }
  8227.       }
  8228. #endif /* COMMENT */
  8229.  
  8230.       debug(F110,"WHILE cmd",ifcond,0);
  8231.  
  8232.       if ((y = cmtxt("Object command","",&s,NULL)) < 0)
  8233.         return(y);            /* Get object command. */
  8234.       p = s;
  8235.       lp = line;
  8236.       if (litcmd(&p,&lp,LINBUFSIZ - 2) < 0) { /* Quote object command */
  8237.           return(-2);
  8238.       }
  8239.       debug(F110,"WHILE body",line,0);
  8240.       if (line[0]) {
  8241.           char *p;
  8242.           x = mlook(mactab,"_while",nmac); /* index of "_while" macro. */
  8243.           if (x < 0) {        /* Not there? */
  8244.           addmmac("_while",whil_def); /* Put it back. */
  8245.           if (mlook(mactab,"_while",nmac) < 0) { /* Look it up again */
  8246.               printf("?WHILE macro definition gone!\n");
  8247.               return(success = 0);
  8248.           }
  8249.           }
  8250.           p = malloc((int)strlen(ifcond) + (int)strlen(line) + 2);
  8251.           if (p) {
  8252.           strcpy(p,ifcond);
  8253.           strcat(p,line);
  8254.           debug(F110,"WHILE dodo",p,0);
  8255.           dodo(x,p,cmdstk[cmdlvl].ccflgs | CF_IMAC);
  8256.           free(p);
  8257.           p = NULL;
  8258.           } else {
  8259.           printf("?Can't allocate storage for WHILE command");
  8260.           return(success = 0);
  8261.           }
  8262.       }
  8263.       return(0);
  8264.       }
  8265.       default:
  8266.     return(-2);
  8267.     }
  8268. }
  8269. #endif /* NOSPL */
  8270.  
  8271. /* Set up a TAKE command file */
  8272.  
  8273. int
  8274. dotake(s) char *s; {
  8275. #ifndef NOSPL
  8276.     extern int tra_cmd;
  8277. #endif /* NOSPL */
  8278. #ifdef OS2
  8279.     extern int term_io;
  8280.     int term_io_sav = term_io;
  8281. #endif /* OS2 */
  8282.  
  8283.     debug(F111,"dotake file",s,cmdlvl);
  8284.  
  8285.     if ((tfile[++tlevel] = fopen(s,"r")) == NULL) {
  8286.     perror(s);
  8287.     debug(F110,"dotake fail",s,0);
  8288.     tlevel--;
  8289.     return(success = 0);
  8290.     } else {
  8291.     tfline[tlevel] = 0;        /* Line counter */
  8292. #ifdef VMS
  8293.     conres();            /* So Ctrl-C will work */
  8294. #endif /* VMS */
  8295. #ifdef OS2
  8296.     term_io = 0;            /* Disable Terminal Emulator I/O */
  8297. #endif /* OS2 */
  8298. #ifndef NOSPL
  8299.     cmdlvl++;            /* Entering a new command level */
  8300.     debug(F101,"dotake cmdlvl","",cmdlvl);
  8301.     debug(F101,"dotake tlevel","",tlevel);
  8302.     if (cmdlvl > CMDSTKL) {
  8303.         debug(F100,"dotake stack overflow","",0);
  8304.         cmdlvl--;
  8305.         fclose(tfile[tlevel--]);
  8306.         printf("?TAKE files and/or DO commands nested too deeply\n");
  8307.         return(success = 0);
  8308.     }
  8309.     if (tfnam[tlevel]) {        /* Copy the filename */
  8310.         free(tfnam[tlevel]);
  8311.         tfnam[tlevel] = NULL;
  8312.     }
  8313.     if (tfnam[tlevel] = malloc(strlen(s) + 1))
  8314.       strcpy(tfnam[tlevel],s);
  8315.     ifcmd[cmdlvl] = 0;        /* Set variables for this cmd file */
  8316.     iftest[cmdlvl] = 0;
  8317.     count[cmdlvl]  = count[cmdlvl-1];  /* Inherit this */
  8318.     intime[cmdlvl] = intime[cmdlvl-1]; /* Inherit this */
  8319.     inpcas[cmdlvl] = inpcas[cmdlvl-1]; /* Inherit this */
  8320.     takerr[cmdlvl] = takerr[cmdlvl-1]; /* Inherit this */
  8321.     merror[cmdlvl] = merror[cmdlvl-1]; /* Inherit this */
  8322.     xquiet[cmdlvl] = quiet;
  8323.     cmdstk[cmdlvl].src = CMD_TF;    /* Say we're in a TAKE file */
  8324.     cmdstk[cmdlvl].lvl = tlevel;    /* nested at this level */
  8325.     cmdstk[cmdlvl].ccflgs = cmdstk[cmdlvl-1].ccflgs;
  8326. #else
  8327.     takerr[tlevel] = takerr[tlevel-1]; /* Inherit this */
  8328. #endif /* NOSPL */
  8329.     }
  8330. #ifndef NOSPL
  8331.     if (tra_cmd)
  8332.       printf("[%d] +F: \"%s\"\n",cmdlvl,s);
  8333. #endif /* NOSPL */
  8334. #ifdef OS2
  8335.     term_io = term_io_sav;
  8336. #endif /* OS2 */
  8337.     return(1);
  8338. }
  8339. #endif /* NOICP */
  8340.