home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / k95source / ckuus4.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  479KB  |  14,372 lines

  1. #include "ckcsym.h"
  2.  
  3. /*  C K U U S 4 --  "User Interface" for C-Kermit, part 4  */
  4.  
  5. /*
  6.   Authors:
  7.     Frank da Cruz <fdc@columbia.edu>,
  8.       The Kermit Project, Columbia University, New York City
  9.     Jeffrey E Altman <jaltman@secure-endpoints.com>
  10.       Secure Endpoints Inc., New York City
  11.  
  12.   Copyright (C) 1985, 2005,
  13.     Trustees of Columbia University in the City of New York.
  14.     All rights reserved.  See the C-Kermit COPYING.TXT file or the
  15.     copyright text in the ckcmai.c module for disclaimer and permissions.
  16. */
  17.  
  18. /*
  19.   File ckuus4.c -- Functions moved from other ckuus*.c modules to even
  20.   out their sizes.
  21. */
  22. #include "ckcdeb.h"
  23. #include "ckcasc.h"
  24. #include "ckcker.h"
  25. #include "ckcnet.h"                     /* Network symbols */
  26. #include "ckuusr.h"
  27. #include "ckuver.h"
  28. #include "ckcxla.h"                     /* Character sets */
  29.  
  30. #ifdef CK_AUTHENTICATION
  31. #include "ckuath.h"
  32. #endif /* CK_AUTHENTICATION */
  33. #ifdef CK_SSL
  34. #include "ck_ssl.h"
  35. #endif /* CK_SSL */
  36.  
  37. #ifdef VMS
  38. #include <errno.h>                      /* For \v(errno) */
  39. extern char * ckvmserrstr(unsigned long);
  40. #ifndef OLD_VMS
  41. #include <lib$routines.h>               /* Not for VAX C 2.4 */
  42. #else
  43. #include <libdef.h>
  44. #endif /* OLD_VMS */
  45. _PROTOTYP(int vmsttyfd, (void) );
  46. #endif /* VMS */
  47.  
  48. #ifdef OS2
  49. #ifndef NT
  50. #define INCL_NOPM
  51. #define INCL_VIO                        /* Needed for ckocon.h */
  52. #include <os2.h>
  53. #undef COMMENT
  54. #else
  55. #include <windows.h>
  56. #include <tapi.h>
  57. #include "ckntap.h"
  58. #define APIRET ULONG
  59. #endif /* NT */
  60. #include "ckocon.h"
  61. #include "ckoetc.h"
  62. int StartedFromDialer = 0;
  63. HWND hwndDialer = 0;
  64. LONG KermitDialerID = 0;
  65. #ifdef putchar
  66. #undef putchar
  67. #endif /* putchar */
  68. #define putchar(x) conoc(x)
  69. #ifdef CK_PID
  70. #include <process.h>
  71. #endif /* CK_PID */
  72. #endif /* OS2 */
  73.  
  74. #ifdef KUI
  75. extern struct keytab * term_font;
  76. extern int ntermfont, tt_font, tt_font_size;
  77. #endif /* KUI */
  78.  
  79. extern xx_strp xxstring;
  80.  
  81. #ifdef DEC_TCPIP
  82. #include <descrip>
  83. #include <dvidef>
  84. #include <dcdef>
  85. #endif /* DEC_TCPIP */
  86.  
  87. #ifdef FNFLOAT
  88. #include <math.h>                       /* Floating-point functions */
  89. #endif /* FNFLOAT */
  90.  
  91. extern int quiet, network, xitsta, escape, nopush, xferstat,
  92.   exitonclose, tn_exit, ttnproto, autodl, flow, byteorder, what, lastxfer;
  93.  
  94. extern int filepeek, nscanfile, makestrlen;
  95. extern char * k_info_dir;
  96.  
  97. #ifndef MAC
  98. #ifndef AMIGA
  99. extern int ttyfd;
  100. #endif /* MAC */
  101. #endif /* AMIGA */
  102.  
  103. #ifdef TNCODE
  104. extern int tn_nlm, tn_b_nlm, tn_b_xfer, tn_sb_bug;
  105. extern int tn_rem_echo;
  106. extern int tn_b_meu, tn_b_ume, tn_auth_krb5_des_bug;
  107. #endif /* TNCODE */
  108.  
  109. char * xferfile = NULL;
  110. int xferlog = 0;
  111.  
  112. extern int local, xargc, stayflg, rcflag, bgset, backgrd, cfilef,
  113.   inserver, srvcdmsg, success;
  114.  
  115. #ifdef VMS
  116. extern int batch;
  117. #endif /* VMS */
  118.  
  119. extern char cmdfil[], *versio, *ckxsys, **xargv;
  120. #ifdef DEBUG
  121. extern char debfil[];                   /* Debug log file name */
  122. extern int debtim;
  123. #endif /* DEBUG */
  124.  
  125. extern int noinit;
  126.  
  127. static char ndatbuf[10];
  128.  
  129. char *months[] = {
  130.     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  131.     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  132. };
  133.  
  134. char *
  135. zzndate() {                             /* Returns today's date as yyyymmdd */
  136.     char * p = NULL;
  137.     int x;
  138.  
  139. /* WARNING - This will fail if asctime() returns non-English month names */
  140.  
  141.     ztime(&p);                          /* Get "asctime" string */
  142.     if (p == NULL || *p == NUL) return("");
  143.     for (x = 20; x < 24; x++)           /* yyyy */
  144.       ndatbuf[x - 20] = p[x];
  145.     ndatbuf[6] = (char) ((p[8] == ' ') ? '0' : p[8]);
  146.     ndatbuf[7] = p[9];                  /* dd */
  147.     for (x = 0; x < 12; x++)            /* mm */
  148.       if (!strncmp(p+4,months[x],3)) break;
  149.     if (x == 12) {
  150.         ndatbuf[4] = ndatbuf[5] = '?';
  151.     } else {
  152.         x++;
  153.         ndatbuf[4] = (char) ((x < 10) ? '0' : '1');
  154.         ndatbuf[5] = (char) ((x % 10) + 48);
  155.     }
  156.     ndatbuf[8] = NUL;
  157.     debug(F110,"zzndate return",ndatbuf,0);
  158.     return((char *)ndatbuf);
  159. }
  160.  
  161. #ifdef DCMDBUF
  162. extern struct cmdptr *cmdstk;
  163. extern char *line, *tmpbuf;
  164. #else
  165. extern struct cmdptr cmdstk[];
  166. extern char line[], tmpbuf[];
  167. #endif /* DCMDBUF */
  168.  
  169. #ifdef OS2
  170. extern char exedir[];
  171. #else
  172. extern char * exedir;
  173. #endif /* OS2 */
  174.  
  175. extern int nettype;
  176.  
  177. #ifndef NOICP                           /* Most of this file... */
  178. #ifdef CKLOGDIAL
  179. extern char diafil[];
  180. #endif /* CKLOGDIAL */
  181.  
  182. #ifndef AMIGA
  183. #ifndef MAC
  184. #include <signal.h>
  185. #endif /* MAC */
  186. #endif /* AMIGA */
  187.  
  188. #ifdef STRATUS                          /* Stratus Computer, Inc.  VOS */
  189. #ifdef putchar
  190. #undef putchar
  191. #endif /* putchar */
  192. #define putchar(x) conoc(x)
  193. #ifdef getchar
  194. #undef getchar
  195. #endif /* getchar */
  196. #define getchar(x) coninc(0)
  197. #endif /* STRATUS */
  198.  
  199.  
  200. #ifdef ANYX25
  201. extern int revcall, closgr, cudata;
  202. int x25ver;
  203. extern char udata[];
  204. #ifndef IBMX25
  205. extern int npadx3;
  206. extern CHAR padparms[];
  207. extern struct keytab padx3tab[];
  208. #endif /* !IBMX25 */
  209. #ifdef IBMX25
  210. /* global variables only available for IBM X.25 - possibly interesting for
  211.  * other implementations
  212.  */
  213. extern x25addr_t local_nua;
  214. extern x25addr_t remote_nua;
  215. #endif /* IBMX25 */
  216. #endif /* ANYX25 */
  217.  
  218. #ifdef NETCONN
  219. #ifndef NODIAL
  220. extern int nnetdir;
  221. extern char *netdir[];
  222. #endif /* NODIAL */
  223. extern char ipaddr[];
  224.  
  225. #ifdef CK_NETBIOS
  226. extern unsigned short netbiosAvail;
  227. extern unsigned long NetbeuiAPI;
  228. extern unsigned char NetBiosName[];
  229. extern unsigned char NetBiosAdapter;
  230. extern unsigned char NetBiosLSN;
  231. #endif /* CK_NETBIOS */
  232.  
  233. #ifdef TCPSOCKET
  234. extern char myipaddr[];
  235. extern int tcp_rdns;
  236. #ifdef CK_DNS_SRV
  237. extern int tcp_dns_srv;
  238. #endif /* CK_DNS_SRV */
  239. extern char * tcp_address;
  240. #ifndef NOHTTP
  241. extern char * tcp_http_proxy;
  242. #endif /* NOHTTP */
  243. #ifdef NT
  244. #ifdef CK_SOCKS
  245. extern char * tcp_socks_svr;
  246. #ifdef CK_SOCKS_NS
  247. extern char * tcp_socks_ns;
  248. #endif /* CK_SOCKS_NS */
  249. #endif /* CK_SOCKS */
  250. #endif /* NT */
  251.  
  252. #ifndef NOTCPOPTS
  253. #ifdef SOL_SOCKET
  254. #ifdef SO_LINGER
  255. extern int tcp_linger;
  256. extern int tcp_linger_tmo;
  257. #endif /* SO_LINGER */
  258. #ifdef SO_DONTROUTE
  259. extern int tcp_dontroute;
  260. #endif /* SO_DONTROUTE */
  261. #ifdef TCP_NODELAY
  262. extern int tcp_nodelay;
  263. #endif /* TCP_NODELAY */
  264. #ifdef SO_SNDBUF
  265. extern int tcp_sendbuf;
  266. #endif /* SO_SNDBUF */
  267. #ifdef SO_RCVBUF
  268. extern int tcp_recvbuf;
  269. #endif /* SO_RCVBUF */
  270. #ifdef SO_KEEPALIVE
  271. extern int tcp_keepalive;
  272. #endif /* SO_KEEPALIVE */
  273. #endif /* SOL_SOCKET */
  274. #endif /* NOTCPOPTS */
  275. #endif /* TCPSOCKET */
  276. #endif /* NETCONN */
  277.  
  278. extern char * floname[];
  279.  
  280. #ifndef NOSPL
  281. extern int fndiags;                     /* Function diagnostics on/off */
  282. extern int divbyzero;
  283. int ispattern = 0;
  284. int isinbuflen = 0;
  285. int isjoin = 0;
  286. #ifdef CK_APC
  287. extern int apcactive;                   /* Nonzero = APC command was rec'd */
  288. extern int apcstatus;                   /* Are APC commands being processed? */
  289. #ifdef DCMDBUF
  290. extern char *apcbuf;                    /* APC command buffer */
  291. #else
  292. extern char apcbuf[];
  293. #endif /* DCMDBUF */
  294. #endif /* CK_APC */
  295.  
  296. extern char evalbuf[];                  /* EVALUATE result */
  297. extern char uidbuf[], pwbuf[], prmbuf[];
  298. _PROTOTYP( static char * fneval, (char *, char * [], int, char * ) );
  299. _PROTOTYP( static VOID myflsh, (void) );
  300. _PROTOTYP( static char * getip, (char *) );
  301. _PROTOTYP( int delta2sec, (char *, long *) );
  302.  
  303. #ifdef NEWFTP
  304. _PROTOTYP( char * ftp_cpl_mode, (void) );
  305. _PROTOTYP( char * ftp_dpl_mode, (void) );
  306. _PROTOTYP( char * ftp_authtype, (void) );
  307. #endif /* NEWFTP */
  308.  
  309. #ifndef NOHTTP
  310. _PROTOTYP( char * http_host, (void) );
  311. _PROTOTYP( int http_isconnected, (void) );
  312. _PROTOTYP( char * http_security, (void) );
  313. #endif /* NOHTTP */
  314.  
  315. #ifndef NOSEXP
  316. _PROTOTYP( char * dosexp, (char *) );
  317. int fsexpflag = 0;
  318. #endif /* NOSEXP */
  319.  
  320. static char hexdigits[16] = {
  321.     '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
  322. };
  323. extern char * tempdir;
  324.  
  325. #ifdef CK_REXX
  326. extern char rexxbuf[];
  327. #endif /* CK_REXX */
  328.  
  329. extern int tfline[];
  330.  
  331. char *wkdays[] = {
  332.     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  333. };
  334. #endif /* NOSPL */
  335.  
  336. #ifdef OS2
  337. extern char startupdir[], inidir[];
  338. #else
  339. #ifdef VMSORUNIX
  340. extern char startupdir[];
  341. #endif /* VMSORUNIX */
  342. #endif /* OS2 */
  343.  
  344. #ifdef OS2
  345. _PROTOTYP (int os2getcp, (void) );
  346. #ifdef TCPSOCKET
  347. extern char tcpname[];
  348. #endif /* TCPSOCKET */
  349. extern int tcp_avail;
  350. #ifdef DECNET
  351. extern int dnet_avail;
  352. #endif /* DECNET */
  353. #ifdef SUPERLAT
  354. extern int slat_avail;
  355. #endif /* SUPERLAT */
  356.  
  357. #ifndef NOTERM
  358. extern int tt_type, max_tt;
  359. extern struct tt_info_rec tt_info[];
  360. #endif /* NOTERM */
  361. extern int tt_rows[], tt_cols[];
  362. #else /* OS2 */
  363. extern int tt_rows, tt_cols;
  364. #endif /* OS2 */
  365.  
  366. #ifdef CK_TAPI
  367. extern int tttapi;
  368. extern int tapipass;
  369. extern struct keytab * tapilinetab;
  370. extern struct keytab * _tapilinetab;
  371. extern int ntapiline;
  372. #endif /* CK_TAPI */
  373.  
  374. extern struct keytab colxtab[];
  375. extern int ncolx;
  376.  
  377. extern char ttname[], *zinptr, *kermrc;
  378. extern char inidir[];
  379.  
  380. extern int activecmd, remonly, cmd_rows, cmd_cols, parity, seslog,
  381.   sessft, sosi, hwparity, tsecs, xargs, zincnt, tlevel, insilence, cmdmsk,
  382.   timint, timef, inbufsize, dialog, binary, carrier, cdtimo, cmask, duplex,
  383.   fmask, inecho, nmac, turnch, turn, kbchar;
  384.  
  385. #ifndef NOXFER
  386. extern CHAR eol,  mypadc, mystch, padch, seol, stchr, * epktmsg, feol;
  387. extern char *cksysid;
  388. extern struct ck_p ptab[];
  389. extern int
  390.   protocol, prefixing, xfrbel, xfrcan, xfrint, xfrchr, xfrnum, pktpaus,
  391.   lscapr, lscapu, xfermode, dest, slostart, maxrps, maxsps, maxtry, mypadn,
  392.   npad, pkttim, bigrbsiz, bigsbsiz, keep, atcapr, autopar, bctr, bctu,
  393.   crunched, ckdelay, ebq, ebqflg, pktlog, retrans, rpackets, rptflg, rptq,
  394.   rtimo, spackets, spsiz, spsizf, spsizr, timeouts, fncact, fncnv, urpsiz,
  395.   wmax, wslotn, wslotr, fdispla, spmax, fnrpath, fnspath, crc16;
  396. #endif /* NOXFER */
  397.  
  398. #ifdef OS2
  399. extern int zxpn;
  400. extern int viewonly;
  401. #endif /* OS2 */
  402.  
  403. #ifndef NOXFER
  404. #ifdef GFTIMER
  405. extern CKFLOAT fptsecs, fpxfsecs;
  406. #endif /* GFTIMER */
  407. extern long xfsecs, tfcps;
  408.  
  409. #ifdef CK_TMPDIR
  410. extern char *dldir;
  411. #endif /* CK_TMPDIR */
  412. #endif /* NOXFER */
  413.  
  414. #ifdef RECURSIVE
  415. extern int recursive;
  416. #endif /* RECURSIVE */
  417.  
  418. #ifdef VMS
  419. extern int frecl;
  420. #endif /* VMS */
  421.  
  422. extern CK_OFF_T ffc, tfc, tlci, tlco;
  423. extern long filcnt, rptn, speed,  ccu, ccp, vernum, xvernum;
  424.  
  425. #ifndef NOSPL
  426. extern char fspec[], myhost[];
  427. #endif /* NOSPL */
  428.  
  429. extern char *tfnam[];                   /* Command file names */
  430.  
  431. extern char pktfil[],                   /* Packet log file name */
  432. #ifdef TLOG
  433.   trafil[],                             /* Transaction log file name */
  434. #endif /* TLOG */
  435.   sesfil[];                             /* Session log file name */
  436.  
  437. #ifndef NOXMIT                          /* TRANSMIT command variables */
  438. extern char xmitbuf[];
  439. extern int xmitf, xmitl, xmitx, xmits, xmitw, xmitt;
  440. #endif /* NOXMIT */
  441.  
  442. extern int cmdlvl;
  443.  
  444. #ifndef NOSPL
  445. /* Script programming language items */
  446. extern char **a_ptr[];                  /* Arrays */
  447. extern int a_dim[];
  448. static char * inpmatch = NULL;
  449. #ifdef CKFLOAT
  450. char * inpscale = NULL;
  451. #endif    /* CKFLOAT */
  452. extern char * inpbuf, inchar[];         /* Buffers for INPUT and REINPUT */
  453. extern char *inpbp;                     /* And pointer to same */
  454. static char *r3 = (char *)0;
  455. extern int incount;                     /* INPUT character count */
  456. extern int m_found;                     /* MINPUT result */
  457. extern int maclvl;                      /* Macro invocation level */
  458. extern struct mtab *mactab;             /* Macro table */
  459. extern char *mrval[];
  460. extern int macargc[], topargc;
  461.  
  462. #ifdef COMMENT
  463. extern char *m_line[];
  464. extern char *topline;
  465. #endif /* COMMENT */
  466.  
  467. extern char *m_arg[MACLEVEL][10]; /* You have to put in the dimensions */
  468. extern char *g_var[GVARS];        /* for external 2-dimensional arrays. */
  469. #ifdef DCMDBUF
  470. extern int *count, *inpcas;
  471. #else
  472. extern int count[], inpcas[];
  473. #endif /* DCMDBUF */
  474. #endif /* NOSPL */
  475.  
  476. #ifdef UNIX
  477. extern int haslock;                     /* For UUCP locks */
  478. extern char flfnam[];
  479. #ifndef USETTYLOCK
  480. extern char lock2[];
  481. #endif /* USETTYLOCK */
  482. #endif /* UNIX */
  483.  
  484. #ifdef OS2ORUNIX
  485. extern int maxnam, maxpath;             /* Longest name, path length */
  486. #endif /* OS2ORUNIX */
  487.  
  488. extern int mdmtyp, mdmsav;
  489.  
  490. #ifndef NODIAL
  491. /* DIAL-related variables */
  492. extern char modemmsg[];
  493. extern MDMINF *modemp[];                /* Pointers to modem info structs */
  494. extern int nmdm, dialhng, dialtmo, dialksp, dialdpy, dialsrt, dialsta;
  495. extern int dialrtr, dialint, dialrstr, dialcon, dialcq, dialfld;
  496. extern int mdmspd, dialec, dialdc, dialmth, dialmauto, dialesc;
  497. extern char *dialnum,   *dialini,  *dialdir[], *dialcmd,  *dialnpr,
  498.  *dialdcon, *dialdcoff, *dialecon, *dialecoff, *dialhcmd, *diallac,
  499.  *dialhwfc, *dialswfc,  *dialnofc, *dialpulse, *dialtone, *dialname,
  500.  *dialaaon, *dialaaoff, *dialmac;
  501. extern char *diallcc,   *dialixp,  *dialixs,   *dialldp,  *diallds,
  502.  *dialpxi,  *dialpxo,   *dialsfx,  *dialtfp;
  503. extern char *diallcp,   *diallcs;
  504. extern int ntollfree, ndialpxx, nlocalac;
  505. extern char *dialtfc[], *diallcac[], *dialpxx[], *matchpxx;
  506. extern int ndialpucc, ndialtocc;
  507. extern char *dialtocc[], *dialpucc[];
  508. extern int ndialdir, dialcnf, dialcvt, dialidt, dialpace;
  509. extern long dialmax, dialcapas;
  510.  
  511. extern struct keytab mdmtab[];
  512.  
  513. #ifdef BIGBUFOK
  514. #define ARGBUFSIZ 8191
  515. #else
  516. #define ARGBUFSIZ 1023
  517. #endif /* BIGBUFOK */
  518.  
  519. #ifdef BIGBUFOK
  520. extern char * dialmsg[];
  521. #endif /* BIGBUFOK */
  522.  
  523. #endif /* NODIAL */
  524.  
  525. #ifndef NOCSETS
  526. /* Translation stuff */
  527. extern int fcharset, tcharset, tslevel, language, nlng, tcsr, tcsl;
  528. extern int dcset7, dcset8;
  529. extern struct keytab lngtab[];
  530. extern struct csinfo fcsinfo[], tcsinfo[];
  531. extern struct langinfo langs[];
  532. #ifdef CK_ANSIC
  533. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
  534. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
  535. #else
  536. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */
  537. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */
  538. #endif /* CK_ANSIC */
  539. #ifdef UNICODE
  540.     extern int ucsbom, ucsorder;
  541. #endif /* UNICODE */
  542. #endif /* NOCSETS */
  543.  
  544. #ifndef NOSPL
  545. /* Built-in variable names, maximum length VNAML (20 characters) */
  546.  
  547. struct keytab vartab[] = {
  548.     { "_line",     VN_TFLN,  CM_INV},   /* 192 */
  549. #ifdef OS2
  550.     { "_regname",  VN_REGN,  CM_INV},   /* 1.1.12 */
  551.     { "_regorg",   VN_REGO,  CM_INV},   /* 1.1.12 */
  552.     { "_regnum",   VN_REGS,  CM_INV},   /* 1.1.12 */
  553. #endif /* OS2 */
  554.     { "apcactive", VN_APC,   CM_INV},   /* 192 */
  555. #ifdef NT
  556.     { "appdata",   VN_APPDATA, 0},      /* 201 */
  557. #endif /* NT */
  558.     { "argc",      VN_ARGC,  0},
  559.     { "args",      VN_ARGS,  0},
  560.     { "authname",  VN_AUTHN, 0},        /* 196 */
  561.     { "authstate", VN_AUTHS, 0},        /* 195 */
  562.     { "authtype",  VN_AUTHT, 0},        /* 195 */
  563.     { "bits",      VN_BITS,  0},        /* 212 */
  564.     { "blockcheck",VN_BLK,   0},        /* 195 */
  565. #ifdef BROWSER
  566.     { "browser",   VN_BROWSR,0},        /* 193 */
  567.     { "browsopts", VN_BROPT, 0},        /* 193 */
  568.     { "browsurl",  VN_URL,   0},        /* 193 */
  569.     { "buildid",   VN_BUILD, 0},        /* 199 */
  570. #endif /* BROWSER */
  571.     { "byteorder", VN_BYTE,  0},        /* 195 */
  572. #ifndef NOCSETS
  573.     { "charset",   VN_CSET,  0},        /* 192 */
  574. #endif /* NOCSETS */
  575.     { "cmdbufsize",VN_CMDBL, 0},        /* 195 */
  576.     { "cmdfile",   VN_CMDF,  0},
  577.     { "cmdlevel",  VN_CMDL,  0},
  578.     { "cmdsource", VN_CMDS,  0},
  579.     { "cols",      VN_COLS,  0},        /* 190 */
  580. #ifdef NT
  581.     { "common",    VN_COMMON, 0},       /* 201 */
  582. #endif /* NT */
  583.     { "connection",VN_CONN,  0},        /* 190 */
  584.     { "count",     VN_COUN,  0},
  585. #ifndef NOXFER
  586.     { "cps",       VN_CPS,   0},        /* 190 */
  587. #endif /* NOXFER */
  588.     { "cpu",       VN_CPU,   0},
  589. #ifndef NOXFER
  590.     { "crc16",     VN_CRC16, 0},        /* 192 */
  591.     { "ctty",      VN_TTYNAM,0},        /* 196 */
  592. #endif /* NOXFER */
  593. #ifndef NOLOGDIAL
  594. #ifndef NOLOCAL
  595.     { "cx_time",   VN_CXTIME,0},        /* 195 */
  596.     { "cx_status", VN_CX_STA,0},        /* 199 */
  597. #endif /* NOLOCAL */
  598. #endif /* NOLOGDIAL */
  599. #ifndef NODIAL
  600.     { "d$ac",      VN_D_AC,  0},        /* 192 */
  601.     { "d$cc",      VN_D_CC,  0},        /* 192 */
  602.     { "d$ip",      VN_D_IP,  0},        /* 192 */
  603.     { "d$lc",      VN_D_LCP, 0},        /* 193 */
  604.     { "d$lcp",     VN_D_LCP, CM_INV},   /* 193 */
  605.     { "d$lp",      VN_D_LP,  0},        /* 192 */
  606.     { "d$px",      VN_D_PXX, 0},        /* 195 */
  607.     { "d$pxx",     VN_D_PXX, CM_INV},   /* 195 */
  608. #endif /* NODIAL */
  609.     { "date",      VN_DATE,  0},
  610.     { "day",       VN_DAY,   0},
  611. #ifdef NT
  612.     { "desktop",   VN_DESKTOP, 0},     /* 201 */
  613. #endif /* NT */
  614. #ifndef NODIAL
  615.     { "dialcount", VN_DRTR,  0},        /* 195 */
  616.     { "dialnumber",VN_DNUM,  0},        /* 192 */
  617.     { "dialresult",VN_MDMSG, 0},        /* 192 */
  618.     { "dialstatus",VN_DIAL,  0},        /* 190 */
  619.     { "dialsuffix",VN_PDSFX, 0},        /* 193 */
  620.     { "dialtype",  VN_DTYPE, 0},        /* 193 */
  621. #endif /* NODIAL */
  622.     { "directory", VN_DIRE,  0},
  623. #ifndef NODIAL
  624.     { "dm_hf",     VN_DM_HF, 0},        /* 199 */
  625.     { "dm_lp",     VN_DM_LP, 0},        /* 195 */
  626.     { "dm_sp",     VN_DM_SP, 0},        /* 195 */
  627.     { "dm_pd",     VN_DM_PD, 0},        /* 195 */
  628.     { "dm_td",     VN_DM_TD, 0},        /* 195 */
  629.     { "dm_wa",     VN_DM_WA, 0},        /* 195 */
  630.     { "dm_wb",     VN_DM_WB, 0},        /* 199 */
  631.     { "dm_wd",     VN_DM_WD, 0},        /* 195 */
  632.     { "dm_rc",     VN_DM_RC, 0},        /* 195 */
  633. #endif /* NODIAL */
  634. #ifndef NOXFER
  635.     { "download",  VN_DLDIR, 0},        /* 192 */
  636. #endif /* NOXFER */
  637.     { "editor",    VN_EDITOR,0},
  638.     { "editfile",  VN_EDFILE,0},
  639.     { "editopts",  VN_EDOPT, 0},
  640.     { "errno",     VN_ERRNO, 0},        /* 192 */
  641.     { "errstring", VN_ERSTR, 0},        /* 192 */
  642.     { "escape",    VN_ESC,   0},        /* 193 */
  643.     { "evaluate",  VN_EVAL,  0},        /* 190 */
  644. #ifdef OS2ORUNIX
  645.     { "exedir",    VN_EXEDIR,0},        /* 192 */
  646. #endif /* OS2ORUNIX */
  647.     { "exitstatus",VN_EXIT,  0},
  648. #ifdef CKCHANNELIO
  649.     { "f_count",   VN_FCOU,  0},        /* 195 */
  650.     { "f_error",   VN_FERR,  0},        /* 195 */
  651.     { "f_max",     VN_FMAX,  0},        /* 195 */
  652.     { "fileerror", VN_FERR,  CM_INV},   /* 195 */
  653.     { "filemax",   VN_FERR,  CM_INV},   /* 195 */
  654. #endif /* CKCHANNELIO */
  655.     { "filename",  VN_FNAM,  0},        /* 193 */
  656.     { "filenumber",VN_FNUM,  0},        /* 193 */
  657.     { "filespec",  VN_FILE,  0},
  658.     { "fsize",     VN_FFC,   0},        /* 190 */
  659. #ifdef GFTIMER
  660.     { "ftime",     VN_FTIME, 0},        /* 199 */
  661. #else
  662.     { "ftime",     VN_NTIM,  CM_INV},
  663. #endif /* GFTIMER */
  664. #ifndef NOFTP
  665. #ifndef SYSFTP
  666.     { "ftp_code",         VN_FTP_C, 0}, /* 199 */
  667.     { "ftp_cpl",          VN_FTP_B, 0}, /* 199 */
  668.     { "ftp_connected",    VN_FTP_X, 0}, /* 199 */
  669.     { "ftp_dpl",          VN_FTP_D, 0}, /* 199 */
  670.     { "ftp_getputremote", VN_FTP_G, 0}, /* 199 */
  671.     { "ftp_host",         VN_FTP_H, 0}, /* 199 */
  672.     { "ftp_loggedin",     VN_FTP_L, 0}, /* 199 */
  673.     { "ftp_message",      VN_FTP_M, 0}, /* 199 */
  674.     { "ftp_msg",          VN_FTP_M, CM_INV}, /* 199 */
  675.     { "ftp_security",     VN_FTP_Z, 0}, /* 199 */
  676.     { "ftp_server",       VN_FTP_S, 0}, /* 199 */
  677. #endif /* SYSFTP */
  678. #endif /* NOFTP */
  679.     { "ftype",     VN_MODE,  0},        /* 190 */
  680. #ifdef KUI
  681.     { "gui_fontname", VN_GUI_FNM, 0},    /* 205 */
  682.     { "gui_fontsize", VN_GUI_FSZ, 0},    /* 205 */
  683.     { "gui_runmode", VN_GUI_RUN, 0},    /* 205 */
  684.     { "gui_xpos",    VN_GUI_XP,  0},    /* 205 */
  685.     { "gui_xres",    VN_GUI_XR,  0},    /* 205 */
  686.     { "gui_ypos",    VN_GUI_YP,  0},    /* 205 */
  687.     { "gui_yres",    VN_GUI_YR,  0},    /* 205 */
  688. #endif /* KUI */
  689.     { "herald",    VN_HERALD, 0},
  690.     { "home",      VN_HOME,   0},
  691.     { "host",      VN_HOST,   0},
  692.     { "hour",      VN_HOUR,   0},       /* 200 */
  693. #ifndef NOHTTP
  694.     { "http_code",      VN_HTTP_C, 0},  /* 199 */
  695.     { "http_connected", VN_HTTP_N, 0},  /* 199 */
  696.     { "http_host",      VN_HTTP_H, 0},  /* 199 */
  697.     { "http_message",   VN_HTTP_M, 0},  /* 199 */
  698.     { "http_security",  VN_HTTP_S, 0},  /* 199 */
  699. #endif /* NOHTTP */
  700.     { "hwparity",  VN_HWPAR, 0},        /* 195 */
  701.     { "input",     VN_IBUF,  0},
  702.     { "inchar",    VN_ICHR,  0},
  703.     { "incount",   VN_ICNT,  0},
  704.     { "inidir",    VN_INI,   0},        /* 192 */
  705.     { "inmatch",   VN_MATCH, 0},        /* 196 */
  706.     { "inscale",   VN_ISCALE,0},        /* 210 */
  707.     { "instatus",  VN_ISTAT, 0},        /* 192 */
  708.     { "intime",    VN_INTIME,0},        /* 193 */
  709.     { "inwait",    VN_INTMO, 0},        /* 195 */
  710.     { "ip",        VN_IPADDR, CM_ABR|CM_INV},
  711.     { "ipaddress", VN_IPADDR,0},        /* 192 */
  712.     { "iprompt",   VN_PROMPT,0},        /* 199 */
  713.     { "kbchar",    VN_KBCHAR,0},        /* 196 */
  714. #ifndef NOLOCAL
  715. #ifdef OS2
  716.     { "keyboard",  VN_KEYB,  0},
  717. #endif /* OS2 */
  718. #endif /* NOLOCAL */
  719. #ifdef CK_KERBEROS
  720.     { "krb4errmsg",    VN_K4EMSG,0},
  721.     { "krb4errno",     VN_K4ENO, 0},
  722.     { "krb4principal", VN_K4PRN, 0},
  723.     { "krb4realm",     VN_K4RLM, 0},
  724.     { "krb4service",   VN_K4SRV, 0},
  725.     { "krb5cc",        VN_K5CC,  0},
  726.     { "krb5errmsg",    VN_K5EMSG,0},
  727.     { "krb5errno",     VN_K5ENO, 0},
  728.     { "krb5principal", VN_K5PRN, 0},
  729.     { "krb5realm",     VN_K5RLM, 0},
  730.     { "krb5service",   VN_K5SRV, 0},
  731. #endif /* CK_KERBEROS */
  732. #ifndef NOLASTFILE
  733.     { "lastfilespec",  VN_LASTFIL, 0},
  734. #endif    /* NOLASTFILE */
  735.     { "line",      VN_LINE,  0},
  736.     { "local",     VN_LCL,   0},
  737. #ifdef UNIX
  738.     { "lockdir",   VN_LCKDIR,0},        /* 195 */
  739.     { "lockpid",   VN_LCKPID,0},        /* 195 */
  740. #endif /* UNIX */
  741.     { "log_connection", VN_LOG_CON, 0}, /* 206 */
  742.     { "log_debug", VN_LOG_DEB, 0},      /* 206 */
  743.     { "log_packet", VN_LOG_PKT, 0},     /* 206 */
  744.     { "log_session", VN_LOG_SES, 0},    /* 206 */
  745.     { "log_transaction", VN_LOG_TRA, 0},/* 206 */
  746.     { "maclevel",  VN_MACLVL,0},        /* 195 */
  747.     { "macro",     VN_MAC,   0},
  748. #ifdef FNFLOAT
  749.     { "math_e",    VN_MA_E,  0},        /* 195 */
  750.     { "math_pi",   VN_MA_PI, 0},        /* 195 */
  751.     { "math_precision", VN_MA_PR, 0},   /* 195 */
  752. #endif /* FNFLOAT */
  753.     { "minput",    VN_MINP,  0},        /* 192 */
  754.     { "model",     VN_MODL,  0},        /* 193 */
  755.     { "modem",     VN_MDM,   0},
  756. #ifndef NOLOCAL
  757. #ifdef OS2
  758.     { "mousecurx", VN_MOU_X, 0},        /* K95 1.1.14 */
  759.     { "mousecury", VN_MOU_Y, 0},        /* K95 1.1.14 */
  760. #endif /* OS2 */
  761. #endif /* NOLOCAL */
  762. #ifndef NODIAL
  763.     { "m_aa_off",  VN_M_AAX, 0},        /* all 192... */
  764.     { "m_aa_on",   VN_M_AAO, 0},
  765.     { "m_dc_off",  VN_M_DCX, 0},
  766.     { "m_dc_on",   VN_M_DCO, 0},
  767.     { "m_dial",    VN_M_DCM, 0},
  768.     { "m_ec_off",  VN_M_ECX, 0},
  769.     { "m_ec_on",   VN_M_ECO, 0},
  770.     { "m_fc_hw",   VN_M_HWF, 0},
  771.     { "m_fc_no",   VN_M_NFC, 0},
  772.     { "m_fc_sw",   VN_M_SWF, 0},
  773.     { "m_hup",     VN_M_HUP, 0},
  774.     { "m_init",    VN_M_INI, 0},
  775.     { "m_name",    VN_M_NAM, 0},        /* 195 */
  776.     { "m_pulse",   VN_M_PDM, 0},
  777.     { "m_sig_cd",  VN_MS_CD, 0},        /* 195 */
  778.     { "m_sig_cts", VN_MS_CTS,0},        /* 195 */
  779.     { "m_sig_dsr", VN_MS_DSR,0},        /* 195 */
  780.     { "m_sig_dtr", VN_MS_DTR,0},        /* 195 */
  781.     { "m_sig_ri",  VN_MS_RI, 0},        /* 195 */
  782.     { "m_sig_rts", VN_MS_RTS,0},        /* 195 */
  783.     { "m_tone",    VN_M_TDM, 0},
  784. #endif /* NODIAL */
  785.     { "name",      VN_NAME,  0},
  786.     { "ndate",     VN_NDAT,  0},
  787.     { "nday",      VN_NDAY,  0},
  788.     { "newline",   VN_NEWL,  0},
  789.     { "ntime",     VN_NTIM,  0},
  790.     { "osname",    VN_OSNAM, 0},        /* 193 */
  791.     { "osrelease", VN_OSREL, 0},        /* 193 */
  792.     { "osversion", VN_OSVER, 0},        /* 193 */
  793. #ifndef NOXFER
  794.     { "packetlen", VN_RPSIZ, 0},        /* 192 */
  795. #endif /* NOXFER */
  796.     { "parity",    VN_PRTY,  0},        /* 190 */
  797.     { "password",  VN_PWD,   CM_INV},   /* 192 */
  798. #ifdef NT
  799.     { "personal",  VN_PERSONAL, 0},     /* 201 */
  800. #endif /* NT */
  801. #ifdef PEXITSTAT
  802.     { "pexitstat", VN_PEXIT, 0},        /* 193 */
  803. #endif /* PEXITSTAT */
  804. #ifdef CK_PID
  805.     { "pid",       VN_PID,   0},        /* 193 */
  806. #endif /* CK_PID */
  807.     { "platform",  VN_SYSV,  0},
  808.     { "printer",   VN_PRINT, 0},        /* 193 */
  809.     { "program",   VN_PROG,  0},
  810.     { "prompt",    VN_PRM,   CM_INV},   /* 192 */
  811. #ifndef NOXFER
  812.     { "protocol",  VN_PROTO, 0},        /* 192 */
  813.     { "p_8bit",    VN_P_8BIT,0},        /* 193 */
  814.     { "p_ctl",     VN_P_CTL, 0},        /* 193 */
  815.     { "p_rpt",     VN_P_RPT, 0},        /* 193 */
  816.     { "query",     VN_QUE,   0},        /* 190 */
  817. #endif /* NOXFER */
  818.     { "return",    VN_RET,   0},
  819. #ifdef CK_REXX
  820.     { "rexx",      VN_REXX,  0},        /* 190 */
  821. #endif /* CK_REXX */
  822. #ifdef TN_COMPORT
  823.     { "rfc2217_signature", VN_TNC_SIG, 0}, /* 201 */
  824.     { "rfc2717_signature", VN_TNC_SIG, CM_INV}, /* 202 */
  825. #endif /* TN_COMPORT */
  826.     { "rows",      VN_ROWS,  0},        /* 190 */
  827. #ifndef NOSEXP
  828.     { "sdepth",    VN_LSEXP,0},         /* 199 */
  829. #endif /* NOSEXP */
  830.     { "secure",    VN_SECURE, 0},       /* 199 */
  831. #ifndef NOLOCAL
  832. #ifdef OS2
  833.     { "select",    VN_SELCT, 0},        /* 192 */
  834. #endif /* OS2 */
  835. #endif /* NOLOCAL */
  836.     { "sendlist",  VN_SNDL,  0},
  837.     { "serial",    VN_SERIAL,0},        /* 195 */
  838.     { "setlinemsg",VN_SLMSG, 0},        /* 195 */
  839. #ifndef NOSEXP
  840.     { "sexpression",VN_SEXP, 0},        /* 199 */
  841. #endif /* NOSEXP */
  842.     { "speed",     VN_SPEE,  0},
  843. #ifdef OS2
  844.     { "space",     VN_SPA,   0},
  845.     { "startup",   VN_STAR,  0},        /* 190 */
  846. #else
  847. #ifdef UNIX
  848.     { "startup",   VN_STAR,  0},        /* 193 */
  849. #else
  850. #ifdef VMS
  851.     { "startup",   VN_STAR,  0},        /* 193 */
  852. #endif /* VMS */
  853. #endif /* UNIX */
  854. #endif /* OS2 */
  855.     { "status",    VN_SUCC,  0},
  856. #ifndef NOSEXP
  857.     { "svalue",    VN_VSEXP, 0},        /* 199 */
  858. #endif /* NOSEXP */
  859. #ifndef NOXFER
  860.     { "sysid",     VN_SYSI,  0},
  861. #endif /* NOXFER */
  862.     { "system",    VN_SYST,  0},
  863.     { "terminal",  VN_TTYP,  0},
  864. #ifdef OS2
  865. #ifndef NOKVERBS
  866.     { "termkey",   VN_TRMK,  CM_INV},   /* 192 */
  867. #endif /* NOKVERBS */
  868. #endif /* OS2 */
  869.     { "test",      VN_TEST,  0},        /* 193 */
  870.     { "textdir",   VN_TXTDIR,0},        /* 195 */
  871. #ifndef NOXFER
  872.     { "tfsize",    VN_TFC,   0},
  873.     { "tftime",    VN_TFTIM, 0},        /* 195 */
  874. #endif /* NOXFER */
  875.     { "time",      VN_TIME,  0},
  876.     { "timestamp", VN_NOW,   0},        /* 200 */
  877.     { "tmpdir",    VN_TEMP,  0},        /* 192 */
  878. #ifdef CK_TRIGGER
  879.     { "trigger",   VN_TRIG,  0},        /* 193 */
  880. #endif /* CK_TRIGGER */
  881. #ifdef CK_TTYFD
  882.     { "ttyfd",     VN_TTYF,  0},
  883. #endif /* CK_TTYFD */
  884.     { "ty_ln",     VN_TY_LN, 0},        /* 195 */
  885.     { "ty_lc",     VN_TY_LC, 0},        /* 195 */
  886.     { "ty_lm",     VN_TY_LM, 0},        /* 195 */
  887. #ifdef BROWSER
  888.     { "url",       VN_URL,   CM_INV},   /* 193 */
  889. #endif /* BROWSER */
  890.     { "userid",    VN_UID,   0},        /* 192 */
  891.     { "version",   VN_VERS,  0},
  892. #ifndef NOXFER
  893.     { "window",    VN_WINDO, 0},        /* 192 */
  894. #endif /* NOXFER */
  895. #ifdef IBMX25
  896.     { "x25local_nua", VN_X25LA, 0},     /* 193 */
  897.     { "x25remote_nua", VN_X25RA, 0},    /* 193 */
  898. #endif /* IBMX25 */
  899. #ifdef CK_SSL
  900.     { "x509_issuer",  VN_X509_I, 0},
  901.     { "x509_subject", VN_X509_S, 0},
  902. #endif /* CK_SSL */
  903. #ifndef NOXFER
  904.     { "xferstatus",VN_XFSTAT,0},        /* 193 */
  905.     { "xfermsg",   VN_XFMSG, 0},        /* 193 */
  906.     { "xfer_badpackets", VN_XF_BC, 0},  /* 195 */
  907.     { "xfer_timeouts",   VN_XF_TM, 0},  /* 195 */
  908.     { "xfer_retransmits",VN_XF_RX, 0},  /* 195 */
  909. #endif /* NOXFER */
  910.     { "xprogram",  VN_XPROG, 0},        /* 193 */
  911.     { "xversion",  VN_XVNUM, 0}         /* 192 */
  912. };
  913. int nvars = (sizeof(vartab) / sizeof(struct keytab));
  914. #endif /* NOSPL */
  915.  
  916. #ifndef NOSPL
  917. struct keytab fnctab[] = {              /* Function names */
  918. #ifdef OS2
  919.     { ".oox",       FN_OOX, CM_INV},    /* ... */
  920. #endif /* OS2 */
  921.  
  922. #ifdef CKCHANNELIO
  923.     { "_eof",       FN_FEOF,   0},
  924.     { "_errmsg",    FN_FERMSG, 0},
  925.     { "_getblock",  FN_FGBLK,  0},
  926.     { "_getchar",   FN_FGCHAR, 0},
  927.     { "_getline",   FN_FGLINE, 0},
  928.     { "_handle",    FN_FILNO,  0},
  929.     { "_line",      FN_NLINE,  0},
  930.     { "_pos",       FN_FPOS,   0},
  931.     { "_putblock",  FN_FPBLK,  0},
  932.     { "_putchar",   FN_FPCHAR, 0},
  933.     { "_putline",   FN_FPLINE, 0},
  934.     { "_status",    FN_FSTAT,  0},
  935. #endif /* CKCHANNELIO */
  936.  
  937.     { "aaconvert",  FN_AADUMP, 0},      /* Associative Array conversion */
  938.     { "absolute",   FN_ABS,  0},        /* Absolute value */
  939. #ifdef TCPSOCKET
  940.     { "addr2name",  FN_HSTADD,CM_INV},  /* IP Address to Hostname */
  941.     { "addrtoname", FN_HSTADD,CM_INV},  /* IP Address to Hostname */
  942. #endif /* TCPSOCKET */
  943.     { "arraylook",  FN_ALOOK,0},        /* Array lookup */
  944.     { "b64decode",  FN_FMB64,0},        /* Base-64 conversion */
  945.     { "b64encode",  FN_TOB64,0},        /* ... */
  946.     { "basename",   FN_BSN,  0},        /* Basename */
  947.     { "break",      FN_BRK,  0},        /* Break (as in Snobol) */
  948.     { "ca",         FN_CAP,  CM_INV|CM_ABR}, /* Abbreviation for capitablize */
  949.     { "cap",        FN_CAP,  CM_INV|CM_ABR}, /* Abbreviation for capitablize */
  950.     { "capitalize", FN_CAP,  0},        /* First Letter -> uppercase */
  951.     { "caps",       FN_CAP,  CM_INV},   /* ditto */
  952.     { "character",  FN_CHR,  0},        /* Character from code */
  953.     { "checksum",   FN_CHK,  0},        /* Checksum */
  954.     { "cmdstack",   FN_CMDSTK,0},       /* Command stack */
  955.     { "cmpdates",   FN_CMPDATE,0},      /* Compare dates */
  956.     { "code",       FN_COD,  0},        /* Code from character */
  957. #ifndef NOPUSH
  958.     { "command",    FN_CMD,  0},        /* Output from a command */
  959. #endif /* NOPUSH */
  960.     { "contents",   FN_CON,  0},        /* Definition (contents) of variable */
  961.     { "crc16",      FN_CRC,  0},        /* CRC-16 */
  962. #ifdef OS2
  963.     { "crypt",      FN_CRY, CM_INV},
  964. #endif /* OS2 */
  965.     { "cvtdate",    FN_DTIM, 0},        /* Convert free date/time to std */
  966. #ifdef ZFCDAT
  967.     { "date",       FN_FD,   0},        /* File modification/creation date */
  968. #endif /* ZFCDAT */
  969.     { "day",        FN_DAY,  0},        /* Day of week */
  970.     { "dayofyear",  FN_JDATE,0},        /* Date to Day of Year */
  971.     { "definition", FN_DEF,  0},        /* Return definition of given macro */
  972.     { "delta2secs", FN_DELSEC, 0},      /* Delta time to seconds */
  973.     { "deltatosecs", FN_DELSEC, CM_INV}, /* Delta time to seconds */
  974. #ifndef NODIAL
  975.     { "dialconvert",FN_PNCVT,0},        /* Convert portable phone number */
  976. #endif /* NODIAL */
  977.     { "diffdates",  FN_DIFDATE,0},      /* Difference of two date-times */
  978.     { "dimension",  FN_DIM,  0},        /* Dimension of array */
  979.     { "dir",        FN_DIR,  CM_INV|CM_ABR}, /* Abbreviation for direct.. */
  980.     { "dire",       FN_DIR,  CM_INV|CM_ABR}, /* Abbreviation for direct.. */
  981.     { "direc",      FN_DIR,  CM_INV|CM_ABR}, /* Abbreviation for direct.. */
  982.     { "direct",     FN_DIR,  CM_INV|CM_ABR}, /* Abbreviation for direct.. */
  983.     { "directo",    FN_DIR,  CM_INV|CM_ABR}, /* Abbreviation for direct.. */
  984.     { "director",   FN_DIR,  CM_INV|CM_ABR}, /* Abbreviation for direct.. */
  985.     { "directories",FN_DIR,  0},        /* List of directories */
  986.     { "directory",  FN_DIR,  CM_INV},        /* List of directories */
  987.     { "dirname",    FN_DNAM, 0},        /* Directory part of filename */
  988.     { "dos2unixpath",FN_PC_DU, },       /* DOS to UNIX path */
  989.     { "dostounixpath",FN_PC_DU, CM_INV}, /* DOS to UNIX path */
  990.     { "doy",        FN_JDATE,CM_INV},   /* Date to Day of Year */
  991.     { "doy2date",   FN_DATEJ,0},        /* Day of Year to date */
  992.     { "doytodate",  FN_DATEJ,CM_INV},   /* Day of Year to date */
  993.     { "emailaddress",FN_EMAIL, 0},    /* Email address */
  994. #ifdef FN_ERRMSG
  995.     { "errstring",  FN_ERRMSG,0},       /* Error code to message */
  996. #endif /* FN_ERRMSG */
  997.     { "evaluate",   FN_EVA,  0},        /* Evaluate given arith expression */
  998.     { "execute",    FN_EXE,  0},        /* Execute given macro */
  999.     { "files",      FN_FC,   0},        /* File count */
  1000. #ifdef FNFLOAT
  1001.     { "fpabsolute", FN_FPABS, 0},       /* Floating-point absolute value */
  1002.     { "fpadd",      FN_FPADD, 0},       /* FP add */
  1003.     { "fpcosine",   FN_FPCOS, 0},       /* FP cosine */
  1004.     { "fpdivide",   FN_FPDIV, 0},       /* FP divide */
  1005.     { "fpexp",      FN_FPEXP, 0},       /* FP e to the x */
  1006.     { "fpint",      FN_FPINT, 0},       /* FP to integer */
  1007.     { "fplog10",    FN_FPLOG, 0},       /* FP base-10 logarithm */
  1008.     { "fplogn",     FN_FPLN,  0},       /* FP natural logarithm */
  1009.     { "fpmaximum",  FN_FPMAX, 0},       /* FP maxinum */
  1010.     { "fpminimum",  FN_FPMIN, 0},       /* FP mininum */
  1011.     { "fpmodulus",  FN_FPMOD, 0},       /* FP modulus */
  1012.     { "fpmultiply", FN_FPMUL, 0},       /* FP multiply */
  1013.     { "fpraise",    FN_FPPOW, 0},       /* FP raise to a power */
  1014.     { "fpround",    FN_FPROU, 0},       /* FP round */
  1015.     { "fpsine",     FN_FPSIN, 0},       /* FP sine */
  1016.     { "fpsqrt",     FN_FPSQR, 0},       /* FP square root */
  1017.     { "fpsubtract", FN_FPSUB, 0},       /* FP subtract */
  1018.     { "fptangent",  FN_FPTAN, 0},       /* FP tangent */
  1019. #endif /* FNFLOAT */
  1020.     { "hex2ip",     FN_HEX2IP,0},       /* Hex to IP address */
  1021.     { "hextoip",    FN_HEX2IP,CM_INV},  /* Hex to IP address */
  1022.     { "hex2n",      FN_HEX2N, CM_INV},  /* Hex to decimal number */
  1023.     { "hexify",     FN_HEX,   0},       /* Hexify (string) */
  1024.     { "index",      FN_IND,   0},       /* Index (string search) */
  1025.     { "ip2hex",     FN_IP2HEX,0},       /* IP address to hex */
  1026.     { "iptohex",    FN_IP2HEX,CM_INV},  /* IP address to hex */
  1027.     { "ipaddress",  FN_IPA,   0},       /* Find and return IP address */
  1028.     { "jdate",      FN_JDATE, CM_INV},  /* Date to Day of Year */
  1029.     { "join",       FN_JOIN,  0},       /* Join array elements */
  1030.     { "keywordvalue",  FN_KWVAL, 0},    /* Keyword=Value */
  1031. #ifdef CK_KERBEROS
  1032.     { "krbflags",      FN_KRB_FG, 0},   /* Kerberos functions */
  1033.     { "krbisvalid",    FN_KRB_IV, 0},
  1034.     { "krbnextticket", FN_KRB_NX, 0},
  1035.     { "krbtickets",    FN_KRB_TK, 0},
  1036.     { "krbtimeleft",   FN_KRB_TT, 0},
  1037. #endif /* CK_KERBEROS */
  1038.     { "left",       FN_LEF,  0},        /* Leftmost n characters of string */
  1039.     { "length",     FN_LEN,  0},        /* Return length of argument */
  1040.     { "literal",    FN_LIT,  0},        /* Return argument literally */
  1041. #ifdef NT
  1042.     { "longpathname",FN_LNAME,0},    /* GetLongPathName() */
  1043. #else
  1044.     { "longpathname",FN_FFN,CM_INV},
  1045. #endif /* NT */
  1046.     { "lop",        FN_STL,  0},        /* Lop */
  1047.     { "lopx",       FN_LOPX, 0},        /* Lopx */
  1048.     { "lower",      FN_LOW,  0},        /* Return lowercased argument */
  1049.     { "lpad",       FN_LPA,  0},        /* Return left-padded argument */
  1050.     { "ltrim",      FN_LTR,  0},        /* Left-Trim */
  1051.     { "maximum",    FN_MAX,  0},        /* Return maximum of two arguments */
  1052.     { "minimum",    FN_MIN,  0},        /* Return minimum of two arguments */
  1053.     { "mjd",        FN_MJD,  0},        /* Date to Modified Julian Date */
  1054.     { "mjd2date",   FN_MJD2, 0},        /* MJD to Date */
  1055.     { "mjdtodate",  FN_MJD2, CM_INV},   /* MJD to Date */
  1056.     { "modulus",    FN_MOD,  0},        /* Return modulus of two arguments */
  1057. #ifdef COMMENT
  1058.     { "msleep",     FN_MSLEEP,0},       /* Sleep for n milliseconds */
  1059. #endif /* COMMENT */
  1060.     { "n2hex",      FN_2HEX, CM_INV},   /* Number to hex */
  1061.     { "n2octal",    FN_2OCT, CM_INV},   /* Number to octal */
  1062.     { "n2time",     FN_N2TIM,0},        /* Number to hh:mm:ss */
  1063. #ifdef TCPSOCKET
  1064.     { "name2addr",  FN_HSTNAM,CM_INV},  /* Hostname to IP Address */
  1065. #endif /* TCPSOCKET */
  1066.     { "nday",       FN_NDAY, 0},        /* Numeric day of week */
  1067.     { "nextfile",   FN_FIL,  0},        /* Next file in list */
  1068.     { "ntime",      FN_NTIM, 0},        /* Time to seconds since midnight */
  1069.     { "ntohex",     FN_2HEX, CM_INV},   /* Number to hex */
  1070.     { "ntooctal",   FN_2OCT, CM_INV},   /* Number to octal */
  1071.     { "ntotime",    FN_N2TIM,CM_INV},   /* Number to hh:mm:ss */
  1072.     { "oct2n",      FN_OCT2N,CM_INV},   /* Octal to decimal number */
  1073.     { "octton",     FN_OCT2N,CM_INV},   /* Octal to decimal number */
  1074.     { "pathname",   FN_FFN,  0},        /* Full file name */
  1075.     { "pattern",    FN_PATTERN, 0},     /* Pattern (for INPUT) */
  1076. #ifdef CK_PERMS
  1077.     { "permissions",FN_PERM, 0},        /* Permissions of file */
  1078. #else
  1079.     { "permissions",FN_PERM, CM_INV},   /* Permissions of file */
  1080. #endif /* CK_PERMS */
  1081.     { "radix",      FN_RADIX,0},        /* Radix conversion */
  1082. #ifndef NORANDOM
  1083.     { "random",     FN_RAND, 0},        /* Random number */
  1084. #endif /* NORANDOM */
  1085. #ifndef NOPUSH
  1086.     { "rawcommand", FN_RAW,  0},        /* Output from a command (raw) */
  1087. #endif /* NOPUSH */
  1088. #ifdef RECURSIVE
  1089.     { "rdirectories", FN_RDIR, 0},      /* Recursive directory list */
  1090.     { "rfiles",       FN_RFIL, 0},      /* Recursive file list */
  1091. #endif /* RECURSIVE */
  1092.     { "rep",        FN_REP, CM_INV|CM_ABR},
  1093.     { "repeat",     FN_REP,  0},        /* Repeat argument given # of times */
  1094.     { "replace",    FN_RPL,  0},        /* Replace characters in string */
  1095.     { "reverse",    FN_REV,  0},        /* Reverse the argument string */
  1096.     { "right",      FN_RIG,  0},        /* Rightmost n characters of string */
  1097.     { "rindex",     FN_RIX,  0},        /* Right index */
  1098.     { "rpad",       FN_RPA,  0},        /* Right-pad the argument */
  1099.     { "rsearch",    FN_RSEARCH, 0},     /* R-L Search for pattern in string */
  1100. #ifdef OS2
  1101.     { "scrncurx",   FN_SCRN_CX,  0},    /* Screen Cursor X Pos */
  1102.     { "scrncury",   FN_SCRN_CY,  0},    /* Screen Cursor Y Pos */
  1103.     { "scrnstr",    FN_SCRN_STR, 0},    /* Screen String */
  1104. #endif /* OS2 */
  1105.     { "search",     FN_SEARCH, 0},      /* L-R Search for pattern in string */
  1106. #ifndef NOSEXP
  1107.     { "sexpression",FN_SEXP, 0},        /* S-Expression */
  1108. #endif /* NOSEXP */
  1109. #ifdef NT
  1110.     { "shortpathname",FN_SNAME,0},    /* GetShortPathName() */
  1111. #else
  1112.     { "shortpathname",FN_FFN,CM_INV},
  1113. #endif /* NT */
  1114.     { "size",       FN_FS,   0},        /* File size */
  1115. #ifdef COMMENT
  1116.     { "sleep",      FN_SLEEP,0},        /* Sleep for n seconds */
  1117. #endif /* COMMENT */
  1118.     { "span",       FN_SPN,  0},        /* Span - like Snobol */
  1119.     { "split",      FN_SPLIT,0},        /* Split string into words */
  1120.     { "stripb",     FN_STB,  0},        /* Strip enclosing braces/brackets */
  1121.     { "stripn",     FN_STN,  0},        /* Strip n chars */
  1122.     { "stripx",     FN_STX,  0},        /* Strip suffix */
  1123.     { "su",         FN_SUB,  CM_INV|CM_ABR},
  1124.     { "sub",        FN_SUB,  CM_INV|CM_ABR},
  1125.     { "subs",       FN_SUB,  CM_INV|CM_ABR},
  1126.     { "subst",      FN_SUB,  CM_INV|CM_ABR},
  1127.     { "substitute", FN_SUBST,0},        /* Substitute chars */
  1128.     { "substring",  FN_SUB,  0},        /* Extract substring from argument */
  1129.     { "tablelook",  FN_TLOOK,0},        /* Table lookup */
  1130.     { "time",       FN_TIME, 0},        /* Free-format time to hh:mm:ss */
  1131.     { "tod2secs",   FN_NTIM, CM_INV},   /* Time-of-day-to-secs-since-midnite */
  1132.     { "todtosecs",  FN_NTIM, CM_INV},   /* Time-of-day-to-secs-since-midnite */
  1133.     { "trim",       FN_TRM,  0},        /* Trim */
  1134.     { "unhexify",   FN_UNH,  0},        /* Unhexify */
  1135.     { "unix2dospath",FN_PC_UD, 0},      /* UNIX to DOS path */
  1136.     { "unixtodospath",FN_PC_UD, CM_INV}, /* UNIX to DOS path */
  1137.     { "untabify",   FN_UNTAB,0},        /* Untabify */
  1138.     { "upper",      FN_UPP,  0},        /* Return uppercased argument */
  1139.     { "utcdate",    FN_TOGMT,0},        /* Date-time to UTC (GMT) */
  1140.     { "verify",     FN_VER,  0},        /* Verify */
  1141.     { "word",       FN_WORD, 0},        /* Extract a word */
  1142.     { "", 0, 0}
  1143. };
  1144. int nfuncs = (sizeof(fnctab) / sizeof(struct keytab)) - 1;
  1145. #endif /* NOSPL */
  1146.  
  1147. #ifndef NOSPL                           /* Buffer for expansion of */
  1148. #ifdef BIGBUFOK                         /* built-in variables. */
  1149. #define VVBUFL 1024
  1150. #else
  1151. #define VVBUFL 256
  1152. #endif /* BIGBUFOK */
  1153. char vvbuf[VVBUFL+1];
  1154. #endif /* NOSPL */
  1155.  
  1156. struct keytab disptb[] = {              /* Log file disposition */
  1157.     { "append",    1,  0},
  1158.     { "new",       0,  0}
  1159. };
  1160.  
  1161. #ifdef CKFLOAT
  1162.  
  1163. /* I N I T F L O A T  --  Deduce floating-point precision by inspection */
  1164.  
  1165. int fp_rounding = 0;                /* Nonzero if printf("%f") rounds */
  1166. int fp_digits = 0;                  /* Digits of floating point precision */
  1167.  
  1168. #ifdef COMMENT
  1169. /* For looking at internal floating-point representations */
  1170. static char fp_xbuf[128];
  1171. static char *
  1172. tohex(s, n) CHAR * s; int n; {
  1173.     int x;
  1174.     char * p = fp_xbuf;
  1175.     while (n-- > 0) {
  1176.         x = (*s >> 4) & 0x0f;
  1177.         *p++ = hexdigits[x];
  1178.         x = *s++ & 0x0f;
  1179.         *p++ = hexdigits[x];
  1180.     }
  1181.     *p = NUL;
  1182.     return((char *)fp_xbuf);
  1183. }
  1184. #endif /* COMMENT */
  1185.  
  1186. char math_pi[] = "3.1415926535897932384626433832795";
  1187. char math_e[] =  "2.7182818284590452353602874713527";
  1188.  
  1189. VOID
  1190. initfloat() {
  1191.     char * buf = NULL;
  1192.     int i, x, y;
  1193. /*
  1194.   We malloc a big temporary buffer for sprintf() to minimize likelihood of
  1195.   (and damage from) sprintf buffer overflows.  In any case, the only way this
  1196.   could happen would be if sprintf() itself had bugs, since the format
  1197.   descriptor says to cut it off at 250 decimal places.
  1198. */
  1199.     if ((buf = (char *)malloc(4096))) {
  1200.         sprintf(buf,"%0.250f",(10.0 / 3.0));
  1201.         for (i = 2; i < 250 && buf[i] == '3'; i++) ;
  1202.         x = i - 1;
  1203.         debug(F111,"initfloat 10.0/3.0",buf,x);
  1204.         sprintf(buf,"%0.250f",(4.0 / 9.0));
  1205.         for (i = 2; i < 250 && buf[i] == '4'; i++) ;
  1206.         y = i - 1;
  1207.         debug(F111,"initfloat 4.0/9.0",buf,y);
  1208.         fp_digits = (x < y) ? x : y;
  1209.         if (fp_digits < sizeof(math_pi) - 1) {
  1210.             math_pi[fp_digits+1] = NUL;
  1211.             math_e[fp_digits+1] = NUL;
  1212.         }
  1213.         sprintf(buf,"%0.6f",(7.0 / 9.0));
  1214.         if (buf[7] == '8') fp_rounding = 1;
  1215.         debug(F111,"initfloat 7.0/9.0",buf,fp_rounding);
  1216.         debug(F101,"initfloat precision","",fp_digits);
  1217.         free(buf);
  1218.     }
  1219. }
  1220. #endif /* CKFLOAT */
  1221.  
  1222. /*
  1223.   P R E S C A N -- A quick look through the command-line options for
  1224.   items that must be handled before the initialization file is executed.
  1225. */
  1226. #ifdef NT
  1227. extern int StartedFromDialer;
  1228. #endif /* NT */
  1229. #ifdef OS2
  1230. extern int k95stdio;
  1231. unsigned long startflags = 0L;
  1232. #endif /* OS2 */
  1233.  
  1234. static char *
  1235. findinpath(arg) char * arg; {
  1236. #ifdef OS2
  1237.     char * scriptenv, * keymapenv;
  1238.     int len;
  1239. #endif /* OS2 */
  1240. #ifdef DCMDBUF
  1241.     extern char * cmdbuf;
  1242. #else
  1243.     extern char cmdbuf[];
  1244. #endif /* DCMDBUF */
  1245.     char takepath[4096];
  1246.     char * s;
  1247.     int x, z;
  1248.  
  1249.     /* Set up search path... */
  1250. #ifdef OS2
  1251.     char * appdata0 = NULL, *appdata1 = NULL;
  1252. #ifdef NT
  1253.     scriptenv = getenv("K95SCRIPTS");
  1254.     keymapenv = getenv("K95KEYMAPS");
  1255.     makestr(&appdata0,(char *)GetAppData(0));
  1256.     makestr(&appdata1,(char *)GetAppData(1));
  1257. #else /* NT */
  1258.     scriptenv = getenv("K2SCRIPTS");
  1259.     keymapenv = getenv("K2KEYMAPS");
  1260. #endif /* NT */
  1261.     if (!scriptenv)
  1262.       scriptenv = getenv("CK_SCRIPTS");
  1263.     if (!scriptenv)
  1264.       scriptenv = "";
  1265.     if (!keymapenv)
  1266.       keymapenv = getenv("CK_KEYMAPS");
  1267.     if (!keymapenv)
  1268.       keymapenv = "";
  1269.  
  1270.     debug(F110,"startupdir",startupdir,0);
  1271.     debug(F110,"common appdata directory",appdata1,0);
  1272.     debug(F110,"appdata directory",appdata0,0);
  1273.     debug(F110,"inidir",inidir,0);
  1274.     debug(F110,"home",zhome(),0);
  1275.     debug(F110,"exedir",exedir,0);
  1276.  
  1277.     len = strlen(scriptenv) + strlen(keymapenv) + 3*strlen(startupdir)
  1278.         + 3*strlen(inidir) + 3*strlen(zhome()) + 3*strlen(exedir)
  1279.         + (appdata0 ? 3*strlen(appdata0) : 0) 
  1280.         + (appdata1 ? 3*strlen(appdata1) : 0)
  1281.         + 6*strlen("SCRIPTS/") + 6*strlen("KEYMAPS/") + 16;
  1282.  
  1283.     if (len >= 4096) {                  /* SAFE (length is checked) */
  1284.         takepath[0] = '\0';
  1285.         debug(F111,"findinpath error - path length too long","len",len);
  1286.     } else
  1287.       sprintf(takepath,
  1288.               /* semicolon-separated path list */
  1289.     "%s%s%s%s%s;%s%s;%s%s;%s%s%s%s%s%s%s%s%s%s%s%s%s;%s%s;%s%s;%s;%s%s;%s%s",
  1290.               scriptenv,
  1291.               (scriptenv[0] && scriptenv[strlen(scriptenv)-1]==';')?"":";",
  1292.               keymapenv,
  1293.               (keymapenv[0] && keymapenv[strlen(keymapenv)-1]==';')?"":";",
  1294.               startupdir,
  1295.               startupdir, "SCRIPTS/",
  1296.               startupdir, "KEYMAPS/",
  1297.               appdata1 ? appdata1 : "", 
  1298.               appdata1 ? "Kermit 95;" : "",
  1299.               appdata1 ? appdata1 : "",
  1300.               appdata1 ? "Kermit 95/SCRIPTS/;" : "",
  1301.               appdata1 ? appdata1 : "",
  1302.               appdata1 ? "Kermit 95/KEYMAPS/;" : "",
  1303.               appdata0 ? appdata0 : "",
  1304.               appdata0 ? "Kermit 95;" : "",
  1305.               appdata0 ? appdata0 : "",
  1306.               appdata0 ? "Kermit 95/SCRIPTS/;" : "",
  1307.               appdata0 ? appdata0 : "",
  1308.               appdata0 ? "Kermit 95/KEYMAPS/;" : "",
  1309.               inidir,
  1310.               inidir, "SCRIPTS/",
  1311.               inidir, "KEYMAPS/",
  1312.               zhome(),
  1313.               zhome(), "SCRIPTS/",
  1314.               zhome(), "KEYMAPS/",
  1315.               exedir,
  1316.               exedir, "SCRIPTS/",
  1317.               exedir, "KEYMAPS/"
  1318.               );
  1319.     debug(F110,"findinpath takepath",takepath,0);
  1320. #ifdef NT
  1321.     makestr(&appdata0,NULL);
  1322.     makestr(&appdata1,NULL);
  1323. #endif /* NT */
  1324. #else /* not OS2 */
  1325. #ifndef NOSPL
  1326.     z = 1024;                           /* Look in home directory */
  1327.     s = takepath;
  1328.     zzstring("\\v(home)",&s,&z);
  1329. #else
  1330.     takepath[0] = '\0';
  1331. #endif /* NOSPL */
  1332. #endif /* OS2 */
  1333. /*
  1334.   All the logic for searching the take path is in the command parser.
  1335.   So even though we aren't parsing commands, we initialize and call the
  1336.   parser from here, with the purported filename stuffed into the command
  1337.   buffer, followed by some carriage returns to make the parser return.
  1338.   If the file is not found, or otherwise not accessible, the parser prints
  1339.   an appropriate message, and then we just exit.
  1340. */
  1341.     cmdini();                           /* Allocate command buffers etc */
  1342.     cmini(0);                           /* Initialize them */
  1343.     /* Stuff filename into command buf with braces in case of spaces */
  1344.     ckmakmsg(cmdbuf,CMDBL,"{",arg,"}",NULL);
  1345.     debug(F110,"findinpath cmdbuf",cmdbuf,0);
  1346.     ckstrncat(cmdbuf,"\r\r",CMDBL);     /* And some carriage returns */
  1347.     if (cmifip("","",&s,&x,0,takepath,xxstring) < 0)
  1348.       return(NULL);
  1349.     cmres();
  1350.     return(s);
  1351. }
  1352.  
  1353. static int tr_int;                      /* Flag if TRANSMIT interrupted */
  1354.  
  1355. #ifndef MAC
  1356. SIGTYP
  1357. #ifdef CK_ANSIC
  1358. trtrap(int foo)                         /* TRANSMIT interrupt trap */
  1359. #else
  1360. trtrap(foo) int foo;                    /* TRANSMIT interrupt trap */
  1361. #endif /* CK_ANSIC */
  1362. /* trtrap */ {
  1363. #ifdef __EMX__
  1364.     signal(SIGINT, SIG_ACK);
  1365. #endif
  1366.     tr_int = 1;                         /* (Need arg for ANSI C) */
  1367.     SIGRETURN;
  1368. }
  1369. #endif /* MAC */
  1370. #endif /* NOICP */
  1371.  
  1372. #ifdef UNIX
  1373. VOID
  1374. getexedir() {
  1375.     extern char * xarg0;
  1376.     long xx;
  1377.   /*
  1378.     Unix provides no standard service for this.  We look in argv[0], and if
  1379.     we're lucky there's a full pathname.  If not we do a PATH search.
  1380.   */
  1381.     if (ckstrchr(xarg0,'/')) {          /* Global copy of argv[0] */
  1382.         int i, k;
  1383.         char * p = NULL;
  1384.         if ((k = ckstrncpy(tmpbuf,xarg0,TMPBUFSIZ-2)) > 0) {
  1385.             p = tmpbuf;
  1386.             /* Convert to fully qualified pathname */
  1387.             if (tmpbuf[0]) if (tmpbuf[0] != '/') {
  1388.                 line[0] = NUL;
  1389.                 zfnqfp(tmpbuf,LINBUFSIZ-2,(char *)line);
  1390.                 if (line[0])
  1391.                   p = line;
  1392.             }
  1393.             xx = zchki(p);
  1394.             if (xx > -1) {        /* Is the result an existing file? */
  1395.                 k = strlen(p);
  1396.                 for (i = k-1; i > 0; i--) { /* Yes, strip name part */
  1397.                     if (p[i] == '/') {
  1398.                         if (i < k-1)
  1399.                           p[i+1] = NUL;
  1400.                         break;
  1401.                     }
  1402.                 }
  1403.             }
  1404.         makestr(&exedir,p);        /* Save the result */
  1405.         }
  1406.     }
  1407.     if (!exedir && xarg0) {             /* Not found? */
  1408.         char * p;
  1409.         p = getenv("PATH");             /* Search the PATH */
  1410.         if (p) {                        /* If there is one... */
  1411.             char * q, * PATH = NULL;
  1412.             int k;
  1413.             makestr(&PATH,p);           /* Pokeable copy of PATH string */
  1414.             if (PATH) {                 /* If malloc succeeded... */
  1415.                 p = PATH;
  1416.                 while (p && *p) {        /* Loop through segments */
  1417.                     q = ckstrchr(p,':'); /* End of this segment */
  1418.                     if (q == p) {       /* Null PATH segment */
  1419.                         p++;            /* Skip over colon */
  1420.                         continue;
  1421.                     }
  1422.                     if (q)              /* If not at end of PATH string */
  1423.                       *q++ = NUL;       /* zero out the colon */
  1424.                     if ((k = ckstrncpy(tmpbuf,p,TMPBUFSIZ)) > 0) {
  1425.                         if (tmpbuf[k-1] != '/') { /* Copy this PATH segment */
  1426.                             tmpbuf[k++] = '/';    /* Append '/' if needed */
  1427.                             tmpbuf[k] = NUL;
  1428.                         }
  1429.                         /* Append the argv[0] value */
  1430.                         if (ckstrncpy(&tmpbuf[k],xarg0,TMPBUFSIZ) > 0) {
  1431.                             if (zchki(tmpbuf) > -1) { /* File exists? */
  1432.                                 tmpbuf[k] = NUL;      /* Yes, we're done */
  1433.                                 zfnqfp(tmpbuf,LINBUFSIZ,(char *)line);
  1434.                                 makestr(&exedir,line);
  1435.                                 break;
  1436.                             }
  1437.                         } else break;
  1438.                     } else break;
  1439.                     p = q;              /* Not found, go to next segment  */
  1440.                 } /* while */
  1441.                 free(PATH);             /* Free PATH copy */
  1442.             }
  1443.         }
  1444.         if (!exedir) {                  /* Still nothing? */
  1445.             if (zchki(xarg0) > -1) {    /* Maybe it's in the current dir */
  1446.                 zfnqfp(zgtdir(),LINBUFSIZ,(char *)line);
  1447.                 makestr(&exedir,line);
  1448.             }
  1449.         }
  1450.     }
  1451.     if (!exedir) {                      /* Still nothing? */
  1452.         makestr(&exedir,"/");           /* Fake it with with root. */
  1453.     }
  1454. }
  1455. #endif /* UNIX */
  1456.  
  1457. int arg_x = 0;
  1458. static int x_prescan = 0;
  1459.  
  1460. /*
  1461.   The argument y once meant something but I can't imagine what so now
  1462.   it's ignored.  (Prior to 22 Aug 98, prescan() was called twice by main(),
  1463.   and the arg differentiated the two calls.  But this caused all sorts of
  1464.   problems & confusion, so I commented out the second call.  This issue might
  1465.   need to be revisited.)
  1466. */
  1467. VOID
  1468. prescan(dummy) int dummy; {             /* Arg is ignored. */
  1469.     extern int howcalled;
  1470.     int yargc; char **yargv;
  1471.     char x;
  1472.     char *yp, *yy;
  1473. #ifdef DEBUG
  1474.     int debcount = 0;
  1475. #endif /* DEBUG */
  1476.     int z;
  1477.  
  1478.     if (x_prescan)                      /* Only run once */
  1479.       return;
  1480.     x_prescan = 1;
  1481.  
  1482.     yargc = xargc;                      /* Make copy of arg vector */
  1483.     yargv = xargv;
  1484.  
  1485. #ifndef NOICP
  1486. #ifdef DCMDBUF
  1487.     if (!kermrc)
  1488.       if (!(kermrc = (char *) malloc(KERMRCL+1)))
  1489.         fatal("prescan: no memory for kermrc");
  1490. #endif /* DCMDBUF */
  1491.     ckstrncpy(kermrc,KERMRC,KERMRCL);   /* Default init file name */
  1492. #endif /* NOICP */
  1493.  
  1494. #ifdef OS2
  1495.     yp = getenv("K95STARTFLAGS");
  1496.     if (yp) {
  1497.         startflags = atoi(yp);
  1498.     }
  1499. #endif /* OS2 */
  1500.  
  1501. #ifdef IKSD
  1502.     if (howcalled == I_AM_IKSD)         /* Internet Kermit Service daemon */
  1503.       inserver = 1;                     /* (See inserver section of ckcmai) */
  1504. #endif /* IKSD */
  1505.  
  1506. /* Command line options for Kermit */
  1507.  
  1508. #ifndef NOCMDL
  1509.     if (yargc > 1
  1510.         && *yargv[1] != '-'
  1511.         && (yargv[1][0] != '=')
  1512. #ifdef KERBANG
  1513.         && (yargv[1][0] != '+')
  1514. #endif /* KERBANG */
  1515. #ifdef IKSD
  1516.         && (howcalled != I_AM_IKSD)
  1517. #endif /* IKSD */
  1518.         ) {                             /* Filename as 1st argument */
  1519. #ifndef NOICP
  1520.         char *s;
  1521. #endif /* NOICP */
  1522. #ifndef NOURL
  1523.         extern int haveurl;
  1524.         extern struct urldata g_url;
  1525.         if (urlparse(yargv[1],&g_url)) {
  1526.             if (!ckstrcmp(g_url.svc,"ftp",-1,0) ||
  1527.                 !ckstrcmp(g_url.svc,"ftps",-1,0)) {
  1528.                 haveurl = 1;
  1529.                 howcalled = I_AM_FTP;
  1530.             } else if (!ckstrcmp(g_url.svc,"telnet",-1,0) ||
  1531.                        !ckstrcmp(g_url.svc,"telnets",-1,0)) {
  1532.                 haveurl = 1;
  1533.                 howcalled = I_AM_TELNET;
  1534.             } else if (!ckstrcmp(g_url.svc,"ssh",-1,0)) {
  1535.                 haveurl = 1;
  1536.                 howcalled = I_AM_SSH;
  1537.             } else if (!ckstrcmp(g_url.svc,"iksd",-1,0) ||
  1538.                        !ckstrcmp(g_url.svc,"kermit",-1,0)) {
  1539.                 haveurl = 1;
  1540.                 howcalled = I_AM_KERMIT;
  1541.             } else if (!ckstrcmp(g_url.svc,"http",-1,0) ||
  1542.                        !ckstrcmp(g_url.svc,"https",-1,0)) {
  1543.                 haveurl = 1;
  1544.                 howcalled = I_AM_HTTP;
  1545.             }
  1546.             if (haveurl) {
  1547.                 while (--yargc > 0) {   /* Go through command-line args */
  1548.                     yargv++;            /* looking for -Y and -d */
  1549.                     yp = *yargv+1;
  1550.                     if (**yargv == '-') {
  1551.                         x = *(*yargv+1);
  1552.                         while (x) {
  1553.                             switch (x) {
  1554. #ifndef NOICP
  1555.                   case '+':
  1556.                   case '-':
  1557.                                 if (doxarg(yargv,1) < 0) {
  1558.                                     fatal("Extended argument error");
  1559.                                 }
  1560.                                 yp = "";
  1561.                                 break;
  1562. #endif /* NOICP */
  1563.                               case 'Y':
  1564.                                 noinit++;
  1565.                                 break;
  1566.  
  1567.                               case 'q':
  1568.                                 quiet = 1;
  1569.                                 break;
  1570.  
  1571.                               case 'h':
  1572.                                   noinit = 1;
  1573. #ifdef OS2
  1574.                                   startflags |= 2;    /* No network DLLs */
  1575.                                   startflags |= 4;    /* No TAPI DLLs */
  1576.                                   startflags |= 8;    /* No Security DLLs */
  1577.                                   startflags |= 16;   /* No Zmodem DLLs */
  1578.                                   startflags |= 32;   /* Stdin */
  1579.                                   startflags |= 64;   /* Stdout */
  1580. #endif /* OS2 */
  1581.                                   break;
  1582.                               case 'd': /* = SET DEBUG ON */
  1583. #ifdef DEBUG
  1584.                                 if (debcount++ > 0)
  1585.                                   debtim = 1;
  1586.                                 if (!deblog)
  1587.                                   deblog = debopn("debug.log",0);
  1588. #endif /* DEBUG */
  1589.                                 break;
  1590. #ifdef OS2
  1591.                               case 'W':
  1592.                                 if (*(yp+1))
  1593.                                   fatal("invalid argument bundling after -W");
  1594.                                 yargv++, yargc--;
  1595.                                 if (yargc < 1)
  1596.                                   fatal("Window handle missing");
  1597.                                 hwndDialer = (HWND) atol(*yargv);
  1598.                                 StartedFromDialer = 1;
  1599.                                 yargv++, yargc--;
  1600.                                 KermitDialerID = atol(*yargv) ;
  1601.                                 break;
  1602.                               case '#': /* K95 initialization options */
  1603.                                 if (*(yp+1)) {
  1604.                                     fatal("invalid argument bundling");
  1605.                                 }
  1606.                                 yargv++, yargc--;
  1607.                                 if (yargc < 1)
  1608.                                   fatal("-# argument missing");
  1609.                                 startflags |= atol(*yargv);
  1610.                                 break;
  1611. #endif /* OS2 */
  1612.                             }
  1613.                             if (!yp)
  1614.                               break;
  1615.                             x = *++yp;
  1616.                         }
  1617.                     }
  1618.                 }
  1619.                 return;
  1620.             }
  1621.         }
  1622.         /* after this point non-Kermit personalities must return */
  1623.         switch (howcalled) {
  1624.       case I_AM_KERMIT:
  1625.       case I_AM_IKSD:
  1626.       case I_AM_SSHSUB:
  1627.             break;
  1628.       default:
  1629.             return;
  1630.         }
  1631. #endif /* NOURL */
  1632.  
  1633. #ifndef NOICP
  1634.         /* If it is not a URL that we recognize, try to treat it as a file */
  1635.  
  1636.         if (!isabsolute(yargv[1]))      /* If not absolute */
  1637.           s = findinpath(yargv[1]);     /* Look in PATH */
  1638.         else
  1639.           s = yargv[1];
  1640.         if (!s)
  1641.           doexit(BAD_EXIT,xitsta);
  1642.         zfnqfp(s,CKMAXPATH,cmdfil);     /* In case of CD in file */
  1643.         yargc -= 1;                     /* Skip past the filename */
  1644.         yargv += 1;                     /* Otherwise we'll get an error */
  1645. #endif /* NOICP */
  1646.     }
  1647.  
  1648. #ifndef NOCMDL
  1649. #ifdef NEWFTP
  1650.     if (howcalled == I_AM_FTP) {        /* Kermit's FTP client personality */
  1651.         while (--yargc > 0) {           /* Go through command-line args */
  1652.             yargv++;                    /* looking for -Y and -d */
  1653.             yp = *yargv+1;
  1654.             if (**yargv == '-') {
  1655.                 x = *(*yargv+1);
  1656.                 while (x) {
  1657.                     switch (x) {
  1658. #ifndef NOICP
  1659.               case '+':
  1660.               case '-':
  1661.                         if (doxarg(yargv,1) < 0) {
  1662.                             fatal("Extended argument error");
  1663.                         }
  1664.                         yp = "";
  1665.                         break;
  1666. #endif /* NOICP */
  1667.                       case 'Y':
  1668.                         noinit++;
  1669.                         break;
  1670.  
  1671.                       case 'q':
  1672.                           quiet = 1;
  1673.                           break;
  1674.  
  1675.                       case 'h':
  1676.                         noinit = 1;
  1677. #ifdef OS2
  1678.                         startflags |= 2;    /* No network DLLs */
  1679.                         startflags |= 4;    /* No TAPI DLLs */
  1680.                         startflags |= 8;    /* No Security DLLs */
  1681.                         startflags |= 16;   /* No Zmodem DLLs */
  1682.                         startflags |= 32;   /* Stdin */
  1683.                         startflags |= 64;   /* Stdout */
  1684. #endif /* OS2 */
  1685.                         break;
  1686.                       case 'd':             /* = SET DEBUG ON */
  1687. #ifdef DEBUG
  1688.                         if (debcount++ > 0)
  1689.                           debtim = 1;
  1690.                         if (!deblog)
  1691.                           deblog = debopn("debug.log",0);
  1692. #endif /* DEBUG */
  1693.                         break;
  1694. #ifdef OS2
  1695.                       case 'W':
  1696.                         if (*(yp+1))
  1697.                           fatal("invalid argument bundling after -W");
  1698.                         yargv++, yargc--;
  1699.                         if (yargc < 1)
  1700.                           fatal("Window handle missing");
  1701.                         hwndDialer = (HWND) atol(*yargv);
  1702.                         StartedFromDialer = 1;
  1703.                         yargv++, yargc--;
  1704.                         KermitDialerID = atol(*yargv) ;
  1705.                         break;
  1706.                       case '#':         /* K95 initialization options */
  1707.                         if (*(yp+1)) {
  1708.                             fatal("invalid argument bundling");
  1709.                         }
  1710.                         yargv++, yargc--;
  1711.                         if (yargc < 1)
  1712.                           fatal("-# argument missing");
  1713.                         startflags |= atol(*yargv);
  1714.                         break;
  1715. #endif /* OS2 */
  1716.                     }
  1717.                     if (!yp)
  1718.                       break;
  1719.                     x = *++yp;
  1720.                 }
  1721.             }
  1722.         }
  1723.         return;
  1724.     }
  1725. #endif /* NEWFTP */
  1726. #endif /* NOCMDL */
  1727.  
  1728.     while (--yargc > 0) {               /* Go through command-line args */
  1729.         yargv++;
  1730.         yp = *yargv+1;                  /* Pointer for bundled args */
  1731.         if (**yargv == '=')             /* Same rules as cmdlin()... */
  1732.           return;
  1733.         debug(F110,"prescan *yargv",*yargv,0);
  1734.  
  1735. #ifndef NOICP
  1736. #ifdef KERBANG
  1737.         yy = *yargv;
  1738.         if (!strcmp(yy,"+") || (*yy == '+' && *(yy+1) < (char)33)) {
  1739.             char * s;
  1740.             yargv++;
  1741.             noinit = 1;
  1742.             if (!*yargv)
  1743.               return;
  1744.             cfilef = 1;
  1745.             s = findinpath(*yargv);
  1746.             if (s) {
  1747.                 zfnqfp(s,CKMAXPATH,cmdfil);
  1748.                 return;
  1749.             } else
  1750.               doexit(BAD_EXIT,xitsta);
  1751.         }
  1752. #endif /* KERBANG */
  1753. #endif /* NOICP */
  1754.         if (!strcmp(*yargv,"--"))       /* getopt() conformance */
  1755.           return;
  1756. #ifdef VMS
  1757.         else if (**yargv == '/')
  1758.           continue;
  1759. #endif /* VMS */
  1760.         else if (**yargv == '-') {      /* Got an option (begins with dash) */
  1761.             x = *(*yargv+1);            /* Get option letter */
  1762.             while (x) {                 /* Allow for bundled options */
  1763.                 debug(F000,"prescan arg","",x);
  1764.                 switch (x) {
  1765. #ifndef NOICP
  1766.                   case '+':
  1767.                   case '-':
  1768.                     if (doxarg(yargv,1) < 0) {
  1769.                         fatal("Extended argument error");
  1770.                     }
  1771. #ifndef COMMENT                /* Jeff 28 Apr 2003 */
  1772.                     yp = NULL;        /* (not "") */
  1773. #else
  1774.                     yargv++, yargc--;
  1775.                     yp = *yargv;
  1776. #endif /* COMMENT */
  1777.                     break;
  1778. #endif /* NOICP */
  1779.  
  1780.                   case '7':             /* Undocumented... */
  1781.                     sstelnet = 1;       /* (because it doesn't work) */
  1782.                     break;
  1783. #ifdef IKSD
  1784.                   case 'A': {
  1785.                       char * p;
  1786.                       inserver = 1;     /* Flag that we are doing this */
  1787.                       srvcdmsg = 2;     /* Preset this */
  1788.                       /* See inserver section of ckcmai.c for more settings */
  1789. #ifdef OS2
  1790.                       if (*(yp+1)) {
  1791.                           fatal("invalid argument bundling after -A");
  1792.                       }
  1793. #ifdef NT
  1794.                       /* Support for Pragma Systems Telnet/Terminal Servers */
  1795.                       p = getenv("PRAGMASYS_INETD_SOCK");
  1796.                       if (p && atoi(p) != 0) {
  1797.                           ttname[0] = '$';
  1798.                           ckstrncpy(&ttname[1],p,TTNAMLEN-1);
  1799.                           break;
  1800.                       }
  1801. #endif /* NT */
  1802.                       yargv++, yargc--;
  1803.                       if (yargc < 1 || **yargv == '-') {
  1804.                           fatal("-A argument missing");
  1805.                       } else {
  1806.                           ttname[0] = '$';
  1807.                           ckstrncpy(&ttname[1],*yargv,TTNAMLEN-1);
  1808.                       }
  1809. #endif /* OS2 */
  1810.                       break;
  1811.                   }
  1812. #endif /* IKSD */
  1813.  
  1814. #ifdef OS2
  1815.                   case 'W':
  1816.                     if (*(yp+1))
  1817.                       fatal("invalid argument bundling after -W");
  1818.                     yargv++, yargc--;
  1819.                     if (yargc < 1)
  1820.                       fatal("Window handle missing");
  1821. #ifdef COMMENT
  1822.                     if (dummy) {
  1823.                         yargv++, yargc--;
  1824.                         break;
  1825.                     } else {
  1826. #endif /* COMMENT */
  1827.                         hwndDialer = (HWND) atol(*yargv);
  1828.                         StartedFromDialer = 1;
  1829.                         yargv++, yargc--;
  1830.                         KermitDialerID = atol(*yargv) ;
  1831. #ifdef COMMENT
  1832.                     }
  1833. #endif /* COMMENT */
  1834.                     break;
  1835.  
  1836.                   case '#':             /* K95 initialization options */
  1837.                     if (*(yp+1)) {
  1838.                         fatal("invalid argument bundling");
  1839.                     }
  1840.                     yargv++, yargc--;
  1841.                     if (yargc < 1)
  1842.                       fatal("-# argument missing");
  1843.                     startflags |= atol(*yargv);
  1844.                     break;
  1845. #endif /* OS2 */
  1846.  
  1847. #ifndef NOSPL
  1848.                   case 'M':                             /* My User Name */
  1849.                     if (*(yp+1)) {
  1850.                         fatal("invalid argument bundling");
  1851.                     }
  1852.                     yargv++, yargc--;
  1853.                     if ((yargc < 1) || (**yargv == '-')) {
  1854.                         fatal("missing username");
  1855.                     }
  1856.                     if ((int)strlen(*yargv) > UIDBUFLEN) {
  1857.                         fatal("username too long");
  1858.                     }
  1859. #ifdef COMMENT
  1860. /*
  1861.   This can't work.  uidbuf is overwritten in sysinit() which has yet to be
  1862.   called.  This cannot be set in prescan().
  1863. */
  1864. #ifdef IKSD
  1865.                     if (!inserver)
  1866. #endif /* IKSD */
  1867.                       ckstrncpy(uidbuf,*yargv,UIDBUFLEN);
  1868. #endif /* COMMENT */
  1869.                     break;
  1870. #endif /* NOSPL */
  1871.                   case 'R':             /* Remote-only advisory */
  1872. #ifdef CK_IFRO
  1873.                     remonly = 1;
  1874. #endif /* CK_IFRO */
  1875.                     break;
  1876.                   case 'S':             /* STAY */
  1877.                     stayflg = 1;
  1878.                     break;
  1879.                   case 'h':
  1880.                     noinit = 1;
  1881. #ifdef OS2
  1882.                     startflags |= 2;    /* No network DLLs */
  1883.                     startflags |= 4;    /* No TAPI DLLs */
  1884.                     startflags |= 8;    /* No Security DLLs */
  1885.                     startflags |= 16;   /* No Zmodem DLLs */
  1886.                     startflags |= 32;   /* Stdin */
  1887.                     startflags |= 64;   /* Stdout */
  1888. #endif /* OS2 */
  1889.                     break;
  1890. #ifndef NOICP
  1891.                   case 'Y':             /* No init file */
  1892.                     noinit = 1;
  1893.                     break;
  1894. #endif /* NOICP */
  1895.  
  1896.                   case 'q':
  1897.                       quiet = 1;
  1898.                       break;
  1899.  
  1900.                   case 'd':             /* = SET DEBUG ON */
  1901. #ifdef DEBUG
  1902.                     if (debcount++ > 0)
  1903.                       debtim = 1;
  1904.                     if (!deblog)
  1905.                       deblog = debopn("debug.log",0);
  1906. #endif /* DEBUG */
  1907.                     break;
  1908.  
  1909.                   case 'x':             /* Server */
  1910.                     arg_x = 1;          /* Note in advance */
  1911.                     break;
  1912. #ifndef NOICP
  1913.                   case 'y':             /* Alternative init file */
  1914.                     noinit = 0;
  1915.                     yargv++, yargc--;
  1916.                     if (yargc < 1) fatal("missing name in -y");
  1917.                     /* Replace init file name */
  1918.                     ckstrncpy(kermrc,*yargv,KERMRCL);
  1919.                     rcflag = 1;         /* Flag that this has been done */
  1920.                     debug(F111,"prescan kermrc",kermrc,rcflag);
  1921.                     break;
  1922. #endif /* NOICP */
  1923.                   case 'z':             /* = SET BACKGROUND OFF */
  1924.                     bgset = 0;
  1925.                     backgrd = 0;
  1926. #ifdef VMS
  1927.                     batch = 0;
  1928. #endif /* VMS */
  1929.                     break;
  1930.  
  1931.                   case 'B':             /* Force background (batch) */
  1932.                     bgset = 1;
  1933.                     backgrd = 1;
  1934. #ifdef VMS
  1935.                     batch = 1;
  1936. #endif /* VMS */
  1937.                     break;
  1938.  
  1939. #ifdef CK_NETBIOS
  1940.                   case 'N':
  1941.                     {
  1942.                         int n ;
  1943.                         yargv++, yargc--;
  1944. #ifdef COMMENT
  1945.                         if (y)
  1946.                           break;
  1947. #endif /* COMMENT */
  1948.                         if (strlen(*yargv) != 1 || (*yargv)[0] == 'X') {
  1949.                             NetBiosAdapter = -1;
  1950.                         } else {
  1951.                             n = atoi(*yargv);
  1952.                             if (n >= 0 && n <= 9)
  1953.                               NetBiosAdapter = n;
  1954.                             else
  1955.                               NetBiosAdapter = -1;
  1956.                         }
  1957.                     }
  1958.                     break;
  1959. #endif /* CK_NETBIOS */
  1960.                   default:
  1961.                     break;
  1962.                 }
  1963.                 if (!yp)
  1964.                   break;
  1965.                 x = *++yp;              /* See if options are bundled */
  1966.             }
  1967.         }
  1968.     }
  1969. #endif /* NOCMDL */
  1970. }
  1971.  
  1972. /*  G E T T C S  --  Get Transfer (Intermediate) Character Set  */
  1973.  
  1974. /*
  1975.   Given two file character sets, this routine picks out the appropriate
  1976.   "transfer" character set to use for translating between them.
  1977.   The transfer character set number is returned.
  1978.  
  1979.   Translation between two file character sets is done, for example,
  1980.   by the CONNECT, TRANSMIT, and TRANSLATE commands.
  1981.  
  1982.   Translation between Kanji character sets is not yet supported.
  1983. */
  1984. int
  1985. gettcs(cs1,cs2) int cs1, cs2; {
  1986. #ifdef NOCSETS                          /* No character-set support */
  1987.     return(0);                          /* so no translation */
  1988. #else
  1989.     int tcs = TC_TRANSP;
  1990. #ifdef KANJI
  1991. /* Kanji not supported yet */
  1992.     if (fcsinfo[cs1].alphabet == AL_JAPAN ||
  1993.         fcsinfo[cs2].alphabet == AL_JAPAN )
  1994.       tcs = TC_TRANSP;
  1995.     else
  1996. #endif /* KANJI */
  1997. #ifdef CYRILLIC
  1998. /*
  1999.   I can't remember why we don't test both sets here, but I think there
  2000.   must have been a reason...
  2001. */
  2002.       if (fcsinfo[cs2].alphabet == AL_CYRIL)
  2003.         tcs = TC_CYRILL;
  2004.       else
  2005. #endif /* CYRILLIC */
  2006. #ifdef HEBREW
  2007.           if (fcsinfo[cs1].alphabet == AL_HEBREW ||
  2008.               fcsinfo[cs2].alphabet == AL_HEBREW )
  2009.             tcs = TC_HEBREW;
  2010.           else
  2011. #endif /* HEBREW */
  2012. #ifdef GREEK
  2013.           if (fcsinfo[cs1].alphabet == AL_GREEK ||
  2014.               fcsinfo[cs2].alphabet == AL_GREEK )
  2015.             tcs = TC_GREEK;
  2016.           else
  2017. #endif /* GREEK */
  2018.  
  2019.             /* Roman sets ... */
  2020.  
  2021. #ifdef LATIN2                           /* East European */
  2022.         if (cs1 == FC_2LATIN  || cs2 == FC_2LATIN || /* Latin-2 */
  2023.             cs1 == FC_CP852   || cs2 == FC_CP852  || /* CP852 */
  2024.             cs1 == FC_CP1250  || cs2 == FC_CP1250 || /* Windows Latin-2 */
  2025.             cs1 == FC_MAZOVIA || cs2 == FC_MAZOVIA)  /* Polish Mazovia */
  2026.           tcs = TC_2LATIN;
  2027.         else
  2028. #endif /* LATIN2 */
  2029.                                         /* West European Euro-aware */
  2030.           if (cs1 == FC_CP858 || cs1 == FC_9LATIN ||
  2031.               cs2 == FC_CP858 || cs2 == FC_9LATIN)
  2032.             tcs = TC_9LATIN;
  2033.           else                          /* Traditional West European */
  2034.             tcs = TC_1LATIN;
  2035.     return(tcs);
  2036. #endif /* NOCSETS */
  2037. }
  2038.  
  2039. #ifndef NOLOCAL
  2040. /*  D O C O N E C T  --  Do the connect command  */
  2041. /*
  2042.   q = 0 means issue normal informational message about how to get back, etc.
  2043.   q != 0 means to skip the message.
  2044. */
  2045.  
  2046. int
  2047. doconect(q,async) int q, async; {
  2048.     int x;                              /* Return code */
  2049. #ifdef CK_AUTODL
  2050.     extern CHAR ksbuf[];
  2051. #endif /* CK_AUTODL */
  2052. #ifndef NOKVERBS                        /* Keyboard macro material */
  2053.     extern int keymac, keymacx;
  2054. #endif /* NOKVERBS */
  2055.     extern int justone, adl_err;
  2056.     int qsave;                          /* For remembering "quiet" value */
  2057. #ifdef OS2
  2058.     extern int term_io;
  2059.     extern int display_demo;
  2060.     int term_io_save;
  2061. #ifdef KUI
  2062.     extern int kui_async;
  2063. #endif /* KUI */
  2064. #endif /* OS2 */
  2065.     int is_tn = 0;
  2066.  
  2067. #ifdef IKSD
  2068.     if (inserver) {
  2069.         if (!quiet)
  2070.           printf("?Sorry, IKSD cannot CONNECT.\r\n");
  2071.         return(success = 0);
  2072.     }
  2073. #endif /* IKSD */
  2074.  
  2075.     is_tn =
  2076. #ifdef TNCODE
  2077.       (local && network && IS_TELNET()) || (!local && sstelnet)
  2078. #else
  2079.         0
  2080. #endif /* TNCODE */
  2081.           ;
  2082. /*
  2083.   Saving, changing, and restoring the global "quiet" variable around calls
  2084.   to conect() to control whether the verbose CONNECT message is printed is
  2085.   obviously less elegant than passing a parameter to conect(), but we do it
  2086.   this way to avoid the need to change all of the ck?con.c modules.  NOTE:
  2087.   it is important to restore the value immediately upon return in case there
  2088.   is an autodownload or APC.
  2089. */
  2090.     qsave = quiet;                      /* Save it */
  2091.     if (!quiet && q > -1)
  2092.       quiet = q;                        /* Use argument temporarily */
  2093.     conres();                           /* Put console back to normal */
  2094.     debug(F101,"doconect justone 1","",justone);
  2095. #ifdef CK_AUTODL
  2096.     ksbuf[0] = NUL;                     /* Autodownload packet buffer */
  2097. #endif /* CK_AUTODL */
  2098. #ifdef OS2
  2099.     display_demo = 1;                   /* Remember to display demo */
  2100. #endif /* OS2 */
  2101.  
  2102. #ifdef IKS_OPTION
  2103.     if (is_tn && TELOPT_U(TELOPT_KERMIT) && ttchk() >= 0
  2104. #ifdef OS2
  2105.        && !viewonly
  2106. #endif /* OS2 */
  2107.         ) {
  2108.         /* If the remote side is in a state of IKS START-SERVER    */
  2109.         /* we request that the state be changed.  We will detect   */
  2110.         /* a failure to adhere to the request when we call ttinc() */
  2111.         if (!iks_wait(KERMIT_REQ_STOP,0) && !tcp_incoming) {
  2112.             if (!quiet) {
  2113.                 printf("\r\nEnter Client/Server Mode...  Use:\r\n\r\n");
  2114.                 printf(
  2115. " REMOTE LOGIN <user> <password> to log in to the server if necessary.\r\n");
  2116.                 printf(" SEND and GET for file transfer.\r\n");
  2117.                 printf(" REMOTE commands for file management.\r\n");
  2118.                 printf(" FINISH to terminate Client/Server mode.\r\n");
  2119.                 printf(" BYE to terminate and close connection.\r\n");
  2120.                 printf(" REMOTE HELP for additional information.\r\n\r\n");
  2121.             }
  2122.             quiet = qsave;
  2123.             return(0);      /* Failure */
  2124.         }
  2125.     }
  2126.  
  2127.     /* Let our peer know our state. */
  2128. #ifdef CK_AUTODL
  2129.     if (is_tn && TELOPT_ME(TELOPT_KERMIT)
  2130. #ifdef OS2
  2131.         && !viewonly
  2132. #endif /* OS2 */
  2133.          ) {
  2134.         if (autodl && !TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
  2135.             tn_siks(KERMIT_START);      /* Send Kermit-Server Start */
  2136.         } else if (!autodl && TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
  2137.             tn_siks(KERMIT_STOP);
  2138.         }
  2139.     }
  2140. #else /* CK_AUTODL */
  2141.     if (is_tn && TELOPT_ME(TELOPT_KERMIT) &&
  2142.     TELOPT_SB(TELOPT_KERMIT).kermit.me_start)
  2143.         tn_siks(KERMIT_STOP);
  2144. #endif /* CK_AUTODL */
  2145. #endif /* IKS_OPTION */
  2146.  
  2147.     debug(F101,"doconect flow","",flow);
  2148. #ifdef OS2
  2149.     debug(F101,"doconect async","",async);
  2150. #ifdef KUI
  2151.     if (kui_async)
  2152.       async = 1;;
  2153. #endif /* KUI */
  2154.     x = conect(async);                  /* Connect the first time */
  2155. #else /* OS2 */
  2156.     x = conect();
  2157. #endif /* OS2 */
  2158.     debok = 1;
  2159.  
  2160. #ifdef IKS_OPTION
  2161.     if (TELOPT_U(TELOPT_KERMIT) &&
  2162.         TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
  2163.         !tcp_incoming && !quiet && ttchk() >= 0
  2164.         ) {
  2165.         printf("\r\nEnter Client/Server Mode...  Use:\r\n\r\n");
  2166.         printf(
  2167. " REMOTE LOGIN <user> <password> to log in to the server if necessary.\r\n");
  2168.         printf(" SEND and GET for file transfer.\r\n");
  2169.         printf(" REMOTE commands for file management.\r\n");
  2170.         printf(" FINISH to terminate Client/Server mode.\r\n");
  2171.         printf(" BYE to terminate and close connection.\r\n");
  2172.         printf(" REMOTE HELP for additional information.\r\n\r\n");
  2173.     }
  2174. #endif /* IKS_OPTION */
  2175.  
  2176.     quiet = qsave;                      /* Restore "quiet" value */
  2177.     debug(F101,"doconect justone 2","",justone);
  2178.  
  2179. #ifdef NETCONN
  2180.     if (network && tn_exit && ttchk() < 0)
  2181.       doexit(GOOD_EXIT,xitsta);         /* Exit with good status */
  2182. #endif /* NETCONN */
  2183.  
  2184. #ifdef OS2ORUNIX
  2185.     /* Exit on disconnect if the port is not open or carrier detect */
  2186.     if (exitonclose && (ttchk() < 0))
  2187.       doexit(GOOD_EXIT,xitsta);
  2188. #endif /* OS2ORUNIX */
  2189.  
  2190. #ifdef CKCONINTB4CB
  2191.     /* The order makes a difference in HP-UX 8.00. */
  2192.     /* The other order makes it think it's in the background when it */
  2193.     /* returns from CONNECT (Apr 1999). */
  2194.     setint();
  2195.     concb((char)escape);                /* Restore console for commands */
  2196. #else
  2197.     /* This is how it has always been so better leave it */
  2198.     /* this way for all non-HP-UX-8.00 builds. */
  2199.     concb((char)escape);                /* Restore console for commands */
  2200.     setint();
  2201. #endif /* CKCONINTB4CB */
  2202.  
  2203. #ifdef OS2
  2204.     if (!async) {
  2205.         term_io_save = term_io;         /* Disable I/O by emulator */
  2206.         term_io = 0;
  2207. #endif /* OS2 */
  2208.  
  2209. #ifdef CK_APC
  2210. /*
  2211.   If an APC command was received during CONNECT mode, we define it now
  2212.   as a macro, execute the macro, and then return to CONNECT mode.
  2213.   We do this in a WHILE loop in case additional APCs come during subsequent
  2214.   CONNECT sessions.
  2215. */
  2216.         debug(F101,"doconect apcactive","",apcactive);
  2217.         debug(F101,"doconect success","",success);
  2218.  
  2219.         while (x > 0 && (apcactive == APC_LOCAL ||
  2220.                          (apcactive == APC_REMOTE && apcstatus != APC_OFF))) {
  2221.             debug(F101,"doconect justone 3","",justone);
  2222.             if (mlook(mactab,"_apc_commands",nmac) == -1) {
  2223.                 debug(F110,"doconect about to execute APC",apcbuf,0);
  2224.                 domac("_apc_commands",apcbuf,cmdstk[cmdlvl].ccflgs|CF_APC);
  2225.                 delmac("_apc_commands",1);
  2226. #ifdef DEBUG
  2227.             } else {
  2228.                 debug(F100,"doconect APC in progress","",0);
  2229. #endif /* DEBUG */
  2230.             }
  2231.             debug(F101,"doconect apcactive after domac","",apcactive);
  2232.             if (!apcactive) {               /* In case CLEAR APC was in APC */
  2233.                 debug(F101,"doconect quit APC loop: apcactive","",apcactive);
  2234.                 break;
  2235.             }
  2236.             /* Also don't reconnect if autodownload failed - very confusing! */
  2237.             /* Let them view the local screen to see what happened. - fdc */
  2238.  
  2239.             /* This should be conditional.  If someone is relying on the */
  2240.             /* connect mode autodownload for the kermit server to use with */
  2241.             /* a remotely executed script we should be able to return to */
  2242.             /* connect mode on the failure.  What we really need to do is */
  2243.             /* report the status of the transfer and then return to CONNECT. */
  2244.             /* In unix this would simply be a printf(), but in K95 it could */
  2245.             /* use a popup dialog to report the status. - Jeff */
  2246.  
  2247. #ifndef NOXFER
  2248.             debug(F101,"doconect xferstat","",xferstat);
  2249.             if (apcactive == APC_LOCAL && !xferstat && adl_err != 0) {
  2250.                 debug(F101,"doconect quit APC loop: xferstat","",xferstat);
  2251.                 apcactive = APC_INACTIVE;
  2252.                 break;
  2253.             }
  2254. #endif /* NOXFER */
  2255. #ifdef OS2
  2256.             msleep(250);
  2257. #endif /* OS2 */
  2258.             debug(F101,"doconect justone 4","",justone);
  2259.             qsave = quiet;              /* Do this again... */
  2260.             if (!quiet && q > -1)
  2261.               quiet = q;
  2262. #ifdef CK_AUTODL
  2263.             ksbuf[0] = NUL;
  2264. #endif /* CK_AUTODL */
  2265. #ifdef IKS_OPTION
  2266. #ifdef CK_AUTODL
  2267.             if (is_tn &&
  2268.                 TELOPT_ME(TELOPT_KERMIT) &&
  2269.                 !TELOPT_SB(TELOPT_KERMIT).kermit.me_start &&
  2270.                 autodl
  2271. #ifdef CK_APC
  2272.                 && !apcactive
  2273. #endif /* CK_APC */
  2274. #ifdef OS2
  2275.                 && !viewonly
  2276. #endif /* OS2 */
  2277.                 ) {
  2278.                 tn_siks(KERMIT_START);  /* Send Kermit-Server Start */
  2279.             }
  2280. #endif /* CK_AUTODL */
  2281. #endif /* IKS_OPTION */
  2282. #ifndef OS2
  2283.             x = conect();               /* Re-CONNECT. */
  2284. #else /* OS2 */
  2285.             x = conect(0);
  2286.             term_io = term_io_save;
  2287. #endif /* OS2 */
  2288.             debok = 1;
  2289.             quiet = qsave;
  2290.             debug(F101,"doconect justone 5","",justone);
  2291. #ifdef NETCONN
  2292.             if (network && ttchk() < 0) {
  2293.                 if (tn_exit || exitonclose)
  2294.                   doexit(GOOD_EXIT,xitsta);
  2295.                 else
  2296.                   break;
  2297.             }
  2298. #endif /* NETCONN */
  2299.  
  2300. #ifdef OS2ORUNIX
  2301.             /* If connection dropped */
  2302.             if (ttchk() < 0) {
  2303.                 concb((char)escape);    /* Restore console. */
  2304.                 if (exitonclose)
  2305.                   doexit(GOOD_EXIT,xitsta);
  2306.                 else
  2307.                   break;
  2308.             }
  2309. #endif /* OS2ORUNIX */
  2310.         } /* Loop back for more. */
  2311. #endif /* CK_APC */
  2312.  
  2313. #ifndef NOKVERBS
  2314.         if ((keymac > 0) && (keymacx > -1)) { /* Executing a keyboard macro? */
  2315.             /* Set up the macro and return */
  2316.             /* Do not clear the keymac flag */
  2317. #ifdef OS2
  2318.         term_io = term_io_save;
  2319. #endif /* OS2 */
  2320.             return(dodo(keymacx,NULL,CF_KMAC|cmdstk[cmdlvl].ccflgs));
  2321.         }
  2322. #endif /* NOKVERBS */
  2323. #ifdef OS2
  2324.         term_io = term_io_save;
  2325.     } /* if (!async) */
  2326. #endif /* OS2 */
  2327.  
  2328. #ifdef CKCONINTB4CB
  2329.     /* The order makes a difference in HP-UX 8.00. */
  2330.     /* The other order makes it think it's in the background when it */
  2331.     /* returns from CONNECT (Apr 1999). */
  2332.     setint();
  2333.     concb((char)escape);                /* Restore console for commands */
  2334. #else
  2335.     /* This is how it has always been so better leave it */
  2336.     /* this way for all non-HP-UX-8.00 builds. */
  2337.     concb((char)escape);                /* Restore console for commands */
  2338.     setint();
  2339. #endif /* CKCONINTB4CB */
  2340. #ifdef OS2
  2341.     if (!async)
  2342. #endif /* OS2 */
  2343.       what = W_COMMAND;                 /* Back in command mode. */
  2344.     return(x);                          /* Done. */
  2345. }
  2346. #endif /* NOLOCAL */
  2347.  
  2348. #ifndef NOICP
  2349. #ifdef COMMENT
  2350. /*
  2351.   It seemed that this was needed for OS/2, in which \v(cmdfile) and other
  2352.   file-oriented variables or functions can return filenames containing
  2353.   backslashes, which are subsequently interpreted as quotes rather than
  2354.   directory separators (e.g. see commented section for VN_CMDF below).
  2355.   But the problem can't be cured at this level.  Example:
  2356.  
  2357.     type \v(cmdfile)
  2358.  
  2359.   Without doubling, the filename is parsed correctly, but then when passed
  2360.   to UNIX 'cat' through the shell, the backslash is removed, and then cat
  2361.   can't open the file.  With doubling, the filename is not parsed correctly
  2362.   and the TYPE command fails immediately with a "file not found" error.
  2363. */
  2364. /*
  2365.   Utility routine to double all backslashes in a string.
  2366.   s1 is pointer to source string, s2 is pointer to destination string,
  2367.   n is length of destination string, both NUL-terminated.
  2368.   Returns 0 if OK, -1 if not OK (destination string too short).
  2369. */
  2370. int
  2371. dblbs(s1,s2,n) char *s1, *s2; int n; {
  2372.     int i = 0;
  2373.     while (*s1) {
  2374.         if (*s1 == '\\') {
  2375.             if (++i > n) return(-1);
  2376.             *s2++ = '\\';
  2377.         }
  2378.         if (++i > n) return(-1);
  2379.         *s2++ = *s1++;
  2380.     }
  2381.     *s2 = NUL;
  2382.     return(0);
  2383. }
  2384. #endif /* COMMENT */
  2385.  
  2386. char *
  2387. gmdmtyp() {                             /* Get modem type */
  2388. #ifndef NODIAL
  2389.     int i, x;
  2390.  
  2391.     debug(F111,"gmdmtyp","mdmtyp",mdmtyp);
  2392.     debug(F111,"gmdmtyp","mdmsav",mdmsav);
  2393.  
  2394.     x = mdmtyp;
  2395.     if (x < 0)                          /* In case of network dialing */
  2396.       x = mdmsav;
  2397.     if (x < 1)
  2398.       return("none");
  2399.     else
  2400.       for (i = 0; i < nmdm; i++)
  2401.         if ((mdmtab[i].kwval == x) && (mdmtab[i].flgs == 0))
  2402.           return(mdmtab[i].kwd);
  2403. #endif /* NODIAL */
  2404.     return("none");
  2405. }
  2406.  
  2407. #ifndef NOXMIT
  2408. #ifndef NOLOCAL
  2409. /*  T R A N S M I T  --  Raw upload  */
  2410.  
  2411. /*  Obey current line, duplex, parity, flow, text/binary settings. */
  2412. /*  Returns 0 upon apparent success, 1 on obvious failure.  */
  2413.  
  2414. /***
  2415.  Things to add:
  2416.  . Make both text and binary mode obey set file bytesize.
  2417.  . Maybe allow user to specify terminators other than CR?
  2418.  . Maybe allow user to specify prompts other than single characters?
  2419.  . Make STATISTICS also work for TRANSMIT.
  2420.  . If TRANSMIT is done without echo, make some kind of (optional) display.
  2421.  . Make the same optimization for binary-mode transmit that was done for
  2422.    text-mode (in the no-echo / no-prompt / no-pause case).
  2423. ***/
  2424.  
  2425. /*  T R A N S M I T  --  Raw upload  */
  2426.  
  2427. /*  s is the filename, t is the turnaround (prompt) character  */
  2428.  
  2429. /*
  2430.   Maximum number of characters to buffer.
  2431.   Must be less than LINBUFSIZ
  2432. */
  2433. #ifdef OS2
  2434. #define XMBUFS 4096                     /* For compatibility with XYZmodem */
  2435. #else /* OS2 */
  2436. #define XMBUFS 1024
  2437. #endif /* OS2 */
  2438.  
  2439. #ifdef TNCODE
  2440. #ifndef IAC
  2441. #define IAC 255
  2442. #endif /* IAC */
  2443. #endif /* TNCODE */
  2444.  
  2445. #define OUTXBUFSIZ 15
  2446. static CHAR inxbuf[OUTXBUFSIZ+1];       /* Host-to-screen expansion buffer */
  2447. static int inxcount = 0;                /* and count */
  2448. static CHAR outxbuf[OUTXBUFSIZ+1];      /* Keyboard-to-host expansion buf */
  2449. static int outxcount = 0;               /* and count */
  2450.  
  2451. /*  T R A N S M I T  --  Unguarded non-protocol file transmission  */
  2452. /*
  2453.   Call with:
  2454.     char * s:   Name of file to transmit.
  2455.     char t:     Turnaround char for text-mode transmission (normally LF).
  2456.     int xlate:  nonzero = charset translation for text-mode xfer, 0 = skip.
  2457.     int binary: nonzero = transmit in binary mode, 0 = in text mode.
  2458. */
  2459. #define XBBUFSIZ 252                    /* For binary blasting */
  2460. static CHAR xbbuf[XBBUFSIZ+4];
  2461.  
  2462. int
  2463. #ifdef CK_ANSIC
  2464. transmit(char * s, char t, int xlate, int binary, int xxecho)
  2465. #else
  2466. transmit(s,t,xlate,binary,xxecho) char *s; char t; int xlate, binary, xxecho;
  2467. #endif /* CK_ANSIC */
  2468. /* transmit */ {
  2469. #ifdef MAC
  2470.     extern char sstate;
  2471.     int count = 100;
  2472. #else
  2473.     int count = 0;
  2474. #ifdef OS2
  2475. #ifdef NT
  2476.     SIGTYP (* oldsig)(int);             /* For saving old interrupt trap. */
  2477. #else /* NT */
  2478.     SIGTYP (* volatile oldsig)(int);
  2479. #endif /* NT */
  2480.  
  2481. #else /* OS2 */
  2482.     SIGTYP (* oldsig)();
  2483. #endif /* OS2 */
  2484. #endif /* MAC */
  2485.     int eof = 0;                        /* End of File flag */
  2486.     int eol = 0;                        /* End of Line flag */
  2487.     int rc = 1;                         /* Return code. 0=fail, 1=succeed. */
  2488.     int myflow;                         /* Local copy of global flow... */
  2489.     int is_tn = 0;                      /* Do Telnet negotiations */
  2490.     int xbufsiz = XMBUFS;               /* Size of TRANSMIT buffer */
  2491.     int x, y, c, i;                     /* Int workers... */
  2492.     int control = 0;                    /* Echo loop control */
  2493.     long nbytes = 0;                    /* File byte count */
  2494.     long zz;                            /* Long worker */
  2495.     char *p;                            /* Char * worker */
  2496.  
  2497. #ifdef PIPESEND
  2498.     extern int pipesend;
  2499. #endif /* PIPESEND */
  2500.  
  2501. #ifndef NOCSETS
  2502.     int tcs = TC_TRANSP;                /* Intermediate (xfer) char set */
  2503.     int langsv = L_USASCII;             /* Save current language */
  2504.     int unicode = 0;
  2505.     int tcssize = 0;
  2506.  
  2507. #ifdef CK_ANSIC /* ANSI C prototypes... */
  2508.     CHAR (*sxo)(CHAR);
  2509.     CHAR (*rxo)(CHAR);
  2510.     CHAR (*sxi)(CHAR);
  2511.     CHAR (*rxi)(CHAR);
  2512. #else /* Not ANSI C... */
  2513.     CHAR (*sxo)();
  2514.     CHAR (*rxo)();
  2515.     CHAR (*sxi)();
  2516.     CHAR (*rxi)();
  2517. #endif /* CK_ANSIC */
  2518. #ifdef UNICODE
  2519.     union ck_short uc;
  2520.     int bomorder = 0;
  2521. #ifdef CK_ANSIC
  2522.     extern int (*xl_ufc[MAXFCSETS+1])(USHORT);  /* Unicode to FCS */
  2523.     extern USHORT (*xl_fcu[MAXFCSETS+1])(CHAR); /* FCS to Unicode */
  2524.     extern int (*xuf)(USHORT);
  2525.     extern USHORT (*xfu)(CHAR);
  2526. #else
  2527.     extern int (*xl_ufc[MAXFCSETS+1])();
  2528.     extern USHORT (*xl_fcu[MAXFCSETS+1])();
  2529.     extern int (*xuf)();
  2530.     extern USHORT (*xfu)();
  2531. #endif /* CK_ANSIC */
  2532. #endif /* UNICODE */
  2533. #endif /* NOCSETS */
  2534.  
  2535.     debug(F101,"xmit t","",t);
  2536.     debug(F101,"xmit xlate","",xlate);
  2537.     debug(F101,"xmit binary","",binary);
  2538.  
  2539. #ifdef PIPESEND
  2540.     if (pipesend) {
  2541.         if (nopush) return(-2);
  2542.         if (zxcmd(ZIFILE,s) < 1) {
  2543.             printf("?Can't start command: %s\n",s);
  2544.             return(0);
  2545.         }
  2546.     } else
  2547. #endif /* PIPESEND */
  2548.     if (zopeni(ZIFILE,s) == 0) {        /* Open the file to be transmitted */
  2549.         printf("?Can't open file %s\n",s);
  2550.         return(0);
  2551.     }
  2552.     x = -1;                             /* Open the communication channel */
  2553.     if (ttopen(ttname,&x,mdmtyp,cdtimo) < 0) {  /* (no harm if already open) */
  2554.         printf("Can't open device %s\n",ttname);
  2555.         return(0);
  2556.     }
  2557.     zz = x ? speed : -1L;
  2558.     if (binary) {                       /* Binary file transmission */
  2559.         myflow = (flow == FLO_XONX) ? FLO_NONE : flow;
  2560.  
  2561.         if (ttvt(zz,myflow) < 0) {      /* So no Xon/Xoff! */
  2562.             printf("Can't condition line\n");
  2563.             return(0);
  2564.         }
  2565.     } else {
  2566.         if (ttpkt(zz,flow,parity) < 0) { /* Put the line in "packet mode" */
  2567.             printf("Can't condition line\n"); /* so Xon/Xoff will work, etc. */
  2568.             return(0);
  2569.         }
  2570.     }
  2571.     is_tn =
  2572. #ifdef TNCODE
  2573.       (local && network && IS_TELNET()) || (!local && sstelnet)
  2574. #else
  2575.         0
  2576. #endif /* TNCODE */
  2577.           ;
  2578.  
  2579. #ifndef NOCSETS
  2580. /* Set up character set translations */
  2581.  
  2582.     tcs = 0;                            /* "Transfer" or "Other" charset */
  2583.     sxo = rxo = NULL;                   /* Initialize byte-to-byte functions */
  2584.     sxi = rxi = NULL;
  2585.     unicode = 0;                        /* Assume Unicode won't be involved */
  2586.     if (!binary && xlate) {             /* Set up charset translations */
  2587. /*
  2588.   In the SENDING direction, we are converting from the local file's
  2589.   character-set (fcharset) to the remote terminal charset (tcsr).  In the
  2590.   RECEIVING direction (echoing) we are converting from the remote end of the
  2591.   terminal charset (tcsr) to its local end (tcsl), which is not necessarily
  2592.   the same as the file character-set.  Especially when the file character
  2593.   set is UCS-2, which is not a valid terminal character set.  The various
  2594.   combinations are represented in this table:
  2595.  
  2596.   FCS = File Character Set
  2597.   RCS = Remote Terminal Character Set
  2598.   CCS = Console (Local Terminal) Character Set
  2599.  
  2600.    8   4   2   1
  2601.   FCS FCS RCS CCS
  2602.   UCS UTF UTF UTF
  2603.    0   0   0   0   =   0   =   No translation
  2604.    0   0   0   1   =   1   =   FCS -> RCS, Echo RCS -> UTF
  2605.    0   0   1   0   =   2   =   FCS -> UTF, Echo UTF -> CCS
  2606.    0   0   1   1   =   3   =   FCS -> UTF, Echo no translation
  2607.  
  2608.    0   1   0   0   =   4   =   UTF -> RCS, Echo RCS -> CCS
  2609.    0   1   0   1   =   5   =   UTF -> RCS, Echo RCS -> UTF
  2610.    0   1   1   0   =   6   =   UTF -> UTF, Echo UTF -> CCS
  2611.    0   1   1   1   =   7   =   No translation
  2612.  
  2613.    1   0   0   0   =   8   =   UCS -> RCS, Echo RCS -> CCS
  2614.    1   0   0   1   =   9   =   UCS -> RCS, Echo RCS -> UTF
  2615.    1   0   1   0   =  10   =   UCS -> UTF, Echo UTF -> CCS
  2616.    1   0   1   1   =  11   =   UCS -> UTF, Echo no translation
  2617. */
  2618. #ifdef UNICODE
  2619.         xfu = NULL;                     /* Unicode translation functions */
  2620.         xuf = NULL;
  2621.         bomorder = ucsorder;            /* UCS-2 byte order */
  2622.  
  2623.         if (fcharset == FC_UCS2)        /* File charset is UCS-2 */
  2624.           unicode |= 8;
  2625.         else if (fcharset == FC_UTF8)   /* File charset is UTF-8 */
  2626.           unicode |= 4;
  2627.         if (tcsr == FC_UTF8)            /* Remote term charset is UTF-8 */
  2628.           unicode |= 2;
  2629.         if (tcsl == FC_UTF8)            /* Local term charset is UTF-8 */
  2630.           unicode |= 1;
  2631. #endif /* UNICODE */
  2632. /*
  2633.   When Unicode not involved -- TCS is the intermediate (xfer) set, and:
  2634.   sxo = File-to-Intermediate charset function
  2635.   rxo = Intermediate-to-Remote-Terminal charset function
  2636.   sxi = Remote-Terminal-to-Intermediate
  2637.   rxi = Intermediate-to-Local-Terminal
  2638. */
  2639.         tcs = gettcs(tcsr,fcharset);    /* Get intermediate set. */
  2640.         sxo = xls[tcs][fcharset];       /* translation function */
  2641.         rxo = xlr[tcs][tcsr];           /* pointers for output functions */
  2642.         sxi = xls[tcs][tcsr];           /* and for input functions. */
  2643.         rxi = xlr[tcs][tcsl];
  2644. /*
  2645.   At this point we have unicode nonzero if Unicode is involved in the
  2646.   conversion, and to 0 if it is not.
  2647.   The following is to prevent use of zmstuff() and zdstuff() by translation
  2648.   functions (stuffing works with file i/o, not with communication i/o).
  2649. */
  2650.         langsv = language;              /* Save current SET LANGUAGE */
  2651.         language = L_USASCII;           /* No language-specific translations */
  2652.     }
  2653. #endif /* NOCSETS */
  2654.  
  2655.     i = 0;                              /* Beginning of buffer. */
  2656. #ifndef MAC
  2657. #ifndef AMIGA
  2658.     oldsig = signal(SIGINT, trtrap);    /* Save current interrupt trap. */
  2659. #endif /* AMIGA */
  2660. #endif /* MAC */
  2661.     tr_int = 0;                         /* Have not been interrupted (yet). */
  2662.     rc = 1;                             /* Return code presumed good. */
  2663. #ifdef VMS
  2664.     conres();
  2665. #endif /* VMS */
  2666.  
  2667. #ifndef NOCSETS
  2668.     debug(F101,"XMIT unicode","",unicode);
  2669. #ifdef UNICODE
  2670.     debug(F101,"XMIT bomorder","",bomorder);
  2671. #endif /* UNICODE */
  2672. #endif /* NOCSETS */
  2673.  
  2674.     c = 0;                              /* Initial condition */
  2675.     while (c > -1 && !eof) {            /* Loop for all characters in file */
  2676.         eol = 0;
  2677. #ifdef MAC
  2678.         /*
  2679.          * It is expensive to run the miniparser so don't do it for
  2680.          * every character.
  2681.          */
  2682.         if (--count < 0) {
  2683.             count = 100;
  2684.             miniparser(1);
  2685.             if (sstate == 'a') {
  2686.                 sstate = '\0';
  2687.                 goto xmitfail;
  2688.             }
  2689.         }
  2690. #else /* Not MAC */
  2691.         if (tr_int) {                   /* Interrupted? */
  2692.             printf("^C...\n");          /* Print message */
  2693.             goto xmitfail;
  2694.         }
  2695. #endif /* MAC */
  2696.         c = zminchar();                 /* Get a file character */
  2697. #ifdef COMMENT
  2698. /* too much */
  2699. #ifdef DEBUG
  2700.         if (deblog) {
  2701.             if (c < 0)
  2702.               debug(F101,"XMIT zminchar","",c);
  2703.             else
  2704.               debug(F000,"XMIT zminchar","",c);
  2705.         }
  2706. #endif /* DEBUG */
  2707. #endif /* COMMENT */
  2708.         if (c < -1) {                   /* Other error */
  2709.             printf("?TRANSMIT file read error: %s\n",ck_errstr());
  2710.             goto xmitfail;
  2711.         } else if (c > -1) {
  2712.             nbytes++;
  2713.             c &= fmask;                 /* Apply SET FILE BYTESIZE mask */
  2714.         } else if (c == -1) {
  2715.             eof = 1;
  2716.             debug(F101,"XMIT eof","",eof);
  2717.         }
  2718.         if (binary) {                   /* Binary... */
  2719.             if (c == -1) {              /* If EOF */
  2720.                 rc = 1;                 /* Success */
  2721.                 eof = 1;
  2722.                 goto xmitexit;          /* Done */
  2723.             }
  2724.             if (!xmitw && !xxecho) {    /* Special "blast" mode */
  2725.                 if (count == XBBUFSIZ) { /* File input buffer full... */
  2726.                     while (count > 0) {
  2727.                         errno = 0;
  2728.                         y = ttol(xbbuf,count);
  2729.                         if (y < 0) {    /* try to send it. */
  2730.                             printf("?TRANSMIT output error: %s\n",
  2731.                                    ck_errstr());
  2732.                             debug(F111,"XMIT binary ttol error",
  2733.                                   ck_errstr(),errno);
  2734.                             rc = 0;
  2735.                             break;
  2736.                         }
  2737.                         if (y < 0) break;
  2738.                         count -= y;
  2739.                     }
  2740.                     count = 0;
  2741.                 }
  2742.                 xbbuf[count++] = c;
  2743. #ifdef TNCODE
  2744.                 if (c == IAC && is_tn)  /* Telnet IAC */
  2745.                   xbbuf[count++] = IAC; /* must be doubled */
  2746. #endif /* TNCODE */
  2747.                 continue;
  2748.             }
  2749.             if (ttoc(dopar((char) c)) < 0) { /* else just send the char */
  2750.                 printf("?Can't transmit character\n");
  2751.                 goto xmitfail;
  2752.             }
  2753. #ifdef TNCODE
  2754.             if (c == IAC && is_tn)      /* Quote Telnet IAC */
  2755.               ttoc((char)IAC);
  2756. #endif /* TNCODE */
  2757.  
  2758.             if (xmitw)                  /* Pause if requested */
  2759.               msleep(xmitw);
  2760.  
  2761.             if (xxecho) {               /* SET TRANSMIT ECHO ON? */
  2762.                 if (duplex) {           /* Yes, for half duplex */
  2763. #ifndef NOLOCAL
  2764. #ifdef OS2
  2765.                     /* Echo to emulator */
  2766.                     scriptwrtbuf((USHORT)(c & cmdmsk));
  2767. #endif /* OS2 */
  2768. #endif /* NOLOCAL */
  2769.                     if (conoc((char)(c & cmdmsk)) < 0) /* echo locally. */
  2770.                       goto xmitfail;
  2771.                 } else {                /* For full duplex, */
  2772.                     int i, n;           /* display whatever is there. */
  2773.                     n = ttchk();        /* See how many chars are waiting */
  2774.                     if (n < 0) {        /* Connection dropped? */
  2775.                         printf("?Connection lost\n");
  2776.                         goto xmitfail;
  2777.                     }
  2778.                     for (i = 0; i < n; i++) { /* Read and echo that many. */
  2779.                         x = ttinc(xmitt); /* Timed read just in case. */
  2780.                         if (x > -1) {   /* If no timeout */
  2781.                             if (parity) x &= 0x7f; /* display the char, */
  2782. #ifndef NOLOCAL
  2783. #ifdef OS2
  2784.                             /* Echo to emulator */
  2785.                             scriptwrtbuf((USHORT)x);
  2786. #endif /* OS2 */
  2787. #endif /* NOLOCAL */
  2788.                             if (conoc((char)(x & cmdmsk)) < 0) {
  2789.                                 printf("?Output error\n");
  2790.                                 goto xmitfail;
  2791.                             }
  2792.                         } else if (x == -2) {
  2793.                             printf("Connection closed.\n");
  2794.                             ttclos(1);
  2795.                             goto xmitfail;
  2796.                         } else if (x == -3) {
  2797.                             printf(
  2798.                             "Session Limit exceeded - closing connection.\n"
  2799.                                    );
  2800.                             ttclos(1);
  2801.                             goto xmitfail;
  2802.                         } else {
  2803.                             printf("?Communications error\n");
  2804.                             goto xmitfail;
  2805.                         }
  2806.                     }
  2807.                 }
  2808.             } else ttflui();            /* Not echoing, just flush input. */
  2809.  
  2810.         } else {                        /* Text mode, line at a time. */
  2811. #ifdef UNICODE
  2812.             if (fcharset == FC_UCS2 && xlate) { /* Special for UCS-2 */
  2813.                 char xbuf[8];
  2814.                 x = 1 - (nbytes & 1);   /* Odd or even byte */
  2815.                 if (x == 0)             /* Note: 1 = the 1st, 0 = 2nd, etc */
  2816.                   uc.x_short = 0;
  2817.                 if (bomorder)           /* Little Endian */
  2818.                   x = 1 - x;            /* Save byte in appropriate half */
  2819.                 debug(F101,"XMIT UCS2 x","",x);
  2820.                 uc.x_char[x] = (CHAR) (c & 0xff);
  2821.                 if (nbytes & 1)         /* First byte, go back for next */
  2822.                   continue;
  2823.                 if (nbytes == 2) {      /* UCS-2 Byte Order Mark */
  2824.                     if (uc.x_short == (USHORT) 0xfeff) {
  2825.                         debug(F100,"XMIT UCS2 BOM FEFF","",bomorder);
  2826.                         continue;
  2827.                     } else if (uc.x_short == (USHORT) 0xfffe) {
  2828.                         bomorder = 1 - bomorder;
  2829.                         debug(F100,"XMIT UCS2 BOM FFFE (swap)","",bomorder);
  2830.                         continue;
  2831.                     }
  2832.                 }
  2833.                 sprintf(xbuf,"%04X",uc.x_short); /* SAFE */
  2834.                 debug(F111,"XMIT UCS2",xbuf,uc.x_short);
  2835.                 if (nbytes & 1)         /* Special eol test for UCS-2 */
  2836.                   if (uc.x_short == '\n')
  2837.                     eol = 1;
  2838. #ifdef COMMENT
  2839.                 if (uc.x_short == 0x2028 || uc.x_short == 0x2029)
  2840.                     eol = 1;
  2841. #endif /* COMMENT */
  2842.             } else
  2843. #endif /* UNICODE */
  2844.               if (c == '\n') {          /* Normal eol test otherwise */
  2845.                   eol = 1;
  2846.             }
  2847.             if (eol) {                  /* End of line? */
  2848.                 int stuff = -1;
  2849.                 debug(F101,"XMIT eol length","",i);
  2850.                 if (i == 0) {           /* Blank line? */
  2851.                     if (xmitf)          /* Yes, insert fill if asked. */
  2852.                       line[i++] = dopar((char) xmitf);
  2853.                 }
  2854.                 if (i == 0 || ((char) line[i-1]) != ((char) dopar(CR)))
  2855.                   line[i++] = dopar(CR); /* Terminate it with CR */
  2856.                 if (xmitl) {
  2857.                     stuff = LF;
  2858. #ifdef TNCODE
  2859.                 } else if (is_tn && (tn_nlm != TNL_CR)) {
  2860.                     /* TELNET NEWLINE ON/OFF/RAW */
  2861.                     stuff = (tn_nlm == TNL_CRLF) ? LF : NUL;
  2862. #endif /* TNCODE */
  2863.                 }
  2864.                 if (stuff > -1)
  2865.                   line[i++] = dopar((char)stuff);
  2866.                 line[i] = NUL;
  2867.                 debug(F111,"XMIT eol line",line,i);
  2868.  
  2869.             } else if (c != -1) {       /* Not a newline, regular character */
  2870.                 int k, x;
  2871.                 outxbuf[0] = c;         /* In case of no translation */
  2872.                 outxcount = 1;          /* Assume result is one byte */
  2873. #ifndef NOCSETS
  2874.                 switch (unicode) {
  2875.                   case 0:               /* No Unicode involved */
  2876.                   case 1:
  2877.                     if (xlate) {        /* If not /TRANSPARENT */
  2878.                         /* Local-to-intermediate */
  2879.                         if (sxo) c = (*sxo)((char)c);
  2880.                         /* Intermediate-to-remote */
  2881.                         if (rxo) c = (*rxo)((char)c);
  2882.                         outxbuf[0] = c;
  2883.                     }
  2884.                     break;
  2885. #ifdef UNICODE
  2886.                   case 2:               /* Local byte to UTF-8 */
  2887.                   case 3:
  2888.                     xfu = xl_fcu[fcharset];
  2889.                     tcssize = fcsinfo[fcharset].size;
  2890.                     outxcount =
  2891.                       b_to_u((CHAR)c,outxbuf,OUTXBUFSIZ,tcssize);
  2892.                     break;
  2893.                   case 4:               /* Local UTF-8 to remote byte */
  2894.                   case 5:
  2895.                     xuf = xl_ufc[tcsr];
  2896.                     x = u_to_b((CHAR)c); /* Convert to byte */
  2897.                     if (x == -1) {      /* If more input bytes needed */
  2898.                         continue;       /* go back and get them */
  2899.                     } else if (x == -2) { /* LS or PS (shouldn't happen) */
  2900.                         outxbuf[0] = CR;
  2901.                     } else if (x == -9) { /* UTF-8 error */
  2902.                         outxbuf[0] = '?'; /* Insert error char */
  2903.                         outxbuf[1] = u_to_b2(); /* Insert next char */
  2904.                         outxcount = 2;
  2905.                     } else {
  2906.                         outxbuf[0] =    /* Otherwise store result */
  2907.                           (unsigned)(x & 0xff);
  2908.                     }
  2909.                     break;
  2910.                   case 6:               /* UTF-8 to UTF-8 */
  2911.                   case 7:
  2912.                     break;
  2913.                   case 8:               /* UCS-2 to byte */
  2914.                   case 9:
  2915.                     xuf = xl_ufc[tcsr];
  2916.                     outxbuf[0] = (*xuf)(uc.x_short);
  2917.                     break;
  2918.                   case 10:
  2919.                   case 11: {            /* UCS-2 to UTF-8 */
  2920.                       int j;
  2921.                       CHAR * buf = NULL;
  2922.                       x = ucs2_to_utf8(uc.x_short,&buf);
  2923.                       if (x < 0) {
  2924.                           outxbuf[0] = 0xff; /* (= U+FFFD) */
  2925.                           outxbuf[1] = 0xbd;
  2926.                           x = 2;
  2927.                       }
  2928.                       for (j = 0; j < x; j++)
  2929.                         outxbuf[j] = buf[j];
  2930.                       outxcount = x;
  2931.                       break;
  2932.                   }
  2933. #endif /* UNICODE */
  2934.                 }
  2935. #endif /* NOCSETS */
  2936.                 outxbuf[outxcount] = NUL;
  2937.                 debug(F111,"XMIT outxbuf",outxbuf,outxcount);
  2938. /*
  2939.   Now the input character (1 or more bytes) is translated into the output
  2940.   expansion buffer (1 or more bytes); outxcount = number of bytes to add to
  2941.   the TRANSMIT line buffer, which we do here, taking care of parity, SI/SO
  2942.   processing, and quoting Telnet IACs.
  2943. */
  2944.                 for (k = 0; k < outxcount; k++) {
  2945.                     c = outxbuf[k];
  2946.                     if (xmits && parity && (c & 0200)) { /* If shifting */
  2947.                         line[i++] = dopar(SO); /* needs to be done, */
  2948.                         line[i++] = dopar((char)c); /* do it here, */
  2949.                         line[i++] = dopar(SI); /* crudely. */
  2950.                     } else {
  2951.                         line[i++] = dopar((char)c);
  2952. #ifdef TNCODE
  2953.                         if (c == IAC && is_tn)
  2954.                           line[i++] = IAC;
  2955. #endif /* TNCODE */
  2956.                     }
  2957.                 }
  2958.             }
  2959. /*
  2960.   Send characters if buffer full, or at end of line, or at end of file.
  2961.   (End of line only if echoing, waiting for a prompt, or pausing.)
  2962. */
  2963.             debug(F000,"XMIT c",ckitoa(i),c);
  2964.             if (i >= xbufsiz || eof || (eol && (xxecho || xmitw || t))) {
  2965.                 p = line;
  2966.                 line[i] = '\0';
  2967.                 debug(F111,"transmit buf",p,i);
  2968.                 if (ttol((CHAR *)p,i) < 0) { /* try to send it. */
  2969.                     printf("?TRANSMIT output error: %s\n",ck_errstr());
  2970.                     rc = 0;
  2971.                     break;
  2972.                 }
  2973.                 i = 0;                  /* Reset buffer pointer. */
  2974. /*
  2975.   Now we handle the echo.  If the user wants to see it, or if we have to
  2976.   wait for the turnaround character, t.  If the echo is being displayed,
  2977.   and terminal character-set translation is required, we do it here.
  2978. */
  2979.                 if (duplex && xxecho) {  /* If local echo, echo it */
  2980.                     if (parity || cmdmsk == 0x7f) { /* Strip hi bits */
  2981.                         char *ss = line;             /* if necessary */
  2982.                         while (*ss) {
  2983.                             *ss &= 0x7f;
  2984.                             ss++;
  2985.                         }
  2986.                     }
  2987. #ifndef NOLOCAL
  2988. #ifdef OS2
  2989.                     {                   /* Echo to emulator */
  2990.                         char *ss = p;
  2991.                         while (*ss) {
  2992.                             scriptwrtbuf((USHORT)*ss);
  2993.                             ss++;
  2994.                         }
  2995.                     }
  2996. #endif /* OS2 */
  2997. #endif /* NOLOCAL */
  2998.                     if (conoll(p) < 0)
  2999.                       goto xmitfail;
  3000.                 }
  3001.                 if (xmitw)              /* Sleep TRANSMIT PAUSE interval */
  3002.                   msleep(xmitw);
  3003.  
  3004.                 control = 0;            /* Readback loop control */
  3005.                 if (t != 0 && eol)      /* TRANSMIT PROMPT given and at EOL */
  3006.                   control |= 1;
  3007.                 if (xxecho && !duplex)   /* Echo desired and is remote */
  3008.                   control |= 2;
  3009.  
  3010.                 if (control) {          /* Do this if reading back the echo */
  3011.                     int n;
  3012.                     x = 0;
  3013.                     while (1) {
  3014.                         if (control & 1) { /* Termination criterion */
  3015.                             if (x == t)    /* for turnaround */
  3016.                               break;
  3017.                         } else if (control & 2) { /* And for echoing */
  3018.                             if ((n = ttchk()) < 1)
  3019.                               break;
  3020.                         }
  3021.                         if ((x = ttinc(xmitt)) < 0) { /* Read with timeout */
  3022.                             switch (x) {
  3023.                               case -2:
  3024.                                 printf("Connection closed.\n");
  3025.                                 ttclos(1);
  3026.                                 goto xmitfail;
  3027.                               case -3:
  3028.                                 printf(
  3029.                               "Session Limit exceeded - closing connection.\n"
  3030.                                        );
  3031.                                 ttclos(1); /* full thru... */
  3032.                                 goto xmitfail;
  3033.                               default:
  3034.                                 printf("?Timeout\n");
  3035.                                 goto xmitfail;
  3036.                             }
  3037.                         }
  3038.                         if (x > -1 && (control & 2)) { /* Echo any echoes */
  3039.                             if (parity)
  3040.                               x &= 0x7f;
  3041.                             c = x;
  3042. #ifndef NOLOCAL
  3043. #ifdef OS2
  3044.                             scriptwrtbuf((USHORT)x);
  3045. #endif /* OS2 */
  3046. #endif /* NOLOCAL */
  3047.                             inxbuf[0] = c;
  3048.                             inxcount = 1;
  3049. #ifndef NOCSETS
  3050.                             switch (unicode & 3) { /* Remote bits */
  3051.                               case 0:
  3052.                                 if (xlate) {
  3053.                                     if (sxi) c = (*sxi)((CHAR)c);
  3054.                                     if (rxi) c = (*rxi)((CHAR)c);
  3055.                                     inxbuf[0] = c;
  3056.                                 }
  3057.                                 break;
  3058. #ifdef UNICODE
  3059.                               case 1:   /* Remote Byte to local UTF-8 */
  3060.                                 xfu = xl_fcu[tcsr];
  3061.                                 tcssize = fcsinfo[tcsr].size;
  3062.                                 inxcount =
  3063.                                   b_to_u((CHAR)c,
  3064.                                          inxbuf,
  3065.                                          OUTXBUFSIZ,
  3066.                                          tcssize
  3067.                                          );
  3068.                                 break;
  3069.                               case 2:   /* Remote UTF-8 to local Byte */
  3070.                                 xuf = xl_ufc[tcsl];
  3071.                                 x = u_to_b((CHAR)c);
  3072.                                 if (x < 0)
  3073.                                   continue;
  3074.                                 inxbuf[0] = (unsigned)(x & 0xff);
  3075.                                 break;
  3076.                               case 3:   /* UTF-8 to UTF-8 */
  3077.                                 break;
  3078. #endif /* UNICODE */
  3079.                             }
  3080. #endif /* NOCSETS */
  3081.                             inxbuf[inxcount] = NUL;
  3082.                             if (conxo(inxcount,(char *)inxbuf) < 0)
  3083.                               goto xmitfail;
  3084.                         }
  3085.                     }
  3086.                 } else                  /* Not echoing */
  3087.                   ttflui();             /* Just flush input buffer */
  3088.             } /* End of buffer-dumping block */
  3089.         } /* End of text mode */
  3090.         if (eof) {
  3091.             rc = 1;
  3092.             goto xmitexit;
  3093.         }
  3094.     } /* End of character-reading loop */
  3095.  
  3096.   xmitfail:                             /* Failure exit point */
  3097.     rc = 0;
  3098.  
  3099.   xmitexit:                             /* General exit point */
  3100.     if (rc > 0) {
  3101.         if (binary && !xmitw && !xxecho) { /* "blasting"? */
  3102.             while (count > 0) {            /* Partial buffer still to go? */
  3103.                 errno = 0;
  3104.                 y = ttol(xbbuf,count);
  3105.                 if (y < 0) {
  3106.                     printf("?TRANSMIT output error: %s\n",
  3107.                            ck_errstr());
  3108.                     debug(F111,"XMIT binary eof ttol error",
  3109.                           ck_errstr(),errno);
  3110.                     rc = 0;
  3111.                     break;
  3112.                 }
  3113.                 count -= y;
  3114.             }
  3115.         } else if (!binary && *xmitbuf) { /* Anything to send at EOF? */
  3116.             p = xmitbuf;                /* Yes, point to string. */
  3117.             while (*p)                  /* Send it. */
  3118.               ttoc(dopar(*p++));        /* Don't worry about echo here. */
  3119.         }
  3120.     }
  3121.  
  3122. #ifndef AMIGA
  3123. #ifndef MAC
  3124.     signal(SIGINT,oldsig);              /* Put old signal action back. */
  3125. #endif /* MAC */
  3126. #endif /* AMIGA */
  3127. #ifdef VMS
  3128.     concb(escape);                      /* Put terminal back, */
  3129. #endif /* VMS */
  3130.     zclose(ZIFILE);                     /* Close file, */
  3131. #ifndef NOCSETS
  3132.     language = langsv;                  /* restore language, */
  3133. #endif /* NOCSETS */
  3134.     ttres();                            /* and terminal modes, */
  3135.     return(rc);                         /* and return successfully. */
  3136. }
  3137. #endif /* NOLOCAL */
  3138. #endif /* NOXMIT */
  3139.  
  3140. #ifndef NOCSETS
  3141.  
  3142. _PROTOTYP( CHAR (*sxx), (CHAR) );       /* Local translation function */
  3143. _PROTOTYP( CHAR (*rxx), (CHAR) );       /* Local translation function */
  3144. _PROTOTYP( CHAR zl1as, (CHAR) );        /* Latin-1 to ascii */
  3145. _PROTOTYP( CHAR xl1as, (CHAR) );        /* ditto */
  3146.  
  3147. /*  X L A T E  --  Translate a local file from one character set to another */
  3148.  
  3149. /*
  3150.   Translates input file (fin) from character set csin to character set csout
  3151.   and puts the result in the output file (fout).  The two character sets are
  3152.   file character sets from fcstab.
  3153. */
  3154.  
  3155. int
  3156. xlate(fin, fout, csin, csout) char *fin, *fout; int csin, csout; {
  3157.  
  3158. #ifndef MAC
  3159. #ifdef OS2
  3160.     extern int k95stdout;
  3161.     extern int wherex[], wherey[];
  3162.     extern unsigned char colorcmd;
  3163. #ifdef NT
  3164.     SIGTYP (* oldsig)(int);             /* For saving old interrupt trap. */
  3165. #else /* NT */
  3166.     SIGTYP (* volatile oldsig)(int);    /* For saving old interrupt trap. */
  3167. #endif /* NT */
  3168. #else /* OS2 */
  3169.     SIGTYP (* oldsig)();
  3170. #endif /* OS2 */
  3171. #endif /* MAC */
  3172. #ifdef CK_ANSIC
  3173.     int (*fn)(char);                    /* Output function pointer */
  3174. #else
  3175.     int (*fn)();
  3176. #endif /* CK_ANSIC */
  3177.     extern int xlatype;
  3178.     int filecode;                       /* Code for output file */
  3179.     int scrnflg = 0;
  3180.  
  3181.     int z = 1;                          /* Return code. */
  3182.     int x, c, c2;                       /* Workers */
  3183. #ifndef UNICODE
  3184.     int tcs;
  3185. #endif /* UNICODE */
  3186.  
  3187.     ffc = 0L;
  3188.  
  3189.     if (zopeni(ZIFILE,fin) == 0) {      /* Open the file to be translated */
  3190. #ifdef COMMENT
  3191.         /* An error message was already printed by zopeni() */
  3192.         printf("?Can't open input file %s\n",fin);
  3193. #endif /* COMMENT */
  3194.         return(0);
  3195.     }
  3196. #ifdef MAC
  3197. /*
  3198.   If user specified no output file, it goes to the screen.  For the Mac,
  3199.   this must be done a special way (result goes to a new window); the Mac
  3200.   doesn't have a "controlling terminal" device name.
  3201. */
  3202.     filecode = !strcmp(fout,CTTNAM) ? ZCTERM : ZOFILE;
  3203. #else
  3204. #ifdef VMS
  3205.     filecode = !strcmp(fout,CTTNAM) ? ZCTERM : ZMFILE;
  3206. #else
  3207. #ifdef OS2
  3208.     filecode = (!stricmp(fout,"con") || !stricmp(fout,"con:")) ?
  3209.         ZCTERM : ZMFILE;
  3210.     if ((filecode == ZCTERM) && !k95stdout && !inserver)
  3211.         csout = FC_UCS2;
  3212. #else /* OS2 */
  3213.     filecode = ZOFILE;
  3214. #endif /* OS2 */
  3215. #endif /* VMS */
  3216. #endif /* MAC */
  3217.     if (zopeno(filecode,fout,NULL,NULL) == 0) { /* And the output file */
  3218.         printf("?Can't open output file %s\n",fout);
  3219.         return(0);
  3220.     }
  3221. #ifndef AMIGA
  3222. #ifndef MAC
  3223.     oldsig = signal(SIGINT, trtrap);    /* Save current interrupt trap. */
  3224. #endif /* MAC */
  3225. #endif /* AMIGA */
  3226.  
  3227.     scrnflg = (filecode == ZCTERM);     /* Set output function */
  3228.     if (scrnflg)
  3229.       fn = NULL;
  3230.     else if (filecode == ZMFILE)
  3231.       fn = putmfil;
  3232.     else
  3233.       fn = putfil;
  3234.  
  3235.     tr_int = 0;                         /* Have not been interrupted (yet). */
  3236.     z = 1;                              /* Return code presumed good. */
  3237.  
  3238.     if (!scrnflg && !quiet)
  3239.       printf(" %s (%s) => %s (%s)\n",   /* Say what we're doing. */
  3240.              fin, fcsinfo[csin].keyword,
  3241.              fout,fcsinfo[csout].keyword
  3242.              );
  3243.  
  3244. #ifndef UNICODE
  3245. /*
  3246.   Non-Unicode picks the "most appropriate" transfer character set as the
  3247.   intermediate set, which results in loss of any characters that the source
  3248.   and target sets have in common, but are lacking from the intermediate set.
  3249. */
  3250. #ifdef KANJI
  3251.     /* Special handling for Japanese... */
  3252.  
  3253.     if (fcsinfo[csin].alphabet == AL_JAPAN ||
  3254.          fcsinfo[csout].alphabet == AL_JAPAN) {
  3255.         USHORT eu;
  3256.         int c, x, y;
  3257.  
  3258.         xpnbyte(-1,0,0,NULL);           /* Reset output machine */
  3259.         xlatype = XLA_JAPAN;
  3260.  
  3261.         while ((c = xgnbyte(FC_JEUC,csin,NULL)) > -1) { /* Get an EUC byte */
  3262.             if (tr_int) {               /* Interrupted? */
  3263.                 printf("^C...\n");      /* Print message */
  3264.                 z = 0;
  3265.                 break;
  3266.             }
  3267.             /* Send EUC byte to output machine */
  3268.             if ((x = xpnbyte(c,TC_JEUC,csout,fn)) < 0) {
  3269.                 z = -1;
  3270.                 break;
  3271.             }
  3272.         }
  3273.         goto xxlate;
  3274.     }
  3275. #endif /* KANJI */
  3276.  
  3277.     /* Regular bytewise conversion... */
  3278.  
  3279.     tcs = gettcs(csin,csout);           /* Get intermediate set. */
  3280.     if (csin == csout) {                /* Input and output sets the same? */
  3281.         sxx = rxx = NULL;               /* If so, no translation. */
  3282.     } else {                            /* Otherwise, set up */
  3283.         if (tcs < 0 || tcs > MAXTCSETS ||
  3284.             csin < 0 || csin > MAXFCSETS ||
  3285.             csout < 0 || csout > MAXFCSETS) {
  3286.             debug(F100,"XLATE csets out of range","",0);
  3287.             sxx = rxx = NULL;
  3288.         } else {
  3289.             sxx = xls[tcs][csin];       /* translation function */
  3290.             rxx = xlr[tcs][csout];      /* pointers. */
  3291.             if (rxx == zl1as) rxx = xl1as;
  3292.         }
  3293.     }
  3294.     while ((c = zminchar()) != -1) { /* Loop for all characters in file */
  3295.         if (tr_int) {                   /* Interrupted? */
  3296.             printf("^C...\n");          /* Print message */
  3297.             z = 0;
  3298.             break;
  3299.         }
  3300.         if (sxx) c = (*sxx)((CHAR)c);   /* From fcs1 to tcs */
  3301.         if (rxx) c = (*rxx)((CHAR)c);   /* from tcs to fcs2 */
  3302.         if (zchout(filecode,(char)c) < 0) { /* Output xlated character */
  3303.             z = -1;
  3304.             break;
  3305.         }
  3306.     }
  3307.     goto xxlate;                        /* Done. */
  3308.  
  3309. #else  /* UNICODE */
  3310. /*
  3311.    Use Unicode as the intermediate character set.  It's simple and gives
  3312.    little or no loss, but the overhead is a bit higher.
  3313. */
  3314.     initxlate(csin,csout);              /* Set up translation functions */
  3315.  
  3316.     if (xlatype == XLA_NONE) {
  3317.         while ((c = zminchar()) != -1) { /* Loop for all characters in file */
  3318.             if (tr_int) {               /* Interrupted? */
  3319.                 printf("^C...\n");      /* Print message */
  3320.                 z = 0;
  3321.                 break;
  3322.             }
  3323.             if (zchout(filecode,(char)c) < 0) { /* Output xlated character */
  3324.                 z = -1;
  3325.                 break;
  3326.             }
  3327.         }
  3328.         goto xxlate;                    /* Done. */
  3329.     }
  3330.  
  3331.  
  3332. #ifndef NOLOCAL
  3333. #ifdef OS2
  3334.     if (csout == FC_UCS2 &&             /* we're translating to UCS-2 */
  3335.         filecode == ZCTERM &&           /* for the real screen... */
  3336.         !k95stdout && !inserver
  3337.         ) {
  3338.         union {
  3339.             USHORT ucs2;
  3340.             UCHAR  bytes[2];
  3341.         } output;
  3342.  
  3343.         while (1) {                     /* In this case we go two-by-two. */
  3344.             if ((c = xgnbyte(FC_UCS2,csin,NULL)) < 0)
  3345.               break;
  3346.             output.bytes[0] = c;
  3347.             if ((c = xgnbyte(FC_UCS2,csin,NULL)) < 0)
  3348.               break;
  3349.             output.bytes[1] = c;
  3350.  
  3351.             if (tr_int) {               /* Interrupted? */
  3352.                 printf("^C...\n");      /* Print message */
  3353.                 z = 0;
  3354.                 break;
  3355.             }
  3356.  
  3357.             VscrnWrtUCS2StrAtt(VCMD,
  3358.                                &output.ucs2,
  3359.                                1,
  3360.                                wherey[VCMD],
  3361.                                wherex[VCMD],
  3362.                                &colorcmd
  3363.                                );
  3364.         }
  3365.     } else
  3366. #endif /* OS2 */
  3367. #endif /* NOLOCAL */
  3368.  
  3369.       /* General case: Get next byte translated from fcs to UCS-2 */
  3370.  
  3371. #ifdef COMMENT
  3372.       while ((c = xgnbyte(FC_UCS2,csin,NULL)) > -1 &&
  3373.               (c2 = xgnbyte(FC_UCS2,csin,NULL)) > -1) {
  3374.           extern int fileorder;
  3375.  
  3376.           if (tr_int) {                 /* Interrupted? */
  3377.               printf("^C...\n");        /* Print message */
  3378.               z = 0;
  3379.               break;
  3380.           }
  3381.           debug(F001,"XLATE c","",c);
  3382.           debug(F001,"XLATE c2","",c2);
  3383.  
  3384.           /* And then send UCS-2 byte to translate-and-output machine */
  3385.  
  3386.           if ((x = xpnbyte(fileorder?c2:c,TC_UCS2,csout,fn)) < 0) {
  3387.               z = -1;
  3388.               break;
  3389.           }
  3390.           if ((x = xpnbyte(fileorder?c:c2,TC_UCS2,csout,fn)) < 0) {
  3391.               z = -1;
  3392.               break;
  3393.           }
  3394.       }
  3395. #else
  3396.     while ((c = xgnbyte(FC_UCS2,csin,NULL)) > -1) {
  3397.           if (tr_int) {                 /* Interrupted? */
  3398.               printf("^C...\n");        /* Print message */
  3399.               z = 0;
  3400.               break;
  3401.           }
  3402.           if ((x = xpnbyte(c,TC_UCS2,csout,fn)) < 0) {
  3403.               z = -1;
  3404.               break;
  3405.           }
  3406.       }
  3407. #endif /* COMMENT */
  3408.  
  3409. #endif /* UNICODE */
  3410.  
  3411.   xxlate:                               /* Common exit point */
  3412.  
  3413. #ifndef AMIGA
  3414. #ifndef MAC
  3415.     signal(SIGINT,oldsig);              /* Put old signal action back. */
  3416. #endif /* MAC */
  3417. #endif /* AMIGA */
  3418.     tr_int = 0;
  3419.     if (z < 0) {
  3420.         if (z == -1)
  3421.           printf("?File output error: %s\n",ck_errstr());
  3422.         z = 0;
  3423.     }
  3424.     zclose(ZIFILE);                     /* Close files */
  3425.     zclose(filecode);                   /* ... */
  3426.     return(success = z);                /* and return status. */
  3427. }
  3428.  
  3429. int
  3430. doxlate() {
  3431. #ifdef OS2ONLY
  3432.     extern int tt_font;
  3433. #endif /* OS2ONLY */
  3434. #ifdef UNIX
  3435.     extern char ** mtchs;               /* zxpand() file list */
  3436. #endif /* UNIX */
  3437.     extern int nfilc;
  3438.     extern struct keytab fcstab[];
  3439.     int x, y, incs, outcs, multiple = 0, wild = 0, fc = 0, len = 0;
  3440.     int ofisdir = 0;
  3441.     char * s, * tocs = "";
  3442.  
  3443.     if ((x = cmifi("File(s) to translate","",&s,&wild,xxstring)) < 0) {
  3444.         if (x == -3) {
  3445.             printf("?Name of an existing file\n");
  3446.             return(-9);
  3447.         } else
  3448.           return(x);
  3449.     }
  3450.     ckstrncpy(line,s,LINBUFSIZ);        /* Save copy of string just parsed. */
  3451.  
  3452.     if ((incs = cmkey(fcstab,nfilc,"from character-set","",xxstring)) < 0)
  3453.       return(incs);
  3454.  
  3455. #ifdef OS2
  3456.     if (isunicode())
  3457.       tocs = "ucs2";
  3458.     else
  3459. #endif /* OS2 */
  3460.       tocs = getdcset();
  3461.  
  3462.     if ((outcs = cmkey(fcstab,nfilc,"to character-set",tocs,xxstring)) < 0)
  3463.       return(outcs);
  3464.     if ((x = cmofi("output file",CTTNAM,&s,xxstring)) < 0) return(x);
  3465.     if (x > 1)
  3466.       ofisdir = 1;
  3467.  
  3468.     len = ckstrncpy(tmpbuf,s,TMPBUFSIZ);
  3469.     if ((y = cmcfm()) < 0) return(y);   /* Confirm the command */
  3470.  
  3471.     if (len < 1)
  3472.       return(-2);
  3473.  
  3474.     if (ofisdir)
  3475.       multiple = 2;
  3476.     else if (wild) {
  3477.         if (isdir(tmpbuf))
  3478.           multiple = 2;
  3479.         else if (!strcmp(tmpbuf,CTTNAM))
  3480.           multiple = 1;
  3481. #ifdef OS2
  3482.         else if (!stricmp(tmpbuf,"con") || !stricmp(tmpbuf,"con:"))
  3483.           multiple = 1;
  3484. #else
  3485. #ifdef UNIXOROSK
  3486.         else if (!strncmp(tmpbuf,"/dev/",4))
  3487.           multiple = 1;
  3488. #endif /* UNIXOROSK */
  3489. #endif /* OS2 */
  3490.         if (!multiple) {
  3491.             printf("?A single file please\n");
  3492.             return(-9);
  3493.         }
  3494.     }
  3495.     if (!multiple) {                    /* Just one file */
  3496.         return(success = xlate(line,tmpbuf,incs,outcs));
  3497.     } else {                            /* Translate multiple files */
  3498.         char dirbuf[CKMAXPATH+4];
  3499.         int k;
  3500. #ifndef ZXREWIND
  3501.         int flags = ZX_FILONLY;
  3502. #endif /* ZXREWIND */
  3503.  
  3504.         if (multiple == 2) {            /* Target is a directory */
  3505.             k = ckstrncpy(dirbuf,tmpbuf,CKMAXPATH+1) - 1;
  3506.             if (k < 0)
  3507.               return(-2);
  3508. #ifdef OS2ORUNIX
  3509.             if (dirbuf[k] != '/') {
  3510.                 dirbuf[k+1] = '/';
  3511.                 dirbuf[k+2] = NUL;
  3512.             }
  3513. #else
  3514. #ifdef OSK
  3515.             if (dirbuf[k] != '/') {
  3516.                 dirbuf[k+1] = '/';
  3517.                 dirbuf[k+2] = NUL;
  3518.             }
  3519. #else
  3520. #ifdef VMS
  3521.             if (ckmatch("*.DIR;1",s,0,0))
  3522.               k = cvtdir(tmpbuf,dirbuf,TMPBUFSIZ);
  3523.             if (dirbuf[k] != ']' &&
  3524.                 dirbuf[k] != '>' &&
  3525.                 dirbuf[k] != ':')
  3526.               return(-2);
  3527. #else
  3528. #ifdef datageneral
  3529.             if (dirbuf[k] != ':') {
  3530.                 dirbuf[k+1] = ':';
  3531.                 dirbuf[k+2] = NUL;
  3532.             }
  3533. #else
  3534. #ifdef STRATUS
  3535.             if (dirbuf[k] != '>') {
  3536.                 dirbuf[k+1] = '>';
  3537.                 dirbuf[k+2] = NUL;
  3538.             }
  3539. #endif /* STRATUS */
  3540. #endif /* datageneral */
  3541. #endif /* VMS */
  3542. #endif /* OSK */
  3543. #endif /* OS2ORUNIX */
  3544.         }
  3545.  
  3546. #ifdef ZXREWIND
  3547.         fc = zxrewind();                /* Rewind the file list */
  3548. #else
  3549.         if (matchdot)  flags |= ZX_MATCHDOT;
  3550.         fc = nzxpand(line,flags);
  3551. #endif /* ZXREWIND */
  3552.  
  3553.         if (fc < 1) {
  3554.             printf("?Wildcard expansion error\n");
  3555.             return(-9);
  3556.         }
  3557. #ifdef UNIX
  3558.         sh_sort(mtchs,NULL,fc,0,0,filecase); /* Sort the file list */
  3559. #endif /* UNIX */
  3560.  
  3561.         while (1) {                     /* Loop through the files */
  3562.             znext(line);
  3563.             if (!line[0])
  3564.               break;
  3565.             if (multiple == 2)
  3566.               ckmakmsg(tmpbuf,TMPBUFSIZ,dirbuf,line,NULL,NULL);
  3567.             if (xlate(line,tmpbuf,incs,outcs) < 1)
  3568.               return(success = 0);
  3569.         }
  3570.     }
  3571.     return(success = 1);
  3572. }
  3573. #endif /* NOCSETS */
  3574.  
  3575. static char hompthbuf[CKMAXPATH+1];
  3576.  
  3577. char *
  3578. homepath() {
  3579.     int x;
  3580.     extern char * myhome;
  3581.     char * h;
  3582.  
  3583.     h = myhome ? myhome : zhome();
  3584.     hompthbuf[0] = NUL;
  3585. #ifdef UNIXOROSK
  3586.     x = ckstrncpy(hompthbuf,h,CKMAXPATH+1);
  3587.     if (x <= 0) {
  3588.         hompthbuf[0] = '/';
  3589.         hompthbuf[1] = NUL;
  3590.     } else if (x < CKMAXPATH - 2 && hompthbuf[x-1] != '/') {
  3591.         hompthbuf[x] = '/';
  3592.         hompthbuf[x+1] = NUL;
  3593.     }
  3594.     return(hompthbuf);
  3595. #else
  3596. #ifdef STRATUS
  3597.     if (strlen(h) < CKMAXPATH)
  3598.       sprintf(hompthbuf,"%s>",h);    /* SAFE */
  3599.     return(hompthbuf);
  3600. #else
  3601.     return(h);
  3602. #endif /* STRATUS */
  3603. #endif /* UNIXOROSK */
  3604. }
  3605.  
  3606. /*  D O L O G  --  Do the log command  */
  3607.  
  3608. int
  3609. dolog(x) int x; {
  3610.     int y, disp; char *s = NULL, * p = NULL, * q = NULL;
  3611.     extern int isguest;
  3612. #ifdef ZFNQFP
  3613.     struct zfnfp * fnp;
  3614. #endif /* ZFNQFP */
  3615.  
  3616.     if (isguest) {
  3617.         printf("?Anonymous log creation not allowed\n");
  3618.         return(-9);
  3619.     }
  3620.     switch (x) {                        /* Which log... */
  3621.  
  3622. #ifdef DEBUG
  3623.       case LOGD:
  3624.         q = "debug.log";
  3625.         y = cmofi("Name of debugging log file",q,&s,xxstring);
  3626.         break;
  3627. #endif /* DEBUG */
  3628.  
  3629.       case LOGP:
  3630.         q = "packet.log";
  3631.         y = cmofi("Name of packet log file",q,&s,xxstring);
  3632.         break;
  3633.  
  3634. #ifndef NOLOCAL
  3635.       case LOGS:
  3636.         q = "session.log";
  3637.         y = cmofi("Name of session log file",q,&s,xxstring);
  3638.         break;
  3639. #endif /* NOLOCAL */
  3640.  
  3641. #ifdef TLOG
  3642.       case LOGT:
  3643.         q = "transact.log";
  3644.         y = cmofi("Name of transaction log file",q,&s,xxstring);
  3645.         break;
  3646. #endif /* TLOG */
  3647.  
  3648. #ifdef CKLOGDIAL
  3649.       case LOGM: {
  3650.           int m, n;
  3651.           char mypath[CKMAXPATH+1];
  3652.           q = CXLOGFILE;
  3653.           m = ckstrncpy(mypath,homepath(),CKMAXPATH);
  3654.           n = strlen(CXLOGFILE);
  3655.           if (m + n < CKMAXPATH)
  3656.             ckstrncat(mypath,CXLOGFILE,CKMAXPATH);
  3657.           else
  3658.             ckstrncpy(mypath,CXLOGFILE,CKMAXPATH);
  3659.           y = cmofi("Name of connection log file",mypath,&s,xxstring);
  3660.           break;
  3661.       }
  3662. #endif /* CKLOGDIAL */
  3663.  
  3664.       default:
  3665.         printf("\n?Unknown log designator - %d\n",x);
  3666.         return(-2);
  3667.     }
  3668.     if (y < 0) return(y);
  3669.     if (y == 2) {                       /* If they gave a directory name */
  3670.         int k;
  3671.         char * ds = "/";
  3672.         k = strlen(s);
  3673.         if (k > 0 && s[k-1] == '/') ds = "";
  3674.         ckmakmsg(tmpbuf,TMPBUFSIZ,s,ds,q,NULL);
  3675.         s = tmpbuf;
  3676.     }
  3677. #ifdef ZFNQFP
  3678. #ifdef OS2ORUNIX
  3679.     if (*s != '|')                      /* Allow for pipes */
  3680. #else
  3681. #ifdef OSK
  3682.     if (*s != '|')
  3683. #endif /* OSK */
  3684. #endif /* OS2ORUNIX */
  3685.       if ((fnp = zfnqfp(s,TMPBUFSIZ - 1,tmpbuf))) {
  3686.           if (fnp->fpath)
  3687.             if ((int) strlen(fnp->fpath) > 0)
  3688.               s = fnp->fpath;
  3689.       } /* else if error keep original string */
  3690. #endif /* ZFNQFP */
  3691.  
  3692.     ckstrncpy(line,s,LINBUFSIZ);
  3693.     s = line;
  3694. #ifdef MAC
  3695.     y = 0;
  3696. #else
  3697.  
  3698.     p = "new";
  3699. #ifdef TLOG
  3700.     if ((x == LOGT && tlogfmt == 2) || x == LOGM)
  3701.       p = "append";
  3702. #endif /* TLOG */
  3703.  
  3704.     if ((y = cmkey(disptb,2,"Disposition",p,xxstring)) < 0)
  3705.       return(y);
  3706. #endif /* MAC */
  3707.     disp = y;
  3708.     if ((y = cmcfm()) < 0) return(y);
  3709.  
  3710.     switch (x) {
  3711.  
  3712. #ifdef DEBUG
  3713.       case LOGD:
  3714.         return(deblog = debopn(s,disp));
  3715. #endif /* DEBUG */
  3716.  
  3717. #ifndef NOXFER
  3718.       case LOGP:
  3719.         return(pktlog = pktopn(s,disp));
  3720. #endif /* NOXFER */
  3721.  
  3722. #ifndef NOLOCAL
  3723.       case LOGS:
  3724.         setseslog(sesopn(s,disp));
  3725.         return(seslog);
  3726. #endif /* NOLOCAL */
  3727.  
  3728. #ifdef TLOG
  3729.       case LOGT:
  3730.         return(tralog = traopn(s,disp));
  3731. #endif /* TLOG */
  3732.  
  3733. #ifdef CKLOGDIAL
  3734.       case LOGM:
  3735.         return(dialog = diaopn(s,disp,0));
  3736. #endif /* CKLOGDIAL */
  3737.  
  3738.       default:
  3739.         return(-2);
  3740.     }
  3741. }
  3742.  
  3743. #ifndef NOXFER
  3744. int
  3745. pktopn(s,disp) char *s; int disp; {
  3746.     static struct filinfo xx;
  3747.  
  3748.     if (!s)
  3749.       s = "";
  3750.     if (!*s)
  3751.       return(0);
  3752.  
  3753.     debug(F111,"pktopn",s,disp);
  3754.  
  3755.     zclose(ZPFILE);
  3756.  
  3757. #ifdef OS2ORUNIX
  3758.     if (s[0] == '|') {                  /* Pipe */
  3759.         char * p = s + 1;
  3760.         debug(F110,"pktopn p",p,0);
  3761.         while (*p) {
  3762.             if (*p != ' ')
  3763.               break;
  3764.             else
  3765.               p++;
  3766.         }
  3767.         debug(F110,"pktopn pipe",p,0);
  3768.         pktlog = zxcmd(ZPFILE,p);
  3769.         debug(F101,"pktopn seslog","",seslog);
  3770.     } else {                            /* File */
  3771. #endif /* OS2ORUNIX */
  3772.         if (disp) {
  3773.             xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
  3774.             xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
  3775.             xx.lblopts = 0;
  3776.             pktlog = zopeno(ZPFILE,s,NULL,&xx);
  3777.         } else pktlog = zopeno(ZPFILE,s,NULL,NULL);
  3778.         if (!pktlog)
  3779.           printf("?%s - %s\n",s,ck_errstr());
  3780. #ifdef OS2ORUNIX
  3781.     }
  3782. #endif /* OS2ORUNIX */
  3783.     if (pktlog > 0)
  3784.       ckstrncpy(pktfil,s,CKMAXPATH+1);
  3785.     else
  3786.       *pktfil = '\0';
  3787.     return(pktlog);
  3788. }
  3789. #endif /* NOXFER */
  3790.  
  3791. int
  3792. traopn(s,disp) char *s; int disp; {
  3793. #ifdef TLOG
  3794.     static struct filinfo xx;
  3795.  
  3796.     if (!s)
  3797.       s = "";
  3798.     if (!*s)
  3799.       return(0);
  3800.  
  3801.     debug(F111,"traopn",s,disp);
  3802.     debug(F101,"traopn tlogfmt","",tlogfmt);
  3803.  
  3804.     zclose(ZTFILE);
  3805.  
  3806. #ifdef OS2ORUNIX
  3807.     if (tlogfmt == 2) {                 /* FTP format is special... */
  3808.         VOID doiklog();
  3809.         if (!disp)                      /* Append? */
  3810.           if (zchki(s) > -1)            /* No - does file exist? */
  3811.             (VOID) zdelet(s);           /* Yes - delete it. */
  3812.         xferlog = 1;
  3813.         ckstrncpy(trafil,s,CKMAXPATH);
  3814.         makestr(&xferfile,s);
  3815.         doiklog();
  3816.         return(1);
  3817.     }
  3818.     if (s[0] == '|') {                  /* Pipe */
  3819.         char * p = s + 1;
  3820.         debug(F110,"traopn p",p,0);
  3821.         while (*p) {
  3822.             if (*p != ' ')
  3823.               break;
  3824.             else
  3825.               p++;
  3826.         }
  3827.         debug(F110,"traopn pipe",p,0);
  3828.         tralog = zxcmd(ZTFILE,p);
  3829.         debug(F101,"traopn tralog","",tralog);
  3830.     }
  3831. #endif /* OS2ORUNIX */
  3832.  
  3833.     if (s[0] != '|') {                  /* File */
  3834.         if (disp) {
  3835.             xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
  3836.             xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
  3837.             xx.lblopts = 0;
  3838.             tralog = zopeno(ZTFILE,s,NULL,&xx);
  3839.         } else tralog = zopeno(ZTFILE,s,NULL,NULL);
  3840.     }
  3841.     if (!tralog)
  3842.       printf("?%s - %s\n",s,ck_errstr());
  3843.     if (tralog > 0 && tlogfmt > 0) {
  3844.         ckstrncpy(trafil,s,CKMAXPATH);
  3845.         tlog(F110,"Transaction Log:",versio,0L);
  3846. #ifndef MAC
  3847.         tlog(F100,ckxsys,"",0L);
  3848. #endif /* MAC */
  3849.         ztime(&s);
  3850.         tlog(F100,s,"",0L);
  3851.     } else
  3852.       *trafil = '\0';
  3853.     return(tralog);
  3854. #else
  3855.     return(0);
  3856. #endif /* TLOG */
  3857. }
  3858.  
  3859. #ifndef NOLOCAL
  3860. int
  3861. sesopn(s,disp) char * s; int disp; {
  3862.     static struct filinfo xx;
  3863.     extern int tsstate;
  3864.  
  3865.     tsstate = 0;                        /* Session log timestamp state */
  3866.  
  3867.     if (!s)
  3868.       s = "";
  3869.     if (!*s)
  3870.       return(0);
  3871.  
  3872.     debug(F111,"sesopn",s,disp);
  3873.  
  3874.     zclose(ZSFILE);
  3875.  
  3876. #ifdef OS2ORUNIX
  3877.     if (s[0] == '|') {                  /* Pipe */
  3878.         char * p = s + 1;
  3879.         debug(F110,"sesopn p",p,0);
  3880.         while (*p) {
  3881.             if (*p != ' ')
  3882.               break;
  3883.             else
  3884.               p++;
  3885.         }
  3886.         debug(F110,"sesopn pipe",p,0);
  3887.         setseslog(zxcmd(ZSFILE,p));
  3888.         debug(F101,"sesopn seslog","",seslog);
  3889.     } else {                            /* File */
  3890. #endif /* OS2ORUNIX */
  3891.         if (disp) {
  3892.             xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
  3893.             xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
  3894.             xx.lblopts = 0;
  3895.             setseslog(zopeno(ZSFILE,s,NULL,&xx));
  3896.         } else
  3897.           setseslog(zopeno(ZSFILE,s,NULL,NULL));
  3898.         if (!seslog)
  3899.           printf("?%s - %s\n",s,ck_errstr());
  3900. #ifdef OS2ORUNIX
  3901.     }
  3902. #endif /* OS2ORUNIX */
  3903.     if (seslog > 0)
  3904.       ckstrncpy(sesfil,s,CKMAXPATH+1);
  3905.     else
  3906.       *sesfil = '\0';
  3907.     return(seslog);
  3908. }
  3909. #endif /* NOLOCAL */
  3910. #endif /* NOICP */
  3911.  
  3912. int
  3913. debopn(s,disp) char *s; int disp; {
  3914. #ifdef DEBUG
  3915. #ifdef CK_UTSNAME
  3916.     extern char unm_mch[], unm_nam[], unm_rel[], unm_ver[], unm_mod[];
  3917. #endif /* CK_UTSNAME */
  3918. #ifdef OS2
  3919.     extern char ckxsystem[];
  3920. #endif /* OS2 */
  3921.     char *tp;
  3922.     static struct filinfo xx;
  3923.  
  3924.     if (!s)
  3925.       s = "";
  3926.     if (!*s)
  3927.       return(0);
  3928.  
  3929.     zclose(ZDFILE);
  3930.  
  3931. #ifdef OS2ORUNIX
  3932.     if (s[0] == '|') {                  /* Pipe */
  3933.         char * p = s + 1;
  3934.         debug(F110,"debopn p",p,0);
  3935.         while (*p) {
  3936.             if (*p != ' ')
  3937.               break;
  3938.             else
  3939.               p++;
  3940.         }
  3941.         debug(F110,"debopn pipe",p,0);
  3942.         deblog = zxcmd(ZDFILE,p);
  3943.         debug(F101,"debopn deblog","",deblog);
  3944.     } else {                            /* File */
  3945. #endif /* OS2ORUNIX */
  3946.         if (disp) {
  3947.             xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
  3948.             xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
  3949.             xx.lblopts = 0;
  3950.             deblog = zopeno(ZDFILE,s,NULL,&xx);
  3951.         } else
  3952.           deblog = zopeno(ZDFILE,s,NULL,NULL);
  3953.         if (!deblog)
  3954.           printf("?%s - %s\n",s,ck_errstr());
  3955. #ifdef OS2ORUNIX
  3956.     }
  3957. #endif /* OS2ORUNIX */
  3958.     if (deblog > 0) {
  3959.         ckstrncpy(debfil,s,CKMAXPATH+1);
  3960.         debug(F110,"Debug Log ",versio,0);
  3961. #ifndef MAC
  3962. #ifdef OS2
  3963.         debug(F110,ckxsys,ckxsystem,0);
  3964. #else /* OS2 */
  3965.         debug(F100,ckxsys,"",0);
  3966. #endif /* OS2 */
  3967. #endif /* MAC */
  3968. #ifdef CK_UTSNAME
  3969.         if (unm_mch[0]) {
  3970.             debug(F110,"uname machine",unm_mch,0);
  3971.             if (unm_mod[0])
  3972.               debug(F110,"uname model  ",unm_mod,0);
  3973.             debug(F110,"uname sysname",unm_nam,0);
  3974.             debug(F110,"uname release",unm_rel,0);
  3975.             debug(F110,"uname version",unm_ver,0);
  3976.         }
  3977. #ifdef KTARGET
  3978.         {
  3979.             char * s;                   /* Makefile target */
  3980.             s = KTARGET;
  3981.             if (!s) s = "";
  3982.             if (!*s) s = "(unknown)";
  3983.             debug(F110,"build target",s,0);
  3984.         }
  3985. #endif /* KTARGET */
  3986.         deblog = 0;
  3987.         ztime(&tp);
  3988.         deblog = 1;
  3989.         debug(F100,tp,"",0);
  3990. #endif /* UTSNAME */
  3991.         debug(F101,"byteorder","",byteorder);
  3992. #ifndef NOICP
  3993. #ifndef NOLOCAL
  3994.         if (local) {
  3995.             debug(F110,"Active connection: ",ttname,0);
  3996.             if (!network) {
  3997.                 debug(F101,"Speed","",speed);
  3998.                 if (hwparity)
  3999.                   debug(F110,"Parity[hardware]",parnam((char)hwparity),0);
  4000.                 else
  4001.                   debug(F110,"Parity",parnam((char)parity),0);
  4002.                 deblog = 0;
  4003.                 debug(F110,"Modem",gmdmtyp(),0);
  4004.                 deblog = 1;
  4005.             }
  4006.         } else {
  4007.             debug(F110,"Active connection: ","none",0);
  4008.         }
  4009. #endif /* NOLOCAL */
  4010. #endif /* NOICP */
  4011.     } else *debfil = '\0';
  4012.     return(deblog);
  4013. #else
  4014.     return(0);
  4015. #endif /* MAC */
  4016. }
  4017.  
  4018.  
  4019. /*  C K D A T E  --  Returns current date/time in standard format  */
  4020.  
  4021. static char nowbuf[18];
  4022.  
  4023. char *
  4024. ckdate() {
  4025.     extern struct keytab cmonths[];
  4026.     int x;
  4027.     char * t;                   /* Substitute today's date */
  4028.     char dbuf[32];
  4029.     ztime(&t);
  4030.  
  4031. /*  012345678901234567890123 */
  4032. /*  Sat Jul  4 12:16:43 1998 */
  4033.  
  4034.     ckstrncpy(dbuf,t,32);
  4035.     t = dbuf;
  4036.     debug(F110,"ckdate dbuf",dbuf,0);
  4037.     nowbuf[0] = t[20];
  4038.     nowbuf[1] = t[21];
  4039.     nowbuf[2] = t[22];
  4040.     nowbuf[3] = t[23];
  4041.  
  4042.     nowbuf[4] = NUL;
  4043.     debug(F110,"ckdate nowbuf",nowbuf,0);
  4044.  
  4045.     t[7] = NUL;
  4046.     if ((x = lookup(cmonths,t+4,12,NULL)) < 0) {
  4047.         debug(F110,"ckdate bad month",t,0);
  4048.         return("<BAD_MONTH>");
  4049.     }
  4050.     sprintf(nowbuf+4,"%02d",x);         /* SAFE */
  4051.     nowbuf[6] = (t[8] == SP) ? '0' : t[8];
  4052.     nowbuf[7] = t[9];
  4053.     nowbuf[8] = ' ';
  4054.  
  4055.     nowbuf[9] = NUL;
  4056.     debug(F110,"ckdate nowbuf",nowbuf,0);
  4057.  
  4058.     for (x = 11; x < 19; x++) nowbuf[x-2] = t[x];
  4059.     nowbuf[17] = NUL;
  4060.     debug(F110,"ckdate nowbuf",nowbuf,0);
  4061.  
  4062.     return((char *)nowbuf);
  4063. }
  4064.  
  4065. #ifndef NOICP
  4066. #ifdef CKLOGDIAL
  4067.  
  4068. /*
  4069.   fc = 0 for initial open, meaning open, then close immediately.
  4070.   fc > 0 for subsequent opens, meaning open for use, leave open.
  4071. */
  4072. int
  4073. diaopn(s,disp,fc) char *s; int disp, fc; {
  4074.     static struct filinfo xx;
  4075.  
  4076.     if (!s)
  4077.       s = "";
  4078.     if (!*s)
  4079.       return(0);
  4080.  
  4081.     debug(F110,"diaopn log",s,0);
  4082.     debug(F101,"diaopn fc",s,fc);
  4083.     debug(F101,"diaopn disp 1",s,disp);
  4084.     if (fc) disp = 1;                   /* Force append if open for use */
  4085.     debug(F101,"diaopn disp 2",s,disp);
  4086.  
  4087.     zclose(ZDIFIL);                     /* In case a log was already open */
  4088.  
  4089. #ifdef OS2ORUNIX
  4090.     if (s[0] == '|') {                  /* Pipe */
  4091.         char * p = s + 1;
  4092.         debug(F110,"diaopn p",p,0);
  4093.         while (*p) {
  4094.             if (*p != ' ')
  4095.               break;
  4096.             else
  4097.               p++;
  4098.         }
  4099.         debug(F110,"diaopn pipe",p,0);
  4100.         dialog = zxcmd(ZDIFIL,p);
  4101.         debug(F101,"diaopn dialog","",dialog);
  4102.     } else {                            /* File */
  4103. #endif /* OS2ORUNIX */
  4104.         if (disp) {
  4105.             xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
  4106.             xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
  4107.             xx.lblopts = 0;
  4108.             dialog = zopeno(ZDIFIL,s,NULL,&xx);
  4109.         } else dialog = zopeno(ZDIFIL,s,NULL,NULL);
  4110.         if (!dialog)
  4111.           printf("?%s - %s\n",s,ck_errstr());
  4112. #ifdef OS2ORUNIX
  4113.     }
  4114. #endif /* OS2ORUNIX */
  4115.     if (dialog > 0)
  4116.       ckstrncpy(diafil,s,CKMAXPATH+1);
  4117.     else
  4118.       *diafil = '\0';
  4119.     if (fc == 0)                        /* Initial open */
  4120.       zclose(ZDIFIL);                   /* close it */
  4121.     return(dialog);
  4122. }
  4123. #endif /* CKLOGDIAL */
  4124.  
  4125. #ifndef NOSHOW
  4126.  
  4127. /*  SHOW command routines */
  4128.  
  4129. char *
  4130. shoxm() {
  4131.     char * s;
  4132.     switch (binary) {
  4133.       case XYFT_T: s = "text";         break;
  4134. #ifdef VMS
  4135.       case XYFT_B: s = "binary fixed"; break;
  4136.       case XYFT_I: s = "image";        break;
  4137.       case XYFT_L: s = "labeled";      break;
  4138.       case XYFT_U: s = "binary undef"; break;
  4139. #else
  4140. #ifdef MAC
  4141.       case XYFT_B: s = "binary";       break;
  4142.       case XYFT_M: s = "macbinary";    break;
  4143. #else
  4144.       case XYFT_B: s = "binary";       break;
  4145. #ifdef CK_LABELED
  4146.       case XYFT_L: s = "labeled";      break;
  4147. #endif /* CK_LABELED */
  4148. #endif /* MAC */
  4149. #endif /* VMS */
  4150.       default: s = "unknown"; break;
  4151.     }
  4152.     return(s);
  4153. }
  4154.  
  4155. #ifndef NOXFER
  4156. VOID                                    /* SHOW TRANSFER */
  4157. shoxfer() {
  4158.     extern int docrc, usepipes, xfrxla, whereflg;
  4159.     extern char * xfrmsg;
  4160.     printf("\n");
  4161.     printf(" Transfer Bell: %s\n",showoff(xfrbel));
  4162.     printf(" Transfer Interruption: %s\n",showoff(xfrint));
  4163.     printf(" Transfer Cancellation: %s\n",showoff(xfrcan));
  4164. #ifndef NOCSETS
  4165.     printf(" Transfer Translation:  %s\n",showoff(xfrxla));
  4166.     printf(" Transfer Character-set: ");
  4167.     if (tcharset == TC_TRANSP)
  4168.       printf("Transparent\n");
  4169.     else
  4170.       printf("%s\n",tcsinfo[tcharset].keyword);
  4171. #endif /* NOCSETS */
  4172.     printf(" Transfer CRC-calculation: %s\n",showoff(docrc));
  4173.     printf(" Transfer Display: ");
  4174.     switch (fdispla) {
  4175.       case XYFD_N: printf("%s\n","none"); break;
  4176.       case XYFD_R: printf("%s\n","serial"); break;
  4177.       case XYFD_C: printf("%s\n","fullscreen"); break;
  4178.       case XYFD_S: printf("%s\n","crt"); break;
  4179.       case XYFD_B: printf("%s\n","brief"); break;
  4180.       case XYFD_G: printf("%s\n","gui"); break;
  4181.     }
  4182.     printf(" Transfer Message: %s\n", xfrmsg ? xfrmsg : "(none)");
  4183.     printf(" Transfer Locking-shift: ");
  4184.     if (lscapu == 2) {
  4185.         printf("forced");
  4186.     } else {
  4187.         printf("%s", (lscapr ? "enabled" : "disabled"));
  4188.         if (lscapr) printf(",%s%s", (lscapu ? " " : " not "), "used");
  4189.     }
  4190.     printf("\n Transfer Mode: %s\n",
  4191.            xfermode == XMODE_A ?
  4192.            "automatic" :
  4193.            "manual"
  4194.            );
  4195.     printf(" Transfer Pipes: %s\n", showoff(usepipes));
  4196.     printf(" Transfer Protocol: %s\n",ptab[protocol].p_name);
  4197.     printf(" Transfer Report: %s\n",showoff(whereflg));
  4198.     printf(" Transfer Slow-start: %s\n",showoff(slostart));
  4199.     printf("\n");
  4200. }
  4201. #endif /* NOXFER */
  4202.  
  4203. VOID
  4204. shoflow() {
  4205.     int i, x;
  4206.     extern int cxflow[], cxtype, ncxname, nfloname, autoflow;
  4207.     extern char * cxname[];
  4208.     printf("\nConnection type:        %s\n",cxname[cxtype]);
  4209.     if (autoflow) {
  4210.         printf("Current flow-control:   %s\n", floname[cxflow[cxtype]]);
  4211.         printf("Switches automatically: yes\n");
  4212.     } else {
  4213.         printf("Current flow-control:   %s\n", floname[flow]);
  4214.         printf("Switches automatically: no\n");
  4215.     }
  4216.     printf("\nDefaults by connection type:\n");
  4217.     debug(F111,"shoflow cxtype",cxname[cxtype],cxtype);
  4218.     debug(F101,"shoflow flow","",flow);
  4219.     for (i = 0; i < ncxname; i++) {
  4220. #ifdef NOLOCAL
  4221.         if (i > 0) break;
  4222. #endif /* NOLOCAL */
  4223. #ifndef NETCONN
  4224.         if (i > 2) break;
  4225. #endif /* NETCONN */
  4226. #ifndef DECNET
  4227.         if (i == CXT_DECNET) continue;
  4228. #endif /* DECNET */
  4229. #ifndef DECNET
  4230. #ifndef SUPERLAT
  4231.         if (i == CXT_LAT) continue;
  4232. #endif /* SUPERLAT */
  4233. #endif /* DECNET */
  4234. #ifndef CK_NETBIOS
  4235.         if (i == CXT_NETBIOS) continue;
  4236. #endif /* CK_NETBIOS */
  4237. #ifndef NPIPE
  4238.         if (i == CXT_NPIPE) continue;
  4239. #endif /* NPIPE */
  4240. #ifndef NETCMD
  4241.         if (i == CXT_PIPE) continue;
  4242. #endif /* NETCMD */
  4243. #ifndef ANYX25
  4244.         if (i == CXT_X25) continue;
  4245. #endif /* ANYX25 */
  4246.         x = cxflow[i];
  4247.         debug(F101,"shoflow x","",x);
  4248.         if (x < nfloname)
  4249.           printf("  %-14s: %s\n",cxname[i],floname[x]);
  4250.         else
  4251.           printf("  %-14s: (%d)\n",cxname[i],x);
  4252.     }
  4253.     printf("\n");
  4254. }
  4255.  
  4256. #ifndef NOLOCAL
  4257. #ifdef ANYX25
  4258. int
  4259. shox25(n) int n; {
  4260.     if (nettype == NET_SX25) {
  4261.         printf("SunLink X.25 V%d.%d",x25ver / 10,x25ver % 10);
  4262.         if (ttnproto == NP_X3) printf(", PAD X.3, X.28, X.29 protocol,");
  4263.         printf("\n");
  4264.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4265.         printf(" Reverse charge call %s",
  4266.                revcall ? "selected" : "not selected");
  4267.         printf (", Closed user group ");
  4268.         if (closgr > -1)
  4269.           printf ("%d",closgr);
  4270.         else
  4271.           printf ("not selected");
  4272.         printf("\n");
  4273.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4274.         printf(" Call user data %s.\n", cudata ? udata : "not selected");
  4275.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4276.     } else if (nettype == NET_VX25) {
  4277.         if (ttnproto == NP_X3) printf(", PAD X.3, X.28, X.29 protocol,");
  4278.         printf("\n");
  4279.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4280.         printf(" Reverse charge call %s",
  4281.                revcall ? "selected" : "not selected");
  4282.         printf (", Closed user group [unsupported]");
  4283.         if (closgr > -1)
  4284.           printf ("%d",closgr);
  4285.         else
  4286.           printf ("not selected");
  4287.         printf (",");
  4288.         printf("\n");
  4289.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4290.         printf(" Call user data %s.\n", cudata ? udata : "not selected");
  4291.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4292.     } else if (nettype == NET_IX25) {
  4293.         printf("AIX NPI X.25\n");
  4294.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4295.         printf("\n Reverse charge call %s",
  4296.                revcall ? "selected" : "not selected");
  4297.         printf (", Closed user group [unsupported]");
  4298.         if (closgr > -1)
  4299.           printf ("%d",closgr);
  4300.         else
  4301.           printf ("not selected");
  4302.         printf (",");
  4303.         printf("\n Call user data %s.\n", cudata ? udata : "not selected");
  4304.     }
  4305.     return(n);
  4306. }
  4307.  
  4308. #ifndef IBMX25
  4309. int
  4310. shopad(n) int n; {
  4311.     int i;
  4312.     printf("\nX.3 PAD Parameters:\n");
  4313.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4314.     for (i = 0; i < npadx3; i++) {
  4315.         printf(" [%d] %s %d\n",padx3tab[i].kwval,padx3tab[i].kwd,
  4316.                padparms[padx3tab[i].kwval]);
  4317.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4318.     }
  4319.     return(n);
  4320. }
  4321. #endif /* IBMX25 */
  4322. #endif /* ANYX25 */
  4323.  
  4324. VOID
  4325. shoparc() {
  4326.     extern int reliable, stopbits, clsondisc;
  4327.     int i; char *s;
  4328.     long zz;
  4329.  
  4330. #ifdef NEWFTP
  4331.     if (ftpisconnected()) {
  4332.         shoftp(1);
  4333.         printf("\n");
  4334.     }
  4335. #endif /* NEWFTP */
  4336.  
  4337.     printf("Communications Parameters:\n");
  4338.  
  4339.     if (network
  4340. #ifdef IKSD
  4341.          || inserver
  4342. #endif /* IKSD */
  4343.          ) {
  4344.         printf(" Network Host: %s%s",ttname,
  4345.                (reliable == SET_ON || (reliable == SET_AUTO && !local)
  4346. #ifdef TN_COMPORT
  4347.                && !istncomport()
  4348. #endif /* TN_COMPORT */
  4349. #ifdef IKSD
  4350.                || inserver
  4351. #endif /* IKSD */
  4352.                ) ? " (reliable)" : "");
  4353. #ifdef TN_COMPORT
  4354.         if (istncomport()) {
  4355.             int modemstate;
  4356.             char * oflow, * iflow = "", * parity, * stopsize, * signature;
  4357.             int baud = tnc_get_baud();
  4358.  
  4359.             switch (tnc_get_oflow()) {
  4360.               case TNC_CTL_OFLOW_NONE:
  4361.                 oflow = "none";
  4362.                 break;
  4363.               case TNC_CTL_OFLOW_XON_XOFF:
  4364.                 oflow = "xon/xoff";
  4365.                 break;
  4366.               case TNC_CTL_OFLOW_RTS_CTS:
  4367.                 oflow = "rts/cts";
  4368.                 break;
  4369.               case TNC_CTL_OFLOW_DCD:
  4370.                 oflow = "dcd";
  4371.                 break;
  4372.               case TNC_CTL_OFLOW_DSR:
  4373.                 oflow = "dsr";
  4374.                 break;
  4375.               default:
  4376.                 oflow = "(unknown)";
  4377.             }
  4378.             switch (tnc_get_iflow()) {
  4379.               case TNC_CTL_IFLOW_NONE:
  4380.                 iflow = "none";
  4381.                 break;
  4382.               case TNC_CTL_IFLOW_XON_XOFF:
  4383.                 iflow = "xon/xoff";
  4384.                 break;
  4385.               case TNC_CTL_IFLOW_RTS_CTS:
  4386.                 iflow = "rts/cts";
  4387.                 break;
  4388.               case TNC_CTL_IFLOW_DTR:
  4389.                 break;
  4390.               default:
  4391.                 iflow = oflow;
  4392.             }
  4393.             switch (tnc_get_parity()) {
  4394.               case TNC_PAR_NONE:
  4395.                 parity = "none";
  4396.                 break;
  4397.               case TNC_PAR_ODD:
  4398.                 parity = "odd";
  4399.                 break;
  4400.               case TNC_PAR_EVEN:
  4401.                 parity = "even";
  4402.                 break;
  4403.               case TNC_PAR_MARK:
  4404.                 parity = "mark";
  4405.                 break;
  4406.               case TNC_PAR_SPACE:
  4407.                 parity = "space";
  4408.                 break;
  4409.               default:
  4410.                 parity = "(unknown)";
  4411.             }
  4412.             switch (tnc_get_stopsize()) {
  4413.               case TNC_SB_1:
  4414.                 stopsize = "1";
  4415.                 break;
  4416.               case TNC_SB_1_5:
  4417.                 stopsize = "1.5";
  4418.                 break;
  4419.               case TNC_SB_2:
  4420.                 stopsize = "2";
  4421.                 break;
  4422.               default:
  4423.                 stopsize = "(unknown)";
  4424.             }
  4425.         signature = (char *)tnc_get_signature();
  4426.             printf("\n  Signature            : %s\n",signature?signature:"");
  4427.             if (baud <= 0)
  4428.               printf("  Speed                : (unknown)\n");
  4429.             else
  4430.               printf("  Speed                : %d\n", baud);
  4431.             printf("  Outbound Flow Control: %s\n", oflow);
  4432.             printf("  Inbound Flow Control : %s\n", iflow);
  4433.             printf("  Parity               : %s\n", parity);
  4434.             printf("  Data Size            : %d\n", tnc_get_datasize());
  4435.             printf("  Stop Bits            : %s\n", stopsize);
  4436.             printf("  DTR Signal           : %d\n", tnc_get_dtr_state());
  4437.             printf("  RTS Signal           : %d\n", tnc_get_rts_state());
  4438.             printf("  Modem State:\n");
  4439.             modemstate = tnc_get_ms();
  4440.             if (modemstate & TNC_MS_EDGE_RING)
  4441.               printf("    Trailing Edge Ring Detector On\n");
  4442.             else
  4443.               printf("    Trailing Edge Ring Detector Off\n");
  4444.             if (modemstate & TNC_MS_CTS_SIG)
  4445.               printf("    CTS Signal On\n");
  4446.             else
  4447.               printf("    CTS Signal Off\n");
  4448.             if (modemstate & TNC_MS_DSR_SIG)
  4449.               printf("    DSR Signal On\n");
  4450.             else
  4451.               printf("    DSR Signal Off\n");
  4452.             if (modemstate & TNC_MS_RI_SIG)
  4453.               printf("    Ring Indicator On\n");
  4454.             else
  4455.               printf("    Ring Indicator Off\n");
  4456.             if (modemstate & TNC_MS_RLSD_SIG)
  4457.               printf("    RLSD (CD) Signal On\n");
  4458.             else
  4459.               printf("    RLSD (CD) Signal Off\n");
  4460.             printf("\n");
  4461.         }
  4462. #endif /* TN_COMPORT */
  4463.     } else {
  4464.  
  4465.         printf(" %s: %s%s, speed: ",
  4466. #ifdef OS2
  4467.                "Port",
  4468. #else
  4469.                "Line",
  4470. #endif /* OS2 */
  4471.                ttname,
  4472. #ifdef CK_TTYFD
  4473.                (local &&
  4474. #ifdef VMS
  4475.                 vmsttyfd() < 0
  4476. #else
  4477.                 ttyfd == -1
  4478. #endif /* VMS */
  4479.                 ) ?
  4480.                  " (closed)" :
  4481.                    (reliable == SET_ON ? " (reliable)" : "")
  4482. #else
  4483.                ""
  4484. #endif /* CK_TTYFD */
  4485.                );
  4486.         if (
  4487. #ifdef CK_TTYFD
  4488. #ifdef VMS
  4489.             vmsttyfd() < 0
  4490. #else
  4491.             ttyfd == -1
  4492. #endif /* VMS */
  4493.             ||
  4494. #endif /* CK_TTYFD */
  4495.             (zz = ttgspd()) < 0) {
  4496.             printf("unknown");
  4497.         } else {
  4498.             if (speed == 8880) printf("75/1200");
  4499.             else if (speed == 134) printf("134.5");
  4500.             else printf("%ld",zz);
  4501.         }
  4502.     }
  4503.     if (network
  4504. #ifdef IKSD
  4505.          || inserver
  4506. #endif /* IKSD */
  4507.          )
  4508.       printf("\n Mode: ");
  4509.     else
  4510.       printf(", mode: ");
  4511.     if (local) printf("local"); else printf("remote");
  4512.     if (network == 0
  4513. #ifdef IKSD
  4514.          && !inserver
  4515. #endif/* IKSD */
  4516.          ) {
  4517. #ifdef CK_TAPI
  4518.         if (tttapi && !tapipass )
  4519.           printf(", modem: %s","TAPI");
  4520.         else
  4521. #endif /* CK_TAPI */
  4522.         printf(", modem: %s",gmdmtyp());
  4523.     } else {
  4524. #ifdef NETCONN
  4525.        if (nettype == NET_TCPA) printf(", TCP/IP");
  4526.        if (nettype == NET_TCPB) printf(", TCP/IP");
  4527.        if (nettype == NET_DEC) {
  4528.            if (ttnproto == NP_LAT) printf(", DECnet LAT");
  4529.            else if ( ttnproto == NP_CTERM ) printf(", DECnet CTERM");
  4530.            else printf(", DECnet");
  4531.        }
  4532.        if (nettype == NET_SLAT) printf(", Meridian Technologies' SuperLAT");
  4533. #ifdef NETFILE
  4534.        if (nettype == NET_FILE) printf(", local file");
  4535. #endif /* NETFILE */
  4536. #ifdef NETCMD
  4537.        if (nettype == NET_CMD) printf(", pipe");
  4538. #endif /* NETCMD */
  4539. #ifdef NETPTY
  4540.        if (nettype == NET_PTY) printf(", pseudoterminal");
  4541. #endif /* NETPTY */
  4542. #ifdef NETDLL
  4543.        if (nettype == NET_DLL) printf(", dynamic load library");
  4544. #endif /* NETDLL */
  4545.        if (nettype == NET_PIPE) printf(", Named Pipes");
  4546. #ifdef SSHBUILTIN
  4547.        if (nettype == NET_SSH)
  4548.          printf(", Secure Shell protocol (SECURE)");
  4549. #endif /* SSHBUILTIN */
  4550. #ifdef ANYX25
  4551.        if (shox25(0) < 0) return;
  4552. #endif /* ANYX25 */
  4553.        if (IS_TELNET()) {
  4554.            printf(", telnet protocol");
  4555.            if (0
  4556. #ifdef CK_ENCRYPTION
  4557.                || ck_tn_encrypting() && ck_tn_decrypting()
  4558. #endif /* CK_ENCRYPTION */
  4559. #ifdef CK_SSL
  4560.                || tls_active_flag || ssl_active_flag
  4561. #endif /* CK_SSL */
  4562.                )
  4563.              printf(" (SECURE)");
  4564.        }
  4565. #ifdef RLOGCODE
  4566.        else if (ttnproto == NP_RLOGIN || ttnproto == NP_K4LOGIN ||
  4567.                 ttnproto == NP_K5LOGIN)
  4568.          printf(", rlogin protocol");
  4569.        else if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN)
  4570.          printf(", rlogin protocol (SECURE)");
  4571. #endif /* RLOGCODE */
  4572. #ifdef CK_KERBEROS
  4573. #ifdef KRB5
  4574.        else if (ttnproto == NP_K5U2U)
  4575.          printf(", Kerberos 5 User to User protocol (SECURE)");
  4576. #endif /* KRB5 */
  4577. #endif /* CK_KERBEROS */
  4578. #endif /* NETCONN */
  4579.     }
  4580.     printf("\n");
  4581.     if (hwparity && local && !network)
  4582.       s = parnam((char)hwparity);
  4583.     else
  4584.       s = parnam((char)parity);
  4585.     printf(" Parity: %s%s",hwparity ? "hardware " : "", s);
  4586. #ifndef NOLOCAL
  4587.     if (local && !network) {
  4588.         int sb;
  4589.         char c;
  4590.         c = s[0];
  4591.         if (islower(c)) c = toupper(c);
  4592.         sb = stopbits;
  4593.         if (sb < 1) {
  4594.             sb = (speed > 0 && speed <= 110L) ? 2 : 1;
  4595.             printf(", stop-bits: (default)");
  4596.         } else {
  4597.             printf(", stop-bits: %d",sb);
  4598.         }
  4599.         if (hwparity)
  4600.           printf(" (8%c%d)",c,sb);
  4601.         else if (parity)
  4602.           printf(" (7%c%d)",c,sb);
  4603.         else
  4604.           printf(" (8N%d)",sb);
  4605.         printf("\n D");
  4606.     } else
  4607.       printf(", d");
  4608. #endif /* NOLOCAL */
  4609.  
  4610.     printf("uplex: %s, ", duplex ? "half" : "full");
  4611.     debug(F101,"shoparp flow","",flow);
  4612.     printf("flow: %s", floname[flow]);
  4613.     printf(", handshake: ");
  4614.     if (turn) printf("%d\n",turnch); else printf("none\n");
  4615. #ifdef COMMENT
  4616.     if (local && !network) {            /* SET CARRIER-WATCH */
  4617. #endif /* COMMENT */
  4618.         if (carrier == CAR_OFF) s = "off";
  4619.         else if (carrier == CAR_ON) s = "on";
  4620.         else if (carrier == CAR_AUT) s = "auto";
  4621.         else s = "unknown";
  4622.         printf(" Carrier-watch: %s", s);
  4623.         if (carrier == CAR_ON) {
  4624.             if (cdtimo) printf(", timeout: %d sec", cdtimo);
  4625.             else printf(", timeout: none");
  4626.         }
  4627. #ifdef COMMENT
  4628.     }
  4629. #endif /* COMMENT */
  4630.     printf(", close-on-disconnect: %s\n",showoff(clsondisc));
  4631.  
  4632. #ifdef UNIX                             /* UUCP lockfile, UNIX only */
  4633.     if (local) {
  4634. #ifndef NOUUCP
  4635.         if (!network && haslock && *flfnam)
  4636.           printf(" Lockfile: %s",flfnam);
  4637. #ifndef USETTYLOCK
  4638.         if (!network && haslock && lock2[0])
  4639.           printf("\n Secondary lockfile: %s",lock2);
  4640. #endif /* USETTYLOCK */
  4641. #else
  4642. #ifdef QNX
  4643.         {
  4644.             extern int qnxportlock, qnxopencount();
  4645.             if (local)
  4646.               printf(" Qnx-port-lock: %s, Open count: %d",
  4647.                      showoff(qnxportlock),
  4648.                      qnxopencount()
  4649.                      );
  4650.             else
  4651.               printf(" Qnx-port-lock: %s", showoff(qnxportlock));
  4652.         }
  4653. #endif /* QNX */
  4654. #endif /* NOUUCP */
  4655.         printf("\n");
  4656.     } else {
  4657.         char * s, * ttglckdir();
  4658.         s = ttglckdir();
  4659.         if (!s) s = "";
  4660.         printf(" Lockfile directory: %s\n", *s ? s : "(none)");
  4661.     }
  4662. #endif /* UNIX */
  4663. #ifndef MACOSX
  4664.     if (!local) {
  4665.         printf(" Typical port device name: %s\n",ttgtpn());
  4666.     }
  4667. #endif    /* MACOSX */
  4668.     if (local) {
  4669.         int i;
  4670.         i = parity ? 7 : 8;
  4671.         if (i == 8) i = (cmask == 0177) ? 7 : 8;
  4672.         printf(" Terminal bytesize: %d,",i);
  4673.         printf(" escape character: %d (^%c)\n",escape,ctl(escape));
  4674.     }
  4675. }
  4676.  
  4677. int
  4678. shotcp(n) int n; {
  4679. #ifdef TCPSOCKET
  4680.     if (nettype == NET_TCPA || nettype == NET_TCPB) {
  4681.         printf("SET TCP parameters:\n");
  4682.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4683.         printf(" Reverse DNS lookup: %s\n", showooa(tcp_rdns));
  4684.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4685.  
  4686. #ifdef CK_DNS_SRV
  4687.         printf(" DNS Service Records lookup: %s\n", showooa(tcp_dns_srv));
  4688.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4689. #endif /* CK_DNS_SRV */
  4690.  
  4691. #ifndef NOTCPOPTS
  4692. #ifdef SOL_SOCKET
  4693. #ifdef SO_KEEPALIVE
  4694.         printf(" Keepalive: %s\n", showoff(tcp_keepalive));
  4695.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4696. #endif /* SO_KEEPALIVE */
  4697.  
  4698. #ifdef SO_LINGER
  4699.         printf(" Linger: %s", tcp_linger ? "on, " : "off\n" );
  4700.         if (tcp_linger) {
  4701.             if (tcp_linger_tmo)
  4702.               printf("%d x 10 milliseconds\n",tcp_linger_tmo);
  4703.             else
  4704.               printf("no timeout\n");
  4705.         }
  4706.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4707. #endif /* SO_LINGER */
  4708.  
  4709. #ifdef SO_DONTROUTE
  4710.         printf(" DontRoute: %s\n", tcp_dontroute ? "on" : "off" );
  4711.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4712. #endif /* SO_DONTROUTE */
  4713.  
  4714. #ifdef TCP_NODELAY
  4715.         printf(" Nodelay: %s\n", showoff(tcp_nodelay));
  4716.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4717. #endif /* TCP_NODELAY */
  4718.  
  4719. #ifdef SO_SNDBUF
  4720.         if (tcp_sendbuf <= 0)
  4721.           printf(" Send buffer: (default size)\n");
  4722.         else
  4723.           printf(" Send buffer: %d bytes\n", tcp_sendbuf);
  4724.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4725. #endif /* SO_SNDBUF */
  4726. #ifdef SO_RCVBUF
  4727.         if (tcp_recvbuf <= 0)
  4728.           printf(" Receive buffer: (default size)\n");
  4729.         else
  4730.           printf(" Receive buffer: %d bytes\n", tcp_recvbuf);
  4731.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4732. #endif /* SO_RCVBUF */
  4733. #endif /* SOL_SOCKET */
  4734. #endif /* NOTCPOPTS */
  4735.         printf(" address: %s\n",tcp_address ? tcp_address : "(none)");
  4736.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4737. #ifndef NOHTTP
  4738.         printf(" http-proxy: %s\n",tcp_http_proxy ? tcp_http_proxy : "(none)");
  4739.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4740. #endif /* NOHTTP */
  4741. #ifdef NT
  4742. #ifdef CK_SOCKS
  4743.         printf(" socks-server: %s\n",tcp_socks_svr ? tcp_socks_svr : "(none)");
  4744.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4745. #ifdef CK_SOCKS_NS
  4746.         printf(" socks-name-server: %s\n",
  4747.                tcp_socks_ns ? tcp_socks_ns : "(none)");
  4748.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4749. #endif /* CK_SOCKS_NS */
  4750. #endif /* CK_SOCKS */
  4751. #endif /* NT */
  4752.     }
  4753. #endif /* TCPSOCKET */
  4754.     return(n);
  4755. }
  4756.  
  4757. #ifdef TNCODE
  4758. int
  4759. shotopt(n) int n; {
  4760.     int opt;
  4761.  
  4762.     printf("%-21s %12s %12s %12s %12s\n\n",
  4763.            "Telnet Option","Me (client)","U (client)",
  4764.            "Me (server)","U (server)");
  4765.     n += 2;
  4766.     if (n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4767.  
  4768.     for ( opt = TELOPT_FIRST; opt <= TELOPT_LAST; opt++) {
  4769.         switch (opt) {
  4770.           case TELOPT_AUTHENTICATION:
  4771.           case TELOPT_ENCRYPTION:
  4772.           case TELOPT_TTYPE:
  4773.           case TELOPT_NAWS:
  4774.           case TELOPT_BINARY:
  4775.           case TELOPT_NEWENVIRON:
  4776.           case TELOPT_SNDLOC:
  4777.           case TELOPT_XDISPLOC:
  4778.           case TELOPT_SGA:
  4779.           case TELOPT_ECHO:
  4780.           case TELOPT_KERMIT:
  4781.           case TELOPT_START_TLS:
  4782.           case TELOPT_FORWARD_X:
  4783.           case TELOPT_COMPORT:
  4784.             break;
  4785.           default:
  4786.             continue;
  4787.         }
  4788.         printf("%03d %-17s ",
  4789.                opt, TELOPT(opt)
  4790.                );
  4791.         printf("%12s %12s ",
  4792.                TELOPT_MODE(TELOPT_DEF_C_ME_MODE(opt)),
  4793.                TELOPT_MODE(TELOPT_DEF_C_U_MODE(opt))
  4794.                );
  4795.         printf("%12s %12s\n",
  4796.                TELOPT_MODE(TELOPT_DEF_S_ME_MODE(opt)),
  4797.                TELOPT_MODE(TELOPT_DEF_S_U_MODE(opt))
  4798.                );
  4799.  
  4800.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4801.         if (sstelnet)
  4802.           printf("%21s %12s %12s %12s %12s\n",
  4803.                  "",
  4804.                  "",
  4805.                  "",
  4806.                  (TELOPT_ME(opt)?"WILL":"WONT"),
  4807.                  (TELOPT_U(opt)?"DO":"DONT")
  4808.                  );
  4809.         else
  4810.           printf("%21s %12s %12s %12s %12s\n",
  4811.                  "",
  4812.                  (TELOPT_ME(opt)?"WILL":"WONT"),
  4813.                  (TELOPT_U(opt)?"DO":"DONT"),
  4814.                  "",
  4815.                  ""
  4816.                  );
  4817.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4818.     }
  4819.     return(n);
  4820. }
  4821.  
  4822. int
  4823. shotel(n) int n; {
  4824.     extern int tn_duplex;
  4825. #ifdef CK_ENVIRONMENT
  4826.     extern int tn_env_flg;
  4827.     extern char tn_env_acct[];
  4828.     extern char tn_env_job[];
  4829.     extern char tn_env_prnt[];
  4830.     extern char tn_env_sys[];
  4831.     extern char * tn_env_uservar[8][2];
  4832.     int x;
  4833. #endif /* CK_ENVIRONMENT */
  4834. #ifdef CK_SNDLOC
  4835.     extern char * tn_loc;
  4836. #endif /* CK_SNDLOC */
  4837.     printf("SET TELNET parameters:\n echo: %s\n NVT newline-mode: ",
  4838.            tn_duplex ? "local" : "remote");
  4839.     switch (tn_nlm) {
  4840.       case TNL_CRNUL: printf("%s\n","off (cr-nul)"); break;
  4841.       case TNL_CRLF:  printf("%s\n","on (cr-lf)"); break;
  4842.       case TNL_CR:    printf("%s\n","raw (cr)"); break;
  4843.       case TNL_LF:    printf("%s\n","(lf)"); break;
  4844.     }
  4845.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4846. #ifdef CK_AUTHENTICATION
  4847.     {
  4848.         int type = ck_tn_authenticated();
  4849.         printf(" authentication: ");
  4850.         switch (sstelnet ?
  4851.                 TELOPT_U_MODE(TELOPT_AUTHENTICATION) :
  4852.                  TELOPT_ME_MODE(TELOPT_AUTHENTICATION)
  4853.                 ) {
  4854.           case TN_NG_AC: printf( "accepted " ); break;
  4855.           case TN_NG_RF: printf( "refused  " ); break;
  4856.           case TN_NG_RQ: printf( "requested"); break;
  4857.           case TN_NG_MU: printf( "required "); break;
  4858.         }
  4859.  
  4860. #ifdef CK_SSL
  4861.         if ((ssl_active_flag || tls_active_flag) &&
  4862.              ck_tn_auth_valid() == AUTH_VALID &&
  4863.              (!TELOPT_U(TELOPT_AUTHENTICATION) ||
  4864.                type == AUTHTYPE_NULL ||
  4865.                type == AUTHTYPE_AUTO))
  4866.             printf("   in use: X.509 certificate\n");
  4867.         else
  4868. #endif /* CK_SSL */
  4869.           printf("   in use: %s\n",AUTHTYPE_NAME(type));
  4870.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4871.         if (forward_flag)
  4872.           printf("  credentials forwarding requested %s\n",
  4873.                  forwarded_tickets ? "and completed" :
  4874.                  "but not completed");
  4875.         else
  4876.           printf("  credentials forwarding disabled\n");
  4877.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4878.     }
  4879. #endif /* CK_AUTHENTICATION */
  4880. #ifdef CK_ENCRYPTION
  4881.     {
  4882.         int i,x;
  4883.         int e_type = ck_tn_encrypting();
  4884.         int d_type = ck_tn_decrypting();
  4885.         char * e_str = NULL, * d_str = NULL;
  4886.         static struct keytab * tnetbl = NULL;
  4887.         static int ntnetbl = 0;
  4888.  
  4889.         x = ck_get_crypt_table(&tnetbl,&ntnetbl);
  4890.  
  4891.         for (i = 0; i < ntnetbl; i++) {
  4892.             if (e_type == tnetbl[i].kwval)
  4893.               e_str = tnetbl[i].kwd;
  4894.             if (d_type == tnetbl[i].kwval)
  4895.               d_str = tnetbl[i].kwd;
  4896.         }
  4897.         printf(" encryption: ");
  4898.         switch (TELOPT_ME_MODE(TELOPT_ENCRYPTION)) {
  4899.           /* This should be changed to report both ME and U modes */
  4900.           case TN_NG_AC: printf( "accepted " ); break;
  4901.           case TN_NG_RF: printf( "refused  " ); break;
  4902.           case TN_NG_RQ: printf( "requested"); break;
  4903.           case TN_NG_MU: printf( "required "); break;
  4904.         }
  4905.         printf("       in use: ");
  4906.         switch ((e_type ? 1 : 0) | (d_type ? 2 : 0)) {
  4907.           case 0:
  4908.             printf("plain text in both directions");
  4909.             break;
  4910.           case 1:
  4911.             printf("%s output, plain text input",e_str);
  4912.             break;
  4913.           case 2:
  4914.             printf("plain text output, %s input",d_str);
  4915.             break;
  4916.           case 3:
  4917.             printf("%s output, %s input",e_str,d_str);
  4918.             break;
  4919.         }
  4920.         printf("\n");
  4921.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4922.     }
  4923. #endif /* CK_ENCRYPTION */
  4924. #ifdef IKS_OPTION
  4925.     printf(" kermit: ");
  4926.     switch (TELOPT_U_MODE(TELOPT_KERMIT)) {
  4927.       case TN_NG_AC: printf( "u, accepted;  " ); break;
  4928.       case TN_NG_RF: printf( "u, refused;   " ); break;
  4929.       case TN_NG_RQ: printf( "u, requested; "); break;
  4930.       case TN_NG_MU: printf( "u, required;  "); break;
  4931.     }
  4932.     switch (TELOPT_ME_MODE(TELOPT_KERMIT)) {
  4933.       case TN_NG_AC: printf( "me, accepted;  " ); break;
  4934.       case TN_NG_RF: printf( "me, refused;   " ); break;
  4935.       case TN_NG_RQ: printf( "me, requested; "); break;
  4936.       case TN_NG_MU: printf( "me, required;  "); break;
  4937.     }
  4938.     if (TELOPT_U(TELOPT_KERMIT))
  4939.       printf(" u, %s",
  4940.              TELOPT_SB(TELOPT_KERMIT).kermit.u_start ?
  4941.              "started" :
  4942.              "stopped"
  4943.              );
  4944.     else
  4945.       printf(" u, n/a");
  4946.     if (TELOPT_ME(TELOPT_KERMIT))
  4947.       printf(" me, %s;",
  4948.              TELOPT_SB(TELOPT_KERMIT).kermit.me_start ?
  4949.              "started" :
  4950.              "stopped"
  4951.              );
  4952.     else
  4953.       printf(" me, n/a;");
  4954.     printf("\n");
  4955.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4956. #endif /* IKS_OPTION */
  4957.     printf(" BINARY newline-mode: ");
  4958.     switch (tn_b_nlm) {
  4959.       case TNL_CRNUL: printf("%s\n","off (cr-nul)"); break;
  4960.       case TNL_CRLF:  printf("%s\n","on (cr-lf)"); break;
  4961.       case TNL_CR:    printf("%s\n","raw (cr)"); break;
  4962.       case TNL_LF:    printf("%s\n","(lf)"); break;
  4963.     }
  4964.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4965.     printf(" binary-mode: ");
  4966.     switch (TELOPT_U_MODE(TELOPT_BINARY)) {
  4967.       case TN_NG_AC: printf( "u, accepted;  " ); break;
  4968.       case TN_NG_RF: printf( "u, refused;   " ); break;
  4969.       case TN_NG_RQ: printf( "u, requested; "); break;
  4970.       case TN_NG_MU: printf( "u, required;  "); break;
  4971.     }
  4972.     switch (TELOPT_ME_MODE(TELOPT_BINARY)) {
  4973.       case TN_NG_AC: printf( "me, accepted; " ); break ;
  4974.       case TN_NG_RF: printf( "me, refused; " ); break;
  4975.       case TN_NG_RQ: printf( "me, requested; "); break;
  4976.       case TN_NG_MU: printf( "me, required;  "); break;
  4977.     }
  4978.     printf("u, %s; me, %s\n",
  4979.            TELOPT_U(TELOPT_BINARY) ? "BINARY" : "NVT",
  4980.            TELOPT_ME(TELOPT_BINARY) ? "BINARY" : "NVT"
  4981.            );
  4982.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4983.     printf(" binary-transfer-mode: %s\n",showoff(tn_b_xfer));
  4984.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4985.     printf(" bug binary-me-means-u-too: %s\n",showoff(tn_b_meu));
  4986.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4987.     printf(" bug binary-u-means-me-too: %s\n",showoff(tn_b_ume));
  4988.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4989.     printf(" bug sb-implies-will-do: %s\n",showoff(tn_sb_bug));
  4990.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4991.     printf(" bug auth-krb5-des: %s\n",showoff(tn_auth_krb5_des_bug));
  4992.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  4993.     printf(" terminal-type: ");
  4994.     if (tn_term) {
  4995.         printf("%s\n",tn_term);
  4996.     } else {
  4997.         char *p;
  4998. #ifdef OS2
  4999.         p = (tt_type >= 0 && tt_type <= max_tt) ?
  5000.           tt_info[tt_type].x_name :
  5001.             "UNKNOWN";
  5002. #else
  5003.         p = getenv("TERM");
  5004. #endif /* OS2 */
  5005.         if (p)
  5006.           printf("none (%s will be used)\n",p);
  5007.         else printf("none\n");
  5008.     }
  5009.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  5010. #ifdef CK_ENVIRONMENT
  5011.     printf(" environment: %s\n", showoff(tn_env_flg));
  5012.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  5013.     printf("   ACCOUNT: %s\n",tn_env_acct);
  5014.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  5015.     printf("   DISPLAY: %s\n",(char *)tn_get_display() ?
  5016.             (char *)tn_get_display() : "");
  5017.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  5018.     printf("   JOB    : %s\n",tn_env_job);
  5019.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  5020.     printf("   PRINTER: %s\n",tn_env_prnt);
  5021.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  5022. #ifndef NOSPL
  5023.     printf("   USER   : %s\n",uidbuf);
  5024.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  5025. #endif /* NOSPL */
  5026.     printf("   SYSTEM : %s\n",tn_env_sys);
  5027.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  5028.     for (x = 0; x < 8; x++) {
  5029.         if (tn_env_uservar[x][0] && tn_env_uservar[x][1]) {
  5030.             printf("   %-7s: %s\n",tn_env_uservar[x][0],
  5031.                    tn_env_uservar[x][1]);
  5032.             if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  5033.         }
  5034.     }
  5035. #endif /* CK_ENVIRONMENT */
  5036. #ifdef CK_SNDLOC
  5037.     printf("  LOCATION: %s\n", tn_loc ? tn_loc : "");
  5038.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  5039. #endif /* CK_SNDLOC */
  5040. #ifdef CK_FORWARD_X
  5041.     printf(" .Xauthority-file: %s\n", (char *)XauFileName() ?
  5042.             (char *)XauFileName() : "(none)");
  5043.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  5044. #endif /* CK_FORWARD_X */
  5045.     return(n);
  5046. }
  5047. #endif /* TNCODE */
  5048.  
  5049. #ifdef CK_NETBIOS
  5050. static int
  5051. shonb(n) int n; {
  5052.     printf("NETBIOS parameters:\n");
  5053.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  5054.     printf(" API       : %s\n",
  5055.            NetbeuiAPI ?
  5056.            "NETAPI.DLL - IBM Extended Services or Novell Netware Requester"
  5057.            : "ACSNETB.DLL - IBM Network Transport Services/2" ) ;
  5058.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  5059.     printf(" Local Name: [%s]\n", NetBiosName);
  5060.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  5061.     printf(" Adapter   : %d\n", NetBiosAdapter);
  5062.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  5063.     if (NetBiosLSN > 0xFF) {
  5064.         printf(" Session   : %d\n", NetBiosLSN);
  5065.     } else {
  5066.         printf(" Session   : none active\n");
  5067.     }
  5068.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  5069.     return(n);
  5070. }
  5071. #endif /* CK_NETBIOS */
  5072.  
  5073. #ifndef NONET
  5074. int
  5075. shonet() {
  5076.  
  5077. #ifndef NETCONN
  5078.     printf("\nNo networks are supported in this version of C-Kermit\n");
  5079.  
  5080. #else
  5081. #ifdef NOLOCAL
  5082.     printf("\nNo networks are supported in this version of C-Kermit\n");
  5083.  
  5084. #else /* rest of this routine */
  5085.  
  5086.     int i, n = 4;
  5087.  
  5088. #ifndef NODIAL
  5089.     if (nnetdir <= 1) {
  5090.         printf("\nNetwork directory: %s\n",netdir[0] ? netdir[0] : "(none)");
  5091.         n++;
  5092.     } else {
  5093.         int i;
  5094.         printf("\nNetwork directories:\n");
  5095.         for (i = 0; i < nnetdir; i++) {
  5096.             printf("%2d. %s\n",i,netdir[i]);
  5097.             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5098.         }
  5099.     }
  5100. #endif /* NODIAL */
  5101.  
  5102. #ifdef SSHCMD
  5103.     {
  5104.         extern char * sshcmd;
  5105.         printf("SSH COMMAND: %s\n",sshcmd ? sshcmd : "ssh -e none");
  5106.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5107.     }
  5108. #endif /* SSHCMD */
  5109.  
  5110. #ifdef OS2
  5111.     printf("\nNetwork availability:\n");
  5112. #else
  5113.     printf("\nSupported networks:\n");
  5114. #endif /* OS2 */
  5115.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5116.  
  5117. #ifdef VMS
  5118.  
  5119. #ifdef TCPWARE
  5120.     printf(" Process Software Corporation TCPware for OpenVMS");
  5121. #else
  5122. #ifdef MULTINET
  5123.     printf(" TGV MultiNet TCP/IP");
  5124. #else
  5125. #ifdef WINTCP
  5126.     printf(" WOLLONGONG WIN/TCP");
  5127. #else
  5128. #ifdef DEC_TCPIP
  5129.     {
  5130.         static $DESCRIPTOR(tcp_desc,"_TCP0:");
  5131.         int status;
  5132.         long devclass;
  5133.         static int itmcod = DVI$_DEVCLASS;
  5134.  
  5135. #ifdef COMMENT
  5136.         status = LIB$GETDVI(&itmcod, 0, &tcp_desc, &devclass);
  5137. #else
  5138.         /* Martin Zinser 9/96 */
  5139.         status = lib$getdvi(&itmcod, 0, &tcp_desc, &devclass);
  5140. #endif /* COMMENT */
  5141.         if ((status & 1) && (devclass == DC$_SCOM))
  5142.           printf(" Process Software Corporation TCPware for OpenVMS");
  5143.         else
  5144. #ifdef UCX50
  5145.           printf(" DEC TCP/IP Services for (Open)VMS 5.0");
  5146. #else
  5147.           printf(" DEC TCP/IP Services for (Open)VMS");
  5148. #endif /* UCX50 */
  5149.     }
  5150. #else
  5151. #ifdef CMU_TCPIP
  5152.     printf(" CMU-OpenVMS/IP");
  5153. #else
  5154.     printf(" None");
  5155. #endif /* CMU_TCPIP */
  5156. #endif /* DEC_TCPIP */
  5157. #endif /* WINTCP */
  5158. #endif /* MULTINET */
  5159. #endif /* TCPWARE */
  5160.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5161. #ifdef TNCODE
  5162.     printf(", TELNET protocol\n\n");
  5163.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5164.     n = shotel(n);
  5165.     if (n < 0) return(0);
  5166.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5167. #endif /* TNCODE */
  5168.     printf("\n");
  5169.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5170.     printf("\n");
  5171.     n = shotcp(++n);
  5172.     if (n < 0) return(0);
  5173. #else /* Not VMS */
  5174.  
  5175. #ifdef SUNX25
  5176.     printf(" SunLink X.25\n");
  5177.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5178. #endif /* SUNX25 */
  5179.  
  5180. #ifdef STRATUSX25
  5181.     printf(" Stratus VOS X.25\n");
  5182.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5183. #endif /* STRATUSX25 */
  5184.  
  5185. #ifdef IBMX25
  5186.     printf(" IBM AIX X.25\n");
  5187.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5188. #endif /* IBMX25 */
  5189.  
  5190. #ifdef HPX25
  5191.     printf(" HP-UX X.25\n");
  5192.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5193. #endif /* HPX25 */
  5194.  
  5195. #ifdef SSHBUILTIN
  5196.     if (ck_ssleay_is_installed())
  5197.         printf(" SSH V1 and V2 protocols\n");
  5198.     else
  5199.         printf(" SSH V1 and V2 protocols - not available\n");
  5200. #endif /* SSHBUILTIN */
  5201.  
  5202. #ifdef DECNET
  5203. #ifdef OS2
  5204. #ifdef NT
  5205.     if (dnet_avail)
  5206.       printf(" DECnet, LAT and CTERM protocols\n");
  5207.     else
  5208.       printf(" DECnet, LAT and CTERM protocols - not available\n");
  5209.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5210. #else /* NT */
  5211.     if (dnet_avail)
  5212.       printf(" DECnet, LAT protocol\n");
  5213.     else
  5214.       printf(" DECnet, LAT protocol - not available\n");
  5215.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5216. #endif /* NT */
  5217. #else
  5218.     printf(" DECnet\n");
  5219.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5220. #endif /* OS2 */
  5221. #endif /* DECNET */
  5222.  
  5223. #ifdef NPIPE
  5224.     printf(" Named Pipes\n");
  5225.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5226. #endif /* NPIPE */
  5227.  
  5228. #ifdef CK_NETBIOS
  5229.     if (netbiosAvail)
  5230.       printf(" NETBIOS\n");
  5231.     else
  5232.       printf(" NETBIOS - not available\n");
  5233.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5234. #endif /* CK_NETBIOS */
  5235.  
  5236. #ifdef SUPERLAT
  5237.     if (slat_avail)
  5238.       printf(" SuperLAT\n");
  5239.     else
  5240.       printf(" SuperLAT - not available\n") ;
  5241.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5242. #endif /* SUPERLAT */
  5243.  
  5244. #ifdef TCPSOCKET
  5245.     if (
  5246. #ifdef OS2
  5247.         tcp_avail
  5248. #else
  5249.         1
  5250. #endif /* OS2 */
  5251.         ) {
  5252.         char ipaddr[16];
  5253.  
  5254.         if (getlocalipaddrs(ipaddr,16,0) < 0) {
  5255. #ifdef OS2ONLY
  5256.             printf(" TCP/IP via %s\n", tcpname);
  5257. #else
  5258.             printf(" TCP/IP\n");
  5259. #endif /* OS2ONLY */
  5260.             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5261.         } else {
  5262.             int i = 1;
  5263. #ifdef OS2ONLY
  5264.           printf(" TCP/IP [%16s] via %s\n", ipaddr, tcpname);
  5265. #else
  5266.           printf(" TCP/IP [%16s]\n",ipaddr);
  5267. #endif /* OS2ONLY */
  5268.             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5269.  
  5270.             while (getlocalipaddrs(ipaddr,16,i++) >= 0) {
  5271.                 printf("        [%16s]\n",ipaddr);
  5272.                 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5273.             }
  5274.         }
  5275.         if (nettype == NET_TCPB) {
  5276.             printf("\n");
  5277.             n = shotcp(++n);
  5278.             if (n < 0) return(0);
  5279. #ifdef TNCODE
  5280.             printf("\n");
  5281.             n = shotel(++n);
  5282.             if (n < 0) return(0);
  5283. #endif /* TNCODE */
  5284.             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5285.         }
  5286. #ifdef OS2
  5287.     } else {
  5288.         printf(" TCP/IP - not available%s\n",tcpname[0] ? tcpname : "" );
  5289.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5290. #endif /* OS2 */
  5291.     }
  5292. #endif /* TCPSOCKET */
  5293.  
  5294. #ifdef CK_NETBIOS
  5295.     if (netbiosAvail && nettype == NET_BIOS) {
  5296.        printf("\n") ;
  5297.        if ((n = shonb(++n)) < 0) return(0);
  5298.        if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5299.     }
  5300. #endif /* CK_NETBIOS */
  5301.  
  5302. #endif /* VMS */
  5303.  
  5304.     printf("\nActive network connection:\n");
  5305.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5306.  
  5307.     if (network) {
  5308.         printf(" Host: %s",ttname);
  5309.         if ((nettype == NET_TCPA || nettype == NET_TCPB) && *ipaddr)
  5310.           printf(" [%s]",ipaddr);
  5311.     } else
  5312.       printf(" Host: none");
  5313.     printf(", via: ");
  5314.     if (nettype == NET_TCPA || nettype == NET_TCPB)
  5315.       printf("tcp/ip\n");
  5316.     else if (nettype == NET_SX25)
  5317.       printf("SunLink X.25\n");
  5318.     else if (nettype == NET_VX25)
  5319.       printf("Stratus VOS X.25\n");
  5320.     else if (nettype == NET_IX25)
  5321.       printf("IBM AIX X.25\n");
  5322.     else if (nettype == NET_HX25)
  5323.       printf("HP-UX X.25\n");
  5324.     else if (nettype == NET_DEC) {
  5325.         if ( ttnproto == NP_LAT )
  5326.           printf("DECnet LAT\n");
  5327.         else if ( ttnproto == NP_CTERM )
  5328.           printf("DECnet CTERM\n");
  5329.         else
  5330.           printf("DECnet\n");
  5331.     } else if (nettype == NET_PIPE)
  5332.       printf("Named Pipes\n");
  5333.     else if (nettype == NET_BIOS)
  5334.       printf("NetBIOS\n");
  5335.     else if (nettype == NET_SLAT)
  5336.       printf("SuperLAT\n");
  5337.  
  5338. #ifdef NETFILE
  5339.     else if ( nettype == NET_FILE )
  5340.       printf("local file\n");
  5341. #endif /* NETFILE */
  5342. #ifdef NETCMD
  5343.     else if ( nettype == NET_CMD )
  5344.       printf("pipe\n");
  5345. #endif /* NETCMD */
  5346. #ifdef NETPTY
  5347.     else if ( nettype == NET_PTY )
  5348.         printf("pseudoterminal\n");
  5349. #endif /* NETPTY */
  5350. #ifdef NETDLL
  5351.     else if ( nettype == NET_DLL )
  5352.       printf("dynamic link library\n");
  5353. #endif /* NETDLL */
  5354.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5355.  
  5356. #ifdef ANYX25
  5357.     if ((nettype == NET_SX25) ||
  5358.         (nettype == NET_VX25) ||
  5359.         (nettype == NET_IX25))
  5360.       if ((n = shox25(n)) < 0) return(0);
  5361. #endif /* ANYX25 */
  5362.  
  5363. #ifdef SSHBUILTIN
  5364.     if (nettype == NET_SSH) {
  5365.         printf("Secure Shell protocol\n");
  5366.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5367.     }
  5368. #endif /* SSHBUILTIN */
  5369.  
  5370.     if (nettype == NET_TCPA || nettype == NET_TCPB) {
  5371. #ifdef RLOGCODE
  5372.         if (ttnproto == NP_RLOGIN) {
  5373.             printf(" LOGIN (rlogin) protocol\n");
  5374.             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5375.         }
  5376. #ifdef CK_KERBEROS
  5377.         else if (ttnproto == NP_K4LOGIN) {
  5378.             printf(" Kerberos 4 LOGIN (klogin) protocol\n");
  5379.             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5380.         }
  5381.         else if (ttnproto == NP_EK4LOGIN) {
  5382.             printf(" Encrypted Kerberos 4 LOGIN (eklogin) protocol\n");
  5383.             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5384.         }
  5385.         else if (ttnproto == NP_K5LOGIN) {
  5386.             printf(" Kerberos 5 LOGIN (klogin) protocol\n");
  5387.             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5388.         }
  5389.         else if (ttnproto == NP_EK5LOGIN) {
  5390.             printf(" Encrypted Kerberos 5 LOGIN (eklogin) protocol\n");
  5391.             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5392.         }
  5393. #endif /* CK_KERBEROS */
  5394. #endif /* RLOGCODE */
  5395. #ifdef CK_KERBEROS
  5396.         if (ttnproto == NP_K5U2U) {
  5397.             printf(" Kerberos 5 User to User protocol\n");
  5398.             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5399.         }
  5400. #endif /* CK_KERBEROS */
  5401.  
  5402. #ifdef TNCODE
  5403.         if (IS_TELNET()) {
  5404.             printf(" TELNET protocol\n");
  5405.             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5406.             printf(" Echoing is currently %s\n",duplex ? "local" : "remote");
  5407.             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5408.         }
  5409. #endif /* TNCODE */
  5410.         if (ttnproto == NP_TCPRAW) {
  5411.             printf(" Raw TCP socket\n");
  5412.             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5413.         }
  5414.     }
  5415.     printf("\n");
  5416. #endif /* NOLOCAL */
  5417. #endif /* NETCONN */
  5418.     return(0);
  5419. }
  5420. #endif /* NONET */
  5421.  
  5422. #ifndef NODIAL
  5423. VOID
  5424. shodial() {
  5425.     if (mdmtyp >= 0 || local != 0) doshodial();
  5426. }
  5427.  
  5428. VOID
  5429. shods(s) char *s; {                     /* Show a dial-related string */
  5430.     char c;
  5431.     if (s == NULL || !(*s)) {           /* Empty? */
  5432.         printf("(none)\n");
  5433.     } else {                            /* Not empty. */
  5434.         while ((c = *s++))              /* Can contain controls */
  5435.           if (c == '\\')                /* a backslash */
  5436.             printf("\\\\");
  5437.           else if (c > 31 && c < 127) {
  5438.               putchar(c);
  5439.           } else
  5440.             printf("\\{%d}",c);
  5441.         printf("\n");
  5442.     }
  5443. }
  5444.  
  5445. int
  5446. doshodial() {
  5447.  
  5448.     int i, n = 2;
  5449.  
  5450.     printf(" Dial status:  %d", dialsta);
  5451.  
  5452. #ifdef BIGBUFOK
  5453.     if (dialsta > 90)
  5454.       printf(" = Unknown error");
  5455.     else if (dialsta < 0)
  5456.       printf(" = (none)");
  5457.     else if (dialsta < 35 && dialmsg[dialsta])
  5458.       printf(" = %s", dialmsg[dialsta]);
  5459. #endif /* BIGBUFOK */
  5460.     n++;
  5461.     if (ndialdir <= 1) {
  5462.         printf("\n Dial directory: %s\n",dialdir[0] ? dialdir[0] : "(none)");
  5463.     } else {
  5464.         int i;
  5465.         printf("\n Dial directories:\n");
  5466.         for (i = 0; i < ndialdir; i++)
  5467.           printf("%2d. %s\n",i+1,dialdir[i]);
  5468.         n += ndialdir;
  5469.     }
  5470.     printf(" Dial method:  ");
  5471.     if      (dialmauto)         printf("auto   ");
  5472.     else if (dialmth == XYDM_D) printf("default");
  5473.     else if (dialmth == XYDM_P) printf("pulse  ");
  5474.     else if (dialmth == XYDM_T) printf("tone   ");
  5475.     printf("         Dial sort: %s\n",dialsrt ? "on" : "off");
  5476.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5477.     printf(" Dial hangup:  %s             Dial display: %s\n",
  5478.            dialhng ? "on " : "off", dialdpy ? "on" : "off");
  5479.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5480.     if (dialrtr > 0) {
  5481.         printf(" Dial retries: %-12d    Dial interval: %d\n",
  5482.                dialrtr, dialint);
  5483.     } else {
  5484.         printf(" Dial retries: (auto)          Dial interval: %d\n", dialint);
  5485.     }
  5486.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5487.     printf(" Dial timeout: ");
  5488. #ifdef CK_TAPI
  5489.     if (tttapi && !tapipass)
  5490.         printf("(tapi)");
  5491.     else
  5492. #endif /* CK_TAPI */
  5493.     if (dialtmo > 0)
  5494.       printf("%4d sec", dialtmo);
  5495.     else
  5496.       printf("0 (auto)");
  5497.     printf("        Redial number: %s\n",dialnum ? dialnum : "(none)");
  5498.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5499.     printf(" Dial confirmation: %s        Dial convert-directory: %s\n",
  5500.            dialcnf ? "on " : "off",
  5501.            dialcvt ? ((dialcvt == 1) ? "on" : "ask") : "off");
  5502.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5503.     printf(" Dial ignore-dialtone: %s", dialidt ? "on " : "off");
  5504.     printf("     Dial pacing: %d\n",dialpace);
  5505.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5506.     printf(
  5507. " Dial prefix:                  %s\n", dialnpr ? dialnpr : "(none)");
  5508.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5509.     printf(
  5510. " Dial suffix:                  %s\n", dialsfx ? dialsfx : "(none)");
  5511.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5512.     printf(
  5513. " Dial country-code:            %-12s", diallcc ? diallcc : "(none)");
  5514.     printf("Dial connect:  %s", dialcon ? ((dialcon == 1) ? "on" : "auto")
  5515.            : "off");
  5516.     if (dialcon != CAR_OFF)
  5517.       printf(" %s", dialcq ? "quiet" : "verbose");
  5518.     printf(
  5519. "\n Dial area-code:               %-12s", diallac ? diallac : "(none)");
  5520.     n++;
  5521.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5522.     printf("Dial restrict: ");
  5523.     if (dialrstr == 5) printf("international\n");
  5524.     else if (dialrstr == 4) printf("long-distance\n");
  5525.     else if (dialrstr == 2) printf("local\n");
  5526.     else if (dialrstr == 6) printf("none\n");
  5527.     else printf("?\n");
  5528.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5529.     printf(" Dial lc-area-codes:           ");
  5530.     if (nlocalac == 0)
  5531.       printf("(none)");
  5532.     else
  5533.       for (i = 0; i < nlocalac; i++)
  5534.         printf("%s ", diallcac[i]);
  5535.     printf(
  5536. "\n Dial lc-prefix:               %s\n", diallcp ? diallcp : "(none)");
  5537.     n++;
  5538.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5539.     printf(
  5540. " Dial lc-suffix:               %s\n", diallcs ? diallcs : "(none)");
  5541.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5542.     printf(
  5543. " Dial ld-prefix:               %s\n", dialldp ? dialldp : "(none)");
  5544.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5545.     printf(
  5546. " Dial ld-suffix:               %s\n", diallds ? diallds : "(none)");
  5547.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5548.     printf(
  5549. " Dial force-long-distance      %s\n", showoff(dialfld));
  5550.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5551.     printf(
  5552. " Dial intl-prefix:             %s\n", dialixp ? dialixp : "(none)");
  5553.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5554.     printf(
  5555. " Dial intl-suffix:             %s\n", dialixs ? dialixs : "(none)");
  5556.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5557.     printf(
  5558. " Dial toll-free-area-code:     ");
  5559.     if (ntollfree == 0)
  5560.       printf("(none)");
  5561.     else
  5562.       for (i = 0; i < ntollfree; i++)
  5563.         printf("%s ", dialtfc[i]);
  5564.     printf("\n");
  5565.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5566.  
  5567.     printf(
  5568. " Dial pulse-countries:         ");
  5569.     if (ndialpucc == 0)
  5570.       printf("(none)");
  5571.     else
  5572.       for (i = 0; i < ndialpucc; i++)
  5573.         printf("%s ", dialpucc[i]);
  5574.     printf("\n");
  5575.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5576.  
  5577.     printf(
  5578. " Dial tone-countries:          ");
  5579.     if (ndialtocc == 0)
  5580.       printf("(none)");
  5581.     else
  5582.       for (i = 0; i < ndialtocc; i++)
  5583.         printf("%s ", dialtocc[i]);
  5584.     printf("\n");
  5585.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5586.  
  5587.     printf(
  5588.     " Dial toll-free-prefix:        %s\n",
  5589.     dialtfp ? dialtfp :
  5590.     (dialldp ? dialldp : "(none)")
  5591.     );
  5592.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5593.     printf(" Dial pbx-exchange:            ");
  5594.     if (ndialpxx == 0)
  5595.       printf("(none)");
  5596.     else
  5597.       for (i = 0; i < ndialpxx; i++)
  5598.         printf("%s ", dialpxx[i]);
  5599.     printf("\n");
  5600.  
  5601.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5602.     printf(
  5603. " Dial pbx-inside-prefix:       %s\n", dialpxi ? dialpxi : "(none)");
  5604.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5605.     printf(
  5606. " Dial pbx-outside-prefix:      %s\n", dialpxo ? dialpxo : "(none)");
  5607.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  5608.     printf(
  5609. " Dial macro:                   %s\n", dialmac ? dialmac : "(none)");
  5610.     return(0);
  5611. }
  5612. #endif /* NODIAL */
  5613. #endif /* NOLOCAL */
  5614.  
  5615. /*  Show File Parameters */
  5616.  
  5617. static char *
  5618. pathval(x) int x; {
  5619.     switch (x) {
  5620.       case PATH_OFF:  return("off");
  5621.       case PATH_ABS:  return("absolute");
  5622.       case PATH_REL:  return("relative");
  5623.       case PATH_AUTO: return("auto");
  5624.       default: return("unknown");
  5625.     }
  5626. }
  5627.  
  5628. VOID
  5629. shofil() {
  5630.     char *s; int i = 0, n = 1;
  5631.     extern char * ifdnam[];
  5632.     extern int wildena;
  5633. #ifdef UNIX
  5634.     extern int wildxpand;
  5635. #endif /* UNIX */
  5636.     extern char * snd_move, * snd_rename, * rcv_move, * rcv_rename;
  5637. #ifdef PATTERNS
  5638.     extern int patterns;
  5639. #endif /* PATTERNS */
  5640.     extern char * rfspec, * sfspec;
  5641. #ifdef UNIX
  5642.     extern int zobufsize, zofbuffer, zofblock;
  5643. #endif /* UNIX */
  5644. #ifdef CK_CTRLZ
  5645.     extern int eofmethod;
  5646. #endif /* CK_CTRLZ */
  5647.  
  5648.     printf("\n");
  5649.  
  5650. #ifdef VMS
  5651.     printf(" File record-Length:      %5d\n",frecl);
  5652.     n++;
  5653. #endif /* VMS */
  5654.  
  5655. #ifndef NOXFER
  5656.     printf(" Transfer mode:           %s\n",
  5657.            xfermode == XMODE_A ?
  5658.            "automatic" :
  5659.            "manual"
  5660.            );
  5661.     n++;
  5662. #ifdef PATTERNS
  5663.     printf(" File patterns:           %s", showooa(patterns));
  5664.     if (xfermode == XMODE_M && patterns)
  5665.       printf(" (but disabled by TRANSFER-MODE MANUAL)");
  5666.     else if (patterns)
  5667.       printf(" (SHOW PATTERNS for list)");
  5668.     printf("\n");
  5669.     n++;
  5670. #endif /* PATTERNS */
  5671.     if (filepeek)
  5672.       printf(" File scan:               on %d\n", nscanfile);
  5673.     else
  5674.       printf(" File scan:               off\n");
  5675.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5676.     if (xfermode == XMODE_A)
  5677.       printf(" Default file type:       %s\n",shoxm());
  5678.     else
  5679.       printf(" File type:               %s\n",shoxm());
  5680.     n++;
  5681.     if (fncnv == XYFN_L)
  5682.       s = "literal";
  5683.     else if (fncnv == XYFN_C)
  5684.       s = "converted";
  5685.     else
  5686.       s = "(unknown)";
  5687.     printf(" File names:              %s\n",s);
  5688.     n++;
  5689.     printf(" Send pathnames:          %s\n", pathval(fnspath));
  5690.     n++;
  5691.     printf(" Receive pathnames:       %s\n", pathval(fnrpath));
  5692.     n++;
  5693. #ifdef UNIXOROSK
  5694.     printf(" Match dot files:         %s\n", matchdot ? "yes" : "no");
  5695.     n++;
  5696. #ifdef UNIX
  5697.     printf(" Wildcard-expansion:      %s (%s)\n", showoff(wildena),
  5698.        wildxpand ? "shell" : "kermit");
  5699.     n++;
  5700. #endif /* UNIX */
  5701. #endif /* UNIXOROSK */
  5702.     printf(" File collision:          ");
  5703.     for (i = 0; i < ncolx; i++)
  5704.       if (colxtab[i].kwval == fncact) break;
  5705.     printf("%s\n", (i == ncolx) ? "unknown" : colxtab[i].kwd);
  5706.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5707.     printf(" File destination:        %s\n",
  5708.            (dest == DEST_D) ? "disk" :
  5709.            ((dest == DEST_S) ? "screen" :
  5710.             ((dest == DEST_N) ? "nowhere" :
  5711.             "printer"))
  5712.            );
  5713.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5714.     s = (keep >= 0 && keep <= 2) ? ifdnam[keep] : "keep";
  5715.     printf(" File incomplete:         %s\n",s);
  5716.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5717.     printf(" File bytesize:           %d\n",(fmask == 0177) ? 7 : 8);
  5718.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5719. #ifndef NOCSETS
  5720.     printf(" File character-set:      %s\n",fcsinfo[fcharset].keyword);
  5721.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5722.     printf(" File default 7-bit:      %s\n",fcsinfo[dcset7].keyword);
  5723.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5724.     printf(" File default 8-bit:      %s\n",fcsinfo[dcset8].keyword);
  5725.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5726. #ifdef UNICODE
  5727.     printf(" File UCS bom:            %s\n",showoff(ucsbom));
  5728.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5729.     printf(" File UCS byte-order:     %s-endian\n",
  5730.            ucsorder ? "little" : "big");
  5731.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5732.     printf(" Computer byteorder:      %s-endian\n",
  5733.            byteorder ? "little" : "big");
  5734.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5735. #endif /* UNICODE */
  5736. #endif /* NOCSETS */
  5737.  
  5738.     printf(" File end-of-line:        ");
  5739.     i = feol;
  5740.     switch (feol) {
  5741.       case XYFA_C: printf("%s\n","cr"); break;
  5742.       case XYFA_L: printf("%s\n","lf"); break;
  5743.       case XYFA_2: printf("%s\n","crlf"); break;
  5744.       default: printf("%d\n",i);
  5745.     }
  5746.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5747. #endif /* NOXFER */
  5748.  
  5749. #ifdef CK_CTRLZ
  5750.     printf(" File eof:                %s\n", eofmethod ? "ctrl-z" : "length");
  5751.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5752. #endif /* CK_CTRLZ */
  5753. #ifndef NOXFER
  5754. #ifdef CK_TMPDIR
  5755.     printf(" File download-directory: %s\n", dldir ? dldir : "(none)");
  5756.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5757. #ifdef COMMENT
  5758.     i = 256;
  5759.     s = line;
  5760.     zzstring("\\v(tmpdir)",&s,&i);
  5761.     printf(" Temporary directory:     %s\n", line);
  5762.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5763. #endif /* COMMENT */
  5764. #endif /* CK_TMPDIR */
  5765. #ifdef VMS
  5766.     {
  5767.         extern int vmssversions, vmsrversions;
  5768.         printf(" Send version-numbers:    %s\n",showoff(vmssversions));
  5769.         if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5770.         printf(" Receive version-numbers: %s\n",showoff(vmsrversions));
  5771.         if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5772.     }
  5773. #endif /* VMS */
  5774.     printf(" Send move-to:            %s\n",
  5775.            snd_move ? snd_move : "(none)");
  5776.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5777.     printf(" Send rename-to:          %s\n",
  5778.            snd_rename ? snd_rename : "(none)");
  5779.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5780.     printf(" Receive move-to:         %s\n",
  5781.            rcv_move ? rcv_move : "(none)");
  5782.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5783.     printf(" Receive rename-to:       %s\n",
  5784.            rcv_rename ? rcv_rename : "(none)");
  5785.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5786. #endif /* NOXFER */
  5787. #ifdef KERMRC
  5788.     printf(" Initialization file:     %s\n", noinit ? "(none)" :
  5789. #ifdef CK_SYSINI
  5790.            CK_SYSINI
  5791. #else
  5792.            kermrc
  5793. #endif /* CK_SYSINI */
  5794.            );
  5795. #endif /* KERMRC */
  5796.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5797.  
  5798.     if (k_info_dir) {
  5799.         printf(" Kermit doc files:        %s\n", k_info_dir);
  5800.         if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5801.     }
  5802.  
  5803. #ifdef CKROOT
  5804.     s = zgetroot();
  5805.     printf(" Root set:                %s\n", s ? s : "(none)");
  5806. #endif /* CKROOT */
  5807.  
  5808. #ifdef UNIX
  5809.     printf(" Disk output buffer:      %d (writes are %s, %s)\n",
  5810.            zobufsize,
  5811.            zofbuffer ? "buffered" : "unbuffered",
  5812.            zofblock ? "blocking" : "nonblocking"
  5813.            );
  5814.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5815. #ifdef DYNAMIC
  5816.     printf(" Stringspace:             %d\n", zsetfil(0,2));
  5817.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5818.     printf(" Listsize:                %d\n", zsetfil(0,4));
  5819.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5820. #endif /* DYNAMIC */
  5821. #endif /* UNIX */
  5822. #ifdef OS2ORUNIX
  5823.     printf(" Longest filename:        %d\n", maxnam);
  5824.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5825.     printf(" Longest pathname:        %d\n", maxpath);
  5826.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5827. #endif /* OS2ORUNIX */
  5828.  
  5829.     printf(" Last file sent:          %s\n", sfspec ? sfspec : "(none)");
  5830.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5831.     printf(" Last file received:      %s\n", rfspec ? rfspec : "(none)");
  5832.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5833.     printf("\n Also see:\n");
  5834.     n++;
  5835.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5836.     printf(" SHOW PROTOCOL, SHOW XFER");
  5837. #ifdef CK_LABELED
  5838.     printf(", SHOW LABELED");
  5839. #endif /* CK_LABELED */
  5840. #ifdef PATTERNS
  5841.     printf(", SHOW PATTERNS");
  5842. #endif /* PATTERNS */
  5843. #ifdef STREAMING
  5844.     printf(", SHOW STREAMING");
  5845. #endif /* STREAMING */
  5846. #ifndef NOCSETS
  5847.     printf(", SHOW CHARACTER-SETS");
  5848. #endif /* NOCSETS */
  5849.     printf("\n\n");
  5850. }
  5851.  
  5852. #ifndef NOXFER
  5853. VOID
  5854. shoparp() {                             /* Protocol */
  5855.     extern int docrc, skipbup;
  5856.     char *s;
  5857.  
  5858. #ifdef CK_TIMERS
  5859.     extern int rttflg;
  5860. #endif /* CK_TIMERS */
  5861.  
  5862.     printf("Protocol: %s\n",ptab[protocol].p_name);
  5863.  
  5864.     if (protocol == PROTO_K) {
  5865.         printf("\nProtocol Parameters:   Send    Receive");
  5866.         if (timef)
  5867.           printf("\n Timeout (used=%2d):%7d*%8d ", timint, rtimo, pkttim);
  5868.         else
  5869.           printf("\n Timeout (used=%2d):%7d%9d ",  timint, rtimo, pkttim);
  5870. #ifdef XFRCAN
  5871.         printf("       Cancellation:    %s",showoff(xfrcan));
  5872.         if (xfrcan)
  5873.           printf(" %d %d", xfrchr, xfrnum);
  5874. #endif /* XFRCAN */
  5875.         printf("\n Padding:      %11d%9d", npad,   mypadn);
  5876.         if (bctr == 4)
  5877.           printf("        Block Check: blank-free-2\n");
  5878.         else
  5879.           printf("        Block Check: %6d\n",bctr);
  5880.         printf(  " Pad Character:%11d%9d", padch,  mypadc);
  5881.         printf("        Delay:       %6d\n",ckdelay);
  5882.         printf(  " Pause:        %11d%9d", pktpaus, pktpaus);
  5883.         printf("        Attributes:      %s\n",showoff(atcapr));
  5884.         printf(  " Packet Start: %11d%9d", mystch, stchr);
  5885.         printf("        Max Retries: %6d%s\n",
  5886.                maxtry,
  5887.                (maxtry == 0) ? " (unlimited)" : ""
  5888.                );
  5889.         printf(  " Packet End:   %11d%9d", seol,   eol);
  5890.         if (ebqflg)
  5891.           printf("        8th-Bit Prefix: '%c'",ebq);
  5892.         else
  5893.           printf("        8th-Bit Prefix: ('%c' but not used)",ebq);
  5894.         printf(  "\n Packet Length:%11d ", spmax);
  5895.         printf("%8d     ",  urpsiz);
  5896.         if (rptflg)
  5897.           printf("   Repeat Prefix:  '%c'",rptq);
  5898.         else
  5899.           printf("   Repeat Prefix:  ('%c' but not used)",rptq);
  5900.         printf(  "\n Maximum Length: %9d%9d", maxsps, maxrps);
  5901.         printf("        Window Size:%7d set, %d used\n",wslotr,wmax);
  5902.         printf(    " Buffer Size:  %11d%9d", bigsbsiz, bigrbsiz);
  5903.         printf("        Locking-Shift:    ");
  5904.         if (lscapu == 2) {
  5905.             printf("forced");
  5906.         } else {
  5907.             printf("%s", (lscapr ? "enabled" : "disabled"));
  5908.             if (lscapr) printf(",%s%s", (lscapu ? " " : " not "), "used");
  5909.         }
  5910.         printf("\n\n");
  5911.  
  5912.         if (!(s = ptab[protocol].h_b_init)) s = "";
  5913.         printf(" Auto-upload command (binary): ");
  5914.         if (*s) {
  5915.             shostrdef((CHAR *)s);
  5916.             printf("\n");
  5917.         } else {
  5918.             printf("(none)\n");
  5919.         }
  5920.         if (!(s = ptab[protocol].h_t_init)) s = "";
  5921.         printf(" Auto-upload command (text):   ");
  5922.         if (*s) {
  5923.             shostrdef((CHAR *)s);
  5924.             printf("\n");
  5925.         } else {
  5926.             printf("(none)\n");
  5927.         }
  5928.         if (!(s = ptab[protocol].h_x_init)) s = "";
  5929.         printf(" Auto-server command:          ");
  5930.         if (*s) {
  5931.             shostrdef((CHAR *)s);
  5932.             printf("\n");
  5933.         } else {
  5934.             printf("(none)\n");
  5935.         }
  5936.         tmpbuf[0] = NUL;
  5937. #ifdef CK_TIMERS
  5938.         if (rttflg) {
  5939.             extern int mintime, maxtime;
  5940.             sprintf(tmpbuf," Packet timeouts: dynamic %d:%d", /* SAFE */
  5941.                     mintime,
  5942.                     maxtime);
  5943.         } else {
  5944.             sprintf(tmpbuf," Packet timeouts: fixed"); /* SAFE */
  5945.         }
  5946. #endif /* CK_TIMERS */
  5947.         if (tmpbuf[0])
  5948.           printf("%-31s",tmpbuf);
  5949.         printf("Send backup: %s\n",showoff(!skipbup));
  5950.  
  5951.         printf(" Transfer mode:   %s", xfermode == XMODE_A ?
  5952.                "automatic   " :
  5953.                "manual      "
  5954.                );
  5955.         printf(" Transfer slow-start: %s, crc: %s\n",
  5956.                showoff(slostart),
  5957.                showoff(docrc)
  5958.                );
  5959. #ifdef PIPESEND
  5960.         {
  5961.             extern int usepipes;
  5962.             printf(" Transfer pipes:  %s         ",usepipes ? "on " : "off");
  5963.         }
  5964. #endif /* PIPESEND */
  5965. #ifndef NOCSETS
  5966.         printf(" Transfer character-set: ");
  5967.         if (tcharset == TC_TRANSP)
  5968.           printf("transparent\n");
  5969.         else
  5970.           printf("%s\n", tcsinfo[tcharset].keyword );
  5971. #endif /* NOCSETS */
  5972. #ifdef PIPESEND
  5973.         {
  5974.             extern char * sndfilter, * rcvfilter;
  5975.             printf(" Send filter:     %s\n", sndfilter ? sndfilter : "(none)");
  5976.             printf(" Receive filter:  %s\n", rcvfilter ? rcvfilter : "(none)");
  5977.         }
  5978. #endif /* PIPESEND */
  5979.         printf("\nAlso see:\n");
  5980.         printf(" SHOW FILE, SHOW XFER");
  5981.  
  5982. #ifdef CK_LABELED
  5983.         printf(", SHOW LABELED");
  5984. #endif /* CK_LABELED */
  5985. #ifdef PATTERNS
  5986.         printf(", SHOW PATTERNS");
  5987. #endif /* PATTERNS */
  5988. #ifdef STREAMING
  5989.         printf(", SHOW STREAMING");
  5990. #endif /* STREAMING */
  5991. #ifndef NOCSETS
  5992.         printf(", SHOW CHARACTER-SETS");
  5993. #endif /* NOCSETS */
  5994.     }
  5995.  
  5996. #ifdef CK_XYZ
  5997. #ifdef XYZ_INTERNAL
  5998.     if (protocol != PROTO_K) {
  5999.         int i;
  6000.         int x;
  6001.         printf(" File type: %s\n", binary ? "binary" : "text");
  6002.         if (protocol == PROTO_Z) {              /* Zmodem */
  6003.             printf(" Window size:   ");
  6004.             if (ptab[protocol].winsize < 1)
  6005.               printf("none\n");
  6006.             else
  6007.               printf("%d\n",wslotr);
  6008. #ifdef COMMENT
  6009.             printf(" Packet (frame) length: ");
  6010.             if (ptab[protocol].spktlen < 0)
  6011.               printf("none\n");
  6012.             else
  6013.               printf("%d\n",spmax);
  6014. #endif /* COMMENT */
  6015.         } else {
  6016.             if (ptab[protocol].spktlen >= 1000)
  6017.               printf(" 1K packets\n");
  6018.             else
  6019.               printf(" 128-byte packets\n");
  6020.         }
  6021.         printf(" Pathname stripping when sending:   %s\n",
  6022.                showoff(ptab[protocol].fnsp)
  6023.                );
  6024.         printf(" Pathname stripping when receiving: %s\n",
  6025.                showoff(ptab[protocol].fnrp)
  6026.                );
  6027.         printf(" Filename collision action:         ");
  6028.         for (i = 0; i < ncolx; i++)
  6029.           if (colxtab[i].kwval == fncact) break;
  6030.         printf("%-12s", (i == ncolx) ? "unknown" : colxtab[i].kwd);
  6031.  
  6032.         printf("\n Escape control characters:          ");
  6033.         x = ptab[protocol].prefix;
  6034.         if (x == PX_ALL)
  6035.           printf("all\n");
  6036.         else if (x == PX_CAU || x==PX_WIL)
  6037.           printf("minimal\n");
  6038.         else
  6039.           printf("none\n");
  6040.         if (!(s = ptab[protocol].h_b_init))
  6041.           s = "";
  6042.         printf(" Autoreceive command (binary): %s\n", *s ? s : "(none)");
  6043.         if (!(s = ptab[protocol].h_t_init))
  6044.           s = "";
  6045.         printf(" Autoreceive command (text):   %s\n", *s ? s : "(none)");
  6046.     }
  6047. #else
  6048.     if (protocol != PROTO_K) {
  6049.         printf("\nExecuted by external commands:\n\n");
  6050.         s = ptab[protocol].p_b_scmd;
  6051.         if (!s) s = "";
  6052.         printf(" SEND command (binary):        %s\n", *s ? s : "(none)");
  6053.         s = ptab[protocol].p_t_scmd;
  6054.         if (!s) s = "";
  6055.         printf(" SEND command (text):          %s\n", *s ? s : "(none)");
  6056.         s = ptab[protocol].p_b_rcmd;
  6057.         if (!s) s = "";
  6058.         printf(" RECEIVE command (binary):     %s\n", *s ? s : "(none)");
  6059.         s = ptab[protocol].p_t_rcmd;
  6060.         if (!s) s = "";
  6061.         printf(" RECEIVE command (text):       %s\n", *s ? s : "(none)");
  6062.         s = ptab[protocol].h_b_init;
  6063.         if (!s) s = "";
  6064.         printf(" Autoreceive command (binary): %s\n", *s ? s : "(none)");
  6065.         s = ptab[protocol].h_t_init;
  6066.         if (!s) s = "";
  6067.         printf(" Autoreceive command (text):   %s\n", *s ? s : "(none)");
  6068.     }
  6069. #endif /* XYZ_INTERNAL */
  6070. #endif /* CK_XYZ */
  6071. }
  6072. #endif /* NOXFER */
  6073.  
  6074. #ifndef NOCSETS
  6075. /* Character-set items */
  6076.  
  6077. extern int s_cset, r_cset, axcset[], afcset[];
  6078. extern struct keytab xfrmtab[];
  6079.  
  6080. VOID
  6081. shoparl() {
  6082. #ifdef COMMENT
  6083.     int i;
  6084. /* Misleading... */
  6085.     printf("\nAvailable Languages:\n");
  6086.     for (i = 0; i < MAXLANG; i++) {
  6087.         printf(" %s\n",langs[i].description);
  6088.     }
  6089. #else
  6090.     printf("\nLanguage-specific translation rules: %s\n",
  6091.            language == L_USASCII ? "none" : langs[language].description);
  6092.     shocharset();
  6093.     printf("\n\n");
  6094. #endif /* COMMENT */
  6095. }
  6096.  
  6097. VOID
  6098. shocharset() {
  6099.     int x;
  6100. #ifdef COMMENT
  6101.     char * s = "Unknown";
  6102.     extern int xlatype;
  6103. #endif /* COMMENT */
  6104.  
  6105. #ifndef NOXFER
  6106.     extern int xfrxla;
  6107. #endif /* NOXFER */
  6108.  
  6109.     debug(F101,"SHOW FILE CHAR","",fcharset);
  6110.     printf("\n");
  6111. #ifndef NOXFER
  6112.     printf(" Transfer Translation: %s\n", showoff(xfrxla));
  6113.     if (!xfrxla) {
  6114.         printf(
  6115.       " Because transfer translation is off, the following are ignored:\n\n");
  6116.     }
  6117. #endif /* NOXFER */
  6118.     printf(" File Character-Set: %s (%s), ",
  6119.            fcsinfo[fcharset].keyword,
  6120.            fcsinfo[fcharset].name
  6121.            );
  6122.     if ((x = fcsinfo[fcharset].size) == 128)
  6123.       printf("7-bit");
  6124.     else if (x == 256)
  6125.       printf("8-bit");
  6126.     else
  6127.       printf("multibyte");
  6128.     printf("\n");
  6129.     printf(" File Scan: %s\n",showoff(filepeek));
  6130.     printf("   Default 7bit-Character-Set: %s\n",fcsinfo[dcset7].keyword);
  6131.     printf("   Default 8bit-Character-Set: %s\n",fcsinfo[dcset8].keyword);
  6132.     printf(" Transfer Character-Set");
  6133. #ifdef COMMENT
  6134.     if (tslevel == TS_L2)
  6135.       printf(": (international)");
  6136.     else
  6137. #endif /* COMMENT */
  6138.     if (tcharset == TC_TRANSP)
  6139.       printf(": Transparent");
  6140.     else
  6141.       printf(": %s (%s)",tcsinfo[tcharset].keyword, tcsinfo[tcharset].name);
  6142.     printf("\n");
  6143. #ifdef COMMENT
  6144.     switch (xlatype) {
  6145.       case XLA_NONE: s = "None"; break;
  6146.       case XLA_BYTE: s = "Byte"; break;
  6147.       case XLA_JAPAN: s = "Japanese"; break;
  6148.       case XLA_UNICODE: s = "Unicode"; break;
  6149.     }
  6150.     printf("\n Translation type: %s\n",s);
  6151. #endif /* COMMENT */
  6152.     printf(" SEND character-set-selection: %s\n",xfrmtab[s_cset].kwd);
  6153.     printf(" RECEIVE character-set-selection: %s\n",xfrmtab[r_cset].kwd);
  6154.     if (s_cset == XMODE_A || r_cset == XMODE_A)
  6155.       printf(
  6156.       " (Use SHOW ASSOCIATIONS to list automatic character-set selections.)\n"
  6157.              );
  6158. }
  6159.  
  6160. VOID
  6161. showassoc() {
  6162.     int i, k, n = 4;
  6163.     char * s;
  6164.     printf("\nFor incoming files:\n\n");
  6165.     printf("Transfer Character-Set   File Character-Set\n");
  6166.     for (i = 1; i <= MAXTCSETS; i++) {
  6167.         k = axcset[i];
  6168.         if (k < 0 || k > MAXFCSETS)
  6169.           s = "(none)";
  6170.         else
  6171.           s = fcsinfo[k].keyword;
  6172.         if (!s) s = "";
  6173.         if (!*s) s = "(none)";
  6174.         printf(" %-25s%s\n",tcsinfo[i].keyword,s);
  6175.         if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  6176.     }
  6177.     printf("\nFor outbound files:\n\n");
  6178.     n += 2;
  6179.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  6180.     printf("File Character-Set       Transfer Character-Set\n");
  6181.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  6182.     for (i = 0; i <= MAXFCSETS; i++) {
  6183.         k = afcset[i];
  6184.         if (k < 0 || k > MAXTCSETS)
  6185.           s = "(none)";
  6186.         else
  6187.           s = tcsinfo[k].keyword;
  6188.         if (!s) s = "";
  6189.         if (!*s) s = "(none)";
  6190.         printf(" %-25s%s\n",fcsinfo[i].keyword,s);
  6191.         if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  6192.     }
  6193. }
  6194. #endif /* NOCSETS */
  6195.  
  6196. VOID
  6197. shopar() {
  6198.     printf("Show what?  (Type \"show ?\" for a list of possibilities.)\n");
  6199. }
  6200. #endif /* NOSHOW */
  6201.  
  6202. #ifndef NOXFER
  6203. /*  D O S T A T  --  Display file transfer statistics.  */
  6204.  
  6205. int
  6206. dostat(brief) int brief; {
  6207.     extern long filrej, peakcps;
  6208.     extern int lastspmax, streamed, cleared, streamok;
  6209.     extern char whoareu[];
  6210.     int n = 0, ftp = 0;
  6211.     extern int docrc, interrupted, fatalio;
  6212.  
  6213.     ftp = lastxfer & W_FTP;
  6214.  
  6215. #ifdef CK_TTGWSIZ
  6216. #ifdef OS2
  6217.     if (tt_cols[VTERM] < 0 || tt_rows[VTERM] < 0)
  6218.       ttgwsiz();
  6219. #else /* OS2 */
  6220.     if (ttgwsiz() > 0) {
  6221.         if (tt_rows > 0 && tt_cols > 0) {
  6222.             cmd_rows = tt_rows;
  6223.             cmd_cols = tt_cols;
  6224.         }
  6225.     }
  6226. #endif /* OS2 */
  6227. #endif /* CK_TTGWSIZ */
  6228.  
  6229.     debug(F101,"dostat xferstat","",xferstat);
  6230.     if (xferstat < 0) {
  6231.         printf(" No file transfers yet.\n");
  6232.         return(1);
  6233.     }
  6234.     n = 0;
  6235.     if (brief) { printf("\n"); n++; };
  6236.     printf(" protocol               : %s\n",
  6237.            ftp ? "ftp" : ptab[protocol].p_name);
  6238.     n++;
  6239.     printf(" status                 : ");
  6240.     if (xferstat) printf("SUCCESS\n");
  6241.     else if (interrupted) printf("FAILURE (interrupted)\n");
  6242.     else if (fatalio) printf("FAILURE (i/o error)\n");
  6243.     else printf("FAILURE\n");
  6244. #ifndef XYZ_INTERNAL
  6245.     if (!ftp && protocol != PROTO_K) {
  6246.         printf("\n external protocol statistics not available\n");
  6247.         return(1);
  6248.     }
  6249. #endif /* XYZ_INTERNAL */
  6250.     n++;
  6251.     if (!ftp) {
  6252.         if (!xferstat > 0) {
  6253.             if (docrc)
  6254.               printf(" crc-16 of file(s)      : %ld\n", crc16);
  6255.             else
  6256.               printf(" crc-16 of file(s)      : (disabled)\n");
  6257.             n++;
  6258.         }
  6259.         if (!xferstat && *epktmsg) {
  6260.             printf(" reason                 : %s\n", epktmsg);
  6261.             n++;
  6262.         }
  6263.     }
  6264.     if (!brief) {
  6265. #ifdef NEWFTP
  6266.         if (ftp) {
  6267.             extern char ftp_srvtyp[];
  6268.             printf(" remote system type     : %s\n",ftp_srvtyp);
  6269.         } else
  6270. #endif /* NEWFTP */
  6271.           if (whoareu[0]) {
  6272.             printf(" remote system type     : %s\n",
  6273.                    getsysid((char *)whoareu));
  6274.             n++;
  6275.         }
  6276.         printf(" files transferred      : %ld\n",filcnt - filrej);
  6277.         if (!ftp)
  6278.           printf(" files not transferred  : %ld\n",filrej);
  6279.         printf(" characters last file   : %s\n",ckfstoa(ffc));
  6280.         printf(" total file characters  : %s\n",ckfstoa(tfc));
  6281.         n += ftp ? 3 : 4;
  6282.         if (!ftp) {
  6283.             printf(" communication line in  : %s\n",ckfstoa(tlci));
  6284.             printf(" communication line out : %s\n",ckfstoa(tlco));
  6285.             printf(" packets sent           : %d\n", spackets);
  6286.             printf(" packets received       : %d\n", rpackets);
  6287.             n += 4;
  6288.         }
  6289.     }
  6290.     if (ftp) goto dotimes;
  6291.  
  6292.     printf(" damaged packets rec'd  : %d\n", crunched);
  6293.     printf(" timeouts               : %d\n", timeouts);
  6294.     printf(" retransmissions        : %d\n", retrans);
  6295.     n += 3;
  6296.  
  6297.     if (!brief) {
  6298.         if (filcnt > 0) {
  6299.             printf(" parity                 : %s",parnam((char)parity));
  6300.             n++;
  6301.             if (autopar) { printf(" (detected automatically)"); n++; }
  6302.             printf(
  6303.                  "\n control characters     : %ld prefixed, %ld unprefixed\n",
  6304.                    ccp, ccu);
  6305.             n++;
  6306.             printf(" 8th bit prefixing      : ");
  6307.             n++;
  6308.             if (ebqflg) printf("yes [%c]\n",ebq); else printf("no\n");
  6309.             n++;
  6310.             printf(" locking shifts         : %s\n", lscapu ? "yes" : "no");
  6311.             n++;
  6312.         }
  6313.     }
  6314.     if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
  6315.     if (streamed > 0)
  6316.       printf(" window slots used      : (streaming)\n");
  6317.     else
  6318.       printf(" window slots used      : %d of %d\n", wmax, wslotr);
  6319.     if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
  6320.     printf(" reliable:              : %s%s\n",
  6321.            streamok ? "" : "not ", "negotiated");
  6322.     if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
  6323.     printf(" clearchannel:          : %s%s\n",
  6324.            cleared  ? "" : "not ", "negotiated");
  6325.     if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
  6326.  
  6327.     if (!brief) {
  6328.         printf(" packet length          : %d (send), %d (receive)\n",
  6329.                lastspmax, urpsiz);
  6330.         if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
  6331.         printf(" compression            : ");
  6332.         if (rptflg)
  6333.           printf("yes [%c] (%ld)\n",(char) rptq,rptn);
  6334.         else
  6335.           printf("no\n");
  6336.         if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
  6337.         if (bctu == 4)
  6338.           printf(" block check type used  : blank-free-2\n");
  6339.         else
  6340.           printf(" block check type used  : %d\n",bctu);
  6341.         if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
  6342.     }
  6343.  
  6344.   dotimes:
  6345.  
  6346. #ifdef GFTIMER
  6347. #ifdef COMMENT
  6348.     printf(" elapsed time           : %0.3f sec, %s\n", fptsecs,hhmmss(tsecs));
  6349. #endif /* COMMENT */
  6350.     printf(" elapsed time           : %s (%0.3f sec)\n",
  6351.            hhmmss((long)(fptsecs + 0.5)),fptsecs);
  6352. #else
  6353. #ifdef COMMENT
  6354.     printf(" elapsed time           : %s (%d sec)\n",hhmmss(tsecs),tsecs);
  6355. #endif /* COMMENT */
  6356.     printf(" elapsed time           : %d sec, %s\n",tsecs,hhmmss(tsecs));
  6357. #endif /* GFTIMER */
  6358.     if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
  6359.     if (!ftp && local && !network && !brief) {
  6360.         if (speed <= 0L) speed = ttgspd();
  6361.         if (speed > 0L) {
  6362.             if (speed == 8880)
  6363.               printf(" transmission rate      : 75/1200 bps\n");
  6364.             else
  6365.               printf(" transmission rate      : %ld bps\n",speed);
  6366.             if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
  6367.         }
  6368.     }
  6369.     if (!ftp && local && !network &&    /* Only makes sense for */
  6370.         mdmtyp == 0 &&                  /* direct serial connections */
  6371.         speed > 99L &&                  /* when we really know the speed */
  6372.         speed != 8880L
  6373.         ) {
  6374.         int eff;
  6375.         eff = (((tfcps * 100L) / (speed / 100L)) + 5L) / 10L;
  6376.         printf(" effective data rate    : %ld cps (%d%%)\n",tfcps,eff);
  6377.     } else
  6378.       printf(" effective data rate    : %ld cps\n", tfcps);
  6379.     if (!ftp && peakcps > 0L && peakcps > tfcps)
  6380.       printf(" peak data rate         : %ld cps\n", peakcps);
  6381.     if (brief)
  6382.       printf("\nUse STATISTICS /VERBOSE for greater detail.\n\n");
  6383.     return(1);
  6384. }
  6385. #endif /* NOXFER */
  6386.  
  6387. #ifndef NOSPL
  6388.  
  6389. /* The INPUT command */
  6390.  
  6391. /*
  6392.   NOTE: An INPUT timeout of 0 means to perform a nonblocking read of the
  6393.   material that has already arrived and is waiting to be read, and perform
  6394.   matches against it, without doing any further reads.  It should succeed
  6395.   or fail instantaneously.
  6396. */
  6397.  
  6398. /* Output buffering for "doinput" */
  6399.  
  6400. #ifdef pdp11
  6401. #define MAXBURST 16             /* Maximum size of input burst */
  6402. #else
  6403. #define MAXBURST 1024
  6404. #endif /* pdp11 */
  6405. #ifdef OSK
  6406. static CHAR *conbuf;            /* Buffer to hold output for console */
  6407. #else
  6408. static CHAR conbuf[MAXBURST];   /* Buffer to hold output for console */
  6409. #endif /* OSK */
  6410. static int concnt = 0;          /* Number of characters buffered */
  6411. #ifdef OSK
  6412. static CHAR *sesbuf;            /* Buffer to hold output for session log */
  6413. #else
  6414. static CHAR sesbuf[MAXBURST];   /* Buffer to hold output for session log */
  6415. #endif /* OSK */
  6416. static int sescnt = 0;          /* Number of characters buffered */
  6417.  
  6418. extern int debses;                      /* TERMINAL DEBUG ON/OFF */
  6419.  
  6420. static VOID                             /* Flush INPUT echoing */
  6421. myflsh() {                              /* and session log output. */
  6422.     if (concnt > 0) {
  6423.         if (debses) {                   /* Terminal debugging? */
  6424.             int i;
  6425.             for (i = 0; i < concnt; i++)
  6426.               conol(dbchr(conbuf[i]));
  6427.         } else
  6428.           conxo(concnt, (char *) conbuf);
  6429.         concnt = 0;
  6430.     }
  6431.     if (sescnt > 0) {
  6432.         logstr((char *) sesbuf, sescnt);
  6433.         sescnt = 0;
  6434.     }
  6435. }
  6436.  
  6437. /* Execute the INPUT and MINPUT commands */
  6438.  
  6439. int instatus = -1;
  6440. long inetime = -1L;
  6441. int inwait = 0;
  6442. int nowrap = 0;
  6443.  
  6444. /* For returning the input sequence that matched */
  6445.  
  6446. #ifdef BIGBUFOK
  6447. #define MATCHBUFSIZ 8191
  6448. #else
  6449. #define MATCHBUFSIZ 1023
  6450. #endif /* BIGBUFOK */
  6451. static char * matchbuf = NULL;
  6452. static int matchindex = 0;
  6453. static int burst = 0;                      /* Chars remaining in input burst */
  6454. /*
  6455.   timo = How long to wait:
  6456.          < 0 = Wait forever
  6457.            0 = Don't wait at all - material must already have arrived
  6458.          > 0 = Wait this many seconds
  6459.   ms   = Array of strings to wait for.
  6460.   mp   = Array of flags.
  6461.          If mp[i] == 0, ms[i] is literal, else it's a pattern.
  6462.   flags = bit mask
  6463.     INPSW_NOM = /NOMATCH
  6464.     INPSW_CLR = /CLEAR
  6465.     INPSW_NOW = /NOWRAP
  6466.   Returns:
  6467.     0 on failure, 1 on success.
  6468. */
  6469. int
  6470. doinput(timo,ms,mp,flags) int timo; char *ms[]; int mp[]; int flags; {
  6471.     extern int inintr;
  6472. #ifdef CK_AUTODL
  6473.     extern int inautodl;
  6474. #endif /* CK_AUTODL */
  6475.     int x, y, i, t, rt, icn, anychar, mi[MINPMAX];
  6476. #ifdef GFTIMER
  6477.     CKFLOAT fpt = 0.0;
  6478. #endif /* GFTIMER */
  6479.     int nomatch = 0;
  6480.     int clearfirst = 0;
  6481.     int lastchar = 0;
  6482.     int waiting = 0;
  6483.     int imask = 0;
  6484.     char ch, *xp, *s;
  6485.     CHAR c;
  6486. #ifndef NOLOCAL
  6487. #ifdef OS2
  6488.     extern int term_io;
  6489.     int term_io_save;
  6490. #endif /* OS2 */
  6491. #endif /* NOLOCAL */
  6492. #ifdef TNCODE
  6493.     static int cr = 0;
  6494. #endif /* TNCODE */
  6495.     int is_tn = 0;
  6496. #ifdef SSHBUILTIN
  6497.     extern int ssh_cas;
  6498.     extern char * ssh_cmd;
  6499. #endif /* SSHBUILTIN */
  6500.  
  6501. /*
  6502.   CK_BURST enables the INPUT speedup code, which depends on ttchk() returning
  6503.   accurate information.  If INPUT fails with this code enabled, change the
  6504.   above "#define" to "#undef".
  6505. */
  6506. #define CK_BURST
  6507.  
  6508.     imask = cmask;
  6509.     if (parity) imask = 0x7f;
  6510.     inwait = timo;                      /* For \v(inwait) */
  6511.  
  6512.     /* Options from command switches */
  6513.  
  6514.     nowrap = flags & INPSW_NOW;        /* 4 = /NOWRAP */
  6515.     nomatch = flags & INPSW_NOM;    /* 1 = /NOMATCH */
  6516.     clearfirst = flags & INPSW_CLR;    /* 2 = /CLEAR */
  6517.  
  6518.     makestr(&inpmatch,NULL);
  6519.     if (!matchbuf) {
  6520.         matchbuf = malloc(MATCHBUFSIZ+1);
  6521.         matchbuf[0] = NUL;
  6522.     }
  6523.     matchindex = 0;
  6524.  
  6525.     /* If last time through we returned because of /NOWRAP and buffer full */
  6526.     /* now we have to clear the buffer to make room for another load. */
  6527.  
  6528.     if (nowrap && instatus == INP_BF)
  6529.       clearfirst = 1;
  6530.  
  6531.     if (clearfirst) {            /* INPUT /CLEAR */
  6532.     int i;
  6533.     myflsh();            /* Flush screen and log buffers */
  6534.     for (i = 0; i < inbufsize; i++)
  6535.       inpbuf[i] = NUL;
  6536.     inpbp = inpbuf;
  6537.     }
  6538.     is_tn =
  6539. #ifdef TNCODE
  6540.         (local && network && IS_TELNET()) || (!local && sstelnet)
  6541. #else
  6542.          0
  6543. #endif /* TNCODE */
  6544.           ;
  6545.  
  6546.     instatus = INP_IE;                  /* 3 = internal error */
  6547.     kbchar = 0;
  6548.  
  6549. #ifdef OSK
  6550.     if (conbuf == NULL) {
  6551.         if ((conbuf = (CHAR *)malloc(MAXBURST*2)) == NULL) {
  6552.             return(0);
  6553.         }
  6554.         sesbuf = conbuf + MAXBURST;
  6555.     }
  6556. #endif /* OSK */
  6557.  
  6558. #ifndef NOLOCAL
  6559.     if (local) {                        /* In local mode... */
  6560.         if ((waiting = ttchk()) < 0) {  /* check that connection is open */
  6561.         if (!quiet) {
  6562.         if ((!network 
  6563. #ifdef TN_COMPORT
  6564.               || istncomport()
  6565. #endif /* TN_COMPORT */
  6566.               ) && carrier != CAR_OFF)
  6567.             printf("?Carrier detect failure on %s.\n", ttname);
  6568.         else
  6569.             printf("?Connection %s %s is not open.\n",
  6570.                network ? "to" : "on",
  6571.                ttname
  6572.                );
  6573.         }
  6574.             instatus = INP_IO;
  6575.             return(0);
  6576.         }
  6577.         debug(F101,"doinput waiting","",waiting);
  6578.         y = ttvt(speed,flow);           /* Put line in "ttvt" mode */
  6579.         if (y < 0) {
  6580.             printf("?INPUT initialization error\n");
  6581.             instatus = INP_IO;
  6582.             return(0);                  /* Watch out for failure. */
  6583.         }
  6584.     }
  6585. #endif /* NOLOCAL */
  6586.  
  6587. #ifdef SSHBUILTIN
  6588.     if ( network && nettype == NET_SSH && ssh_cas && ssh_cmd && 
  6589.          !(strcmp(ssh_cmd,"kermit") && strcmp(ssh_cmd,"sftp"))) {
  6590.         if (!quiet)
  6591.       printf("?SSH Subsystem active: %s\n", ssh_cmd);
  6592.         instatus = INP_IKS;
  6593.         return(0);
  6594.     }
  6595. #endif /* SSHBUILTIN */
  6596.  
  6597.     debug(F111,"doinput ms[0]",ms[0],waiting);
  6598.  
  6599.     if (!ms[0]) {                       /* If we were passed a NULL pointer */
  6600.         anychar = 1;                    /*  ... */
  6601.     } else {
  6602.         y = (int)strlen(ms[0]);         /* Or if search string is empty */
  6603.         anychar = (y < 1);              /* any input character will do. */
  6604.     }
  6605.     if (nomatch) anychar = 0;        /* Don't match anything */
  6606.  
  6607.     if (!anychar && waiting == 0 && timo == 0)
  6608.       return(0);
  6609.  
  6610. #ifndef NODEBUG
  6611.     if (deblog) {
  6612.         char xbuf[24];
  6613.         debug(F101,"doinput anychar","",anychar);
  6614.         debug(F101,"doinput timo","",timo);
  6615.         debug(F101,"doinput echo","",inecho);
  6616. #ifdef CK_BURST
  6617.         debug(F101,"doinput burst","",burst);
  6618. #endif    /* CK_BURST */
  6619.         y = -1;
  6620.         while (ms[++y]) {
  6621.             sprintf(xbuf,"doinput string %2d",y); /* SAFE (24) */
  6622.             debug(F111,xbuf,ms[y],mp[y]);
  6623.         }
  6624.     }
  6625. #endif /* NODEBUG */
  6626.  
  6627. #ifdef IKS_OPTION
  6628.     if (is_tn) {
  6629.         /* If the remote side is in a state of IKS START-SERVER    */
  6630.         /* we request that the state be changed.  We will detect   */
  6631.         /* a failure to adhere to the request when we call ttinc() */
  6632.         if (TELOPT_U(TELOPT_KERMIT) &&
  6633.             TELOPT_SB(TELOPT_KERMIT).kermit.u_start)
  6634.           iks_wait(KERMIT_REQ_STOP,0);  /* Send Request-Stop */
  6635. #ifdef CK_AUTODL
  6636.         /* If we are processing packets during INPUT and we have not */
  6637.         /* sent a START message, do so now.                          */
  6638.         if (inautodl && TELOPT_ME(TELOPT_KERMIT) &&
  6639.             !TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
  6640.             tn_siks(KERMIT_START);      /* Send Kermit-Server Start */
  6641.         }
  6642. #endif /* CK_AUTODL */
  6643.     }
  6644. #endif /* IKS_OPTION */
  6645.     x = 0;                              /* Return code, assume failure */
  6646.     instatus = INP_TO;                  /* Status, assume timeout */
  6647.  
  6648.     for (y = 0; y < MINPMAX; y++)    /* Initialize... */
  6649.       mi[y] = 0;                        /*  ..string pattern match position */
  6650.  
  6651.     if (!inpcas[cmdlvl]) {              /* INPUT CASE = IGNORE?  */
  6652.         y = -1;
  6653.         while ((xp = ms[++y])) {    /* Convert each target to lowercase */
  6654.             while (*xp) {
  6655.                 if (isupper(*xp)) *xp = (char) tolower(*xp);
  6656.                 xp++;
  6657.             }
  6658.         }
  6659.     }
  6660.     rtimer();                           /* Reset timer. */
  6661. #ifdef GFTIMER
  6662.     rftimer();                          /* Floating-point timer too. */
  6663. #endif /* GFTIMER */
  6664.     inetime = -1L;                      /* Initialize elapsed time. */
  6665.     t = 0;                              /* Time now is 0. */
  6666.     m_found = 0;                        /* Default to timed-out */
  6667.     incount = 0;                        /* Character counter */
  6668.     rt = (timo == 0) ? 0 : 1;           /* Character-read timeout interval */
  6669.  
  6670. #ifndef NOLOCAL
  6671. #ifdef OS2
  6672.     term_io_save = term_io;             /* Disable I/O by emulator */
  6673.     term_io = 0;
  6674. #endif /* OS2 */
  6675. #endif /* NOLOCAL */
  6676.  
  6677.     while (1) {                         /* Character-getting loop */
  6678. #ifdef CK_APC
  6679.         /* Check to see if there is an Autodown or other APC command */
  6680.         if (apcactive == APC_LOCAL ||
  6681.             (apcactive == APC_REMOTE && apcstatus != APC_OFF)) {
  6682.             if (mlook(mactab,"_apc_commands",nmac) == -1) {
  6683.                 debug(F110,"doinput about to execute APC",apcbuf,0);
  6684.                 domac("_apc_commands",apcbuf,cmdstk[cmdlvl].ccflgs|CF_APC);
  6685.                 delmac("_apc_commands",1);
  6686.                 apcactive = APC_INACTIVE;
  6687. #ifdef DEBUG
  6688.             } else {
  6689.                 debug(F100,"doinput APC in progress","",0);
  6690. #endif /* DEBUG */
  6691.             }
  6692.         }
  6693. #endif /* CK_APC */
  6694.  
  6695.         if (timo == 0 && waiting < 1) { /* Special exit criterion */
  6696.             instatus = INP_TO;          /* for timeout == 0 */
  6697.             break;
  6698.         }
  6699.         if (local) {                    /* One case for local */
  6700.             y = ttinc(rt);              /* Get character from comm device */
  6701.             debug(F101,"doinput ttinc(rt) returns","",y);
  6702.             if (y < -1) {               /* Connection failed. */
  6703.                 instatus = INP_IO;      /* Status = i/o error */
  6704. #ifndef NOLOCAL
  6705. #ifdef OS2
  6706.                 term_io = term_io_save;
  6707. #endif /* OS2 */
  6708. #endif /* NOLOCAL */
  6709.                 switch (y) {
  6710.                   case -2:              /* Connection lost */
  6711.                     if (local && !network && carrier != CAR_OFF) {
  6712.                         dologend();
  6713.                         printf("Connection closed.\n");
  6714.                         ttclos(1);
  6715.                     }
  6716.                     break;
  6717.                   case -3:
  6718.                     dologend();
  6719.                     printf("Session Limit exceeded - closing connection.\n");
  6720.                     ttclos(1);
  6721.                   default:
  6722.                     break;
  6723.                 }
  6724.                 debug(F111,"doinput Connection failed","returning 0",y);
  6725.                 return(0);
  6726.             }
  6727.             if (inintr) {
  6728.                 debug(F111,"doinput","inintr",inintr);
  6729.                 if ((icn = conchk()) > 0) { /* Interrupted from keyboard? */
  6730.                     debug(F101,"input interrupted from keyboard","",icn);
  6731.                     kbchar = coninc(0);
  6732.                     if (kbchar >= 0) {
  6733.                         while (--icn > 0) {
  6734.                             debug(F110,"doinput","absorbing",0);
  6735.                             coninc(0);      /* Yes, absorb what was typed. */
  6736.                         }
  6737.                         instatus = INP_UI;  /* Fail and remember why. */
  6738.                         break;
  6739.                     }
  6740.                 }
  6741.             }
  6742.         } else {                        /* Another for remote */
  6743.             y = coninc(rt);
  6744.             debug(F101,"doinput coninc(rt) returns","",y);
  6745.         }
  6746.         if (y > -1) {                   /* A character arrived */
  6747.             debug(F111,"doinput","a character arrived",y);
  6748.             if (timo == 0)
  6749.               waiting--;
  6750. #ifndef OS2
  6751. #define TN_NOLO
  6752. #endif /* OS2 */
  6753. #ifdef NOLOCAL
  6754. #define TN_NOLO
  6755. #endif /* NOLOCAL */
  6756.  
  6757. #ifdef TN_NOLO
  6758.             debug(F100,"doinput TN_NOLO","",0);
  6759. #ifdef TNCODE
  6760.             /* Check for telnet protocol negotiation */
  6761.             if (is_tn) {
  6762.                 switch (y & 0xff) {
  6763.                   case IAC:
  6764.                     cr = 0;
  6765.                     myflsh();   /* Break from input burst for tn_doop() */
  6766. #ifdef CK_BURST
  6767.                     burst = 0;
  6768. #endif /* CK_BURST */
  6769.                     waiting -= 2;       /* (not necessarily...) */
  6770.                     switch (tn_doop((CHAR)(y & 0xff),duplex,ttinc)) {
  6771.                       case 2: duplex = 0; continue;
  6772.                       case 1: duplex = 1; continue;
  6773. #ifdef IKS_OPTION
  6774.                       case 4:
  6775.                         if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
  6776.                              !tcp_incoming) {
  6777.                             instatus = INP_IKS;
  6778.                             printf(
  6779.  " Internet Kermit Service in SERVER mode.\n Please use REMOTE commands.\n"
  6780.                                    );
  6781.                             break;
  6782.                         }
  6783.                         continue;
  6784. #endif /* IKS_OPTION */
  6785.                       case 6:           /* TELNET DO LOGOUT received */
  6786.             continue;
  6787.               case 3:        /* A quoted IAC */
  6788.             break;
  6789.                       default:
  6790.             continue;
  6791.                     }
  6792.                   case CR:
  6793.                     cr = 1;
  6794.                     break;
  6795.                   case NUL:
  6796.                     if (!TELOPT_U(TELOPT_BINARY) && cr) {
  6797.                         cr = 0;
  6798.                         continue;
  6799.                     }
  6800.                     cr = 0;
  6801.                     break;
  6802.                   default:
  6803.                     cr = 0;
  6804.                 }
  6805.                 /* I'm echoing remote chars */
  6806.                 if (TELOPT_ME(TELOPT_ECHO) && tn_rem_echo)
  6807.                   ttoc((char)y);
  6808.             }
  6809. #endif /* TNCODE */
  6810. #ifdef CK_AUTODL
  6811.             /* Check for file transfer packets */
  6812.             if (inautodl) autodown(y);
  6813. #endif /* CK_AUTODL */
  6814. #else  /* TN_NOLO */
  6815.             debug(F100,"doinput !TN_NOLO","",0);
  6816. #ifdef TNCODE
  6817.             /* Check for telnet protocol negotiation */
  6818.             if (is_tn) {
  6819.                 int tx;
  6820.                 switch (y & 0xff) {
  6821.                   case IAC:
  6822.                     myflsh();   /* Break from input burst for tn_doop() */
  6823. #ifdef CK_BURST
  6824.                     burst = 0;
  6825. #endif /* CK_BURST */
  6826. #ifdef IKS_OPTION
  6827.                     tx = scriptwrtbuf((USHORT)y);
  6828.                     if (tx == 4) {
  6829.                         if (TELOPT_U(TELOPT_KERMIT) && 
  6830.                 TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
  6831.                             !tcp_incoming
  6832.                             ) {
  6833.                             instatus = INP_IKS;
  6834.                             printf(
  6835.   " Internet Kermit Service in SERVER mode.\n Please use REMOTE commands.\n"
  6836.                                    );
  6837.                             break;
  6838.                         }
  6839.                     } else if (tx == 6) {
  6840.                         /* TELNET DO LOGOUT received */
  6841.  
  6842.                     }
  6843. #else /* IKS_OPTION */
  6844.                     /* Handles Telnet negotiations */
  6845.                     tx = scriptwrtbuf((USHORT)y);
  6846.                     if (tx == 6) {
  6847.                         /* TELNET DO LOGOUT received */
  6848.                     }
  6849. #endif /* IKS_OPTION */
  6850.                     waiting -= 2;       /* (not necessarily...) */
  6851.                     cr = 0;
  6852.                     continue;           /* and autodownload check */
  6853.                   case CR:
  6854.                     cr = 1;
  6855.                     tx = scriptwrtbuf((USHORT)y);
  6856.                     if (tx == 6) {
  6857.                         /* TELNET DO LOGOUT received */
  6858.                     }
  6859.                     break;
  6860.                   case NUL:
  6861.                     cr = 0;
  6862.                     if (!TELOPT_U(TELOPT_BINARY) && cr)
  6863.                       continue;
  6864.                     tx = scriptwrtbuf((USHORT)y);
  6865.                     if (tx == 6) {
  6866.                         /* TELNET DO LOGOUT received */
  6867.                     }
  6868.                     break;
  6869.                   default:
  6870.                     cr = 0;
  6871.                     tx = scriptwrtbuf((USHORT)y);
  6872.                     if (tx == 6) {
  6873.                         /* TELNET DO LOGOUT received */
  6874.                     }
  6875.                 }
  6876.                 /* I'm echoing remote chars */
  6877.                 if (TELOPT_ME(TELOPT_ECHO) && tn_rem_echo)
  6878.                   ttoc((CHAR)y);
  6879.             } else
  6880. #endif /* TNCODE */
  6881.               /* Handles terminal emulation responses */
  6882.               scriptwrtbuf((USHORT)y);
  6883. #endif /* TN_NOLO */
  6884.  
  6885.             /* Real input character to be checked */
  6886.  
  6887. #ifdef CK_BURST
  6888.             burst--;                    /* One less character waiting */
  6889.             debug(F101,"doinput burst","",burst);
  6890. #endif /* CK_BURST */
  6891.             c = (CHAR) (imask & (CHAR) y); /* Mask off any parity */
  6892.             inchar[0] = c;              /* Remember character for \v(inchar) */
  6893. #ifdef COMMENT
  6894. #ifdef CK_BURST
  6895.             /* Update "lastchar" time only once during input burst */
  6896.             if (burst <= 0)
  6897. #endif /* CK_BURST */
  6898. #endif /* COMMENT */
  6899.               lastchar = gtimer();      /* Remember when it came */
  6900.  
  6901.             if (c == '\0') {            /* NUL, we can't use it */
  6902.                 if (anychar) {          /* Except if any character will do? */
  6903.                     x = 1;              /* Yes, done. */
  6904.             instatus = INP_OK;
  6905.                     incount = 1;        /* This must be the first and only. */
  6906.                     break;
  6907.                 } else goto refill;    /* Otherwise continue INPUTting */
  6908.             }
  6909.             *inpbp++ = c;               /* Store char in circular buffer */
  6910.             incount++;                  /* Count it for \v(incount) */
  6911.  
  6912.             if (matchbuf) {
  6913.                 if (matchindex < MATCHBUFSIZ) {
  6914.                     matchbuf[matchindex++] = c;
  6915.                     matchbuf[matchindex] = NUL;
  6916.                 }
  6917.             }
  6918. #ifdef MAC
  6919.             {
  6920.                 extern char *ttermw;    /* fake pointer cast */
  6921.                 if (inecho) {
  6922.                     outchar(ttermw, c); /* echo to terminal window */
  6923.                     /* this might be too much overhead to do here ? */
  6924.                     updatecommand(ttermw);
  6925.                 }
  6926.             }
  6927. #else /* Not MAC */
  6928.             if (inecho) {               /* Buffer console output */
  6929.                 conbuf[concnt++] = c;
  6930.             }
  6931. #endif /* MAC */
  6932. #ifndef OS2
  6933.             if (seslog) {
  6934. #ifdef UNIX
  6935.                 if (sessft != 0 || c != '\r')
  6936. #else
  6937. #ifdef OSK
  6938.                 if (sessft != 0 || c != '\012')
  6939. #endif /* OSK */
  6940. #endif /* UNIX */
  6941.                   sesbuf[sescnt++] = c; /* Buffer session log output */
  6942.             }
  6943. #endif /* OS2 */
  6944.             if (anychar) {              /* Any character will do? */
  6945.                 x = 1;
  6946.         instatus = INP_OK;
  6947.                 break;
  6948.             }
  6949.             if (!inpcas[cmdlvl]) {      /* Ignore alphabetic case? */
  6950.                 if (isupper(c))         /* Yes, convert input char to lower */
  6951.                   c = (CHAR) tolower(c);
  6952.             }
  6953.             debug(F000,"doinput char","",c);
  6954.  
  6955.             /* Here is the matching section */
  6956.  
  6957.             y = -1;                     /* Loop thru search strings */
  6958.             while (!nomatch && (s = ms[++y])) {    /* ...as many as we have. */
  6959.                 if (mp[y]) {            /* Pattern match? */
  6960. #ifdef COMMENT
  6961.                     int j;
  6962.                     /* This is gross but it works... */
  6963.                     /* We could just as easily have prepended '*' to the  */
  6964.                     /* pattern and skipped the loop, except then we would */
  6965.                     /* not have any way to identify the matching string.  */
  6966.                     for (j = 0; j < matchindex; j++) {
  6967.                         if (ckmatch(s,&matchbuf[j],1,1)) {
  6968.                             matchindex = j;
  6969.                 instatus = INP_OK;
  6970.                             x = 1;
  6971.                             break;
  6972.                         }
  6973.                     }
  6974.                     if (x > 0)
  6975.                       break;
  6976. #else
  6977.                     /* July 2001 - ckmatch() returns match position. */
  6978.                     /* It works and it's not gross. */
  6979.             /* (4 = floating pattern) */
  6980.                     x = ckmatch(s,matchbuf,inpcas[cmdlvl],1+4);
  6981.                     if (x > 0) {
  6982.                         matchindex = x - 1;
  6983.             instatus = INP_OK;
  6984.                         x = 1;
  6985.                         break;
  6986.                     }
  6987. #endif /* COMMENT */
  6988.                     continue;
  6989.                 }                       /* Literal match. */
  6990.                 i = mi[y];              /* Match-position in search string. */
  6991.                 debug(F000,"compare char","",(CHAR)s[i]);
  6992.                 if (c == (CHAR) s[i]) { /* Check for match */
  6993.                     i++;                /* Got one, go to next character */
  6994.                 } else {                /* Don't have a match */
  6995.                     int j;
  6996.                     for (j = i; i > 0; ) { /* Back up in search string */
  6997.                         i--; /* (Do this here to prevent compiler foulup) */
  6998.                         /* j is the length of the substring that matched */
  6999.                         if (c == (CHAR) s[i]) {
  7000.                             if (!strncmp(s,&s[j-i],i)) {
  7001.                                 i++;          /* c actually matches -- cfk */
  7002.                                 break;
  7003.                             }
  7004.                         }
  7005.                     }
  7006.                 }
  7007.                 if ((CHAR) s[i] == (CHAR) '\0') { /* Matched to end? */
  7008.                     ckstrncpy(matchbuf,ms[y],MATCHBUFSIZ);
  7009.                     matchindex = 0;
  7010.             instatus = INP_OK;  /* Yes, */
  7011.                     x = 1;            
  7012.                     break;              /* done. */
  7013.                 }
  7014.                 mi[y] = i;              /* No, remember match-position */
  7015.             }
  7016.             if (x == 1) {               /* Set \v(minput) result */
  7017.         instatus = INP_OK;
  7018.                 m_found = y + 1;
  7019.                 break;
  7020.             }
  7021.             if (inpbp >= inpbuf + inbufsize) { /* Reached end of buffer? */
  7022.         if (nowrap) {        /* If /NOWRAP...*/
  7023.             instatus = INP_BF;    /* ...return indicating buffer full. */
  7024.             *inpbp = NUL;
  7025.             goto xinput;
  7026.         }
  7027.                 *inpbp = NUL;           /* Make it null-terminated */
  7028.                 inpbp = inpbuf;         /* Yes. */
  7029.             }
  7030.         }
  7031. #ifdef CK_BURST
  7032.         else if (y <= -1 && burst > 0) {
  7033.             debug(F111,"doinput (y<=-1&&burst>0)","burst",burst);
  7034.                                         /* A timeout occurred so there can't */
  7035.             burst = 0;                  /* be data waiting; must check timo */
  7036.         }
  7037.       refill:
  7038.         if (burst <= 0) {               /* No buffered chars remaining... */
  7039.             myflsh();                   /* Flush buffered output */
  7040.             if (local) {                /* Get size of next input burst */
  7041.                 burst = ttchk();
  7042.                 if (burst < 0) {        /* ttchk() says connection is closed */
  7043.                     instatus = INP_IO;  /* Status = i/o error */
  7044. #ifndef NOLOCAL
  7045. #ifdef OS2
  7046.                     term_io = term_io_save;
  7047. #endif /* OS2 */
  7048. #endif /* NOLOCAL */
  7049.  
  7050.             if ((!network 
  7051. #ifdef TN_COMPORT
  7052.                  || istncomport()
  7053. #endif /* TN_COMPORT */
  7054.              ) && carrier != CAR_OFF) {
  7055.     /* The test is written this way because the Microsoft compiler
  7056.      * is producing bad code if written:
  7057.      *
  7058.      *  if (network && (!istncomport() || carrier == CAR_OFF) )
  7059.      */
  7060.             break;
  7061.                      } else {
  7062.              printf("Fatal error - disconnected.\n");
  7063.              ttclos(1);
  7064.              break;
  7065.              }
  7066.                 }
  7067.                 if (inintr) {
  7068.                     if ((icn = conchk()) > 0) { /* Interrupt from keyboard? */
  7069.                         kbchar = coninc(0);
  7070.                         debug(F101,"input interrupted from keyboard","",icn);
  7071.                         while (--icn > 0) coninc(0); /* Yes, absorb chars. */
  7072.                         break;          /* And fail. */
  7073.                     }
  7074.                 }
  7075.             } else {
  7076.                 burst = conchk();
  7077.             }
  7078.             debug(F101,"doinput burst","",burst);
  7079.             /* Prevent overflow of "conbuf" and "sesbuf" */
  7080.             if (burst > MAXBURST)
  7081.               burst = MAXBURST;
  7082.  
  7083.             /* Did not match, timer exceeded? */
  7084.             t = gtimer();
  7085.             debug(F111,"doinput gtimer","burst",t);
  7086.             debug(F101,"doinput timo","",timo);
  7087.             if ((t >= timo) && (timo > 0))
  7088.               break;
  7089.             else if (insilence > 0 && (t - lastchar) > insilence)
  7090.               break;
  7091.         } else {
  7092.             debug(F111,"doinput (burst > 0)","burst",burst);
  7093.         }
  7094. #else  /* CK_BURST */
  7095.       refill:
  7096.         myflsh();                       /* Flush buffered output */
  7097.         /* Did not match, timer exceeded? */
  7098.         t = gtimer();
  7099.         debug(F111,"doinput gtimer","no burst",t);
  7100.         debug(F101,"doinput timo","",timo);
  7101.         if ((t >= timo) && (timo > -1))
  7102.           break;
  7103.         else if (insilence > 0 && (t - lastchar) > insilence)
  7104.           break;
  7105. #endif /* CK_BURST */
  7106.     }                                   /* Still have time left, continue. */
  7107.   xinput:
  7108.     myflsh();                           /* Flush buffered output */
  7109.     if (instatus == INP_BF) {        /* Buffer full and /NOWAIT */
  7110.     x = 0;                /* Must not succeed */
  7111.     } else {                /* Buffer full and /NOWAIT */
  7112.     if (nomatch) x = 1;        /* Succeed if nomatch and timed out */
  7113.     if (x > 0 && !nomatch)
  7114.       instatus = 0;
  7115.     }
  7116. #ifndef NOLOCAL
  7117. #ifdef OS2
  7118.     term_io = term_io_save;
  7119. #endif /* OS2 */
  7120. #endif /* NOLOCAL */
  7121. #ifdef COMMENT
  7122. #ifdef IKS_OPTION
  7123. #ifdef CK_AUTODL
  7124.     if (is_tn && TELOPT_ME(TELOPT_KERMIT) && inautodl) {
  7125.         tn_siks(KERMIT_STOP);           /* Send Kermit-Server Stop */
  7126.     }
  7127. #endif /* CK_AUTODL */
  7128. #endif /* IKS_OPTION */
  7129. #endif /* COMMENT */
  7130.  
  7131. #ifdef GFTIMER
  7132.     fpt = gftimer();                    /* Get elapsed time */
  7133.  
  7134. /* If a long is 32 bits, it would take about 50 days for this to overflow. */
  7135.  
  7136.     inetime = (int)(fpt * (CKFLOAT)1000.0);
  7137. #else
  7138.     inetime = (int)(gtimer() * 1000);
  7139. #endif /* GFTIMER */
  7140.  
  7141.     if (x > 0)
  7142.       makestr(&inpmatch,&matchbuf[matchindex]); /* \v(inmatch) */
  7143.     return(x);                          /* Return the return code. */
  7144. }
  7145. #endif /* NOSPL */
  7146.  
  7147. #ifndef NOSPL
  7148. /* REINPUT Command */
  7149.  
  7150. /*
  7151.   Note, the timeout parameter is required, but ignored.  Syntax is compatible
  7152.   with MS-DOS Kermit except timeout can't be omitted.  This function only
  7153.   looks at the characters already received and does not read any new
  7154.   characters from the connection.
  7155. */
  7156. int
  7157. doreinp(timo,s,pat) int timo; char *s; int pat; {
  7158.     int x, y, i;
  7159.     char *xx, *xp, *xq = (char *)0;
  7160.     CHAR c;
  7161.  
  7162.     if (!s) s = "";
  7163.     debug(F101,"doreinput pat","",pat);
  7164.  
  7165.     y = (int)strlen(s);
  7166.     debug(F111,"doreinput search",s,y);
  7167.  
  7168.     if (y > inbufsize) {                /* If search string longer than */
  7169.         debug(F101,"doreinput inbufsize","",inbufsize);
  7170.         return(0);                      /* input buffer, fail. */
  7171.     }
  7172.     makestr(&inpmatch,NULL);
  7173.     if (!matchbuf)
  7174.       matchbuf = malloc(MATCHBUFSIZ+1);
  7175.     matchindex = 0;
  7176.  
  7177.     x = 0;                              /* Return code, assume failure */
  7178.     i = 0;                              /* String pattern match position */
  7179.  
  7180.     if (!inpcas[cmdlvl]) {              /* INPUT CASE = IGNORE?  */
  7181.         xp = malloc(y+2);               /* Make a separate copy of the */
  7182.         if (!xp) {                      /* search string. */
  7183.             printf("?malloc error 6\n");
  7184.             return(x);
  7185.         } else xq = xp;                 /* Keep pointer to beginning. */
  7186.         while (*s) {                    /* Yes, convert to lowercase */
  7187.             *xp = *s;
  7188.             if (isupper(*xp)) *xp = (char) tolower(*xp);
  7189.             xp++; s++;
  7190.         }
  7191.         *xp = NUL;                      /* Terminate it! */
  7192.         s = xq;                         /* Move search pointer to it. */
  7193.     }
  7194.     xx = *inpbp ? inpbp : inpbuf;       /* Current INPUT buffer pointer */
  7195.     do {
  7196.         c = *xx++;                      /* Get next character */
  7197.         if (!c) break;
  7198.         if (xx >= inpbuf + inbufsize)   /* Wrap around if necessary */
  7199.           xx = inpbuf;
  7200.         if (!inpcas[cmdlvl]) {          /* Ignore alphabetic case? */
  7201.             if (isupper(c)) c = (CHAR) tolower(c); /* Yes */
  7202.         }
  7203.         if (pat) {
  7204.             int j;
  7205.             if (matchbuf) {
  7206.                 if (matchindex < MATCHBUFSIZ) {
  7207.                     matchbuf[matchindex++] = c;
  7208.                     matchbuf[matchindex] = NUL;
  7209.                 }
  7210.                 for (j = 0; j < matchindex; j++) { /* Gross but effective */
  7211.                     if (ckmatch(s,&matchbuf[j],1,1)) {
  7212.                         debug(F101,"GOT IT","",j);
  7213.                         matchindex = j;
  7214.                         x = 1;
  7215.                         break;
  7216.                     }
  7217.                 }
  7218.             }
  7219.             if (x > 0)
  7220.               break;
  7221.             continue;
  7222.         }
  7223.         debug(F000,"doreinp char","",c);
  7224.         debug(F000,"compare char","",(CHAR) s[i]);
  7225.         if (((char) c) == ((char) s[i])) { /* Check for match */
  7226.             i++;                        /* Got one, go to next character */
  7227.         } else {                        /* Don't have a match */
  7228.             int j;
  7229.             for (j = i; i > 0; ) {      /* [jrs] search backwards for it  */
  7230.                 i--;
  7231.                 if (((char) c) == ((char) s[i])) {
  7232.                     if (!strncmp(s,&s[j-i],i)) {
  7233.                         i++;
  7234.                         break;
  7235.                     }
  7236.                 }
  7237.             }
  7238.         }                               /* [jrs] or return to zero from -1 */
  7239.         if (s[i] == '\0') {             /* Matched all the way to end? */
  7240.             ckstrncpy(matchbuf,s,MATCHBUFSIZ);
  7241.             matchindex = 0;
  7242.             x = 1;                      /* Yes, */
  7243.             break;                      /* done. */
  7244.         }
  7245.     } while (xx != inpbp && x < 1);     /* Until back where we started. */
  7246.  
  7247.     if (!inpcas[cmdlvl]) if (xq) free(xq); /* Free this if it was malloc'd. */
  7248.     makestr(&inpmatch,&matchbuf[matchindex]); /* \v(inmatch) */
  7249.     return(x);                          /* Return search result. */
  7250. }
  7251.  
  7252. /*  X X S T R I N G  --  Interpret strings containing backslash escapes  */
  7253. /*  Z Z S T R I N G  --  (new name...)  */
  7254. /*
  7255.  Copies result to new string.
  7256.   strips enclosing braces or doublequotes.
  7257.   interprets backslash escapes.
  7258.   returns 0 on success, nonzero on failure.
  7259.   tries to be compatible with MS-DOS Kermit.
  7260.  
  7261.  Syntax of input string:
  7262.   string = chars | "chars" | {chars}
  7263.   chars = (c*e*)*
  7264.   where c = any printable character, ascii 32-126
  7265.   and e = a backslash escape
  7266.   and * means 0 or more repetitions of preceding quantity
  7267.   backslash escape = \operand
  7268.   operand = {number} | number | fname(operand) | v(name) | $(name) | m(name)
  7269.   number = [r]n[n[n]]], i.e. an optional radix code followed by 1-3 digits
  7270.   radix code is oO (octal), xX (hex), dD or none (decimal) (see xxesc()).
  7271. */
  7272.  
  7273. #ifndef NOFRILLS
  7274. int
  7275. yystring(s,s2) char *s; char **s2; {    /* Reverse a string */
  7276.     int x;
  7277.     static char *new;
  7278.     new = *s2;
  7279.     if (!s || !new) return(-1);         /* Watch out for null pointers. */
  7280.     if ((x = (int)strlen(s)) == 0) {    /* Recursion done. */
  7281.         *new = '\0';
  7282.         return(0);
  7283.     }
  7284.     x--;                                /* Otherwise, call self */
  7285.     *new++ = s[x];                      /* to reverse rest of string. */
  7286.     s[x] = 0;
  7287.     return(yystring(s,&new));
  7288. }
  7289. #endif /* NOFRILLS */
  7290.  
  7291. static char ipabuf[16] = { NUL };       /* IP address buffer */
  7292.  
  7293. static char *
  7294. getip(s) char *s; {
  7295.     char c=NUL;                         /* Workers... */
  7296.     int i=0, p=0, d=0;
  7297.     int state = 0;                      /* State of 2-state FSA */
  7298.  
  7299.     while ((c = *s++)) {
  7300.         switch(state) {
  7301.           case 0:                       /* Find first digit */
  7302.             i = 0;                      /* Output buffer index */
  7303.             ipabuf[i] = NUL;            /* Initialize output buffer */
  7304.             p = 0;                      /* Period counter */
  7305.             d = 0;                      /* Digit counter */
  7306.             if (isdigit(c)) {           /* Have first digit */
  7307.                 d = 1;                  /* Count it */
  7308.                 ipabuf[i++] = c;        /* Copy it */
  7309.                 state = 1;              /* Change state */
  7310.             }
  7311.             break;
  7312.  
  7313.           case 1:                       /* In numeric field */
  7314.             if (isdigit(c)) {           /* Have digit */
  7315.                 if (++d > 3)            /* Too many */
  7316.                   state = 0;            /* Start over */
  7317.                 else                    /* Not too many */
  7318.                   ipabuf[i++] = c;      /* Keep it */
  7319.             } else if (c == '.' && p < 3) { /* Have a period */
  7320.                 p++;                    /* Count it */
  7321.                 if (d == 0)             /* Not preceded by a digit */
  7322.                   state = 0;            /* Start over */
  7323.                 else                    /* OK */
  7324.                   ipabuf[i++] = c;      /* Keep it */
  7325.                 d = 0;                  /* Reset digit counter */
  7326.             } else if (p == 3 && d > 0) { /* Not part of address */
  7327.                 ipabuf[i] = NUL;        /* If we have full IP address */
  7328.                 return((char *)ipabuf); /* Return it */
  7329.             } else {                    /* Otherwise */
  7330.                 state = 0;              /* Start over */
  7331.                 ipabuf[0] = NUL;        /* (in case no more chars left) */
  7332.             }
  7333.         }
  7334.     }                                   /* Fall thru at end of string */
  7335.     ipabuf[i] = NUL;                    /* Maybe we have one */
  7336.     return((p == 3 && d > 0) ? (char *)ipabuf : "");
  7337. }
  7338. #endif /* NOSPL */
  7339.  
  7340. /* Date Routines */
  7341.  
  7342. /* Z J D A T E  --  Convert yyyymmdd date to Day of Year */
  7343.  
  7344. static int jdays[12] = {  0,31,59,90,120,151,181,212,243,273,304,334 };
  7345. static int ldays[12] = {  0,31,60,91,121,152,182,213,244,274,305,335 };
  7346. static char zjdbuf[12] = { NUL, NUL };
  7347. /*
  7348.   Deinde, ne in posterum a XII kalendas aprilis aequinoctium recedat,
  7349.   statuimus bissextum quarto quoque anno (uti mos est) continuari debere,
  7350.   praeterquam in centesimis annis; qui, quamvis bissextiles antea semper
  7351.   fuerint, qualem etiam esse volumus annum MDC, post eum tamen qui deinceps
  7352.   consequentur centesimi non omnes bissextiles sint, sed in quadringentis
  7353.   quibusque annis primi quique tres centesimi sine bissexto transigantur,
  7354.   quartus vero quisque centesimus bissextilis sit, ita ut annus MDCC, MDCCC,
  7355.   MDCCCC bissextiles non sint. Anno vero MM, more consueto dies bissextus
  7356.   intercaletur, februario dies XXIX continente, idemque ordo intermittendi
  7357.   intercalandique bissextum diem in quadringentis quibusque annis perpetuo
  7358.   conservetur.  - Gregorius XIII, Anno Domini MDLXXXII.
  7359. */
  7360. char *
  7361. zjdate(date) char * date; {             /* date = yyyymmdd */
  7362.     char year[5];
  7363.     char month[3];
  7364.     char day[3];
  7365.     int d, m, x, y;
  7366.     int leapday, j;
  7367.     char * time = NULL;
  7368.  
  7369.     if (!date) date = "";               /* Validate arg */
  7370.     x = strlen(date);
  7371.     if (x < 1) return("0");
  7372.     if (x < 8) return("-1");
  7373.     for (x = 0; x < 8; x++)
  7374.       if (!isdigit(date[x]))
  7375.         return("-1");
  7376.  
  7377.     if (date[8]) if (date[9])
  7378.       time = date + 9;
  7379.  
  7380.     year[0] = date[0];                  /* Isolate year */
  7381.     year[1] = date[1];
  7382.     year[2] = date[2];
  7383.     year[3] = date[3];
  7384.     year[4] = '\0';
  7385.  
  7386.     month[0] = date[4];                 /* Month */
  7387.     month[1] = date[5];
  7388.     month[2] = '\0';;
  7389.  
  7390.     day[0] = date[6];                   /* And day */
  7391.     day[1] = date[7];
  7392.     day[2] = '\0';
  7393.  
  7394.     leapday = 0;                        /* Assume no leap day */
  7395.     y = atoi(year);
  7396.     m = atoi(month);
  7397.     d = atoi(day);
  7398.     if (m > 2) {                        /* No Leap day before March */
  7399.         if (y % 4 == 0) {               /* If year is divisible by 4 */
  7400.             leapday = 1;                /* It's a Leap year */
  7401.             if (y % 100 == 0) {         /* Except if divisible by 100 */
  7402.                 if (y % 400 != 0)       /* but not by 400 */
  7403.                   leapday = 0;
  7404.             }
  7405.         }
  7406.     }
  7407.     j = jdays[m - 1] + d + leapday;     /* Day of year */
  7408.     if (time)
  7409.       sprintf(zjdbuf,"%04d%03d %s",y,j,time); /* SAFE */
  7410.     else
  7411.       sprintf(zjdbuf,"%04d%03d",y,j);   /* SAFE */
  7412.     return((char *)zjdbuf);
  7413. }
  7414.  
  7415. static char jzdbuf[32];
  7416.  
  7417. /* J Z D A T E  --  Convert Day of Year to yyyyddmm date */
  7418.  
  7419. char *
  7420. jzdate(date) char * date; {             /* date = yyyyddd */
  7421.     char year[5];                       /* with optional time */
  7422.     char day[4];
  7423.     char * time = NULL, * p;
  7424.     int d, m, x, y;
  7425.     int leapday, j;
  7426.     int * zz;
  7427.  
  7428.     if (!date) date = "";               /* Validate arg */
  7429.     x = strlen(date);
  7430.  
  7431.     debug(F111,"jzdate len",date,x);
  7432.  
  7433.     if (x < 1) return("0");
  7434.     if (x < 7) return("-1");
  7435.     if (x > 8) time = date + 8;
  7436.  
  7437.     for (x = 0; x < 7; x++)
  7438.       if (!isdigit(date[x]))
  7439.         return("-1");
  7440.  
  7441.     year[0] = date[0];                  /* Isolate year */
  7442.     year[1] = date[1];
  7443.     year[2] = date[2];
  7444.     year[3] = date[3];
  7445.     year[4] = '\0';
  7446.  
  7447.     debug(F110,"jzdate year",year,0);
  7448.  
  7449.     day[0] = date[4];                   /* And day */
  7450.     day[1] = date[5];
  7451.     day[2] = date[6];
  7452.     day[3] = '\0';
  7453.  
  7454.     debug(F110,"jzdate day",day,0);
  7455.  
  7456.     j = atoi(day);
  7457.     if (j > 366)
  7458.       return("-1");
  7459.  
  7460.     leapday = 0;                        /* Assume no leap day */
  7461.     y = atoi(year);
  7462.     if (y % 4 == 0) {                   /* If year is divisible by 4 */
  7463.         leapday = 1;                    /* It's a Leap year */
  7464.         if (y % 100 == 0) {             /* Except if divisible by 100 */
  7465.             if (y % 400 != 0)           /* but not by 400 */
  7466.               leapday = 0;
  7467.         }
  7468.     }
  7469.     debug(F101,"jzdate leapday","",leapday);
  7470.     zz = leapday ? ldays : jdays;
  7471.  
  7472.     for (x = 0; x < 11; x++)
  7473.       if (j > zz[x] && j <= zz[x+1])
  7474.         break;
  7475.     m = x + 1;
  7476.  
  7477.     debug(F101,"jzdate m","",m);
  7478.  
  7479.     d = j - zz[x];
  7480.  
  7481.     debug(F101,"jzdate d","",d);
  7482.  
  7483.     if (time)
  7484.       sprintf(jzdbuf,"%04d%02d%02d %s",y,m,d,time); /* SAFE */
  7485.     else
  7486.       sprintf(jzdbuf,"%04d%02d%02d",y,m,d); /* SAFE */
  7487.  
  7488.     debug(F101,"jzdate jzdbuf",jzdbuf,0);
  7489.  
  7490.     p = ckcvtdate((char *)jzdbuf, 0);   /* Convert to standard form */
  7491.     ckstrncpy(jzdbuf,p,32);
  7492.     if (!time) jzdbuf[8] = NUL;         /* Remove time if not wanted */
  7493.     return((char *)jzdbuf);
  7494. }
  7495.  
  7496. /* M J D  --  Modified Julian Date */
  7497. /*
  7498.   Call with:
  7499.     Standard-format date-time string: yyyymmdd[ hh:mm:ss].
  7500.     The time, if any, is ignored.
  7501.  
  7502.   Returns:
  7503.     -1L on error, otherwise:
  7504.     The number of days since 17 Nov 1858 as a whole number:
  7505.     16 Nov 1858 = -1, 17 Nov 1858 = 0, 18 Nov 1858 = 1, 19 Nov 1858 = 2, ...
  7506.  
  7507.   The Modified Julian Date is defined by the International Astronomical
  7508.   Union as the true Julian date minus 2400000.5 days.  The true Julian
  7509.   date is the number days since since noon of 1 January 4713 BCE of the
  7510.   Julian proleptic calendar.  Conversions between calendar dates and
  7511.   Julian dates, however, assume Gregorian dating.
  7512. */
  7513. long
  7514. mjd(date) char * date; {
  7515.     char year[5];
  7516.     char month[3];
  7517.     char day[3];
  7518.     int x, a, d, m, y;
  7519.     long z;
  7520.  
  7521.     if (!date) date = "";               /* Validate arg */
  7522.     x = strlen(date);
  7523.     if (x < 1) return(0L);
  7524.     if (x < 8) return(-1L);
  7525.     for (x = 0; x < 8; x++)
  7526.       if (!isdigit(date[x]))
  7527.         return(-1L);
  7528.  
  7529.     year[0] = date[0];                  /* Isolate year */
  7530.     year[1] = date[1];
  7531.     year[2] = date[2];
  7532.     year[3] = date[3];
  7533.     year[4] = '\0';
  7534.  
  7535.     month[0] = date[4];                 /* Month */
  7536.     month[1] = date[5];
  7537.     month[2] = '\0';;
  7538.     m = atoi(month);
  7539.  
  7540.     day[0] = date[6];                   /* And day */
  7541.     day[1] = date[7];
  7542.     day[2] = '\0';
  7543.     d = atoi(day);
  7544.  
  7545.     a = (14-m)/12;                      /* Calculate true Julian date */
  7546.     y = atoi(year) + 4800 - a;
  7547.     m = m + 12 * a - 3;
  7548.     z = d + (long)(306*m+5)/10 + (long)(y*365) + y/4 - y/100 + y/400 - 32045L;
  7549.  
  7550.     z -= 2400001L;                      /* Convert JD to MJD */
  7551.  
  7552.     return(z);
  7553. }
  7554.  
  7555. static char mjd2dbuf[32];
  7556.  
  7557. /*  M J D 2 D A T E  --  Converts MJD to yyyymmdd  */
  7558.  
  7559. char *
  7560. #ifdef CK_ANSIC
  7561. mjd2date(long mjd)
  7562. #else
  7563. mjd2date(mjd) long mjd;
  7564. #endif /* CK_ANSIC */
  7565. /* mjd2date */ {
  7566.     long jd, l, n;
  7567.     int d, m, y;
  7568.     jd = (long)(mjd + 2400001L);
  7569.     l = jd + 68569;
  7570.     n = 4 * l / 146097L;
  7571.     l = l - (146097 * n + 3) / 4;
  7572.     y = 4000 * (l + 1) / 1461001L;
  7573.     l = l - 1461 * y / 4 + 31;
  7574.     m = 80 * l / 2447;
  7575.     d = l - 2447 * m / 80;
  7576.     l = m / 11;
  7577.     m = m + 2 - 12 * l;
  7578.     y = 100 * (n - 49) + y + l;
  7579.     sprintf(mjd2dbuf,"%04d%02d%02d",y,m,d); /* SAFE */
  7580.     return((char *)mjd2dbuf);
  7581. }
  7582.  
  7583. #ifndef NOSPL
  7584. static char ** flist = (char **) NULL;  /* File list for \fnextfile() */
  7585. static int flistn = 0;                  /* Number of items in file list */
  7586.  
  7587. /*
  7588.   The function return-value buffer must be global, since fneval() returns a
  7589.   pointer to it.  fneval() is called only by zzstring(), which always copies
  7590.   the result out of this buffer to somewhere else, so it's OK to have only
  7591.   one buffer for this in most cases.  However, since function calls can be
  7592.   nested -- e.g. functions whose arguments are functions, or recursive
  7593.   functions, at some point we should convert this to an array of buffers,
  7594.   indexed by function depth (which might or might not be the same as the
  7595.   "depth" variable).  Also, since function results are potentially quite big,
  7596.   we'd need to allocate and deallocate dynamically as we descend and ascend
  7597.   function depth.  Left for a future release...
  7598. */
  7599. char fnval[FNVALL+2];                   /* Function return value  */
  7600. static int fndepth = 0;                 /* (we don't actually use this yet) */
  7601. int fnsuccess = 1;
  7602. extern int fnerror;
  7603.  
  7604. /* f p f o r m a t  --  Floating-point number nicely formatted.  */
  7605. /*
  7606.    Returns results from a circular 1K buffer.
  7607.    Don't count on too many results remaining available at once; it could
  7608.    be anywhere from 5 to maybe 100, depending on the sizes of the results.
  7609. */
  7610. #ifdef CKFLOAT
  7611. #define FPFMTSIZ 1024
  7612. static char fpfmtbuf[FPFMTSIZ] = { NUL, NUL };
  7613. static int fpfbufpos = 0;               /* (why was this char before?) */
  7614.  
  7615. char *
  7616. fpformat(fpresult,places,round) CKFLOAT fpresult; int places, round; {
  7617.     char fbuf[16];                      /* For creating printf format */
  7618.     int nines = 0, sign = 0, x, y, i, j, size = 0;
  7619.     char * buf;
  7620.     CKFLOAT ftmp;
  7621.  
  7622.     x = places ? places : (fp_digits ? fp_digits : 6);
  7623.  
  7624.     debug(F101,"fpformat fpresult","",fpresult);
  7625.     debug(F101,"fpformat places","",places);
  7626.     debug(F101,"fpformat fpfbufpos 1","",fpfbufpos);
  7627.  
  7628.     ftmp = fpresult;
  7629.     if (ftmp < 0.0) ftmp = 0.0 - fpresult;
  7630.  
  7631. #ifdef FNFLOAT
  7632.     if (!fp_rounding &&                 /* If printf doesn't round, */
  7633.         (places > 0 ||                  /* round result to decimal places. */
  7634.          (places == 0 && round)))
  7635.       fpresult += (0.5 / pow(10.0,(CKFLOAT)places));
  7636.     y = (ftmp == 0.0) ? 1 : (int)log10(ftmp);
  7637.     size = y + x + 3;                   /* Estimated length of result */
  7638.     if (fpresult < 0.0) size++;
  7639. #else
  7640.     size = 200;                         /* No way to estimate, be generous */
  7641. #endif /* FNFLOAT */
  7642.  
  7643.     debug(F101,"fpformat size","",size);
  7644.  
  7645.     if (fpfbufpos > (FPFMTSIZ - size))  /* Wrap around if necessary */
  7646.       fpfbufpos = 0;
  7647.     debug(F101,"fpformat fpfbufpos 1","",fpfbufpos);
  7648.  
  7649.     buf = &fpfmtbuf[fpfbufpos];
  7650.  
  7651.     if (places > 0) {                   /* If places specified */
  7652.         /* use specified places to write given number of digits */
  7653.         sprintf(fbuf,"%%0.%df",places); /* SAFE */
  7654.         sprintf(buf,fbuf,fpresult);     /* SAFE */
  7655.     } else {                            /* Otherwise... */
  7656.         /* Go for max precision */
  7657.         sprintf(fbuf,"%%0.%df",fp_digits); /* SAFE */
  7658.         sprintf(buf,fbuf,fpresult);     /* SAFE */
  7659.     }
  7660.     if (buf[0] == '-') sign = 1;
  7661.     debug(F111,"fpresult 1 errno",buf,errno); /* Check for over/underflow */
  7662.     debug(F111,"fpresult 1 fpfbufpos",buf,fpfbufpos);
  7663.     /* Give requested decimal places */
  7664.     for (i = sign; i < FPFMTSIZ && buf[i]; i++) {
  7665.         if (buf[i] == '.')              /* First find the decimal point */
  7666.           break;
  7667.         else if (i > fp_digits + sign - 1) /* replacing garbage */
  7668.           buf[i] = '0';                 /* digits with 0... */
  7669.     }
  7670.     if (buf[i] == '.') {                /* Have decimal point */
  7671.         int gotend = 0;
  7672.         /* places < 0 so truncate fraction */
  7673.         if (places < 0 || (places == 0 && round)) {
  7674.             buf[i] = NUL;
  7675.         } else if (places > 0) {        /* d > 0 so this many decimal places */
  7676.             i++;                           /* First digit after decimal */
  7677.             for (j = 0; j < places; j++) { /* Truncate after d decimal */
  7678.                 if (!buf[j+i])        /* places or extend to d  */
  7679.                   gotend = 1;              /* decimal places. */
  7680.                 if (gotend || j+i+sign > fp_digits)
  7681.                   buf[j+i] = '0';
  7682.             }
  7683.             buf[j+i] = NUL;
  7684.         } else {                        /* places == 0 so Do The Right Thing */
  7685.             for (j = (int)strlen(buf) - 1; j > i+1; j--) {
  7686.                 if ((j - sign) > fp_digits)
  7687.                   buf[j] = '0';
  7688.                 if (buf[j] == '0')
  7689.                   buf[j] = NUL; /* Strip useless trailing 0's. */
  7690.                 else
  7691.                   break;
  7692.             }
  7693.         }
  7694.     }
  7695.     fpfmtbuf[FPFMTSIZ-1] = NUL;
  7696.     j = strlen(buf);
  7697.     sign = 0;
  7698.     for (i = j-1; i >= 0; i--) {
  7699.         if (buf[i] == '9')
  7700.           nines++;
  7701.         else
  7702.           break;
  7703.     }
  7704.     /* Do something about xx.xx99999999... */
  7705.     if (nines > 5) {
  7706.         if (isdigit(buf[i]) && i < FPFMTSIZ - 2) {
  7707.             buf[i] = buf[i] + 1;
  7708.             buf[i+1] = '0';
  7709.             buf[i+2] = '\0';
  7710.         }
  7711.     }
  7712.     if (!strncmp(buf,"-0.0",FPFMTSIZ))
  7713.       ckstrncpy(buf,"0.0",FPFMTSIZ);
  7714.     fpfbufpos += (int)strlen(buf) + 1;
  7715.     return((char *)buf);
  7716. }
  7717. #endif /* CKFLOAT */
  7718.  
  7719. static VOID
  7720. evalerr(fn) char * fn; {
  7721.     if (fndiags) {
  7722.         if (divbyzero)
  7723.           ckmakmsg(fnval,FNVALL,"<ERROR:DIVIDE_BY_ZERO:\\f",fn,"()>",NULL);
  7724.         else
  7725.           ckmakmsg(fnval,FNVALL,"<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  7726.     }
  7727. }
  7728.  
  7729. char *
  7730. dokwval(s,sep) char * s, sep; {
  7731.     char c = '\0', * p, * kw = NULL, * vp = NULL;
  7732.     int x;
  7733.     if (!s) return("0");
  7734.     if (!*s) return("0");
  7735.     debug(F110,"kwval arg",s,0);
  7736.     debug(F110,"kwval sep",ckctoa(sep),0);
  7737.     p = (char *)malloc((int)strlen(s)+1);
  7738.     if (!p) return("0");
  7739.     strcpy(p,s);                        /* SAFE */
  7740.     s = p;
  7741.     while (*s < '!' && *s > '\0')       /* Get first nonblank */
  7742.       s++;
  7743.     if (!*s) return("0");
  7744.     if (*s == sep) return("0");
  7745.     kw = s;                             /* Keyword */
  7746.     while (*s > ' ') {
  7747.         if (*s == sep) {                /* keyword=... */
  7748.             c = *s;
  7749.             break;
  7750.         }
  7751.         s++;
  7752.     }
  7753.     *s++ = NUL;                         /* Terminate keyword */
  7754.     while (*s < '!' && *s > '\0')       /* Skip blanks */
  7755.       s++;
  7756.     if (!c && *s == sep) {
  7757.         c = *s++;                       /* Have separator */
  7758.         while (*s < '!' && *s > '\0')   /* Skip blanks */
  7759.           s++;
  7760.     }
  7761.     if (c) {
  7762.         vp = s;
  7763.         while (*s > ' ')                /* Skip to end */
  7764.           s++;
  7765.         *s = NUL;                       /* Terminate value */
  7766.     }
  7767.     debug(F110,"kwval c",ckctoa(c),0);
  7768.     debug(F110,"kwval keyword",kw,0);
  7769.     debug(F110,"kwval value",vp,0);
  7770.     x = c ? addmac(kw,vp) : -1;
  7771.     free(p);
  7772.     return((x < 0) ? "0" : "1");
  7773. }
  7774.  
  7775. static int
  7776. isaarray(s) char * s; {            /* Is s an associative array element */
  7777.     int state = 0;
  7778.     CHAR c;
  7779.     if (!s) return(0);
  7780.     while ((c = *s++)) {
  7781.     if (!isprint(c)) {
  7782.         return(0);
  7783.     } else if (c == '<') {
  7784.         if (state != 0)
  7785.           return(0);
  7786.         state = 1;
  7787.     } else if (c == '>') {
  7788.         return((state != 1 || *s) ? 0 : 1);
  7789.     }
  7790.     }
  7791.     return(0);
  7792. }
  7793.  
  7794. static char *                           /* Evaluate builtin functions */
  7795. fneval(fn,argp,argn,xp) char *fn, *argp[]; int argn; char * xp; {
  7796.     int i=0, j=0, k=0, len1=0, len2=0, len3=0, n=0, t=0, x=0, y=0;
  7797.     int cx, failed = 0;                 /* Return code, 0 = ok */
  7798.     long z = 0L;
  7799.     char *bp[FNARGS + 1];               /* Pointers to malloc'd strings */
  7800.     char c = NUL;
  7801.     char *p = NULL, *s = NULL;
  7802.     char *val1 = NULL, *val2 = NULL;    /* Pointers to numeric string values */
  7803.  
  7804. #ifdef RECURSIVE
  7805.     int rsave = recursive;
  7806. #endif /* RECURSIVE */
  7807. #ifdef OS2
  7808.     int zsave = zxpn;
  7809. #endif /* OS2 */
  7810.  
  7811.     if (!fn) fn = "";                   /* Protect against null pointers */
  7812.     if (!*fn) return("");
  7813.  
  7814.     for (i = 0; i < FNARGS; i++)        /* Initialize argument pointers */
  7815.       bp[i] = NULL;
  7816. /*
  7817.   IMPORTANT: Note that argn is not an accurate count of the number of
  7818.   arguments.  We can't really tell if an argument is null until after we
  7819.   execute the code below.  So argn is really the maximum number of arguments
  7820.   we might have.  Argn should always be at least 1, even if the function is
  7821.   called with empty parentheses (but don't count on it).
  7822. */
  7823.     debug(F111,"fneval",fn,argn);
  7824.     debug(F110,"fneval",argp[0],0);
  7825.     if (argn > FNARGS)                  /* Discard excess arguments */
  7826.       argn = FNARGS;
  7827.  
  7828.     fndepth++;
  7829.     debug(F101,"fneval fndepth","",fndepth);
  7830.     p = fnval;
  7831.     fnval[0] = NUL;
  7832.     y = lookup(fnctab,fn,nfuncs,&x);    /* Look up the function name */
  7833.     cx = y;                             /* Because y is too generic... */
  7834.     if (cx < 0) {                        /* Not found */
  7835.         failed = 1;
  7836.         if (fndiags) {                  /* FUNCTION DIAGNOSTIC ON */
  7837.             int x;
  7838.             x = strlen(fn);
  7839.             /* The following sprintf's are safe */
  7840.             switch (cx) {
  7841.               case -1:
  7842.                 if (x + 32 < FNVALL)
  7843.                   sprintf(fnval,"<ERROR:NO_SUCH_FUNCTION:\\f%s()>",fn);
  7844.                 else
  7845.                   sprintf(fnval,"<ERROR:NO_SUCH_FUNCTION>");
  7846.                 break;
  7847.               case -2:
  7848.                 if (x + 26 < FNVALL)
  7849.                   sprintf(fnval,"<ERROR:NAME_AMBIGUOUS:\\f%s()>",fn);
  7850.                 else
  7851.                   sprintf(fnval,"<ERROR:NAME_AMBIGUOUS>");
  7852.                 break;
  7853.               case -3:
  7854.                 sprintf(fnval,"<ERROR:FUNCTION_NAME_MISSING:\\f()>");
  7855.                 break;
  7856.               default:
  7857.                 if (x + 26 < FNVALL)
  7858.                   sprintf(fnval,"<ERROR:LOOKUP_FAILURE:\\f%s()>",fn);
  7859.                 else
  7860.                   sprintf(fnval,"<ERROR:LOOKUP_FAILURE>");
  7861.                 break;
  7862.             }
  7863.         }
  7864.         goto fnend;                     /* Always leave via common exit */
  7865.     }
  7866.     fn = fnctab[x].kwd;                 /* Full name of function */
  7867.  
  7868.     if (argn < 0) {
  7869.         failed = 1;
  7870.         p = fnval;
  7871.         if (fndiags)
  7872.           sprintf(fnval,"<ERROR:MISSING_ARG:\\f%s()>",fn);
  7873.         goto fnend;
  7874.     }
  7875.     if (cx == FN_LIT) {                 /* literal(arg1) */
  7876.         debug(F010,"flit",xp,0);
  7877.         p = xp ? xp : "";               /* Return a pointer to arg itself */
  7878.         goto fnend;
  7879.     }
  7880.  
  7881. #ifdef DEBUG
  7882.     if (deblog) {
  7883.         int j;
  7884.         for (j = 0; j < argn; j++)
  7885.       debug(F111,"fneval arg",argp[j],j);
  7886.     }
  7887. #endif /* DEBUG */
  7888.     for (j = argn-1; j >= 0; j--) {     /* Uncount empty trailing args */
  7889.         if (!argp[j])
  7890.           argn--;
  7891.         else if (!*(argp[j]))
  7892.           argn--;
  7893.         else break;
  7894.     }
  7895.     debug(F111,"fneval argn",fn,argn);
  7896. /*
  7897.   \fliteral() and \fcontents() are special functions that do not evaluate
  7898.   their arguments, and are treated specially here.  After these come the
  7899.   functions whose arguments are evaluated in the normal way.
  7900. */
  7901. #ifdef COMMENT
  7902.     /* (moved up) */
  7903.     if (cx == FN_LIT) {                 /* literal(arg1) */
  7904.         debug(F110,"flit",xp,0);
  7905.         p = xp ? xp : "";               /* Return a pointer to arg itself */
  7906.         goto fnend;
  7907.     }
  7908. #endif /* COMMENT */
  7909.     if (cx == FN_CON) {                 /* Contents of variable, unexpanded. */
  7910.         char c;
  7911.         if (!(p = argp[0]) || !*p) {
  7912.             failed = 1;
  7913.             p = fnval;
  7914.             if (fndiags)
  7915.               sprintf(fnval,"<ERROR:MISSING_ARG:\\fcontents()>");
  7916.             goto fnend;
  7917.         }
  7918.         p = brstrip(p);
  7919.         if (*p == CMDQ) p++;
  7920.         if ((c = *p) == '%') {          /* Scalar variable. */
  7921.             c = *++p;                   /* Get ID character. */
  7922.             p = "";                     /* Assume definition is empty */
  7923.             if (!c) {                   /* Double paranoia */
  7924.                 failed = 1;
  7925.                 p = fnval;
  7926.                 if (fndiags)
  7927.                   sprintf(fnval,"<ERROR:ARG_BAD_VARIABLE:\\fcontents()>");
  7928.                 goto fnend;
  7929.             }
  7930.             if (c >= '0' && c <= '9') { /* Digit for macro arg */
  7931.                 if (maclvl < 0)         /* Digit variables are global */
  7932.                   p = g_var[c];         /* if no macro is active */
  7933.                 else                    /* otherwise */
  7934.                   p = m_arg[maclvl][c - '0']; /* they're on the stack */
  7935.             } else if (c == '*') {
  7936. #ifdef COMMENT
  7937.                 p = (maclvl > -1) ? m_line[maclvl] : topline;
  7938.                 if (!p) p = "";
  7939. #else
  7940.                 int nx = FNVALL;
  7941.                 char * sx = fnval;
  7942.                 p = fnval;
  7943. #ifdef COMMENT
  7944.                 if (cmdsrc() == 0 && topline)
  7945.                   p = topline;
  7946.                 else
  7947. #endif /* COMMENT */
  7948.                   if (zzstring("\\fjoin(&_[],{ },1)",&sx,&nx) < 0) {
  7949.                     failed = 1;
  7950.                     p = fnval;
  7951.                     if (fndiags)
  7952.                       sprintf(fnval,"<ERROR:OVERFLOW:\\fcontents()>");
  7953.             debug(F110,"zzstring fcontents(\\%*)",p,0);
  7954.                 }
  7955. #endif /* COMMENT */
  7956.             } else {
  7957.                 if (isupper(c)) c -= ('a'-'A');
  7958.                 p = g_var[c];           /* Letter for global variable */
  7959.             }
  7960.             if (!p) p = "";
  7961.             goto fnend;
  7962.         } else if (c == '&') {          /* Array reference. */
  7963.             int vbi, d;
  7964.             if (arraynam(p,&vbi,&d) < 0) { /* Get name and subscript */
  7965.                 failed = 1;
  7966.                 p = fnval;
  7967.                 if (fndiags)
  7968.                   sprintf(fnval,"<ERROR:ARG_BAD_ARRAY:\\fcontents()>");
  7969.                 goto fnend;
  7970.             }
  7971.             if (chkarray(vbi,d) > 0) {  /* Array is declared? */
  7972.                 vbi -= ARRAYBASE;       /* Convert name to index */
  7973.                 if (a_dim[vbi] >= d) {  /* If subscript in range */
  7974.                     char **ap;
  7975.                     ap = a_ptr[vbi];    /* get data pointer */
  7976.                     if (ap) {           /* and if there is one */
  7977.                         p = ap[d];
  7978.                         goto fnend;
  7979.                     }
  7980.                 }
  7981.             } else {
  7982.                 failed = 1;
  7983.                 p = fnval;
  7984.                 if (fndiags)
  7985.                   sprintf(fnval,"<ERROR:ARG_NOT_ARRAY:\\fcontents()>");
  7986.                 goto fnend;
  7987.             }
  7988.         } else {
  7989.             failed = 1;
  7990.             p = fnval;
  7991.             if (fndiags)
  7992.               sprintf(fnval,"<ERROR:ARG_NOT_VARIABLE:\\fcontents()>");
  7993.             goto fnend;
  7994.         }
  7995.     }
  7996.     p = fnval;                          /* Default result pointer */
  7997.     fnval[0] = NUL;                     /* Default result = empty string */
  7998.  
  7999.     for (i = 0; i < argn; i++) {        /* Loop to expand each argument */
  8000.         n = MAXARGLEN;                  /* Allow plenty of space */
  8001.         bp[i] = s = malloc(n+1);        /* Allocate space for this argument */
  8002.         if (bp[i] == NULL) {            /* Handle failure to get space */
  8003.             failed = 1;
  8004.             if (fndiags)
  8005.               ckmakmsg(fnval,FNVALL,"<ERROR:MALLOC_FAILURE:\\f",fn,"()>",NULL);
  8006.             goto fnend;
  8007.         }
  8008.         p = argp[i] ? argp[i] : "";     /* Point to this argument */
  8009.  
  8010. /*
  8011.   Trim leading and trailing spaces from the original argument, before
  8012.   evaluation.  This code new to edit 184.  Fixed in edit 199 to trim
  8013.   blanks BEFORE stripping braces.
  8014.  
  8015. */
  8016.         {
  8017.             int x, j;
  8018.             x = strlen(p);
  8019.             j = x - 1;                  /* Trim trailing whitespace */
  8020.             while (j > 0 && (*(p + j) == SP || *(p + j) == HT))
  8021.               *(p + j--) = NUL;
  8022.             while (*p == SP || *p == HT) /* Strip leading whitespace */
  8023.               p++;
  8024.             x = strlen(p);
  8025.             if (*p == '{' && *(p+x-1) == '}') { /* NOW strip braces */
  8026.                 p[x-1] = NUL;
  8027.                 p++;
  8028.                 x -= 2;
  8029.             }
  8030.         }
  8031.  
  8032. /* Now evaluate the argument */
  8033.  
  8034.         debug(F111,"fneval calling zzstring",p,n);
  8035.         t = zzstring(p,&s,&n);          /* Expand arg into new space */
  8036.         debug(F101,"fneval zzstring","",t);
  8037.         debug(F101,"fneval zzstring","",n);
  8038.         if (t < 0) {
  8039.             debug(F101,"fneval zzstring fails, arg","",i);
  8040.             failed = 1;
  8041.             if (fndiags) {
  8042.                 if (n == 0)
  8043.                   ckmakmsg(fnval,FNVALL,
  8044.                            "<ERROR:ARG_TOO_LONG:\\f",fn,"()>",NULL);
  8045.                 else
  8046.                   ckmakmsg(fnval,FNVALL,
  8047.                            "<ERROR:ARG_EVAL_FAILURE:\\f",fn,"()>",NULL);
  8048.             }
  8049.             goto fnend;
  8050.         }
  8051.         debug(F111,"fneval arg",bp[i],i);
  8052.     }
  8053.  
  8054. #ifdef DEBUG
  8055.     if (deblog) {
  8056.         int j;
  8057.         for (j = 0; j < argn; j++) {
  8058.             debug(F111,"fneval arg post eval",argp[j],j);
  8059.             debug(F111,"fneval evaluated arg",bp[j],j);
  8060.         }
  8061.     }
  8062. #endif /* DEBUG */
  8063. /*
  8064.   From this point on, bp[0..argn-1] are not NULL and all must be freed
  8065.   before returning.
  8066. */
  8067.     if (argn < 1) {                     /* Catch required args missing */
  8068.         switch (cx) {
  8069.           case FN_DEF:
  8070.           case FN_EVA:
  8071.           case FN_EXE:
  8072.           case FN_CHR:
  8073.           case FN_COD:
  8074.           case FN_MAX:
  8075.           case FN_MIN:
  8076.           case FN_MOD:
  8077.           case FN_FD:
  8078.           case FN_FS:
  8079.           case FN_TOD:
  8080.           case FN_FFN:
  8081.           case FN_BSN:
  8082.           case FN_RAW:
  8083.           case FN_CMD:
  8084.           case FN_2HEX:
  8085.           case FN_2OCT:
  8086.           case FN_DNAM:
  8087. #ifdef FN_ERRMSG
  8088.           case FN_ERRMSG:
  8089. #endif /* FN_ERRMSG */
  8090. #ifdef CK_KERBEROS
  8091.           case FN_KRB_TK:
  8092.           case FN_KRB_NX:
  8093.           case FN_KRB_IV:
  8094.           case FN_KRB_TT:
  8095.           case FN_KRB_FG:
  8096. #endif /* CK_KERBEROS */
  8097.           case FN_MJD2:
  8098.           case FN_N2TIM:
  8099.           case FN_DIM:
  8100.           case FN_DATEJ:
  8101.           case FN_PNCVT:
  8102.           case FN_PERM:
  8103.           case FN_ALOOK:
  8104.           case FN_TLOOK:
  8105.           case FN_ABS:
  8106.           case FN_AADUMP:
  8107.           case FN_JOIN:
  8108. #ifdef CKFLOAT
  8109.           case FN_FPABS:
  8110.           case FN_FPEXP:
  8111.           case FN_FPLOG:
  8112.           case FN_FPLN:
  8113.           case FN_FPMOD:
  8114.           case FN_FPSQR:
  8115.           case FN_FPADD:
  8116.           case FN_FPDIV:
  8117.           case FN_FPMUL:
  8118.           case FN_FPPOW:
  8119.           case FN_FPSUB:
  8120.           case FN_FPINT:
  8121.           case FN_FPROU:
  8122.           case FN_FPSIN:
  8123.           case FN_FPCOS:
  8124.           case FN_FPTAN:
  8125. #endif /* CKFLOAT */
  8126. #ifdef TCPSOCKET
  8127.           case FN_HSTADD:
  8128.           case FN_HSTNAM:
  8129. #endif /* TCPSOCKET */
  8130.           case FN_DELSEC:
  8131.           case FN_KWVAL:
  8132. #ifdef COMMENT
  8133.           case FN_SLEEP:
  8134.           case FN_MSLEEP:
  8135. #endif /* COMMENT */
  8136. #ifdef NT
  8137.           case FN_SNAME:
  8138.           case FN_LNAME:
  8139. #endif /* NT */
  8140.           case FN_EMAIL:
  8141.             failed = 1;
  8142.             p = fnval;
  8143.             if (fndiags)
  8144.               ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
  8145.             goto fnend;
  8146.         }
  8147.     }
  8148.     p = fnval;                          /* Reset these again. */
  8149.     fnval[0] = NUL;
  8150.  
  8151.     switch (cx) {                       /* Do function on expanded args. */
  8152. #ifdef TCPSOCKET
  8153.       case FN_HSTADD:
  8154.         p = ckaddr2name(bp[0]);
  8155.         goto fnend;
  8156.       case FN_HSTNAM:
  8157.         p = ckname2addr(bp[0]);
  8158.         goto fnend;
  8159. #endif /* TCPSOCKET */
  8160.  
  8161.       case FN_DEF:                      /* \fdefinition(arg1) */
  8162.         k = isaarray(bp[0]) ?
  8163.         mxxlook(mactab,bp[0],nmac) :
  8164.         mxlook(mactab,bp[0],nmac);
  8165.         p = (k > -1) ? mactab[k].mval : "";
  8166.         goto fnend;
  8167.  
  8168.       case FN_EVA:                      /* \fevaluate(arg1) */
  8169.         p = *(bp[0]) ? evalx(bp[0]) : "";
  8170.         if (!*p && fndiags) {
  8171.             failed = 1;
  8172.             p = fnval;
  8173.             evalerr(fn);
  8174.         }
  8175.         goto fnend;
  8176.  
  8177.       case FN_EXE:                      /* \fexecute(arg1) */
  8178.         j = (int)strlen(s = bp[0]);     /* Length of macro invocation */
  8179.         p = "";                         /* Initialize return value to null */
  8180.         if (j) {                        /* If there is a macro to execute */
  8181.             while (*s == SP) s++,j--;   /* strip leading spaces */
  8182.             p = s;                      /* remember beginning of macro name */
  8183.             for (i = 0; i < j; i++) {   /* find end of macro name */
  8184.                 if (*s == SP)
  8185.                   break;
  8186.                 s++;
  8187.             }
  8188.             if (*s == SP)       {       /* if there was a space after */
  8189.                 *s++ = NUL;             /* terminate the macro name */
  8190.                 while (*s == SP) s++;   /* skip past any extra spaces */
  8191.             } else
  8192.               s = "";                   /* maybe there are no arguments */
  8193.             if (p && *p) {
  8194.                 k = mlook(mactab,p,nmac); /* Look up the macro name */
  8195.                 debug(F111,"fexec mlook",p,k);
  8196.             } else
  8197.               k = -1;
  8198.             if (k < 0) {
  8199.                 char * p2 = p;
  8200.                 failed = 1;
  8201.                 p = fnval;
  8202.                 if (fndiags)
  8203.                   ckmakxmsg(fnval,FNVALL,
  8204.                             "<ERROR:NO_SUCH_MACRO:\\f",fn,"(",p2,")>",
  8205.                             NULL,NULL,NULL,NULL,NULL,NULL,NULL);
  8206.                 goto fnend;
  8207.             }
  8208. /*
  8209.   This is just a WEE bit dangerous because we are copying up to 9 arguments
  8210.   into the space reserved for one.  It won't overrun the buffer, but if there
  8211.   are lots of long arguments we might lose some.  The other problem is that if
  8212.   the macro has more than 3 arguments, the 4th through last are all
  8213.   concatenated onto the third.  (The workaround is to use spaces rather than
  8214.   commas to separate them.)  Leaving it like this to avoid having to allocate
  8215.   tons more buffers.
  8216. */
  8217.             if (argn > 1) {             /* Commas used instead of spaces */
  8218.                 int i;
  8219.                 char *p = bp[0];        /* Reuse this space */
  8220.                 *p = NUL;               /* Make into dodo() arg list */
  8221.                 for (i = 1; i < argn; i++) {
  8222.                     ckstrncat(p,bp[i],MAXARGLEN);
  8223.                     ckstrncat(p," ",MAXARGLEN);
  8224.                 }
  8225.                 s = bp[0];              /* Point to new list */
  8226.             }
  8227.             p = "";                     /* Initialize return value */
  8228.             if (k >= 0) {               /* If macro found in table */
  8229.                 /* Go set it up (like DO cmd) */
  8230.                 if ((j = dodo(k,s,cmdstk[cmdlvl].ccflgs)) > 0) {
  8231.                     if (cmpush() > -1) { /* Push command parser state */
  8232.                         extern int ifc;
  8233.                         int ifcsav = ifc; /* Push IF condition on stack */
  8234.                         k = parser(1);  /* Call parser to execute the macro */
  8235.                         cmpop();        /* Pop command parser */
  8236.                         ifc = ifcsav;   /* Restore IF condition */
  8237.                         if (k == 0) {   /* No errors, ignore action cmds. */
  8238.                             p = mrval[maclvl+1]; /* If OK, set return value. */
  8239.                             if (p == NULL) p = "";
  8240.                         }
  8241.                     } else {            /* Can't push any more */
  8242.                         debug(F100,"zzstring fneval fexec failure","",0);
  8243.                         printf("\n?\\fexec() too deeply nested\n");
  8244.                         while (cmpop() > -1) ;
  8245.                         p = "";
  8246.                     }
  8247.                 }
  8248.             }
  8249.         }
  8250.         debug(F110,"zzstring fneval fexecute final p",p,0);
  8251.         goto fnend;
  8252.  
  8253. #ifdef RECURSIVE
  8254.       case FN_RDIR:                     /* \frdir..() - Recursive dir count */
  8255.       case FN_RFIL:                     /* \frfiles() - Recursive file count */
  8256.         /* recursive = 2; */            /* fall thru... */
  8257. #endif /* RECURSIVE */
  8258.       case FN_FC:                       /* \ffiles() - File count. */
  8259.       case FN_DIR: {                    /* \ffdir.() - Directory count. */
  8260.           char abuf[16], *s;
  8261.           char ** ap = NULL;
  8262.           int x, xflags = 0;
  8263.           if (matchdot)
  8264.             xflags |= ZX_MATCHDOT;
  8265.           if (cx == FN_RDIR || cx == FN_RFIL) {
  8266.               xflags |= ZX_RECURSE;
  8267. #ifdef CKSYMLINK
  8268.               /* Recursive - don't follow symlinks */
  8269.               xflags |= ZX_NOLINKS;
  8270. #endif /* CKSYMLINK */
  8271.           }
  8272.           failed = 0;
  8273.           if (argn < 1) {
  8274.               p = "0";
  8275.               goto fnend;
  8276.           }
  8277.           if (cx == FN_DIR || cx == FN_RDIR) { /* Only list directories */
  8278.           debug(F100,"FN_DIR or FN_DIR","",0);
  8279.               xflags |= ZX_DIRONLY;
  8280. #ifdef OS2
  8281.               zxpn = 1;                 /* Use the alternate list */
  8282. #endif /* OS2 */
  8283.           } else {                      /* List only files */
  8284.           debug(F100,"Not FN_DIR or FN_DIR","",0);
  8285.               xflags |= ZX_FILONLY;
  8286. #ifdef OS2
  8287.               zxpn = 1;                 /* Use the alternate list */
  8288. #endif /* OS2 */
  8289.           }
  8290.           if (*(bp[0])) {
  8291.               k = nzxpand(bp[0],xflags);
  8292.               if (k < 0) k = 0;
  8293.               sprintf(fnval,"%d",k);    /* SAFE */
  8294.               p = fnval;
  8295.           } else
  8296.             p = "0";
  8297.  
  8298.           if (argn > 1) {               /* Assign list to array */
  8299.               fnval[0] = NUL;           /* Initial return value */
  8300.               ckstrncpy(abuf,bp[1],16); /* Get array reference */
  8301.               s = abuf;
  8302.               if (*s == CMDQ) s++;
  8303.               failed = 1;               /* Assume it's bad */
  8304.               p = fnval;                /* Point to result */
  8305.               if (fndiags)              /* Default is this error message */
  8306.                 ckmakmsg(fnval,FNVALL,
  8307.                          "<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
  8308.               if (s[0] != '&')          /* "Address" of array */
  8309.                 goto fnend;
  8310.               if (s[2])
  8311.                 if (s[2] != '[' || s[3] != ']')
  8312.                   goto fnend;
  8313.               if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */
  8314.                 s[1] += 32;
  8315.               if ((x = dclarray(s[1],k)) < 0) /* File list plus count */
  8316.                 goto fnend;
  8317.               failed = 0;               /* Unset failure flag */
  8318.               ap = a_ptr[x];            /* Point to array we just declared */
  8319.               sprintf(fnval,"%d",k);    /* SAFE */
  8320.           }
  8321. #ifdef OS2
  8322.           if (ap) {                     /* We are making an array */
  8323.               int i;
  8324.               char tmp[16];
  8325.               ap[0] = NULL;             /* Containing number of files    */
  8326.               makestr(&(ap[0]),ckitoa(k));
  8327.  
  8328.               ckstrncpy(tmp,fnval,16);  /* Save return value */
  8329.  
  8330.               for (i = 1; i <= k; i++) { /* Fill it */
  8331.                   ap[i] = NULL;
  8332.                   znext(fnval);         /* Next filename */
  8333.                   if (!*fnval)          /* No more, done */
  8334.                     break;              /* In case a premature end */
  8335.                   makestr(&(ap[i]),fnval);
  8336.               }
  8337. #ifdef ZXREWIND
  8338.               k = zxrewind();           /* Reset the file expansion */
  8339. #else
  8340.               k = nzxpand(bp[0],xflags);
  8341. #endif /* ZXREWIND */
  8342.               ckstrncpy(fnval,tmp,FNVALL); /* Restore return value */
  8343.           }
  8344. #else /* OS2 */
  8345.           {                             /* Make copies of the list */
  8346.               int i; char tmp[16];
  8347.               if (flist) {              /* Free old file list, if any */
  8348.                   for (i = 0; flist[i]; i++) { /* and each string */
  8349.                       free(flist[i]);
  8350.                       flist[i] = NULL;
  8351.                   }
  8352.                   free((char *)flist);
  8353.               }
  8354.               ckstrncpy(tmp,fnval,16);  /* Save our return value */
  8355.               flist = (char **) malloc((k+1) * sizeof(char *)); /* New array */
  8356.               if (flist) {
  8357.                   for (i = 0; i <= k; i++) { /* Fill it */
  8358.                       flist[i] = NULL;
  8359.                       znext(fnval);     /* Next filename */
  8360.                       if (!*fnval)      /* No more, done */
  8361.                         break;
  8362.                       makestr(&(flist[i]),fnval);
  8363.                   }
  8364.                   if (ap) {             /* If array pointer given */
  8365.                       ap[0] = NULL;
  8366.                       makestr(&(ap[0]),ckitoa(k));
  8367.                       for (i = 0; i < k; i++) { /* Copy file list to array */
  8368.                           ap[i+1] = NULL;
  8369.                           makestr(&(ap[i+1]),flist[i]);
  8370.                       }
  8371.                   }
  8372.               }
  8373.               ckstrncpy(fnval,tmp,FNVALL); /* Restore return value */
  8374.               flistn = 0;               /* Reset global list pointer */
  8375.           }
  8376. #endif /* OS2 */
  8377. #ifdef RECURSIVE
  8378.           recursive = rsave;
  8379. #endif /* RECURSIVE */
  8380. #ifdef OS2
  8381.           zxpn = zsave;
  8382. #endif /* OS2 */
  8383.       }
  8384.       goto fnend;
  8385.  
  8386.       case FN_FIL:                      /* \fnextfile() - Next file in list. */
  8387.         p = fnval;                      /* (no args) */
  8388.         *p = NUL;
  8389. #ifdef OS2
  8390.         zxpn = 1;                       /* OS/2 - use the alternate list */
  8391.         znext(p);                       /* Call system-dependent function */
  8392.         zxpn = zsave;                   /* Restore original list */
  8393. #else
  8394.         if (flist)                      /* Others, use our own list. */
  8395.           if (flist[flistn])
  8396.             p = flist[flistn++];
  8397. #endif /* OS2 */
  8398.         goto fnend;
  8399.  
  8400.     } /* Break up big switch... */
  8401.  
  8402.     switch (cx) {
  8403.       case FN_IND:                      /* \findex(s1,s2,start) */
  8404.       case FN_RIX:                      /* \frindex(s1,s2,start) */
  8405.       case FN_SEARCH:                   /* \fsearch(pat,string,start) */
  8406.       case FN_RSEARCH: {                /* \frsearch(pat,string,start) */
  8407.         int i = 0, right = 0, search = 0;
  8408.         right = (cx == FN_RIX || cx == FN_RSEARCH);
  8409.         search = (cx == FN_SEARCH || cx == FN_RSEARCH);
  8410.         p = "0";
  8411.         if (argn > 1) {                 /* Only works if we have 2 or 3 args */
  8412.             int start = 0;
  8413.             char * pat = NULL;
  8414.             len1 = (int)strlen(pat = bp[0]); /* length of string to look for */
  8415.             len2 = (int)strlen(s = bp[1]); /* length of string to look in */
  8416.             if (len1 < 1 || len2 < 1)   /* Watch out for empty strings */
  8417.               goto fnend;
  8418.             start = right ? -1 : 0;     /* Default starting position */
  8419.             if (argn > 2) {
  8420.                 val1 = *(bp[2]) ? evalx(bp[2]) : "1";
  8421.                 if (chknum(val1)) {
  8422.                     int t;
  8423.                     t = atoi(val1);
  8424.                     if (!search) {      /* Index or Rindex */
  8425.                         j = len2 - len1; /* Length difference */
  8426.                         t--;             /* Convert position to 0-based */
  8427.                         if (t < 0) t = 0;
  8428.                         start = t;
  8429.                         if (!right && start < 0) start = 0;
  8430.                     } else {            /* Search or Rsearch */
  8431.                         int x;
  8432.                         if (t < 0) t = 0;
  8433.                         if (right) {    /* Right to left */
  8434.                             if (t > len2) t = len2;
  8435.                             start = len2 - t - 1;
  8436.                             if (start < 0)
  8437.                               goto fnend;
  8438.                             x = len2 - t;
  8439.                             s[x] = NUL;
  8440.                         } else {        /* Left to right */
  8441.                             start = t - 1;
  8442.                             if (start < 0) start = 0;
  8443.                             if (start >= len2)
  8444.                               goto fnend;
  8445.                         }
  8446.                     }
  8447.                 } else {
  8448.                     failed = 1;
  8449.                     evalerr(fn);
  8450.                     p = fnval;
  8451.                     goto fnend;
  8452.                 }
  8453.             }
  8454.             if (search) {               /* \fsearch() or \frsearch() */
  8455.                 if (right && pat[0] == '^') {
  8456.                     right = 0;
  8457.                     start = 0;
  8458.                 }
  8459.                 if (right) {
  8460.                     if (start < 0) start = len2 - 1;
  8461.                     for (i = start;
  8462.                          i >= 0 && !ckmatch(pat,s+i,inpcas[cmdlvl],1+4);
  8463.                          i--) ;
  8464.                     if (i < 0) i = 0; else i++;
  8465.                 } else {
  8466.                     i = ckmatch(pat,&s[start],inpcas[cmdlvl],1+4);
  8467.                     if (start > 0) i += start;
  8468.                 }
  8469.             } else {
  8470.                 i = ckindex(pat,bp[1],start,right,inpcas[cmdlvl]);
  8471.             }
  8472.             sprintf(fnval,"%d",i);      /* SAFE */
  8473.             p = fnval;
  8474.         }
  8475.         goto fnend;
  8476.       }
  8477.  
  8478.       case FN_RPL:                      /* \freplace(s1,s2,s3) */
  8479.       /*
  8480.         s = bp[0] = source string
  8481.             bp[1] = match string
  8482.             bp[2] = replacement string
  8483.             bp[3] = which occurrence (default = all);
  8484.         p = fnval = destination (result) string
  8485.       */
  8486.         if (argn < 1)                   /* Nothing */
  8487.           goto fnend;
  8488.         if (argn < 2) {                 /* Only works if we have 2 or 3 args */
  8489.             ckstrncpy(p,bp[0],FNVALL);
  8490.         } else {
  8491.             int occur = 0, xx = 0, j2;
  8492.             len1 = (int)strlen(bp[0]);  /* length of string to look in */
  8493.             len2 = (int)strlen(bp[1]);  /* length of string to look for */
  8494.             len3 = (argn < 3) ? 0 : (int)strlen(bp[2]); /* Len of replacemnt */
  8495.             j = len1 - len2 + 1;
  8496.             j2 = j;
  8497.             if (argn > 3) {
  8498.                 if (chknum(bp[3])) {
  8499.                     occur = atoi(bp[3]);
  8500.                 } else {
  8501.                     failed = 1;
  8502.                     if (fndiags)
  8503.                       ckmakmsg(fnval,FNVALL,
  8504.                                "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  8505.                     goto fnend;
  8506.                 }
  8507.             }
  8508.             /* If args out of whack... */
  8509.             if (j < 1 || len1 == 0 || len2 == 0) {
  8510.                 ckstrncpy(p,bp[0],FNVALL); /* just return original string */
  8511.                 p[FNVALL] = NUL;
  8512.             } else {
  8513.               ragain:
  8514.                 s = bp[0];              /* Point to beginning of string */
  8515.                 while (j-- > 0) {       /* For each character */
  8516.                     if (!ckstrcmp(bp[1],s,len2,inpcas[cmdlvl]) &&
  8517.                         (occur == 0 || occur == ++xx)) {
  8518.                         if (len3) {
  8519.                             ckstrncpy(p,bp[2],FNVALL);
  8520.                             p += len3;
  8521.                         }
  8522.                         s += len2;      /* and skip past it. */
  8523.                     } else {            /* No, */
  8524.                         *p++ = *s++;    /* just copy this character */
  8525.                     }
  8526.                 }
  8527.                 *p = NUL;
  8528.                 while ((*p++ = *s++));
  8529.                 if (occur < 0) {        /* cheap... */
  8530.                     occur = xx + occur + 1;
  8531.                     xx = 0;
  8532.                     p = fnval;
  8533.                     j = j2;
  8534.                     if (occur > 0)
  8535.                       goto ragain;
  8536.                 }
  8537.             }
  8538.         }
  8539.         p = fnval;
  8540.         goto fnend;
  8541.  
  8542.       case FN_CHR:                      /* \fcharacter(arg1) */
  8543.         val1 = *(bp[0]) ? evalx(bp[0]) : "";
  8544.         if (chknum(val1)) {             /* Must be numeric */
  8545.             i = atoi(val1);
  8546.             if (i >= 0 && i < 256) {    /* Must be an 8-bit value */
  8547.                 p = fnval;
  8548.                 *p++ = (char) i;
  8549.                 *p = NUL;
  8550.                 p = fnval;
  8551.             } else {
  8552.                 failed = 1;
  8553.                 if (fndiags)
  8554.                   ckmakmsg(fnval,FNVALL,
  8555.                            "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
  8556.             }
  8557.         } else {
  8558.             failed = 1;
  8559.             evalerr(fn);
  8560.         }
  8561.         goto fnend;
  8562.  
  8563.       case FN_COD:                      /* \fcode(char) */
  8564.         if ((int)strlen(bp[0]) > 0) {
  8565.             p = fnval;
  8566.             i = *bp[0];
  8567.             sprintf(p,"%d",(i & 0xff)); /* SAFE */
  8568.         } else p = "0";            /* Can't happen */
  8569.         goto fnend;
  8570.  
  8571.       case FN_LEN:                      /* \flength(arg1) */
  8572.         if (argn > 0) {
  8573.             p = fnval;
  8574.             sprintf(p,"%d",(int)strlen(bp[0])); /* SAFE */
  8575.         } else p = "0";
  8576.         goto fnend;
  8577.  
  8578.       case FN_LOW:                      /* \flower(arg1) */
  8579.         s = bp[0] ? bp[0] : "";
  8580.         p = fnval;
  8581.         while (*s) {
  8582.             if (isupper(*s))
  8583.               *p = (char) tolower(*s);
  8584.             else
  8585.               *p = *s;
  8586.             p++; s++;
  8587.         }
  8588.         *p = NUL;
  8589.         p = fnval;
  8590.         goto fnend;
  8591.  
  8592.       case FN_MAX:                      /* \fmax(arg1,arg2) */
  8593.       case FN_MIN:                      /* \fmin(arg1,arg2) */
  8594.       case FN_MOD:                      /* \fmod(arg1,arg2) */
  8595.         val1 = *(bp[0]) ? evalx(bp[0]) : "";
  8596. #ifdef COMMENT
  8597.         /* No longer necessary because evalx() no longer overwrites its */
  8598.         /* result every time it's called (2000/09/23). */
  8599.         free(bp[0]);
  8600.         bp[0] = NULL;
  8601. #endif /* COMMENT */
  8602.         if (argn > 1) {
  8603. #ifdef COMMENT
  8604.             /* Ditto... */
  8605.             bp[0] = malloc((int)strlen(val1)+1);
  8606.             if (bp[0])
  8607.               strcpy(bp[0],val1);       /* safe */
  8608.             val1 = bp[0];
  8609. #endif /* COMMENT */
  8610.             val2 = *(bp[1]) ? evalx(bp[1]) : "";
  8611.             if (chknum(val1) && chknum(val2)) {
  8612.                 i = atoi(val1);
  8613.                 j = atoi(val2);
  8614.                 switch (y) {
  8615.                   case FN_MAX:
  8616.                     if (j < i) j = i;
  8617.                     break;
  8618.                   case FN_MIN:
  8619.                     if (j > i) j = i;
  8620.                     break;
  8621.                   case FN_MOD:
  8622.                     if (j == 0) {
  8623.                         failed = 1;
  8624.                         if (fndiags)
  8625.                           ckmakmsg(fnval,FNVALL,
  8626.                                    "<ERROR:DIVIDE_BY_ZERO:\\f",fn,"()>",NULL);
  8627.                         else
  8628.                           fnval[0] = NUL;
  8629.                         goto fnend;
  8630.                     } else
  8631.                       j = i % j;
  8632.                 }
  8633.                 p = fnval;
  8634.                 sprintf(p,"%d",j);      /* SAFE */
  8635.             } else {
  8636.                 failed = 1;
  8637.                 evalerr(fn);
  8638.             }
  8639.         } else p = val1;
  8640.         goto fnend;
  8641.     } /* Break up big switch... */
  8642.  
  8643.     switch (y) {
  8644.       case FN_SUB:                      /* \fsubstr(arg1,arg2,arg3) */
  8645.       case FN_RIG:                      /* \fright(arg1,arg2) */
  8646.       case FN_LEF:                      /* \fleft(arg1,arg2) */
  8647.         if (argn < 1)
  8648.           goto fnend;
  8649.         val1 = "";
  8650.         if (argn > 1)
  8651.           if (*(bp[1]))
  8652.             val1 =  evalx(bp[1]);
  8653. #ifdef COMMENT
  8654.         if (bp[1]) free(bp[1]);         /* Have to copy this */
  8655.         bp[1] = malloc((int)strlen(val1)+1);
  8656.         if (!bp[1]) {
  8657.             failed = 1;
  8658.             if (fndiags) {
  8659.                 p = fnval;
  8660.                 ckmakmsg(fnval,FNVALL,
  8661.                          "<ERROR:MALLOC_FAILURE:\\f",fn,"()>",NULL);
  8662.             }
  8663.             goto fnend;
  8664.         }
  8665.         strcpy(bp[1],val1);             /* safe */
  8666.         val1 = bp[1];
  8667. #endif /* COMMENT */
  8668.         val2 = "";
  8669.         if (argn > 2)
  8670.           if (*(bp[2]))
  8671.             val2 = evalx(bp[2]);
  8672.         if (
  8673.             ((argn > 1) && (int)strlen(val1) && !rdigits(val1)) ||
  8674.             ((cx == FN_SUB) &&
  8675.               ((argn > 2) && (int)strlen(val2) && !rdigits(val2)))
  8676.             ) {
  8677.             failed = 1;
  8678.             evalerr(fn);
  8679.         } else {
  8680.             int lx;
  8681.             p = fnval;                  /* pointer to result */
  8682.             lx = strlen(bp[0]);         /* length of arg1 */
  8683.             if (cx == FN_SUB) {         /* substring */
  8684.                 k = (argn > 2) ? atoi(val2) : MAXARGLEN; /* length */
  8685.                 j = (argn > 1) ? atoi(val1) : 1; /* start pos for substr */
  8686.             } else if (cx == FN_LEF) {  /* left */
  8687.                 k = (argn > 1) ? atoi(val1) : lx;
  8688.                 j = 1;
  8689.             } else {                             /* right */
  8690.                 k = (argn > 1) ? atoi(val1) : lx; /* length */
  8691.                 j = lx - k + 1;                  /* start pos for right */
  8692.                 if (j < 1) j = 1;
  8693.             }
  8694.             if (k > 0 && j <= lx) {              /* if start pos in range */
  8695.                 s = bp[0]+j-1;                   /* point to source string */
  8696.                 for (i = 0; (i < k) && (*p++ = *s++); i++) ;  /* copy */
  8697.             }
  8698.             *p = NUL;                   /* terminate the result */
  8699.             p = fnval;                  /* and point to it. */
  8700.         }
  8701.         goto fnend;
  8702.  
  8703.       case FN_UPP:                      /* \fupper(arg1) */
  8704.         s = bp[0] ? bp[0] : "";
  8705.         p = fnval;
  8706.         while (*s) {
  8707.             if (islower(*s))
  8708.               *p = (char) toupper(*s);
  8709.             else
  8710.               *p = *s;
  8711.             p++; s++;
  8712.         }
  8713.         *p = NUL;
  8714.         p = fnval;
  8715.         goto fnend;
  8716.  
  8717.       case FN_REP:                      /* \frepeat(text,number) */
  8718.         if (argn < 1)
  8719.           goto fnend;
  8720.         val1 = "1";
  8721.         if (argn > 1)
  8722.           if (*(bp[1]))
  8723.             val1 = evalx(bp[1]);
  8724.         if (chknum(val1)) {             /* Repeat count */
  8725.             n = atoi(val1);
  8726.             debug(F111,"SUNDAY frepeat n",val1,n);
  8727.             if (n > 0) {                /* Make n copies */
  8728.                 p = fnval;
  8729.                 *p = '\0';
  8730.                 k = (int)strlen(bp[0]); /* Make sure string has some length */
  8731.                 debug(F111,"SUNDAY frepeat k","",k);
  8732.                 debug(F111,"SUNDAY frepeat FNVALL","",FNVALL);
  8733.                 if (k * n >= FNVALL) {  /* But not too much... */
  8734.                     failed = 1;
  8735.                     if (fndiags)
  8736.                       ckmakmsg(fnval,FNVALL,
  8737.                                "<ERROR:RESULT_TOO_LONG:\\f",fn,"()>",NULL);
  8738.                     else
  8739.                       fnval[0] = NUL;
  8740.                     p = fnval;
  8741.                     goto fnend;
  8742.                 }
  8743.                 if (k > 0) {            /* If there is something to copy */
  8744.                     for (i = 0; i < n; i++) { /* Copy loop */
  8745.                         s = bp[0];
  8746.                         for (j = 0; j < k; j++) {
  8747.                             if ((p - fnval) >= FNVALL)
  8748.                               break;    /* shouldn't happen... */
  8749.                             else
  8750.                               *p++ = *s++;
  8751.                         }
  8752.                     }
  8753.                     *p = NUL;
  8754.                 }
  8755.             }
  8756.         } else {
  8757.             failed = 1;
  8758.             evalerr(fn);
  8759.         }
  8760.         p = fnval;
  8761.         goto fnend;
  8762.  
  8763. #ifndef NOFRILLS
  8764.       case FN_REV:                      /* \freverse() */
  8765.         if (argn < 1)
  8766.           goto fnend;
  8767.         yystring(bp[0],&p);
  8768.         goto fnend;
  8769. #endif /* NOFRILLS */
  8770.  
  8771.       case FN_RPA:                      /* \frpad() and \flpad() */
  8772.       case FN_LPA:
  8773.         if (argn < 1)
  8774.           goto fnend;
  8775.         val1 = "";
  8776.         if (argn > 1)
  8777.           if (*(bp[1]))
  8778.             val1 = evalx(bp[1]);
  8779.         if (argn == 1) {                /* If a number wasn't given */
  8780.             p = fnval;                  /* just return the original string */
  8781.             ckstrncpy(p,bp[0],FNVALL);
  8782.         } else if (argn > 1 &&  !*val1) {
  8783.             failed = 1;
  8784.             evalerr(fn);
  8785.         } else /* if (chknum(val1)) */ { /* Repeat count */
  8786.             char pc;
  8787.             n = atoi(val1);
  8788.             if (n >= 0) {
  8789.                 p = fnval;
  8790.                 k = (int)strlen(bp[0]); /* Length of string to be padded */
  8791.                 if (k >= n) {           /* It's already long enough */
  8792.                     ckstrncpy(p,bp[0],FNVALL);
  8793.                 } else {
  8794.                     if (n + k <= FNVALL) {
  8795.                         pc = (char) ((argn < 3) ? SP : *bp[2]);
  8796.                         if (!pc) pc = SP;
  8797.                         if (cx == FN_RPA) { /* RPAD */
  8798.                             strncpy(p,bp[0],k); /* (leave it like this) */
  8799.                             p[k] = NUL;
  8800.                             p += k;
  8801.                             for (i = k; i < n; i++)
  8802.                               *p++ = pc;
  8803.                         } else {        /* LPAD */
  8804.                             n -= k;
  8805.                             for (i = 0; i < n; i++)
  8806.                               *p++ = pc;
  8807.                             strncpy(p,bp[0],k); /* (leave it like this) */
  8808.                             p[k] = NUL;
  8809.                             p += k;
  8810.                         }
  8811.                     }
  8812.                     *p = NUL;
  8813.                 }
  8814.             }
  8815.         }
  8816.         p = fnval;
  8817.         goto fnend;
  8818.  
  8819. #ifdef ZFCDAT
  8820.       case FN_FD:                       /* \fdate(filename) */
  8821.         p = fnval;
  8822.         s = zfcdat(bp[0]);
  8823.         if (!s) s = "";
  8824.         if (!*s) {
  8825.             failed = 1;
  8826.             if (fndiags)
  8827.               ckmakmsg(fnval,FNVALL,"<ERROR:FILE_NOT_FOUND:\\f",fn,"()>",NULL);
  8828.             goto fnend;
  8829.         }
  8830.         ckstrncpy(fnval,s,FNVALL);
  8831. #endif /* ZFCDAT */
  8832.         goto fnend;
  8833.  
  8834.     } /* Break up big switch... */
  8835.  
  8836.     switch (y) {
  8837.       case FN_FS: {            /* \fsize(filename) */
  8838.       CK_OFF_T z;
  8839.       p = fnval;
  8840.       z = zchki(bp[0]);
  8841.       if (z < (CK_OFF_T)0) {
  8842.           failed = 1;
  8843.           if (fndiags) {
  8844.           if (z == (CK_OFF_T)-1)
  8845.             ckmakmsg(fnval,FNVALL,
  8846.                  "<ERROR:FILE_NOT_FOUND:\\f",fn,"()>",NULL);
  8847.           else if (z == (CK_OFF_T)-2)
  8848.             ckmakmsg(fnval,FNVALL,
  8849.                  "<ERROR:FILE_NOT_READABLE:\\f",fn,"()>",NULL);
  8850.           else if (z == (CK_OFF_T)-3)
  8851.             ckmakmsg(fnval,FNVALL,
  8852.                  "<ERROR:FILE_NOT_ACCESSIBLE:\\f",fn,"()>",NULL);
  8853.           else
  8854.             ckmakmsg(fnval,FNVALL,
  8855.                  "<ERROR:FILE_ERROR:\\f",fn,"()>",NULL);
  8856.           }
  8857.           goto fnend;
  8858.       }
  8859.       ckstrncpy(fnval,ckfstoa(z),FNVALL);
  8860.       goto fnend;
  8861.       }
  8862.       case FN_VER:                      /* \fverify() */
  8863.     p = "-1";
  8864.     if (argn == 1)            /* No second arg */
  8865.       goto fnend;
  8866.     else if (!bp[1])        /* Or second arg null */
  8867.       goto fnend;
  8868.     else if (!*(bp[1]))        /* or empty. */
  8869.       goto fnend;
  8870.         p = "0";
  8871.         if (argn > 1) {                 /* Only works if we have 2 or 3 args */
  8872.             int start;
  8873.             char *s2, ch1, ch2;
  8874.             start = 0;
  8875.             if (argn > 2) {             /* Starting position specified */
  8876.                 val1 = *(bp[2]) ? evalx(bp[2]) : "0";
  8877.                 if (chknum(val1)) {
  8878.                     start = atoi(val1) /* - 1 */;
  8879.                     if (start < 0) start = 0;
  8880.                     if (start > (int)strlen(bp[1]))
  8881.                       goto verfin;
  8882.                 } else {
  8883.                     failed = 1;
  8884.                     evalerr(fn);
  8885.                     goto fnend;
  8886.                 }
  8887.             }
  8888.             i = start;
  8889.             p = "0";
  8890.             for (s = bp[1] + start; *s; s++,i++) {
  8891.                 ch1 = *s;
  8892.                 if (!inpcas[cmdlvl]) if (islower(ch1)) ch1 = toupper(ch1);
  8893.                 j = 0;
  8894.                 for (s2 = bp[0]; *s2; s2++) {
  8895.                     ch2 = *s2;
  8896.                     if (!inpcas[cmdlvl]) if (islower(ch2)) ch2 = toupper(ch2);
  8897.                     if (ch1 == ch2) {
  8898.                         j = 1;
  8899.                         break;
  8900.                     }
  8901.                 }
  8902.                 if (j == 0) {
  8903.                     sprintf(fnval,"%d",i+1); /* SAFE */
  8904.                     p = fnval;
  8905.                     break;
  8906.                 }
  8907.             }
  8908.         }
  8909.       verfin:
  8910.         goto fnend;
  8911.  
  8912.       case FN_IPA:                      /* Find and return IP address */
  8913.         if (argn > 0) {                 /* in argument string. */
  8914.             int start = 0;
  8915.             if (argn > 1) {             /* Starting position specified */
  8916.                 if (chknum(bp[1])) {
  8917.                     start = atoi(bp[1]) - 1;
  8918.                     if (start < 0) start = 0;
  8919.                 } else {
  8920.                     failed = 1;
  8921.                     if (fndiags)
  8922.                       ckmakmsg(fnval,FNVALL,
  8923.                                "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  8924.                     goto fnend;
  8925.                 }
  8926.             }
  8927.             p = getip(bp[0]+start);
  8928.         } else p = "";
  8929.         goto fnend;
  8930.  
  8931. #ifdef OS2
  8932.       case FN_CRY:
  8933.         p = "";
  8934.         if (argn > 0) {
  8935.             p = fnval;
  8936.             ckstrncpy(p,bp[0],FNVALL);
  8937.             ck_encrypt(p);
  8938.         }
  8939.         goto fnend;
  8940.  
  8941.       case FN_OOX:
  8942.         p = "";
  8943.         if (argn > 0)
  8944.           p = (char *) ck_oox(bp[0], (argn > 1) ? bp[1] : "");
  8945.         goto fnend;
  8946. #endif /* OS2 */
  8947.  
  8948.       case FN_HEX:                      /* \fhexify(arg1) */
  8949.         if (argn < 1)
  8950.           goto fnend;
  8951.         if ((int)strlen(bp[0]) < (FNVALL / 2)) {
  8952.             s = bp[0];
  8953.             p = fnval;
  8954.             while (*s) {
  8955.                 x = (*s >> 4) & 0x0f;
  8956.                 *p++ = hexdigits[x];
  8957.                 x = *s++ & 0x0f;
  8958.                 *p++ = hexdigits[x];
  8959.             }
  8960.             *p = NUL;
  8961.             p = fnval;
  8962.         }
  8963.         goto fnend;
  8964.  
  8965.       case FN_UNTAB:            /* \funtab(arg1) */
  8966.     if (argn < 1)
  8967.       goto fnend;
  8968.     if ((int)strlen(bp[0]) < (FNVALL * 2)) {
  8969.         s = bp[0];
  8970.         p = fnval;
  8971.         if (untabify(bp[0],p,FNVALL) < 0) {
  8972.         failed = 1;
  8973.         if (fndiags)
  8974.           ckmakmsg(fnval,FNVALL,
  8975.                "<ERROR:OVERFLOW:\\f",fn,"()>",NULL);
  8976.         }
  8977.         goto fnend;
  8978.     }
  8979.  
  8980.       case FN_UNH: {                    /* \funhex(arg1) */
  8981.           int c[2], i;
  8982.           if (argn < 1)
  8983.             goto fnend;
  8984.           if ((int)strlen(bp[0]) < (FNVALL * 2)) {
  8985.               s = bp[0];
  8986.               p = fnval;
  8987.               while (*s) {
  8988.                   for (i = 0; i < 2; i++) {
  8989.                       c[i] = *s++;
  8990.                       if (!c[i]) { p = ""; goto unhexfin; }
  8991.                       if (islower(c[i])) c[i] = toupper(c[i]);
  8992.                       if (c[i] >= '0' && c[i] <= '9') {
  8993.                           c[i] -= 0x30;
  8994.                       } else if (c[i] >= 'A' && c[i] <= 'F') {
  8995.                           c[i] -= 0x37;
  8996.                       } else {
  8997.                           failed = 1;
  8998.                           if (fndiags)
  8999.                             ckmakmsg(fnval,
  9000.                                      FNVALL,
  9001.                                      "<ERROR:ARG_OUT_OF_RANGE:\\f",
  9002.                                      fn,
  9003.                                      "()>",
  9004.                                      NULL
  9005.                                      );
  9006.                           goto fnend;
  9007.                       }
  9008.                   }
  9009.                   *p++ = ((c[0] << 4) & 0xf0) | (c[1] & 0x0f);
  9010.               }
  9011.               *p = NUL;
  9012.               p = fnval;
  9013.           }
  9014.         unhexfin:
  9015.           goto fnend;
  9016.       }
  9017.  
  9018.       case FN_BRK: {                    /* \fbreak() */
  9019.           char * c;                     /* Characters to break on */
  9020.           char c2, s2;
  9021.           int start = 0;
  9022.           int done = 0;
  9023.           if (argn < 1)
  9024.             goto fnend;
  9025.           if (argn > 2) {
  9026.               s = bp[2] ? bp[2] : "0";
  9027.               if (chknum(s)) {
  9028.                   start = atoi(s);
  9029.                   if (start < 0) start = 0;
  9030.                   if (start > (int)strlen(bp[0]))
  9031.                     goto brkfin;
  9032.               } else {
  9033.                   failed = 1;
  9034.                   if (fndiags)
  9035.                     ckmakmsg(fnval,FNVALL,
  9036.                              "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  9037.                   goto fnend;
  9038.               }
  9039.           }
  9040.           s = bp[0] + start;            /* Source pointer */
  9041.  
  9042.           while (*s && !done) {
  9043.               s2 = *s;
  9044.               if (!inpcas[cmdlvl] && islower(s2)) s2 = toupper(s2);
  9045.               c = bp[1] ? bp[1] : "";   /* Character to break on */
  9046.               while (*c) {
  9047.                   c2 = *c;
  9048.                   if (!inpcas[cmdlvl] && islower(c2)) c2 = toupper(c2);
  9049.                   if (c2 == s2) {
  9050.                       done = 1;
  9051.                       break;
  9052.                   }
  9053.                   c++;
  9054.               }
  9055.               if (done) break;
  9056.               *p++ = *s++;
  9057.           }
  9058.           *p = NUL;                     /* terminate the result */
  9059.           p = fnval;                    /* and point to it. */
  9060.         brkfin:
  9061.           goto fnend;
  9062.       }
  9063.  
  9064.       case FN_SPN: {                    /* \fspan() */
  9065.           char *q;
  9066.           char c1, c2;
  9067.           int start = 0;
  9068.           if (argn < 1)
  9069.             goto fnend;
  9070.           if (argn > 2) {               /* Starting position */
  9071.               s = bp[2] ? bp[2] : "0";
  9072.               if (chknum(s)) {
  9073.                   start = atoi(s);
  9074.                   if (start < 0) start = 0;
  9075.               } else {
  9076.                   failed = 1;
  9077.                   if (fndiags)
  9078.                     ckmakmsg(fnval,FNVALL,
  9079.                              "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  9080.                   goto fnend;
  9081.               }
  9082.           }
  9083.           s = bp[0] + start;            /* Source pointer */
  9084.           if (argn > 1 &&
  9085.               (int)strlen(bp[1]) > 0 &&
  9086.               start <= (int)strlen(bp[0])) {
  9087.               while (*s) {              /* Loop thru source string */
  9088.                   q = bp[1];            /* Span string */
  9089.                   c1 = *s;
  9090.                   if (!inpcas[cmdlvl])
  9091.                     if (islower(c1)) c1 = toupper(c1);
  9092.                   x = 0;
  9093.                   while ((c2 = *q++)) {
  9094.                       if (!inpcas[cmdlvl])
  9095.                         if (islower(c2)) c2 = toupper(c2);
  9096.                       if (c1 == c2) { x = 1; break; }
  9097.                   }
  9098.                   if (!x) break;
  9099.                   *p++ = *s++;
  9100.               }
  9101.               *p = NUL;                 /* Terminate and return the result */
  9102.               p = fnval;
  9103.           }
  9104.           goto fnend;
  9105.       }
  9106.     } /* Break up big switch... */
  9107.  
  9108.     switch (y) {
  9109.       case FN_TRM:                      /* \ftrim(s1[,s2]) */
  9110.       case FN_LTR:                      /* \fltrim(s1[,s2]) */
  9111.         if (argn < 1)
  9112.           goto fnend;
  9113.         if ((len1 = (int)strlen(bp[0])) > 0) {
  9114.             if (len1 > FNVALL)
  9115.               len1 = FNVALL;
  9116.             s = " \t\r\n";
  9117.             if (argn > 1)               /* Trim list given */
  9118.               s = bp[1];
  9119.             len2 = (int)strlen(s);
  9120.             if (len2 < 1) {             /* or not... */
  9121.                 s = " \t\r\n";          /* Default is to trim whitespace */
  9122.                 len2 = 2;
  9123.             }
  9124.             if (cx == FN_TRM) {         /* Trim from right */
  9125.                 char * q, p2, q2;
  9126.                 ckstrncpy(fnval,bp[0],FNVALL); /* Copy string to output */
  9127.                 p = fnval + len1 - 1;   /* Point to last character */
  9128.  
  9129.                 while (p >= (char *)fnval) { /* Go backwards */
  9130.                     q = s;              /* Point to trim list */
  9131.                     p2 = *p;
  9132.                     if (!inpcas[cmdlvl])
  9133.                       if (islower(p2)) p2 = toupper(p2);
  9134.                     while (*q) {        /* Is this char in trim list? */
  9135.                         q2 = *q;
  9136.                         if (!inpcas[cmdlvl])
  9137.                           if (islower(q2)) q2 = toupper(q2);
  9138.                         if (p2 == q2) { /* Yes, null it out */
  9139.                             *p = NUL;
  9140.                             break;
  9141.                         }
  9142.                         q++;
  9143.                     }
  9144.                     if (!*q)            /* Trim list exhausted */
  9145.                       break;            /* So we're done. */
  9146.                     p--;                /* Else keep trimming */
  9147.                 }
  9148.             } else {                    /* Trim from left */
  9149.                 char * q, p2, q2;
  9150.                 p = bp[0];              /* Source */
  9151.                 while (*p) {
  9152.                     p2 = *p;
  9153.                     if (!inpcas[cmdlvl])
  9154.                       if (islower(p2)) p2 = toupper(p2);
  9155.                     q = s;
  9156.                     while (*q) {        /* Is this char in trim list? */
  9157.                         q2 = *q;
  9158.                         if (!inpcas[cmdlvl])
  9159.                           if (islower(q2)) q2 = toupper(q2);
  9160.                         if (p2 == q2) { /* Yes, point past it */
  9161.                             p++;        /* and try next source character */
  9162.                             break;
  9163.                         }
  9164.                         q++;            /* No, try next trim character */
  9165.                     }
  9166.                     if (!*q)            /* Trim list exhausted */
  9167.                       break;            /* So we're done. */
  9168.                 }
  9169.                 ckstrncpy(fnval,p,FNVALL);
  9170.             }
  9171.             p = fnval;
  9172.         } else p = "";
  9173.         goto fnend;
  9174.  
  9175.       case FN_CAP:                      /* \fcapitalize(arg1) */
  9176.         if (argn < 1)
  9177.           goto fnend;
  9178.         s = bp[0];
  9179.         p = fnval;
  9180.         x = 0;
  9181.         while ((c = *s++)) {
  9182.             if (isalpha(c)) {
  9183.                 if (x == 0) {
  9184.                     x = 1;
  9185.                     if (islower(c))
  9186.                       c = toupper(c);
  9187.                 } else if (isupper(c))
  9188.                   c = tolower(c);
  9189.             }
  9190.             *p++ = c;
  9191.         }
  9192.         *p = NUL;
  9193.         p = fnval;
  9194.         goto fnend;
  9195.  
  9196. #ifdef COMMENT
  9197.       case FN_TOD:                      /* Time of day to secs since midnite */
  9198.         sprintf(fnval,"%ld",tod2sec(bp[0])); /* SAFE */
  9199.         goto fnend;
  9200. #endif /* COMMENT */
  9201.  
  9202.       case FN_FFN:                      /* Full pathname of file */
  9203.         zfnqfp(bp[0],FNVALL,p);
  9204.         if (!p) p = "";
  9205.         goto fnend;
  9206.  
  9207.       case FN_CHK: {                    /* \fchecksum() */
  9208.           long chk = 0;
  9209.           p = (argn > 0) ? bp[0] : "";
  9210.           while (*p) chk += *p++;
  9211.           sprintf(fnval,"%lu",chk);     /* SAFE */
  9212.           p = fnval;
  9213.           goto fnend;
  9214.       }
  9215.  
  9216. #ifndef NOXFER
  9217.       case FN_CRC:                      /* \fcrc16() */
  9218.         if (argn > 0)
  9219.           sprintf(fnval,"%u",           /* SAFE */
  9220.                   chk3((CHAR *)bp[0],(int)strlen(bp[0])));
  9221.         else
  9222.           p = "0";
  9223.         goto fnend;
  9224. #endif /* NOXFER */
  9225.  
  9226.       case FN_BSN:                      /* \fbasename() */
  9227.         zstrip(bp[0],&p);
  9228.         goto fnend;
  9229.  
  9230. #ifndef NOLOCAL
  9231. #ifdef OS2
  9232.       case FN_SCRN_CX:                  /* \fscrncurx() */
  9233.         p = fnval;
  9234.         sprintf(p,"%d",(int)VscrnGetCurPos(VTERM)->x); /* SAFE */
  9235.         goto fnend;
  9236.  
  9237.       case FN_SCRN_CY:                  /* \fscrncury() */
  9238.         p = fnval;
  9239.         sprintf(p,"%d",(int)VscrnGetCurPos(VTERM)->y); /* SAFE */
  9240.         goto fnend;
  9241.  
  9242.       case FN_SCRN_STR: {               /* \fscrnstr() */
  9243.           videoline * line = NULL;
  9244.           viocell * cells = NULL;
  9245.           int row = 0, col = 0, len = 0;
  9246.           /* NOTE: On Unicode systems, the screen contents are stored in */
  9247.           /* in Unicode.  Therefore, we should really be performing a    */
  9248.           /* conversion to the local character set.                      */
  9249.  
  9250.           /* 6/18/2000 - added the translation to lcs */
  9251.  
  9252.           if (bp[0] == NULL || bp[0][0] == '\0') {
  9253.               row = 0;
  9254.           } else {
  9255.               if (chknum(bp[0])) {
  9256.                   row = atoi(bp[0]);
  9257.                   if (row < 0)
  9258.                     row = 0;
  9259.               } else {
  9260.                   failed = 1;
  9261.                   if (fndiags)
  9262.                     ckmakmsg(fnval,FNVALL,
  9263.                              "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  9264.                   goto fnend;
  9265.               }
  9266.           }
  9267.           line = VscrnGetLineFromTop( VTERM, (USHORT) row );
  9268.           if (line != NULL) {
  9269.               if (bp[1] == NULL || bp[1][0] == '\0')
  9270.                 col = 0;
  9271.               else {
  9272.                   if (chknum(bp[0])) {
  9273.                       col = atoi(bp[1]);
  9274.                       if (col < 0 || col >= line->width)
  9275.                         col = 0;
  9276.                   } else {
  9277.                       failed = 1;
  9278.                       if (fndiags)
  9279.                         ckmakmsg(fnval,FNVALL,
  9280.                                  "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  9281.                       goto fnend;
  9282.                   }
  9283.               }
  9284.               if (bp[2] == NULL || bp[2][0] == '\0') {
  9285.                   len = line->width - (col+1);
  9286.               } else {
  9287.                   if (!chknum(bp[2])) {
  9288.                       failed = 1;
  9289.                       if (fndiags)
  9290.                         ckmakmsg(fnval,FNVALL,
  9291.                                  "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  9292.                       goto fnend;
  9293.                   }
  9294.                   len = atoi(bp[2]);
  9295.                   if (len < 0 || len > line->width)
  9296.                     len = line->width;
  9297.               }
  9298.               cells = line->cells;
  9299.               for (i = 0; i < len; i++) {
  9300.                   int pos = i + col;
  9301.                   if (pos < line->width) {
  9302.                       if (isunicode())
  9303.                         fnval[i] = (CHAR) utolxlat(cells[pos].c);
  9304.                       else
  9305.                         fnval[i] = (CHAR) (cells[pos].c & 0xFF);
  9306.                       if (fnval[i] == 0)
  9307.                         fnval[i] = SP;
  9308.                   } else
  9309.                     fnval[i] = SP;
  9310.               }
  9311.               fnval[i] = '\0';
  9312.           } else {
  9313.               fnval[0] = '\0';
  9314.           }
  9315.           p = fnval;
  9316.           goto fnend;
  9317.       }
  9318. #endif /* OS2 */
  9319. #endif /* NOLOCAL */
  9320.  
  9321. #ifndef NOPUSH
  9322.       case FN_RAW:                      /* \frawcommand() */
  9323.       case FN_CMD: {                    /* \fcommand() */
  9324.           int x, c, n = FNVALL;
  9325.           x = 0;                        /* Completion flag */
  9326. /*
  9327.   ZIFILE can be safely used because we can't possibly be transferring a file
  9328.   while executing this function.
  9329. */
  9330.           if (!nopush && zxcmd(ZIFILE,bp[0]) > 0) { /* Open the command */
  9331.               while (n-- > -1) {        /* Read from it */
  9332.                   if ((c = zminchar()) < 0) {
  9333.                       x = 1;             /* EOF - set completion flag */
  9334.                       if (cx == FN_CMD) { /* If not "rawcommand" */
  9335.                           p--;           /* remove trailing newlines */
  9336.                           while (*p == CR || *p == LF)
  9337.                             p--;
  9338.                           p++;
  9339.                       }
  9340.                       *p = NUL;         /* Terminate the string */
  9341.                       break;
  9342.                   } else                /* Command still running */
  9343.                     *p++ = c;           /* Copy the bytes */
  9344.               }
  9345.               zclose(ZIFILE);           /* Close the command */
  9346.           }
  9347.           /* Return null string if command's output was too long. */
  9348.           p = fnval;
  9349.           if (!x) {
  9350.               failed = 1;
  9351.               if (fndiags)
  9352.                 ckmakmsg(fnval,FNVALL,
  9353.                          "<ERROR:RESULT_TOO_LONG:\\f",fn,"()>",NULL);
  9354.           }
  9355.           goto fnend;
  9356.       }
  9357. #endif /* NOPUSH */
  9358.     } /* Break up big switch... */
  9359.  
  9360.     switch (y) {
  9361.       case FN_STX:                      /* \fstripx(string,c) */
  9362.         if (!(s = bp[0]))               /* Make sure there is a string */
  9363.           goto fnend;
  9364.         c = '.';                        /* Character to strip from */
  9365.         if (argn > 1) if (*bp[1]) c = *bp[1];
  9366.         n = ckstrncpy(fnval,bp[0],FNVALL);
  9367.         while (--n >= 0) {
  9368.             if (fnval[n] == c) {
  9369.                 fnval[n] = NUL;
  9370.                 break;
  9371.             }
  9372.         }
  9373.         p = fnval;
  9374.         goto fnend;
  9375.  
  9376.       case FN_STL:                      /* \flop(string,c) */
  9377.       case FN_LOPX: {            /* \flopx(string,c) */
  9378.       int n = 1;
  9379.       if (!(s = bp[0]))        /* Make sure there is a string */
  9380.         goto fnend;
  9381.       c = '.';            /* Character to strip to */
  9382.       if (argn > 1) if (*bp[1]) c = *bp[1];
  9383.       if (argn > 2) if (*bp[2]) {
  9384.           n = 0;
  9385.           if (isfloat(bp[2],0)) {
  9386.           n = (int)floatval;
  9387.           if (n < 0) n = 0;
  9388.           }
  9389.       }
  9390.       x = 0;
  9391.       if (cx == FN_LOPX) {        /* Lopx (from right) */
  9392.           if (n == 0)
  9393.         goto fnend;
  9394.           s += strlen(s) - 1;    /* We already know it's > 0 */
  9395.           while (s-- >= bp[0]) {
  9396.           if (*s == c) {
  9397.               n--;
  9398.               if (n == 0) {
  9399.               s++;
  9400.               x = 1;
  9401.               break;
  9402.               }
  9403.           }
  9404.           }
  9405.           if (!x) s = "";
  9406.       } else {            /* Lop (from left) */
  9407.           if (n == 0) {
  9408.           p = bp[0];
  9409.           goto fnend;
  9410.           }
  9411.           while (*s++) {
  9412.           if (*(s-1) == c) {
  9413.               if (--n == 0) {
  9414.               x = 1;
  9415.               break;
  9416.               }
  9417.           }
  9418.           }
  9419.           if (!x) s = bp[0];
  9420.       }
  9421.       ckstrncpy(fnval,s,FNVALL);
  9422.       p = fnval;
  9423.       goto fnend;
  9424.       }
  9425.       case FN_STN:                      /* \fstripn(string,n) */
  9426.         if (argn < 1)                   /* Remove n chars from right */
  9427.           goto fnend;
  9428.         val1 = "0";
  9429.         if (argn > 1)
  9430.           if (*(bp[1]))
  9431.             val1 = evalx(bp[1]);
  9432.         if (!chknum(val1)) {
  9433.             failed = 1;
  9434.             evalerr(fn);
  9435.             goto fnend;
  9436.         }
  9437.         n = atoi(val1);
  9438.         if (n < 0) n = 0;
  9439.         k = (int)strlen(s = bp[0]) - n;
  9440.         if (k < 0) k = 0;
  9441.         p = fnval;
  9442.         while (k-- > 0)
  9443.           *p++ = *s++;
  9444.         *p = NUL;
  9445.         p = fnval;
  9446.         goto fnend;
  9447.  
  9448.       case FN_STB: {                    /* \fstripb(string,c) */
  9449.           char c2 = NUL;
  9450.           int i, k = 0;
  9451.           char * gr_opn = "\"{'([<";    /* Group open brackets */
  9452.           char * gr_cls = "\"}')]>";    /* Group close brackets */
  9453.  
  9454.           p = fnval;
  9455.           *p = NUL;
  9456.           if (!(s = bp[0]))             /* Make sure there is a string */
  9457.             goto fnend;
  9458.           if ((x = strlen(s)) < 1)
  9459.             goto fnend;
  9460.           c = NUL;                      /* Brace/bracket kind */
  9461.           if (argn > 1) {
  9462.               if (*bp[1]) {
  9463.                   if (chknum(bp[1])) {
  9464.                       k = atoi(bp[1]);
  9465.                       if (k < 0) k = 63;
  9466.                       for (i = 0; i < 6; i++) {
  9467.                           if (k & (1<<i)) {
  9468.                               if (s[0] == gr_opn[i] && s[x-1] == gr_cls[i]) {
  9469.                                   ckstrncpy(fnval,s+1,FNVALL);
  9470.                                   fnval[x-2] = NUL;
  9471.                                   goto fnend;
  9472.                               }
  9473.                           }
  9474.                       }
  9475.                       ckstrncpy(fnval,s,FNVALL); /* No match */
  9476.                       goto fnend;
  9477.                   }
  9478.               }
  9479.           }
  9480.           c = *bp[1];
  9481.           if (!c) c = s[0];
  9482.           if (argn > 2) if (*bp[2]) c2 = *bp[2];
  9483.           if (*s == c) {
  9484.               if (!c2) {
  9485.                   switch (c) {
  9486.                     case '(': c2 = ')'; break;
  9487.                     case '[': c2 = ']'; break;
  9488.                     case '{': c2 = '}'; break;
  9489.                     case '<': c2 = '>'; break;
  9490.                     case '"': c2 = '"'; break;
  9491.                     case 39:  c2 = 39;  break;
  9492.                     case 96:  c2 = 39;  break;
  9493.                     default:
  9494.                       if (argn == 2) {
  9495.                           c2 = c;
  9496.                       } else {
  9497.                           strncpy(fnval,s,x); /* Leave it like this */
  9498.                           fnval[x] = NUL;
  9499.                           goto fnend;
  9500.                       }
  9501.                   }
  9502.               }
  9503.               if (s[x-1] == c2) {
  9504.                   strncpy(fnval,s+1,x-2); /* Leave it like this */
  9505.                   fnval[x-2] = NUL;
  9506.                   goto fnend;
  9507.               }
  9508.           }
  9509.           strncpy(fnval,s,x);
  9510.           fnval[x] = NUL;
  9511.           goto fnend;
  9512.       }
  9513.  
  9514.       case FN_2HEX:                     /* Number to hex */
  9515.       case FN_2OCT:                     /* Number to octal */
  9516.         val1 = evalx(bp[0]);
  9517.         if (!*val1) {
  9518.             failed = 1;
  9519.             evalerr(fn);
  9520.             goto fnend;
  9521.         }
  9522.         sprintf(fnval, cx == FN_2HEX ? "%lx" : "%lo", atol(val1)); /* SAFE */
  9523.         if (cx == FN_2HEX && (int)(strlen(fnval)&1))
  9524.           sprintf(fnval,"0%lx",atol(val1)); /* SAFE */
  9525.         p = fnval;
  9526.         goto fnend;
  9527.  
  9528.       case FN_DNAM: {                   /* Directory part of file name */
  9529.           char *s;
  9530.           zfnqfp(bp[0],FNVALL,p);       /* Get full name */
  9531.           if (!isdir(p)) {              /* Is it already a directory? */
  9532.               zstrip(p,&s);             /* No get basename */
  9533.               if (*s) {
  9534.                   x = ckindex(s,p,0,0,0); /* Pos of latter in former */
  9535.                   if (x > 0) p[x-1] = NUL;
  9536.               }
  9537.           }
  9538.           if (!p) p = "";
  9539.           goto fnend;
  9540.       }
  9541.  
  9542. #ifndef NORANDOM
  9543.       case FN_RAND:                     /* Random number */
  9544. #ifdef CK_SSL
  9545.         if (RAND_bytes((unsigned char *)&k,sizeof(k)) < 0)
  9546. #endif /* CK_SSL */
  9547.           k = rand();
  9548.         x = 0;
  9549.         if (argn > 0) {
  9550.             if (!chknum(bp[0])) {
  9551.                 failed = 1;
  9552.                 if (fndiags)
  9553.                   ckmakmsg(fnval,FNVALL,
  9554.                            "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  9555.                 goto fnend;
  9556.             }
  9557.             x = atoi(bp[0]);
  9558.         }
  9559. #ifdef COMMENT
  9560.         sprintf(fnval,"%d", (x > 0 && k > 0) || (x < 0 && k < 0) ? k % x : 
  9561.                 (x == 0 ? 0 : (0 - (k % (-x)))));
  9562. #else
  9563.         debug(F111,"rand",ckitoa(x),k);
  9564. #ifdef SUNOS4
  9565. /* This is really strange but on SunOS, if we are requesting random numbers */
  9566. /* between 0 and 4 or less, they always come out in sequence: 0 1 2 3 0 1 2 */
  9567. /* Shifting the result of rand() in this case gives a more random result.   */
  9568.         if (x < 5)
  9569.           k = k >> 5;
  9570. #endif /* SUNOS4 */
  9571.         if ((x > 0 && k > 0) || (x < 0 && k < 0))
  9572.           x = k % x;
  9573.         else if (x == 0)
  9574.           x = 0;
  9575.         else
  9576.           x = 0 - (k % (-x));
  9577.         debug(F101,"rand x","",x);
  9578.         sprintf(fnval,"%d", x);         /* SAFE */
  9579. #endif /* COMMENT */
  9580.         p = fnval;
  9581.         goto fnend;
  9582. #endif /* NORANDOM */
  9583.     } /* Break up big switch... */
  9584.  
  9585.     switch (y) {
  9586.       case FN_SPLIT:                    /* \fsplit(s1,a,s2,s3,mask) */
  9587.       case FN_WORD: {                   /* \fword(s1,n,s2,s3,mask) */
  9588.           int wordnum = 0;
  9589.           int splitting = 0;
  9590.           int x;
  9591.           int array = 0;
  9592.           int grouping = 0;
  9593.           int nocollapse = 0;
  9594.           char * sep = "";
  9595.           char * notsep = "";
  9596.           char * bp0 = NULL;
  9597.           char * bp1 = NULL;
  9598.           char   abuf[16];
  9599.           struct stringarray * q = NULL;
  9600.  
  9601.           splitting = (cx == FN_SPLIT); /* Our job */
  9602.  
  9603.           fnval[0] = splitting ? '0' : NUL; /* Initial return value */
  9604.           fnval[1] = NUL;
  9605.           p = fnval;
  9606.           bp0 = bp[0];                  /* Source string */
  9607.           if (!bp0) bp0 = "";
  9608.           debug(F111,"fsplit bp[0]",bp0,argn);
  9609.           if (argn < 1 || !*bp0)        /* If none, return default value */
  9610.             goto fnend;
  9611.  
  9612.           bp1 = bp[1];                  /* Function-dependent arg */
  9613.           if (!bp1) bp1 = "";           /* (array or number) */
  9614.           debug(F110,"fsplit bp[1]",bp1,0);
  9615.           if (bp[5]) {
  9616.               if (!chknum(bp[5])) {
  9617.                   failed = 1;
  9618.                   ckmakmsg(fnval,FNVALL,
  9619.                            "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  9620.                   goto fnend;
  9621.               }
  9622.               x = atoi(bp[5]);
  9623.               nocollapse = x;
  9624.           }
  9625.           if (!splitting) {             /* \fword(): n = desired word number */
  9626.               val1 = "1";               /* Default is first word */
  9627.               if (argn > 1)             /* Word number supplied */
  9628.                 if (*bp1)
  9629.                   val1 = evalx(bp1);
  9630.               if (!chknum(val1)) {
  9631.                   failed = 1;
  9632.                   ckmakmsg(fnval,FNVALL,
  9633.                            "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  9634.                   goto fnend;
  9635.               }
  9636.               n = atoi(val1);
  9637.           } else if (argn > 1 && *bp1) { /* \fsplit(): n = word count */
  9638.               ckstrncpy(abuf,bp1,16);   /* Get array reference */
  9639.               debug(F110,"fsplit abuf 1",abuf,0);
  9640.               failed = 1;               /* Assume it's bad */
  9641.               if (fndiags)              /* Default is this error message */
  9642.                 ckmakmsg(fnval,FNVALL,
  9643.                          "<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
  9644.               if (abuf[0] != '&')       /* "Address" of array */
  9645.                 goto fnend;             /* It's bad */
  9646.               if (abuf[2]) {            /* Check for brackets */
  9647.                   if (abuf[2] != '[' || abuf[3] != ']') {
  9648.                       goto fnend;       /* Bad */
  9649.                   }
  9650.               }
  9651.               debug(F110,"fsplit abuf 2",abuf,0);
  9652.               if (abuf[1] > 64 && abuf[1] < 91) /* Convert upper to lower */
  9653.                 abuf[1] += 32;
  9654.               if (abuf[1] < 97 || abuf[1] > 122) { /* Check for a-z */
  9655.                   goto fnend;
  9656.               }
  9657.               debug(F110,"fsplit abuf 3",abuf,0);
  9658.               array = 1;
  9659.               fnval[0] = NUL;           /* No error, erase message */
  9660.               failed = 0;               /* Unset failure flag */
  9661.               n = 0;                    /* Initialize word counter */
  9662.           }
  9663.           if (argn > 2)                 /* Have break set? */
  9664.             sep = bp[2];
  9665.           debug(F111,"fsplit sep",sep,argn);
  9666.           if (argn > 3)                 /* Have include set? */
  9667.             notsep = bp[3];
  9668.           debug(F111,"fsplit notsep",notsep,argn);
  9669.           if (argn > 4) {               /* Have grouping set? */
  9670.               char * bp4 = bp[4];
  9671.               debug(F111,"fsplit bp4",bp4,argn);
  9672.               if (!bp4) bp4 = "0";
  9673.               if (!*bp4) bp4 = "0";
  9674.               if (chknum(bp4)) {
  9675.                   grouping = atoi(bp4);
  9676.                   if (grouping == -1)
  9677.                     grouping = 127;
  9678.               } else {
  9679.                   failed = 1;
  9680.                   if (fndiags)
  9681.                     ckmakmsg(fnval,FNVALL,
  9682.                              "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  9683.                   goto fnend;
  9684.               }
  9685.           }
  9686.           /* Args parsed, now do the work */
  9687.  
  9688.           debug(F111,"fsplit bp0",bp0,n);
  9689.           q = cksplit(splitting,n,bp0,sep,notsep,grouping,0,nocollapse);
  9690.  
  9691.           wordnum = q ? q->a_size : -1; /* Check result */
  9692.           if (wordnum < 0) {
  9693.               failed = 1;               /* Failure */
  9694.               if (fndiags)
  9695.                 ckmakmsg(fnval,FNVALL,
  9696.                          (wordnum == -1) ?
  9697.                          "<ERROR:MALLOC_FAILURE:\\f" :
  9698.                          "<ERROR:TOO_MANY_WORDS:\\f",
  9699.                          fn,
  9700.                          "()>",
  9701.                          NULL
  9702.                          );
  9703.               goto fnend;
  9704.           }
  9705.           if (splitting) {              /* \fsplit() result */
  9706.               ckstrncpy(fnval,ckitoa(wordnum),FNVALL);
  9707.               if (array) {              /* Array was not declared. */
  9708.                   int i;
  9709.                   if ((x = dclarray(abuf[1],wordnum)) < 0) { /* Declare it. */
  9710.                       failed = 1;
  9711.                       if (fndiags)
  9712.                         ckmakmsg(fnval,FNVALL,
  9713.                                  "<ERROR:MALLOC_FAILURE:\\f",fn,"()>",NULL);
  9714.                       goto fnend;
  9715.                   }
  9716.                   for (i = 1; i <= wordnum; i++) { /* Copy results */
  9717.                       makestr(&(a_ptr[x][i]),q->a_head[i]);
  9718.                   }
  9719.                   a_ptr[x][0] = NULL;   /* Array is 1-based */
  9720.                   makestr(&(a_ptr[x][0]),fnval); /* Element = size */
  9721.               }
  9722.           } else {                      /* \fword() result */
  9723.               char * s;
  9724.               s = q->a_head[1];
  9725.               if (!s) s = "";
  9726.               ckstrncpy(fnval,s,FNVALL);
  9727.           }
  9728.           goto fnend;                   /* Done */
  9729.       }
  9730.  
  9731.     } /* Break up big switch... */
  9732.  
  9733.     switch (y) {
  9734.  
  9735. #ifdef CK_KERBEROS
  9736.       case FN_KRB_TK:                   /* Kerberos tickets */
  9737.       case FN_KRB_NX:                   /* Kerberos next ticket */
  9738.       case FN_KRB_IV:                   /* Kerberos ticket is valid */
  9739.       case FN_KRB_FG:                   /* Kerberos Ticket flags */
  9740.       case FN_KRB_TT: {                 /* Kerberos ticket time */
  9741.           int kv = 0;                   /* Kerberos version */
  9742.           int n = 0;
  9743.           char * s = NULL;
  9744.           if (rdigits(bp[0])) {
  9745.               kv = atoi(bp[0]);
  9746.           } else {
  9747.               failed = 1;
  9748.               if (fndiags)
  9749.                 ckmakmsg(fnval,FNVALL,
  9750.                          "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  9751.               goto fnend;
  9752.           }
  9753.           if (kv != 4 && kv != 5) {
  9754.               failed = 1;
  9755.               if (fndiags)
  9756.                 ckmakmsg(fnval,FNVALL,
  9757.                          "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
  9758.               goto fnend;
  9759.           }
  9760.           if ((cx == FN_KRB_IV || cx == FN_KRB_TT || cx == FN_KRB_FG) &&
  9761.                argn < 2) {
  9762.               failed = 1;
  9763.               if (fndiags)
  9764.                 ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
  9765.               goto fnend;
  9766.           }
  9767.           switch (y) {
  9768.             case FN_KRB_TK:             /* Number of Kerberos tickets */
  9769. #ifdef CK_AUTHENTICATION
  9770.               switch (kv) {
  9771.                 case 4:
  9772.                   n = ck_krb4_get_tkts();
  9773.                   sprintf(fnval, "%d", (n >= 0) ? n : 0); /* SAFE */
  9774.                   goto fnend;
  9775.                 case 5: {
  9776.                     extern char * krb5_d_cc;
  9777.                     n = ck_krb5_get_tkts(krb5_d_cc);
  9778.                     sprintf(fnval, "%d", (n >= 0) ? n : 0); /* SAFE */
  9779.                     goto fnend;
  9780.                 }
  9781.               }
  9782. #else
  9783.               sprintf(fnval,"%d",0);    /* SAFE */
  9784. #endif /* CK_AUTHENTICATION */
  9785.               goto fnend;
  9786.  
  9787.             case FN_KRB_NX:             /* Kerberos next ticket */
  9788. #ifdef CK_AUTHENTICATION
  9789.               switch (kv) {
  9790.                 case 4:
  9791.                   s = ck_krb4_get_next_tkt();
  9792.                   ckstrncpy(fnval, s ? s : "",FNVALL);
  9793.                   goto fnend;
  9794.                 case 5:
  9795.                   s = ck_krb5_get_next_tkt();
  9796.                   ckstrncpy(fnval, s ? s : "",FNVALL);
  9797.                   goto fnend;
  9798.               }
  9799. #else
  9800.               sprintf(fnval,"k%d next-ticket-string",kv); /* SAFE */
  9801. #endif /* CK_AUTHENTICATION */
  9802.               goto fnend;
  9803.  
  9804.             case FN_KRB_IV:             /* Kerberos ticket is valid */
  9805. #ifdef CK_AUTHENTICATION
  9806.               /* Return 1 if valid, 0 if not */
  9807.               switch (kv) {
  9808.                 case 4:
  9809.                   n = ck_krb4_tkt_isvalid(bp[1]);
  9810.                   sprintf(fnval, "%d", n > 0 ? 1 : 0); /* SAVE */
  9811.                   goto fnend;
  9812.                 case 5: {
  9813.                     extern char * krb5_d_cc;
  9814.                     n = ck_krb5_tkt_isvalid(krb5_d_cc,bp[1]);
  9815.                     sprintf(fnval,"%d", n > 0 ? 1 : 0); /* SAFE */
  9816.                     goto fnend;
  9817.                 }
  9818.               }
  9819. #else
  9820.               sprintf(fnval,"%d",0);    /* SAFE */
  9821. #endif /* CK_AUTHENTICATION */
  9822.               goto fnend;
  9823.  
  9824.             case FN_KRB_TT:             /* Kerberos ticket time */
  9825. #ifdef CK_AUTHENTICATION
  9826.               switch (kv) {
  9827.                 case 4:
  9828.                   n = ck_krb4_tkt_time(bp[1]);
  9829.                   sprintf(fnval,"%d", n >= 0 ? n : 0); /* SAFE */
  9830.                   goto fnend;
  9831.                 case 5: {
  9832.                     extern char * krb5_d_cc;
  9833.                     n = ck_krb5_tkt_time(krb5_d_cc,bp[1]);
  9834.                     sprintf(fnval,"%d", n >= 0 ? n : 0); /* SAFE */
  9835.                     goto fnend;
  9836.                 }
  9837.               }
  9838. #else
  9839.               ckstrncpy(fnval,"600",FNVALL); /* Some time */
  9840. #endif /* CK_AUTHENTICATION */
  9841.               goto fnend;
  9842.  
  9843.             case FN_KRB_FG:             /* Kerberos ticket flags */
  9844. #ifdef CK_AUTHENTICATION
  9845.               switch (kv) {
  9846.                 case 4:
  9847.                   fnval[0] = '\0';
  9848.                   goto fnend;
  9849.                 case 5: {
  9850.                     extern char * krb5_d_cc;
  9851.                     ckstrncpy(fnval,ck_krb5_tkt_flags(krb5_d_cc,bp[1]),FNVALL);
  9852.                     goto fnend;
  9853.                 }
  9854.               }
  9855. #else
  9856.               fnval[0] = '\0';
  9857. #endif /* CK_AUTHENTICATION */
  9858.               goto fnend;
  9859.           }
  9860.           p = fnval;
  9861.           goto fnend;
  9862.       }
  9863. #endif /* CK_KERBEROS */
  9864.  
  9865. #ifdef FN_ERRMSG
  9866.       case FN_ERRMSG:
  9867.         if (rdigits(bp[0])) {
  9868.             k = atoi(bp[0]);
  9869.         } else {
  9870.             failed = 1;
  9871.             if (fndiags)
  9872.              ckmakmsg(fnval,FNVALL,"<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  9873.             goto fnend;
  9874.         }
  9875. #ifdef VMS
  9876.         ckstrncpy(fnval,ckvmserrstr(k),FNVALL);
  9877. #else
  9878.         x = errno;
  9879.         errno = k;
  9880.         ckstrncpy(fnval,ck_errstr(),FNVALL);
  9881.         errno = x;
  9882. #endif /* VMS */
  9883.         p = fnval;
  9884.         goto fnend;
  9885. #endif /* FN_ERRMSG */
  9886.  
  9887.       case FN_DIM: {
  9888.           int max;
  9889.           char abuf[16], *s;
  9890.           fnval[0] = NUL;               /* Initial return value */
  9891.           ckstrncpy(abuf,bp[0],16);     /* Get array reference */
  9892.           s = abuf;
  9893.           if (*s == CMDQ) s++;
  9894.           failed = 1;                   /* Assume it's bad */
  9895.           p = fnval;                    /* Point to result */
  9896.           if (fndiags)                  /* Default is this error message */
  9897.             ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
  9898.           if (s[0] != '&') {            /* "Address" of array */
  9899.               goto fnend;
  9900.           }
  9901.           if (s[2]) {
  9902.               if (s[2] != '[' || s[3] != ']') {
  9903.                   goto fnend;
  9904.               }
  9905.           }
  9906.           if (s[1] >= 64 && s[1] < 91)  /* Convert upper to lower */
  9907.             s[1] += 32;
  9908.           if (s[1] < 95 || s[1] > 122) { /* Check for a-z */
  9909.               goto fnend;                       /* Bad */
  9910.           }
  9911.           if ((max = chkarray(s[1],1)) < 1)
  9912.             max = 0;
  9913.           failed = 0;                   /* Unset failure flag */
  9914.           sprintf(fnval,"%d",max);      /* SAFE */
  9915.           goto fnend;
  9916.       }
  9917.  
  9918.     } /* Break up big switch... */
  9919.  
  9920.     switch (y) {
  9921.       case FN_JDATE:
  9922.         if (argn < 1)                   /* Check number of args */
  9923.           p = ckdate();                 /* None, get today's date-time */
  9924.         else                            /* Some */
  9925.           p = bp[0];                    /* Use first */
  9926.         p = ckcvtdate(p,0);             /* Convert to standard form */
  9927.         ckstrncpy(fnval,zjdate(p),FNVALL); /* Convert to Julian */
  9928.         p = fnval;                      /* Point to result */
  9929.         failed = 0;
  9930.         if (*p == '-') {
  9931.             failed = 1;
  9932.             if (fndiags)                /* Default is this error message */
  9933.               ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_DATE:\\f",fn,"()>",NULL);
  9934.         }
  9935.         goto fnend;
  9936.  
  9937.       case FN_DATEJ:
  9938.         ckstrncpy(fnval,jzdate(bp[0]),FNVALL); /* Convert to yyyy<dayofyear> */
  9939.         p = fnval;                      /* Point to result */
  9940.         failed = 0;
  9941.         if (*p == '-') {
  9942.             failed = 1;
  9943.             if (fndiags)                /* Default is this error message */
  9944.               ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_DATE:\\f",fn,"()>",NULL);
  9945.         }
  9946.         goto fnend;
  9947.  
  9948.       case FN_DTIM:                     /* \fcvtdate() */
  9949.       case FN_TIME:                     /* Free-format time to hh:mm:ss */
  9950.       case FN_NTIM:                     /* Time to sec since midnight */
  9951.         s = (argn > 0) ? bp[0] : "";
  9952.         if (!s) s = "";
  9953.         if (!*s)
  9954.           p = ckdate();                 /* None, get today's date */
  9955.         else                            /* Some */
  9956.           p = bp[0];                    /* Use first */
  9957.     {
  9958.         char * s;
  9959.         s = p;
  9960.         while (*s) {
  9961.         if (*s < 32) {
  9962.             *s = NUL;
  9963.             break;
  9964.         }
  9965.         s++;
  9966.         }
  9967.         /* do { if (*s < '!') *s = NUL; break; } while (*s++); */
  9968.     }
  9969.         p = ckcvtdate(p,2);             /* Convert to standard form */
  9970.         if (*p == '<') {
  9971.             failed = 1;
  9972.             if (fndiags)                /* Default is this error message */
  9973.               ckmakmsg(fnval,FNVALL,
  9974.                        "<ERROR:ARG_BAD_DATE_OR_TIME:\\f",fn,"()>",NULL);
  9975.             p = fnval;
  9976.             goto fnend;
  9977.         }
  9978.         if (argn > 1) {            /* Format code */
  9979.             s = bp[1];
  9980.             if (!s) s = "";
  9981.             if (!*s) s = "0";
  9982.             if (!chknum(s)) {
  9983.                 failed = 1;
  9984.                 if (fndiags)
  9985.                   ckmakmsg(fnval,FNVALL,
  9986.                            "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  9987.                 p = fnval;
  9988.                 goto fnend;
  9989.             }
  9990.             x = atoi(s);
  9991.             /* if (x) */ p = shuffledate(p,x);
  9992.         }
  9993.         if (cx == FN_TIME) {
  9994.             p += 9;
  9995.         } else if (cx == FN_NTIM) {
  9996.             long sec = 0L;
  9997.             p[11] = NUL;
  9998.             p[14] = NUL;
  9999.             sec = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
  10000.             sprintf(fnval,"%ld",sec);   /* SAFE */
  10001.             p = fnval;
  10002.         }
  10003.         goto fnend;
  10004.  
  10005.       case FN_MJD:                      /* Modified Julian Date */
  10006.         if (argn < 1)                   /* Check number of args */
  10007.           p = zzndate();                /* None, get today's date-time */
  10008.         else                            /* Some */
  10009.           p = bp[0];                    /* Use first */
  10010.         p = ckcvtdate(p,0);             /* Convert to standard form */
  10011.         if (*p == '-') {
  10012.             failed = 1;
  10013.             if (fndiags)                /* Default is this error message */
  10014.               ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_DATE:\\f",fn,"()>",NULL);
  10015.             goto fnend;
  10016.         }
  10017.         /* Convert to modified Julian date */
  10018.         sprintf(fnval,"%ld",mjd(p));    /* SAFE */
  10019.         p = fnval;                      /* Point to result */
  10020.         goto fnend;
  10021.  
  10022.       case FN_MJD2: {
  10023.           long k = 0L;
  10024.           int n = 0;
  10025.           p = evalx(bp[0]);
  10026.           if (*p == '-') {
  10027.               p++;
  10028.               n = 1;
  10029.           }
  10030.           if (!rdigits(p)) {
  10031.               failed = 1;
  10032.               evalerr(fn);
  10033.               p = fnval;
  10034.               goto fnend;
  10035.           } else {
  10036.               k = atol(p);
  10037.               if (n) k = -k;
  10038.           }
  10039.           ckstrncpy(fnval,mjd2date(k),FNVALL); /* Convert to Date */
  10040.           p = fnval;                    /* Point to result */
  10041.           failed = 0;
  10042.           goto fnend;
  10043.       }
  10044.  
  10045. #ifndef NODIAL
  10046.       case FN_PNCVT: {                  /* Convert phone number */
  10047.           extern char * pncvt();
  10048.           failed = 0;
  10049.           p = pncvt(bp[0]);
  10050.           if (!p) p = "";
  10051.           if (!*p) {
  10052.             failed = 1;
  10053.             if (fndiags)                /* Default is this error message */
  10054.               ckmakmsg(fnval,FNVALL,
  10055.                        "<ERROR:ARG_BAD_PHONENUM:\\f",fn,"()>",NULL);
  10056.         }
  10057.         goto fnend;
  10058.       }
  10059. #endif /* NODIAL */
  10060.  
  10061.       case FN_DAY:
  10062.       case FN_NDAY:
  10063.         if (argn < 1)                   /* Check number of args */
  10064.           p = zzndate();                /* None, get today's date-time */
  10065.         else                            /* Some */
  10066.           p = bp[0];                    /* Use first */
  10067.         p = ckcvtdate(p,0);             /* Convert to standard form */
  10068.         if (*p == '-') {
  10069.             failed = 1;
  10070.             if (fndiags)                /* Default is this error message */
  10071.               ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_DATE:\\f",fn,"()>",NULL);
  10072.             goto fnend;
  10073.         }
  10074.         failed = 0;
  10075.         z = mjd(p);                     /* Convert to modified Julian date */
  10076.         z = z % 7L;
  10077.         if (z < 0) {
  10078.             z = 0 - z;
  10079.             k = 6 - ((int)z + 3) % 7;
  10080.         } else {
  10081.             k = ((int)z + 3) % 7;    /* Day of week */
  10082.         }
  10083.         p = fnval;                      /* Point to result */
  10084.         if (cx == FN_NDAY)
  10085.           sprintf(fnval,"%d",k);        /* SAFE */
  10086.         else
  10087.           ckstrncpy(fnval,wkdays[k],FNVALL);
  10088.         goto fnend;
  10089.  
  10090.       case FN_N2TIM: {                  /* Sec since midnight to hh:mm:ss */
  10091.           long k = 0L;
  10092.           int n = 0, hh, mm, ss;
  10093.           char * s = bp[0];
  10094.           if (argn < 1)                 /* If no arg substitute 0 */
  10095.             s = "0";
  10096.           p = evalx(s);                 /* Evaluate expression silently */
  10097.           if (*p == '-') {              /* Check result for minus sign */
  10098.               p++;
  10099.               n = 1;
  10100.           }
  10101.           if (!rdigits(p)) { /* Check for numeric */
  10102.               failed = 1;
  10103.               ckmakmsg(fnval,FNVALL,
  10104.                        "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  10105.               p = fnval;
  10106.               goto fnend;
  10107.           } else {
  10108.               k = atol(p);
  10109.               if (n) k = -k;
  10110.           }
  10111.           if (k < 0) {                  /* Check for negative */
  10112.               failed = 1;
  10113.               if (fndiags)
  10114.                 ckmakmsg(fnval,FNVALL,
  10115.                          "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
  10116.               p = fnval;
  10117.               goto fnend;
  10118.           }
  10119.           hh = k / 3600L;               /* Have positive number */
  10120.           mm = (k % 3600L) / 60L;       /* break it down... */
  10121.           ss = ((k % 3600L) % 60L);
  10122.  
  10123.           sprintf(fnval,"%02d:%02d:%02d",hh,mm,ss); /* SAFE */
  10124.           p = fnval;
  10125.           failed = 0;
  10126.           goto fnend;
  10127.       }
  10128.  
  10129.       case FN_PERM: {                   /* File permissions */
  10130.           p = fnval;
  10131.           z = zchki(bp[0]);
  10132.           if (z < 0) {
  10133.               failed = 1;
  10134.               if (fndiags) {
  10135.                   if (z == -1)
  10136.                     ckmakmsg(fnval,FNVALL,
  10137.                              "<ERROR:FILE_NOT_FOUND:\\f",fn,"()>",NULL);
  10138.                   else if (z == -2)
  10139.                     ckmakmsg(fnval,FNVALL,
  10140.                              "<ERROR:FILE_NOT_READABLE:\\f",fn,"()>",NULL);
  10141.                   else if (z == -3)
  10142.                     ckmakmsg(fnval,FNVALL,
  10143.                              "<ERROR:FILE_NOT_ACCESSIBLE:\\f",fn,"()>",NULL);
  10144.                   else
  10145.                     ckmakmsg(fnval,FNVALL,
  10146.                              "<ERROR:FILE_ERROR:\\f",fn,"()>",NULL);
  10147.               }
  10148.               goto fnend;
  10149.           }
  10150. #ifdef CK_PERMS
  10151.           ckstrncpy(fnval,ziperm(bp[0]),FNVALL);
  10152. #else
  10153.           ckstrncpy(fnval,"(unknown)",FNVALL);
  10154. #endif /* CK_PERMS */
  10155.           goto fnend;
  10156.       }
  10157.       case FN_TLOOK:                    /* tablelook() */
  10158.       case FN_ALOOK: {                  /* arraylook() */
  10159.           int i, x, hi, lo, max, cmdlen;
  10160.           char abuf[16], *s, *pat;
  10161.           char kwbuf[256];
  10162.           char delim = ':';
  10163.           failed = 1;                   /* Assume failure */
  10164.           ckstrncpy(fnval,"-1",FNVALL);
  10165.           pat = bp[0];                  /* Point to search pattern */
  10166.           if (!pat) pat = "";           /* Watch out for NULL pointer */
  10167.           cmdlen = strlen(pat);         /* Get pattern length */
  10168.           if (argn < 2 /* || cmdlen < 1 */ ) { /* Need two args */
  10169.               if (fndiags)
  10170.                 ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
  10171.               goto fnend;
  10172.           }
  10173.           ckstrncpy(abuf,bp[1],16);     /* Get array reference */
  10174.           if (argn > 2)
  10175.             delim = *(bp[2]);
  10176.           s = abuf;
  10177.           if ((x = arraybounds(s,&lo,&hi)) < 0) { /* Get index and bounds */
  10178.               if (fndiags)
  10179.                ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
  10180.               goto fnend;
  10181.           }
  10182.           p = fnval;                    /* Point to result */
  10183.           max = a_dim[x];               /* Size of array */
  10184.           if (lo < 0) lo = 0;           /* Use given range if any */
  10185.           if (lo > max) lo = max;
  10186.           if (hi < 0) hi = max;
  10187.           if (hi > max) hi = max;
  10188.           failed = 0;                   /* Unset failure flag */
  10189.           if (max < 1)
  10190.             goto fnend;
  10191.           kwbuf[255] = NUL;
  10192.           for (i = lo; i <= hi; i++) {
  10193.               if (!a_ptr[x][i])
  10194.                 continue;
  10195.               if (cx == FN_ALOOK) {
  10196.                   if (ckmatch(pat,a_ptr[x][i],inpcas[cmdlvl],1+4)) {
  10197.                       sprintf(fnval,"%d",i); /* SAFE */
  10198.                       goto fnend;
  10199.                   }
  10200.               } else if (cx == FN_TLOOK) {
  10201.                   char * aa;
  10202.                   int j = 0, v = 0, len;
  10203.                   if (i == hi)
  10204.                     break;
  10205.                   aa = a_ptr[x][i];     /* Point to this array element */
  10206.                   if (!aa) aa = "";
  10207.                   while (j < 254 && *aa) { /* Isolate keyword */
  10208.                       if (*aa == delim)
  10209.                         break;
  10210.                       kwbuf[j++] = *aa++;
  10211.                   }
  10212.                   kwbuf[j] = NUL;
  10213.                   len = j;
  10214.                   v = 0;
  10215.                   if ((len == cmdlen && !ckstrcmp(kwbuf,pat,len,0)) ||
  10216.                       ((v = !ckstrcmp(kwbuf,pat,cmdlen,0)) &&
  10217.                        ckstrcmp(a_ptr[x][i+1],pat,cmdlen,0))) {
  10218.                       sprintf(fnval,"%d",i); /* SAFE */
  10219.                       goto fnend;
  10220.                   }
  10221.                   if (v) {              /* Ambiguous */
  10222.                       ckstrncpy(fnval,"-2",FNVALL);
  10223.                       goto fnend;
  10224.                   }
  10225.               }
  10226.           }
  10227.           if (cx == FN_TLOOK) {         /* tablelook() last element */
  10228.               ckstrncpy(fnval,"-1",FNVALL);
  10229.               if (!ckstrcmp(a_ptr[x][hi],pat,cmdlen,0))
  10230.                 sprintf(fnval,"%d",hi); /* SAFE */
  10231.           }
  10232.           goto fnend;
  10233.       }
  10234.       case FN_TOB64:                    /* Base-64 conversion */
  10235.       case FN_FMB64:
  10236.         p = fnval;
  10237.         *p = NUL;
  10238.         if (argn < 1)
  10239.           goto fnend;
  10240.         if (cx == FN_TOB64) {
  10241.             x = b8tob64(bp[0],-1,fnval,FNVALL);
  10242.         } else {
  10243.             x = strlen(bp[0]);
  10244.             if (x % 4) {                /* length must be multiple of 4 */
  10245.                 failed = 1;
  10246.                 ckmakmsg(fnval,FNVALL,
  10247.                          "<ERROR:ARG_INCOMPLETE:\\f",fn,"()>",NULL);
  10248.                 goto fnend;
  10249.             }
  10250.             b64tob8(NULL,0,NULL,0);     /* Reset */
  10251.             x = b64tob8(bp[0],-1,fnval,FNVALL);
  10252.             b64tob8(NULL,0,NULL,0);     /* Reset again */
  10253.         }
  10254.         if (x < 0) {
  10255.             failed = 1;
  10256.             if (fndiags) {
  10257.                 char * m = "INTERNAL_ERROR";
  10258.                 switch (x) {
  10259.                   case -1: m = "ARG_TOO_LONG"; break;
  10260.                   case -2: m = "ARG_OUT_OF_RANGE"; break;
  10261.                 }
  10262.                 if (ckmakmsg(fnval,FNVALL,"<ERROR:",m,"\\f",fn) > 0)
  10263.                   ckstrncat(fnval,"()>",FNVALL);
  10264.             }
  10265.         }
  10266.         goto fnend;
  10267.  
  10268.       case FN_ABS: {
  10269.           char * s;
  10270.           s = bp[0];
  10271.           if (*s == '-' || *s == '+')
  10272.             s++;
  10273.           if (!rdigits(s)) {
  10274.               if (fndiags)
  10275.                 ckmakmsg(fnval,FNVALL,
  10276.                          "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  10277.               goto fnend;
  10278.           }
  10279.           ckstrncpy(fnval,s,FNVALL);
  10280.           goto fnend;
  10281.       }
  10282.  
  10283.       case FN_AADUMP: {
  10284.           char abuf[16], *s = NULL, **ap = NULL, **vp = NULL;
  10285.           char pattern[VNAML];
  10286.           int slen, i, j, k, first = -1;
  10287.           extern int xdelmac();
  10288.           p = fnval;
  10289.           if (argn < 2) {
  10290.               if (fndiags)
  10291.                 ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG2:\\f",fn,"()>",NULL);
  10292.               goto fnend;
  10293.           }
  10294.           debug(F101,"aaconvert argn","",argn);
  10295.           s = bp[0];
  10296.           slen = strlen(s);
  10297.  
  10298.           /* Count elements so we can create the array */
  10299.  
  10300.           ckmakmsg(pattern,VNAML,s,"<*>",NULL,NULL);
  10301.           for (k = 0, i = 0; i < nmac; i++) {
  10302.               if (ckmatch(pattern,mactab[i].kwd,0,1)) {
  10303.                   if (first < 0)        /* Remember location of first match */
  10304.                     first = i;
  10305.                   k++;
  10306.               }
  10307.           }
  10308.           debug(F101,"aaconvert matches","",k);
  10309.           debug(F101,"aaconvert first","",first);
  10310.           fnval[0] = NUL;               /* Initial return value */
  10311.           ckstrncpy(abuf,bp[1],16);     /* Get array reference */
  10312.           s = abuf;
  10313.           if (*s == CMDQ) s++;
  10314.           p = fnval;                    /* Point to result */
  10315.           if (fndiags)                  /* Default is this error message */
  10316.             ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
  10317.           if (s[0] != '&')              /* Address of array */
  10318.             goto fnend;
  10319.           if (s[2])
  10320.             if (s[2] != '[' || s[3] != ']')
  10321.               goto fnend;
  10322.           if (s[1] >= 64 && s[1] < 91)  /* Convert upper to lower */
  10323.             s[1] += 32;
  10324.           if ((x = dclarray(s[1],k)) < 0) /* Declare array to size */
  10325.             goto fnend;
  10326.           ap = a_ptr[x];                /* Point to array we just declared */
  10327.           /* debug(F111,"aaconvert array 1",abuf,ap); */
  10328.           abuf[0] = NUL;
  10329.           if (argn > 2) {
  10330.               ckstrncpy(abuf,bp[2],16); /* Get value array reference */
  10331.               s = abuf;
  10332.               if (*s == CMDQ) s++;
  10333.               if (s[0] != '&')          /* Address of array */
  10334.                 goto fnend;
  10335.               if (s[2])
  10336.                 if (s[2] != '[' || s[3] != ']')
  10337.                   goto fnend;
  10338.               if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */
  10339.                 s[1] += 32;
  10340.               if ((x = dclarray(s[1],k)) < 0)
  10341.                 goto fnend;
  10342.               vp = a_ptr[x];            /* Point to array we just declared */
  10343.           }
  10344.           /* debug(F111,"aaconvert array 2",abuf,vp); */
  10345.           makestr(&ap[0],ckitoa(k));
  10346.           if (vp) makestr(&vp[0],ckitoa(k));
  10347.           if (fndiags)
  10348.            ckmakmsg(fnval,FNVALL,"<ERROR:ASSOCIATIVE_ARRAY:\\f",fn,"()>",NULL);
  10349.  
  10350.           /* Copy macro index & value to the arrays and then remove the */
  10351.           /* macro, so the 'first' pointer keeps indicating the next one. */
  10352.           /* We could combine the initial counting loop with this one but */
  10353.           /* then it would be harder to create the array and anyway this */
  10354.           /* function is plenty fast as it is. */
  10355.  
  10356.           for (i = 1; i <= k; ) {
  10357.               if (!ckmatch(pattern,mactab[first].kwd,0,1)) {
  10358.                   debug(F111,"aaconvert oddball",mactab[first].kwd,first);
  10359.                   first++;
  10360.                   continue;
  10361.               }
  10362.               ckstrncpy(tmpbuf,mactab[first].kwd,TMPBUFSIZ); /* Macro name */
  10363.               s = tmpbuf;                       /* Make writeable copy */
  10364.               s += slen;                        /* Isolate "index" */
  10365.               j = strlen(s) - 1;
  10366.               if (*s != '<' || *(s+j) != '>') { /* Check syntax */
  10367.                   /* This shouldn't happen */
  10368.                   debug(F111,"aaconvert ERROR",mactab[first].kwd,first);
  10369.                   goto fnend;
  10370.               }
  10371.               *(s+j) = NUL;             /* Remove final '>' */
  10372.               debug(F111,"aaconvert",s+1,i);
  10373.               makestr(&(ap[i]),s+1);    /* Set first array to index */
  10374.               if (vp)
  10375.                 makestr(&(vp[i]),mactab[first].mval); /* 2nd to value */
  10376.               if (xdelmac(first) < 0)
  10377.                 goto fnend;
  10378.               i++;
  10379.           }
  10380.           sprintf(fnval,"%d",k);        /* SAFE */
  10381.           p = fnval;                    /* Return size of array */
  10382.           debug(F110,"aaconvert return",p,0);
  10383.           failed = 0;                   /* Unset failure flag */
  10384.           goto fnend;
  10385.       }
  10386.  
  10387.     } /* End of switch() */
  10388.  
  10389. #ifdef FNFLOAT
  10390. /*
  10391.   Floating-point functions.  To be included only if FNFLOAT is defined, which
  10392.   should happen only if CKFLOAT is also defined, and if the math library is
  10393.   linked in.  Even then, we might have float-vs-double confusion as well as
  10394.   confusion about what the final "%f" format effector is supposed to reference
  10395.   (32 bits, 64 bits, etc).  Expect trouble if CKFLOAT does not match the data
  10396.   type of math library functions or args.
  10397. */
  10398.     if (cx == FN_FPABS ||               /* Floating-point functions */
  10399.         cx == FN_FPADD ||
  10400.         cx == FN_FPDIV ||
  10401.         cx == FN_FPEXP ||
  10402.         cx == FN_FPLOG ||
  10403.         cx == FN_FPLN  ||
  10404.         cx == FN_FPMOD ||
  10405.         cx == FN_FPMAX ||
  10406.         cx == FN_FPMIN ||
  10407.         cx == FN_FPMUL ||
  10408.         cx == FN_FPPOW ||
  10409.         cx == FN_FPSQR ||
  10410.         cx == FN_FPINT ||
  10411.         cx == FN_FPSUB ||
  10412.         cx == FN_FPROU ||
  10413.         cx == FN_FPSIN ||
  10414.         cx == FN_FPCOS ||
  10415.         cx == FN_FPTAN) {
  10416.         CKFLOAT farg[2], fpresult = 0.0;
  10417.         char fpbuf[64], * bp0;
  10418.         double dummy;
  10419.         /* int sign = 0; */
  10420.         int i, j, places = 0;
  10421.         int argcount = 1;
  10422.  
  10423.         failed = 1;
  10424.         p = fnval;
  10425.         bp0 = bp[0];
  10426.         if (!bp0)
  10427.           bp0 = "0";
  10428.         else if (!*bp0)
  10429.           bp0 = "0";
  10430.         if (!isfloat(bp0,0)) {
  10431.             k = mxlook(mactab,bp0,nmac);
  10432.             bp0 = (k > -1) ? mactab[k].mval : NULL;
  10433.             if (bp0) {
  10434.                 if (!isfloat(bp0,0)) {
  10435.                     if (fndiags)
  10436.                       ckmakmsg(fnval,FNVALL,
  10437.                                "<ERROR:ARG_NOT_FLOAT:\\f",fn,"()>",NULL);
  10438.                     goto fnend;
  10439.                 }
  10440.             }
  10441.         }
  10442.         if (cx == FN_FPINT) {           /* Float to int */
  10443.             failed = 0;
  10444.             ckstrncpy(fnval,bp0,FNVALL);
  10445.             for (i = 0; fnval[i]; i++) {
  10446.                 if (fnval[i] == '.') {
  10447.                     fnval[i] = NUL;
  10448.                     break;
  10449.                 }
  10450.             }
  10451.             goto fnend;
  10452.         }
  10453.         switch (y) {                    /* These need 2 args */
  10454.           case FN_FPADD:
  10455.           case FN_FPDIV:
  10456.           case FN_FPMOD:
  10457.           case FN_FPMAX:
  10458.           case FN_FPMIN:
  10459.           case FN_FPMUL:
  10460.           case FN_FPPOW:
  10461.           case FN_FPSUB:
  10462.             argcount = 2;
  10463.         }
  10464.         /* Missing arguments are supplied as 0.0 */
  10465.  
  10466.         debug(F111,fn,"argcount",argcount);
  10467.         for (i = 0; i < argcount; i++) { /* Get floating-point args */
  10468. #ifdef DEBUG
  10469.             if (deblog) {
  10470.                 ckmakmsg(fpbuf,
  10471.                          64,
  10472.                          "bp[",
  10473.                          ckitoa(i),
  10474.                          bp[i] ? bp[i] : "(null)",
  10475.                          "]"
  10476.                          );
  10477.                 debug(F100,fpbuf,"",0);
  10478.             }
  10479. #endif /* DEBUG */
  10480.             if (!bp[i]) {
  10481.                 farg[i] = 0.0;
  10482.             } else if (!*(bp[i])) {
  10483.                 farg[i] = 0.0;
  10484.             } else if (!isfloat(bp[i],0)) {
  10485.                 char * tmp;
  10486.                 k = mxlook(mactab,bp[i],nmac);
  10487.                 tmp = (k > -1) ? mactab[k].mval : NULL;
  10488.                 if (tmp) {
  10489.                     if (!isfloat(tmp,0)) {
  10490.                         if (fndiags)
  10491.                           ckmakmsg(fnval,FNVALL,
  10492.                                    "<ERROR:ARG_NOT_FLOAT:\\f",fn,"()>",NULL);
  10493.                         goto fnend;
  10494.                     }
  10495.                 }
  10496.             }
  10497.             farg[i] = floatval;
  10498.  
  10499. #ifdef DEBUG
  10500.             if (deblog) {
  10501.                 sprintf(fpbuf,"farg[%d]=%f",i,farg[i]); /* SAFE */
  10502.                 debug(F100,fpbuf,"",0);
  10503.             }
  10504. #endif /* DEBUG */
  10505.         }
  10506.         if (bp[argcount]) {             /* Get decimal places */
  10507.             char * s;
  10508.             s = bp[argcount];
  10509.             if (!s) s = "";
  10510.             if (!*s) s = "0";
  10511.             s = evalx(s);
  10512.             if (!s) s = "";
  10513.             if (!*s) {
  10514.                 evalerr(fn);
  10515.                 goto fnend;
  10516.             }
  10517.             places = atoi(s);
  10518.         }
  10519.         errno = 0;
  10520.         failed = 0;
  10521.         switch (y) {                    /* Now do the requested function */
  10522.           case FN_FPABS:                /* Floating-point absolute value */
  10523. #ifndef COMMENT
  10524.             fpresult = fabs(farg[0]);
  10525. #else
  10526.             if (farg[0] < 0.0)
  10527.               fpresult = 0.0 - farg[0];
  10528. #endif /* COMMENT */
  10529.             break;
  10530.           case FN_FPADD:                /* FP add */
  10531.             fpresult = farg[0] + farg[1];
  10532.             break;
  10533.           case FN_FPDIV:                /* FP divide */
  10534.           case FN_FPMOD:                /* FP modulus */
  10535.             if (!farg[1]) {
  10536.                 failed = 1;
  10537.                 if (fndiags)
  10538.                   ckmakmsg(fnval,FNVALL,
  10539.                            "<ERROR:DIVIDE_BY_ZERO:\\f",fn,"()>",NULL);
  10540.             } else
  10541.               fpresult = (cx == FN_FPDIV) ?
  10542.                 (farg[0] / farg[1]) :
  10543.                   fmod(farg[0],farg[1]);
  10544.             break;
  10545.           case FN_FPEXP:                /* FP e to the x */
  10546.             fpresult = (CKFLOAT) exp(farg[0]);
  10547.             break;
  10548.           case FN_FPLOG:                /* FP base-10 logarithm */
  10549.           case FN_FPLN:                 /* FP natural logarithm */
  10550.             if (farg[0] < 0.0) {
  10551.                 failed = 1;
  10552.                 if (fndiags)
  10553.                   ckmakmsg(fnval,FNVALL,
  10554.                            "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
  10555.             } else
  10556.               fpresult = (cx == FN_FPLOG) ? log10(farg[0]) : log(farg[0]);
  10557.             break;
  10558.           case FN_FPMUL:                /* FP multiply */
  10559.             fpresult = farg[0] * farg[1];
  10560.             break;
  10561.           case FN_FPPOW:                /* FP raise to a power */
  10562.             fpresult = modf(farg[1],&dummy);
  10563.             if ((!farg[0] && farg[1] <= 0.0) ||
  10564.                 (farg[0] < 0.0 && fpresult)) {
  10565.                 failed = 1;
  10566.                 if (fndiags)
  10567.                   ckmakmsg(fnval,FNVALL,
  10568.                            "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
  10569.             } else
  10570.               fpresult = pow(farg[0],farg[1]);
  10571.             break;
  10572.           case FN_FPSQR:                /* FP square root */
  10573.             if (farg[0] < 0.0) {
  10574.                 failed = 1;
  10575.                 if (fndiags)
  10576.                   ckmakmsg(fnval,FNVALL,
  10577.                            "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
  10578.             } else
  10579.               fpresult = sqrt(farg[0]);
  10580.             break;
  10581.           case FN_FPSUB:                /* FP subtract */
  10582.             fpresult = farg[0] - farg[1];
  10583.             break;
  10584.           case FN_FPROU:                /* FP round */
  10585.             fpresult = farg[0];
  10586.             break;
  10587.           case FN_FPSIN:                /* FP sine */
  10588.             fpresult = (CKFLOAT) sin(farg[0]);
  10589.             break;
  10590.           case FN_FPCOS:                /* FP cosine */
  10591.             fpresult = (CKFLOAT) cos(farg[0]);
  10592.             break;
  10593.           case FN_FPTAN:                /* FP tangent */
  10594.             fpresult = (CKFLOAT) tan(farg[0]);
  10595.             break;
  10596.           case FN_FPMAX:
  10597.             fpresult = (farg[0] > farg[1]) ? farg[0] : farg[1];
  10598.             break;
  10599.           case FN_FPMIN:
  10600.             fpresult = (farg[0] < farg[1]) ? farg[0] : farg[1];
  10601.             break;
  10602.         }
  10603.  
  10604.         /* Get here with fpresult = function result */
  10605.  
  10606.         if (errno) {                    /* If range or domain error */
  10607.             failed = 1;
  10608.             if (fndiags)
  10609.               ckmakmsg(fnval,FNVALL,
  10610.                        "<ERROR:FLOATING-POINT-OP:\\f",fn,"()>",NULL);
  10611.         }
  10612.         if (failed)                     /* and/or any other kind of error, */
  10613.           goto fnend;                   /* fail. */
  10614. #ifndef COMMENT
  10615.         /* Call routine containing code that was formerly inline */
  10616.         ckstrncpy(fnval,fpformat(fpresult,places,cx == FN_FPROU),FNVALL);
  10617. #else
  10618.         {
  10619.             char fbuf[16];              /* For creating printf format */
  10620.             if (!fp_rounding &&         /* If printf doesn't round, */
  10621.                 (places > 0 ||          /* round result to decimal places. */
  10622.                  (places == 0 && cx == FN_FPROU)))
  10623.               fpresult += (0.5 / pow(10.0,(CKFLOAT)places));
  10624.             if (places > 0) {                   /* If places specified */
  10625.                 /* use specified places to write given number of digits */
  10626.                 sprintf(fbuf,"%%0.%df",places); /* SAFE */
  10627.                 sprintf(fnval,fbuf,fpresult);   /* SAFE */
  10628.             } else {                            /* Otherwise... */
  10629. #ifdef COMMENT
  10630. /*
  10631.   Here we want to print exactly fp_digits significant digits, no matter which
  10632.   side of the decimal point they are on.  That is, we want want the default
  10633.   format to show the maximum number of non-garbage digits, AND we want the last
  10634.   such digit to be rounded.  Of course there is no way to do that, since the
  10635.   digit after the last non-garbage digit is, well, garbage.  So the following
  10636.   clever ruse does no good.
  10637. */
  10638.                 int sign = 0, m = 0;
  10639.                 sprintf(fnval,"%f",fpresult);
  10640.                 if (fnval[0] == '-') sign = 1;
  10641.                 for (i = sign; i < FNVALL; i++) {
  10642.                     if (isdigit(fnval[i]))
  10643.                       m++;
  10644.                     else
  10645.                       break;
  10646.                 }
  10647.                 if (m > 1) {
  10648.                     int d = fp_digits - m;
  10649.                     if (d < 1) d = 1;
  10650.                     sprintf(fbuf,"%%%d.%df",fp_digits+sign+1,d);
  10651.                 } else {
  10652.                     sprintf(fbuf,"%%0.%df",fp_digits);
  10653.                 }
  10654.                 sprintf(fnval,fbuf,fpresult);
  10655. #else
  10656.                 /* Go for max precision */
  10657.                 sprintf(fbuf,"%%0.%df",fp_digits); /* SAFE */
  10658.                 sprintf(fnval,fbuf,fpresult); /* SAFE */
  10659.  
  10660. #endif /* COMMENT */
  10661.             }
  10662.             if (fnval[0] == '-') sign = 1;
  10663.         }
  10664.         debug(F111,"fpresult 1",fnval,errno); /* Check for over/underflow */
  10665.         for (i = sign; fnval[i]; i++) { /* Give requested decimal places */
  10666.             if (fnval[i] == '.')        /* First find the decimal point */
  10667.               break;
  10668.             else if (i > fp_digits + sign - 1) /* replacing garbage */
  10669.               fnval[i] = '0';           /* digits with 0... */
  10670.         }
  10671.         if (fnval[i] == '.') {          /* Have decimal point */
  10672.             int gotend = 0;
  10673.             /* d < 0 so truncate fraction */
  10674.             if (places < 0 || (places == 0 && cx == FN_FPROU)) {
  10675.                 fnval[i] = NUL;
  10676.             } else if (places > 0) {    /* d > 0 so this many decimal places */
  10677.                 i++;                           /* First digit after decimal */
  10678.                 for (j = 0; j < places; j++) { /* Truncate after d decimal */
  10679.                     if (!fnval[j+i])           /* places or extend to d  */
  10680.                       gotend = 1;              /* decimal places. */
  10681.                     if (gotend || j+i+sign > fp_digits)
  10682.                       fnval[j+i] = '0';
  10683.                 }
  10684.                 fnval[j+i] = NUL;
  10685.             } else {                    /* d == 0 so Do The Right Thing */
  10686.                 for (j = (int)strlen(fnval) - 1; j > i+1; j--) {
  10687.                     if ((j - sign) > fp_digits)
  10688.                       fnval[j] = '0';
  10689.                     if (fnval[j] == '0')
  10690.                       fnval[j] = NUL;   /* Strip useless trailing 0's. */
  10691.                     else
  10692.                       break;
  10693.                 }
  10694.             }
  10695.         }
  10696. #endif /* COMMENT */
  10697.         debug(F111,"fpresult 2",fnval,errno);
  10698.         goto fnend;
  10699.  
  10700.     }
  10701. #endif /* FNFLOAT */
  10702.  
  10703. #ifdef CKCHANNELIO
  10704.     if (cx == FN_FSTAT  ||              /* File functions */
  10705.         cx == FN_FPOS   ||
  10706.         cx == FN_FEOF   ||
  10707.         cx == FN_FGCHAR ||
  10708.         cx == FN_FGLINE ||
  10709.         cx == FN_FGBLK  ||
  10710.         cx == FN_FPCHAR ||
  10711.         cx == FN_FPLINE ||
  10712.         cx == FN_FPBLK  ||
  10713.         cx == FN_NLINE  ||
  10714.         cx == FN_FERMSG ||
  10715.         cx == FN_FILNO) {
  10716.         int x = 0, t = 0, channel;
  10717.         long z;
  10718.         extern int z_maxchan;
  10719.  
  10720.         failed = 1;                     /* Assume failure */
  10721.         p = fnval;                      /* until we validate args */
  10722.         if (cx == FN_FERMSG) {
  10723.             extern int z_error;
  10724.             if (argn < 1) {
  10725.                 x = z_error;
  10726.             } else if (chknum(bp[0])) {
  10727.                 x = atoi(bp[0]);
  10728.             } else if (fndiags)
  10729.               ckmakmsg(fnval,FNVALL,
  10730.                        "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  10731.             failed = 0;
  10732.             ckstrncpy(fnval,ckferror(x),FNVALL);
  10733.             goto fnend;
  10734.         }
  10735.         if (argn < 1) {                 /* All file functions need channel */
  10736.             if (fndiags)
  10737.               ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
  10738.             goto fnend;
  10739.         }
  10740.         if (rdigits(bp[0])) {           /* Channel must be numeric */
  10741.             channel = atoi(bp[0]);
  10742.         } else {                        /* Fail if it isn't */
  10743.             if (fndiags)
  10744.               ckmakmsg(fnval,FNVALL,
  10745.                        "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  10746.             goto fnend;
  10747.         }
  10748.         if (channel < 0 || channel > z_maxchan) { /* Check channel range */
  10749.             if (fndiags)
  10750.               ckmakmsg(fnval,FNVALL,
  10751.                        "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
  10752.             goto fnend;
  10753.         }
  10754.         x = z_getmode(channel);         /* Find out about the channel */
  10755.  
  10756.         failed = 0;                     /* Assume success from here down */
  10757.         if (cx == FN_FSTAT) {           /* Status / modes of channel */
  10758.             if (x > -1)
  10759.               x &= FM_RWB;              /* Mask out irrelevant bits */
  10760.             else                        /* In this case not open is OK */
  10761.               x = 0;                    /* 0 if not open, 1-7 if open */
  10762.             sprintf(fnval,"%d",x);      /* SAFE */
  10763.             goto fnend;
  10764.         } else if (x < 1) {             /* Not \f_status() so must be open */
  10765.             failed = 1;
  10766.             if (fndiags)
  10767.               ckmakmsg(fnval,FNVALL,"<ERROR:FILE_NOT_OPEN:\\f",fn,"()>",NULL);
  10768.             goto fnend;
  10769.         }
  10770.         switch (y) {                    /* Do the requested function */
  10771.           case FN_FPOS:                 /* Get position */
  10772.             z = z_getpos(channel);    /* FIX THIS */
  10773.             sprintf(fnval,"%ld",z);     /* SAFE */
  10774.             goto fnend;
  10775.  
  10776.           case FN_NLINE:                /* Get line number */
  10777.             z = z_getline(channel);    /* FIX THIS */
  10778.             sprintf(fnval,"%ld",z);     /* SAFE */
  10779.             goto fnend;
  10780.  
  10781.           case FN_FEOF:                 /* Check EOF */
  10782.             t = 0;
  10783.             if (x & FM_EOF) t = 1;
  10784.             sprintf(fnval,"%d",t);      /* SAFE */
  10785.             goto fnend;
  10786.  
  10787.           case FN_FILNO:                /* Get file handle */
  10788.             x = z_getfnum(channel);
  10789.             sprintf(fnval,"%d",x);      /* SAFE */
  10790.             goto fnend;
  10791.  
  10792.           case FN_FPBLK:                /* Read or write block */
  10793.           case FN_FGBLK:
  10794.             if (argn < 2) {
  10795.                 if (fndiags)
  10796.                   ckmakmsg(fnval,FNVALL,
  10797.                            "<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
  10798.                 goto fnend;
  10799.             }
  10800.             if (rdigits(bp[1])) {
  10801.                 t = atoi(bp[1]);
  10802.             } else {
  10803.                 if (fndiags)
  10804.                   ckmakmsg(fnval,FNVALL,
  10805.                            "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  10806.                 goto fnend;
  10807.             }
  10808.           case FN_FGCHAR:               /* Read or write character or line */
  10809.           case FN_FPCHAR:
  10810.           case FN_FGLINE:
  10811.           case FN_FPLINE:
  10812.             fnval[0] = NUL;
  10813.             switch (y) {
  10814.               case FN_FGCHAR: t = z_in(channel,fnval,FNVALL,1,1); break;
  10815.               case FN_FGLINE: t = z_in(channel,fnval,FNVALL,FNVALL-1,0); break;
  10816.               case FN_FGBLK:
  10817.                 if (t >= FNVALL) t = FNVALL - 1;
  10818.                 t = z_in(channel,fnval,FNVALL,t,1);
  10819.                 break;
  10820.               case FN_FPCHAR: t = z_out(channel,bp[1],1,1);  break;
  10821.               case FN_FPLINE: t = z_out(channel,bp[1],-1,0); break;
  10822.               case FN_FPBLK:  t = z_out(channel,bp[1],-1,1); break;
  10823.             }
  10824.             if (t < 0) {                /* Handle read/write error */
  10825.                 failed = 1;
  10826.                 if (fndiags && t != FX_EOF)
  10827.                   ckmakmsg(fnval,FNVALL,
  10828.                            "<ERROR:FILE_ERROR_%d:\\f",fn,"()>",NULL);
  10829.                 goto fnend;
  10830.             }
  10831.             if (cx == FN_FGCHAR)        /* Null terminate char */
  10832.               fnval[1] = NUL;
  10833.             /* Write (put) functions return numeric status code */
  10834.             if (cx == FN_FPCHAR || cx == FN_FPLINE || cx == FN_FPBLK)
  10835.               sprintf(fnval,"%d",t);    /* SAFE */
  10836.             goto fnend;
  10837.         }
  10838.     }
  10839. #endif /* CKCHANNELIO */
  10840.  
  10841.     if (cx == FN_PATTERN) {             /* \fpattern() for INPUT */
  10842.         ispattern = 1;
  10843.         if (argn > 0) {
  10844.             p = fnval;
  10845.             ckstrncpy(fnval,bp[0],FNVALL);
  10846.         } else p = "";
  10847.         goto fnend;
  10848.     }
  10849.     if (cx == FN_HEX2N || cx == FN_OCT2N) { /* \fhex2n(), \foct2n() */
  10850.         p = "0";
  10851.         if (argn < 1)
  10852.           goto fnend;
  10853.         p = ckradix(bp[0], ((cx == FN_HEX2N) ? 16 : 8), 10);
  10854.         if (!p) {
  10855.             if (fndiags)
  10856.               ckmakmsg(fnval,FNVALL,
  10857.                        "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
  10858.             goto fnend;
  10859.         }
  10860.         failed = 0;
  10861.         ckstrncpy(fnval,p,FNVALL);
  10862.         p = fnval;
  10863.         goto fnend;
  10864.     }
  10865.  
  10866.     if (cx == FN_HEX2IP) {
  10867.         int c[2], ip[4], i, k;
  10868.         p = "0";
  10869.         if (argn < 1)
  10870.           goto fnend;
  10871.         s = bp[0];
  10872.         if ((int)strlen(s) != 8) {
  10873.             failed = 1;
  10874.             if (fndiags)
  10875.               ckmakmsg(fnval,FNVALL,
  10876.                        "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
  10877.             goto fnend;
  10878.         }
  10879.         p = fnval;
  10880.         for (k = 0; k < 8; k += 2) {
  10881.             for (i = 0; i < 2; i++) {
  10882.                 c[i] = *s++;
  10883.                 if (islower(c[i])) c[i] = toupper(c[i]);
  10884.                 if (c[i] >= '0' && c[i] <= '9') {
  10885.                     c[i] -= 0x30;
  10886.                 } else if (c[i] >= 'A' && c[i] <= 'F') {
  10887.                     c[i] -= 0x37;
  10888.                 } else {
  10889.                     failed = 1;
  10890.                     if (fndiags)
  10891.                       ckmakmsg(fnval,FNVALL,
  10892.                                "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
  10893.                     goto fnend;
  10894.                 }
  10895.                 ip[k/2] = c[0] << 4 | c[1];
  10896.             }
  10897.             sprintf(p,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]); /* SAFE */
  10898.         }
  10899.         goto fnend;
  10900.     }
  10901.     if (cx == FN_IP2HEX) {
  10902.         int ip[4], i;
  10903.         char * q;
  10904.         p = "00000000";
  10905.         if (argn < 1)
  10906.           goto fnend;
  10907.         s = bp[0];
  10908.         p = fnval;
  10909.         for (i = 0; i < 3; i++) {
  10910.             q = ckstrchr(s,'.');
  10911.             if (q) {
  10912.                 *q++ = NUL;
  10913.                 ip[i] = atoi(s);
  10914.                 s = q;
  10915.             } else {
  10916.                 failed = 1;
  10917.                 if (fndiags)
  10918.                   ckmakmsg(fnval,FNVALL,
  10919.                            "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
  10920.                 goto fnend;
  10921.             }
  10922.         }
  10923.         ip[3] = atoi(s);
  10924.         sprintf(p,"%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]); /* SAFE */
  10925.         goto fnend;
  10926.     }
  10927.     if (cx == FN_RADIX) {
  10928.         failed = 1;
  10929.         p = fnval;
  10930.         if (argn < 3) {
  10931.             if (fndiags)
  10932.               ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
  10933.             goto fnend;
  10934.         }
  10935.         if (!rdigits(bp[1]) || !rdigits(bp[2])) {
  10936.             if (fndiags)
  10937.               ckmakmsg(fnval,FNVALL,
  10938.                        "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  10939.             goto fnend;
  10940.         }
  10941.         p = ckradix(bp[0],atoi(bp[1]),atoi(bp[2]));
  10942.         if (!p) {
  10943.             if (fndiags)
  10944.               ckmakmsg(fnval,FNVALL,
  10945.                        "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
  10946.             goto fnend;
  10947.         }
  10948.         failed = 0;
  10949.         ckstrncpy(fnval,p,FNVALL);
  10950.         p = fnval;
  10951.         goto fnend;
  10952.     }
  10953.     if (cx == FN_JOIN) {
  10954.         int i, x, y, z, flag, hi, lo, max, seplen, grouping = 0;
  10955.         char abuf[16], c, *s, *q, *sep = NULL;
  10956.         char * gr_opn = "\"{'([<";      /* Group open brackets */
  10957.         char * gr_cls = "\"}')]>";      /* Group close brackets */
  10958.         char lb[2], rb[2];              /* Selected left and right brackets */
  10959.  
  10960.         failed = 1;                     /* Assume failure */
  10961.         fnval[0] = NUL;
  10962.         debug(F101,"FNJOIN ARGN","",argn);
  10963.  
  10964.         ckstrncpy(abuf,bp[0],16);       /* Get array reference */
  10965.         s = abuf;
  10966.         if ((x = arraybounds(s,&lo,&hi)) < 0) {  /* Get index and bounds */
  10967.             if (fndiags)
  10968.               ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
  10969.             goto fnend;
  10970.         }
  10971.         p = fnval;                      /* Point to result */
  10972.         max = a_dim[x];                 /* Size of array */
  10973.         if (lo < 0) lo = 1;             /* Use given range if any */
  10974.         if (lo > max) lo = max;
  10975. #ifdef COMMENT
  10976.     hi = max;
  10977. #else
  10978. /*
  10979.   This is a workaround for the problem in which the dimension of the \&_[]
  10980.   array (but not its contents) grows upon entry to a SWITCH block.  But this
  10981.   code prevents the dimension from growing.  Go figure.
  10982. */
  10983.         if (hi < 0) {            /* Bounds not given */
  10984.             if (x)            /* Regular array */
  10985.           hi = max;
  10986.         else            /* Argument vector array */
  10987.           for (hi = max; hi >= lo; hi--) { /* ignore any trailing */
  10988.           if (!a_ptr[x][hi]) continue; /* empty elements */
  10989.           if (!*(a_ptr[x][hi])) continue;
  10990.           break;
  10991.           }
  10992.     }
  10993. #endif /* COMMENT */
  10994.         if (hi > max) hi = max;
  10995.         failed = 0;                     /* Unset failure flag */
  10996.         if (max < 1)
  10997.           goto fnend;
  10998.         sep = " ";                      /* Separator */
  10999.         if (argn > 1)
  11000.           if (bp[1])
  11001.             if (*bp[1])
  11002.               sep = bp[1];
  11003.         lb[0] = NUL;
  11004.         rb[0] = NUL;
  11005.         lb[1] = NUL;
  11006.         rb[1] = NUL;
  11007.         if (argn > 2) {                 /* Grouping? */
  11008.             char * bp2 = bp[2];
  11009.             if (!bp2) bp2 = "0";
  11010.             if (!*bp2) bp2 = "0";
  11011.             if (chknum(bp2)) {
  11012.                 grouping = atoi(bp2);
  11013.                 if (grouping < 0 || grouping > 63)
  11014.                   grouping = 1;
  11015.             } else {
  11016.                 failed = 1;
  11017.                 if (fndiags)
  11018.                   ckmakmsg(fnval,FNVALL,
  11019.                            "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  11020.                 goto fnend;
  11021.             }
  11022.             if (grouping) {             /* Take lowest-order one */
  11023.                 int j, k;               /* and set the others to 0 */
  11024.                 for (k = 0; k < 6; k++) {
  11025.                     j = 1 << k;
  11026.                     if (grouping & j) {
  11027.                         lb[0] = gr_opn[k];
  11028.                         rb[0] = gr_cls[k];
  11029.                         break;
  11030.                     }
  11031.                 }
  11032.             }
  11033.         }
  11034.         if (argn > 3)                   /* Nonzero 4th arg for no separator */
  11035.           if (chknum(bp[3]))
  11036.             if (atoi(bp[3]) > 0)
  11037.               sep = NULL;
  11038.         if (!sep) {
  11039.             sep = "";
  11040.             seplen = 0;
  11041.         } else
  11042.           seplen = strlen(sep);
  11043.         for (i = lo; i <= hi; i++) {    /* Loop thru selected array elements */
  11044.             s = a_ptr[x][i];            /* Get next element */
  11045.             if (!s)
  11046.               s = "";
  11047.             flag = 0;                   /* Buffer overrun flag */
  11048.             if (grouping) {             /* Does this element need quoting? */
  11049.                 q = s;                  /* Look for spaces */
  11050.                 while ((c = *q++)) { if (c == SP) { flag++; break; } }
  11051.             }
  11052.             y = strlen(s);              /* Get length of this element */
  11053.             if (cx == 0 && grouping)    /* If empty it might need quoting */
  11054.               flag = 1;
  11055.             if (flag) {                 /* Add grouping if needed */
  11056.                 char * s2 = NULL;
  11057.                 y += 2;
  11058.                 if ((q = (char *)malloc(y+1))) {
  11059.                     ckmakmsg(q,y+1,(char *)lb,s,(char *)rb,NULL);
  11060.                     makestr(&s2,q);
  11061.                     free(q);
  11062.                     s = s2;
  11063.                 }
  11064.             }
  11065.             z = 0;                      /* Number of chars copied */
  11066.             flag = 0;                   /* flag is now buffer-overrun flag */
  11067.             if (y > 0)                  /* If this string is not empty */
  11068.               z = ckstrncat(fnval,s,FNVALL); /* copy it. */
  11069.             if (z < y)                  /* Check for buffer overrun. */
  11070.               flag++;
  11071.             if (!flag && *sep && i < hi) { /* If buffer still has room */
  11072.                 z = ckstrncat(fnval,sep,FNVALL); /* copy delimiter */
  11073.                 if (z < seplen)
  11074.                   flag++;
  11075.             }
  11076.             if (flag) {
  11077.                 failed = 1;
  11078.                 if (fndiags)
  11079.                   ckmakmsg(fnval,FNVALL,
  11080.                            "<ERROR:RESULT_TOO_LONG:\\f",fn,"()>",NULL);
  11081.                 goto fnend;
  11082.             }
  11083.         }
  11084.     isjoin = 1;
  11085.         goto fnend;
  11086.     }
  11087.     if (cx == FN_SUBST) {               /* \fsubstitute() */
  11088.         CHAR c, * s, * r, * tp[2], buf1[256], buf2[256], buf3[256];
  11089.         int len, i, j, state = 0, lo = 0, hi = 0;
  11090.  
  11091.         failed = 0;
  11092.         p = fnval;                      /* Result pointer */
  11093.         *p = NUL;
  11094.         if (!bp[0])                     /* No target, no result*/
  11095.           goto fnend;
  11096.  
  11097.         len = strlen(bp[0]);            /* Length of source */
  11098.         if (len == 0)
  11099.           goto fnend;
  11100.         if (len > FNVALL) {
  11101.             failed = 1;
  11102.             if (fndiags)
  11103.               ckmakmsg(fnval,FNVALL,
  11104.                        "<ERROR:RESULT_TOO_LONG:\\f",fn,"()>",NULL);
  11105.             goto fnend;
  11106.         }
  11107.         if (!bp[1]) {
  11108.             ckstrncpy(bp[0],fnval,FNVALL);
  11109.             goto fnend;
  11110.         }
  11111.         tp[0] = buf1;                   /* For s2-s3 interpretation loop */
  11112.         tp[1] = buf2;
  11113.  
  11114.         for (i = 0; i < 256; i++) {     /* Initialize working buffers */
  11115.             buf1[i] = 0;                /* s2 expansion buffer */
  11116.             buf2[i] = 0;                /* s3 expansion buffer */
  11117.             buf3[i] = i;                /* Translation table */
  11118.         }
  11119.         for (i = 0; i < 2; i++) {       /* Interpret s2 and s3 */
  11120.             s = (CHAR *)bp[i+1];        /* Arg pointer */
  11121.             if (!s) s = (CHAR *)"";
  11122.             r = tp[i];                  /* To construct interpreted arg */
  11123.             j = 0;                      /* Output buf pointer */
  11124.             state = 0;                  /* Initial state */
  11125.             while (c = *s++) {          /* Loop thru arg chars */
  11126.                 if (j > 255)            /* Output buf full */
  11127.                   break;
  11128.                 switch (state) {
  11129.                   case 0:               /* Normal state */
  11130.                     switch (c) {
  11131.                       case '\\':        /* Have quote */
  11132.                         state = 1;
  11133.                         break;
  11134.                       case '[':         /* Have range starter */
  11135.                         state = 2;
  11136.                         break;
  11137.                       default:          /* Anything else */
  11138.                         r[j++] = c;
  11139.                         break;
  11140.                     }
  11141.                     continue;
  11142.                   case 1:               /* Quoted char */
  11143.                     r[j++] = c;
  11144.                     state = 0;
  11145.                     continue;
  11146.                   case 2:               /* Range bottom */
  11147.                     lo = c;
  11148.                     state++;
  11149.                     continue;
  11150.                   case 3:               /* Range separater */
  11151.                     if (c != '-') {
  11152.                         failed = 1;
  11153.                         if (fndiags)
  11154.                           ckmakmsg(fnval,FNVALL,
  11155.                                    "<ERROR:BAD_RANGE:\\f",fn,"()>",NULL);
  11156.                         goto fnend;
  11157.                     }
  11158.                     state++;
  11159.                     continue;
  11160.                   case 4:               /* Range top */
  11161.                     hi = c;
  11162.                     state++;
  11163.                     continue;
  11164.                   case 5:               /* Range end */
  11165.                     if (c != ']') {
  11166.                         failed = 1;
  11167.                         if (fndiags)
  11168.                           ckmakmsg(fnval,FNVALL,
  11169.                                    "<ERROR:BAD_RANGE:\\f",fn,"()>",NULL);
  11170.                         goto fnend;
  11171.                     }
  11172.                     for (k = lo; k <= hi && j < 255; k++) /* Fill in */
  11173.                       r[j++] = k;
  11174.                     lo = 0; hi = 0;     /* Reset */
  11175.                     state = 0;
  11176.                     continue;
  11177.                 }
  11178.             }
  11179.         }
  11180.         for (i = 0; i < 256 && buf1[i]; i++) {  /* Create translation table */
  11181.             k = (unsigned)buf1[i];
  11182.             buf3[k] = buf2[i];
  11183.         }
  11184.         s = (CHAR *)bp[0];              /* Point to source string */
  11185.         for (i = 0; i < len; i++) {     /* Translation loop */
  11186.             k = (unsigned)s[i];         /* Get next char */
  11187.             if (!buf3[k])               /* Remove this char */
  11188.               continue;
  11189.             *p++ = buf3[k];             /* Substitute this char */
  11190.         }
  11191.         *p = NUL;
  11192.         p = fnval;
  11193.         goto fnend;
  11194.     }
  11195.  
  11196. #ifndef NOSEXP
  11197.     if (cx == FN_SEXP) {                /* \fsexpression(arg1) */
  11198.         char * p2;
  11199.         fsexpflag++;
  11200.         p = (argn > 0) ? dosexp(bp[0]) : "";
  11201.         fsexpflag--;
  11202.         p2 = fnval;
  11203.         while ((*p2++ = *p++)) ;
  11204.         p = fnval;
  11205.         goto fnend;
  11206.     }
  11207. #endif /* NOSEXP */
  11208.  
  11209.     if (cx == FN_CMDSTK) {              /* \fcmdstack(n1,n2) */
  11210.         int i, j, k;
  11211.         char * s;
  11212.  
  11213.         if (bp[0])
  11214.           val1 = *(bp[0]) ? evalx(bp[0]) : ckitoa(cmdlvl);
  11215.         else
  11216.           val1 = ckitoa(cmdlvl);
  11217. #ifdef COMMENT
  11218.         free(bp[0]);                    /* (evalx() always uses same buffer) */
  11219.         bp[0] = NULL;                   /* (not any more!) */
  11220. #endif /* COMMENT */
  11221.         failed = 1;
  11222.         if (argn > 1) {
  11223. #ifdef COMMENT
  11224.             makestr(&(bp[0]),val1);
  11225.             val1 = bp[0];
  11226. #endif /* COMMENT */
  11227.             val2 = *(bp[1]) ? evalx(bp[1]) : "0";
  11228.             if (!(chknum(val1) && chknum(val2))) {
  11229.                 if (fndiags)
  11230.                   ckmakmsg(fnval,FNVALL,
  11231.                            "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  11232.                 goto fnend;
  11233.             }
  11234.         } else {
  11235.             val1 = ckitoa(cmdlvl);
  11236.             val2 = "0";
  11237.         }
  11238.         i = atoi(val1);                 /* Level */
  11239.         j = atoi(val2);                 /* Flags */
  11240.         if (i < 0 || i > cmdlvl) {
  11241.             if (fndiags)
  11242.               ckmakmsg(fnval,FNVALL,
  11243.                        "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
  11244.             goto fnend;
  11245.         }
  11246.         failed = 0;
  11247.         p = fnval;
  11248.         k = cmdstk[i].src;              /* What (prompt, file, macro) */
  11249.         if (j) {
  11250.             ckstrncpy(fnval,ckitoa(k),FNVALL);
  11251.             goto fnend;
  11252.         }
  11253.         switch (k) {
  11254.           case CMD_KB:
  11255.             ckstrncpy(fnval,"(prompt)",FNVALL);
  11256.             break;
  11257.           case CMD_TF:
  11258.             s = tfnam[cmdstk[i].lvl];
  11259.             if (!zfnqfp(s,FNVALL,fnval))
  11260.               ckstrncpy(fnval,s,FNVALL);
  11261.             break;
  11262.           case CMD_MD:
  11263.             ckstrncpy(fnval,m_arg[cmdstk[i].lvl][0],FNVALL);
  11264.             break;
  11265.         }
  11266.         goto fnend;
  11267.     }
  11268. #ifdef CKFLOAT
  11269.     if (cx == FN_DIFDATE) {             /* \fdiffdates(d1,d2) */
  11270.         char * d1, * d2;
  11271.         d1 = bp[0] ? bp[0] : ckdate();
  11272.         d2 = bp[1] ? bp[1] : ckdate();
  11273.         p = (char *)cmdiffdate(d1,d2);
  11274.         if (!p) {
  11275.             failed = 1;
  11276.             if (fndiags) {
  11277.                 ckmakmsg(fnval,FNVALL,"<ERROR:BAD_DATE:\\f",fn,"()>",NULL);
  11278.                 p = fnval;
  11279.             }
  11280.         }
  11281.         goto fnend;
  11282.     }
  11283. #endif /* CKFLOAT */
  11284.     if (cx == FN_CMPDATE) {             /* \fcmddates(d1,d2) */
  11285.         int x = 0;
  11286.         char d1[18], d2[18], * dp;
  11287.         failed = 0;
  11288.         d1[0] = NUL;
  11289.         d2[0] = NUL;
  11290.         p = fnval;
  11291.         dp = cmcvtdate(bp[0],1);
  11292.         if (dp) {
  11293.             ckstrncpy(d1,dp,18);
  11294.             if ((dp = cmcvtdate(bp[1],1))) {
  11295.                 ckstrncpy(d2,dp,18);
  11296.                 x = 1;
  11297.             }
  11298.         }
  11299.         if (x == 0) {
  11300.             failed = 1;
  11301.             if (fndiags)
  11302.               ckmakmsg(fnval,FNVALL,"<ERROR:BAD_DATE:\\f",fn,"()>",NULL);
  11303.         } else {
  11304.             x = strcmp(d1,d2);
  11305.             if (x > 0)
  11306.               x = 1;
  11307.             else if (x < 0)
  11308.               x = -1;
  11309.             sprintf(fnval,"%d",x);
  11310.         }
  11311.         goto fnend;
  11312.     }
  11313.     if (cx == FN_TOGMT) {               /* \futcdate(d1) */
  11314.         char * d1, * dp;
  11315.         char datebuf[32];
  11316.         char d2[32];
  11317.         p = fnval;
  11318.         failed = 1;
  11319.         if ((dp = cmcvtdate(bp[0],1))) { /* The given date */
  11320.             ckstrncpy(datebuf,dp,18);
  11321.             ckstrncpy(d2,dp,18);        /* local time */
  11322.             ckstrncat(datebuf,"Z",19);  /* Same time GMT */
  11323.             if ((dp = cmcvtdate(datebuf,1))) /* converted to local time */
  11324.               ckstrncpy(datebuf,dp,18);
  11325.             if ((p = (char *)cmdiffdate(d2,datebuf))) { /* Get offset */
  11326.                 ckstrncat(d2,p,32);     /* Append offset to local time */
  11327.                 if ((dp = cmcvtdate(d2,1))) {
  11328.                     failed = 0;
  11329.                     ckstrncpy(fnval,dp,FNVALL);
  11330.                     p = fnval;
  11331.                 }
  11332.             }
  11333.         }
  11334.         if (failed && fndiags)
  11335.           ckmakmsg(fnval,FNVALL,"<ERROR:BAD_DATE:\\f",fn,"()>",NULL);
  11336.         goto fnend;
  11337.     }
  11338.     if (cx == FN_DELSEC) {              /* \fdelta2secs(delta-time) */
  11339.         long secs;
  11340.         p = fnval;
  11341.         if ((x = delta2sec(bp[0],&secs)) < 0) {
  11342.             failed = 1;
  11343.             if (fndiags)
  11344.               ckmakmsg(fnval,FNVALL,
  11345.                        (x == -1) ?
  11346.                          "<ERROR:BAD_DELTA_TIME:\\f" :
  11347.                          "<ERROR:OVERFLOW:\\f",
  11348.                        fn,
  11349.                        "()>",
  11350.                        NULL
  11351.                        );
  11352.             goto fnend;
  11353.         }
  11354.         sprintf(p,"%ld",secs);
  11355.         goto fnend;
  11356.     }
  11357.     if (cx == FN_PC_DU) {
  11358.         char c, * s = bp[0];
  11359.         if (!s) s = "";
  11360.         p = fnval;
  11361.         while ((c = *s++)) {
  11362.             if (c == ':') {
  11363.                 if (*s != '\\')
  11364.                   *p++ = '/';
  11365.             } else if (c == '\\') {
  11366.                 *p++ = '/';
  11367.             } else {
  11368.                 *p++ = c;
  11369.             }
  11370.         }
  11371.         *p = NUL;
  11372.         p = fnval;
  11373.         goto fnend;
  11374.     }
  11375.     if (cx == FN_PC_UD) {               /* Unix to DOS path */
  11376.         char c, * s = bp[0];
  11377.         if (!s) s = "";
  11378.         if (*s == '~') {                /* Skip leading tilde */
  11379.             s++;
  11380.             if (*s == '/')
  11381.               s++;
  11382.         }
  11383.         p = fnval;
  11384.         while ((c = *s++))
  11385.           *p ++ = (c == '/') ? '\\' : c;
  11386.         *p = NUL;
  11387.         p = fnval;
  11388.         goto fnend;
  11389.     }
  11390.     if (cx == FN_KWVAL) {               /* Keyword=Value */
  11391.         p = dokwval(bp[0],bp[1]?*(bp[1]):'=');
  11392.         goto fnend;
  11393.     }
  11394. #ifdef COMMENT
  11395. /* Cute idea but doesn't work */
  11396.     if (cx == FN_SLEEP || cx == FN_MSLEEP) {
  11397.         p = "";
  11398.         if (chknum(bp[0])) {
  11399.             x = atoi(bp[0]);
  11400.         } else {
  11401.             failed = 1;
  11402.             if (fndiags) {
  11403.                 ckmakmsg(fnval,FNVALL,
  11404.                          "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
  11405.                 p = fnval;
  11406.             }
  11407.             goto fnend;
  11408.         }
  11409.         if (cx == FN_SLEEP)
  11410.           x *= 1000;
  11411.         msleep(x);
  11412.         goto fnend;
  11413.     }
  11414. #endif /* COMMENT */
  11415.  
  11416. #ifdef NT
  11417.     if (cx == FN_SNAME) {
  11418.         GetShortPathName(bp[0],fnval,FNVALL);
  11419.         goto fnend;
  11420.     }
  11421.     if (cx == FN_LNAME) {
  11422.         ckGetLongPathName(bp[0],fnval,FNVALL);
  11423.         goto fnend;
  11424.     }
  11425. #endif /* NT */
  11426.  
  11427. /*
  11428.   \femailaddress():
  11429.   Picks the email address out of an RFC 2822 From: or Sender: header.
  11430.   Added 26 Nov 2005.  Handles all common, and some uncommon, cases but
  11431.   doesn't totally bother about nested comments.  Needed this for fetching
  11432.   email from a POP server and then constructing the BSD "From " line.
  11433.   Works with or without the "From: " or "Sender: " tag.
  11434. */
  11435.     if (cx == FN_EMAIL) {
  11436.         char c, * s = bp[0], * s2, * ap = "";
  11437.     int k, state = 0, quote = 0, infield = 0;
  11438.     int pc = 0;            /* For nested comments */
  11439.         if (!s) s = "";
  11440.     if (!*s) goto xemail;
  11441.     while (*s == SP || *s == HT) s++;
  11442.     if (ckindex("From: ",s,0,0,0) == 1) s += 6;
  11443.     if (ckindex("Sender: ",s,0,0,0) == 1) s += 8;
  11444.     while (*s == SP || *s == HT) s++;    
  11445.  
  11446.     k = strlen(s);            /* Strip junk from end */
  11447.     if (k < 1) goto xemail;
  11448.     k--;
  11449.     while (k >= 0 && s[k] == CR || s[k] == LF)
  11450.       s[k--] = NUL;
  11451.     while (k >= 0 && s[k] == SP || s[k] == HT)
  11452.       s[k--] = NUL;
  11453.     if (k == 0)
  11454.       goto xemail;
  11455.     k = 0;
  11456.     for (s2 = s; *s2; s2++) {    /* Strip leading whitespace */
  11457.         if (*s2 == SP || *s2 == HT) {
  11458.         k = 1;
  11459.         break;
  11460.         }
  11461.     }
  11462.     if (!k) {            /* Simple address */
  11463.         ap = s;
  11464.         goto xemail;
  11465.     }
  11466.     do {                /* Not simple, have to extract it */
  11467.         if (quote) {
  11468.         quote = 0;
  11469.         continue;
  11470.         } else if (*s == '\\') {
  11471.         quote = 1;
  11472.         continue;
  11473.         }
  11474.         switch (state) {
  11475.           case 0:
  11476.         if (!infield && *s == '"') { /* Quoted string */
  11477.             infield = 1;
  11478.             c = '"';
  11479.             state = 1;
  11480.         } else if (!infield && *s == '(') { /* Comment in parens */
  11481.             pc++;
  11482.             infield = 1;
  11483.             c = ')';
  11484.             if (*ap) *s = NUL;
  11485.             state = 1;
  11486.         } else if (!infield && *s == '<') { /* Address */
  11487.             infield = 1;
  11488.             c = '>';
  11489.             ap = s+1;
  11490.             state = 2;
  11491.         } else if (infield && (*s == SP || *s == HT)) {
  11492.             infield = 0;
  11493.         } else {        /* One or more bare words */
  11494.             infield = 1;    /* Could be an address */
  11495.             if (!*ap) ap = s;    /* Could be comments */
  11496.         }
  11497.         continue;
  11498.           case 1:            /* In Quoted string or Comment */
  11499.         if (infield && *s == c) { /* Look for end */
  11500.             infield = 0;
  11501.             *s++ = NUL;
  11502.             while (*s == SP || *s == HT) s++;
  11503.             if (!*ap)
  11504.               ap = s;
  11505.             state = 0;
  11506.         }
  11507.         continue;
  11508.           case 2:            /* In address */
  11509.         if (infield && *s == c) { /* Looking for end */
  11510.             infield = 0;
  11511.             *s = NUL;
  11512.             break;
  11513.         }
  11514.         }
  11515.     } while (*s++);
  11516.  
  11517.       xemail:
  11518.     if (*ap) {
  11519.         while (*ap == SP || *ap == HT) ap++;
  11520.     }
  11521.     k = strlen(ap) - 1;
  11522.     while (k >= 0 && (ap[k] == SP || ap[k] == HT))
  11523.       ap[k--] = NUL;
  11524.     if (*ap) {
  11525.         failed = 0;
  11526.         if (*ap == '<') {
  11527.         k = strlen(ap);
  11528.         if (*(ap+k-1) == '>') {
  11529.             ap[k-1] = NUL;
  11530.             ap++;
  11531.         }
  11532.         }
  11533.     } else
  11534.       failed = 1;
  11535.     /* Here we might also want check against "*@*.*" */
  11536.     ckstrncpy(fnval,ap,FNVALL);
  11537.     goto fnend;
  11538.     }
  11539.  
  11540. /* Note: when adding new functions remember to update dohfunc in ckuus2.c. */
  11541.  
  11542.     failed = 1;
  11543.     if (fndiags)
  11544.       ckmakmsg(fnval,FNVALL,"<ERROR:UNKNOWN_FUNCTION:\\f",fn,"()>",NULL);
  11545.  
  11546.   fnend:
  11547.     /* Free temporary storage for aguments */
  11548.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  11549.     fndepth--;
  11550.     if (failed) {                       /* Handle failure */
  11551.         debug(F111,"fnend",fnval,errno);
  11552.         if (!p) p = "";
  11553.         if (p[0]) {
  11554.             /* In case this wasn't caught above... */
  11555.             k = strlen(p);
  11556.             if (p[0] != '<' && p[k-1] != '>') {
  11557.                 ckmakmsg(fnval,FNVALL,"<ERROR:BAD_ARG:\\f",fn,"()>",NULL);
  11558.                 p = fnval;
  11559.             }
  11560.         } else {
  11561.             ckmakmsg(fnval,FNVALL,"<ERROR:UNKNOWN:\\f",fn,"()>",NULL);
  11562.             p = fnval;
  11563.         }
  11564.         if (fnerror)                    /* SET FUNCTION ERROR ON */
  11565.           fnsuccess = 0;                /* Make command fail (see ckuus5.c) */
  11566.         debug(F111,"fneval failed",p,fnsuccess);
  11567.         if (fndiags)                    /* SET FUNCTION DIAGNOSTICS ON */
  11568.           printf("?%s\n",p);            /* Print error message now. */
  11569.         else
  11570.           return("");                   /* Return nothing. */
  11571.     }
  11572.     return(p);
  11573. }
  11574. #endif /* NOSPL */
  11575.  
  11576. static char ckpidbuf[32] = "????";
  11577.  
  11578. #ifdef VMS
  11579. _PROTOTYP(long zgpid,(void));
  11580. #endif /* VMS */
  11581.  
  11582. char *
  11583. ckgetpid() {                            /* Return pid as string */
  11584. #ifdef CK_PID
  11585. #ifdef OS2
  11586. #define getpid _getpid
  11587.     unsigned long zz;
  11588. #else
  11589.     long zz;
  11590. #endif /* OS2 */
  11591. #ifdef VMS
  11592.     zz = zgpid();
  11593. #else
  11594.     zz = getpid();
  11595. #endif /* VMS */
  11596.     sprintf(ckpidbuf,"%ld",zz);         /* SAFE */
  11597. #endif /* CK_PID */
  11598.     return((char *)ckpidbuf);
  11599. }
  11600.  
  11601. #ifndef NOSPL
  11602. #define EMBUFLEN 128                    /* Error message buffer length */
  11603.  
  11604. static char embuf[EMBUFLEN+1];
  11605.  
  11606. char *                                  /* Evaluate builtin variable */
  11607. nvlook(s) char *s; {
  11608.     int x, y, cx;
  11609.     long z;
  11610.     char *p;
  11611. #ifndef NODIAL
  11612.     MDMINF * m;
  11613. #endif /* NODIAL */
  11614. #ifndef NOKVERBS                        /* Keyboard macro material */
  11615.     extern int keymac, keymacx;
  11616. #endif /* NOKVERBS */
  11617. #ifdef CK_LOGIN
  11618.     extern int isguest;
  11619. #endif /* CK_LOGIN */
  11620.     if (!s) s = "";
  11621.     x = strlen(s);
  11622.     if (fndiags) {                      /* FUNCTION DIAGNOSTIC ON */
  11623.         if (x + 32 < EMBUFLEN)
  11624.           sprintf(embuf,"<ERROR:NO_SUCH_VARIABLE:\\v(%s)>",s); /* SAFE */
  11625.         else
  11626.           sprintf(embuf,"<ERROR:NO_SUCH_VARIABLE>"); /* SAFE */
  11627.     } else                              /* FUNCTION DIAGNOSTIC OFF */
  11628.       embuf[0] = NUL;
  11629.     x = VVBUFL;
  11630.     p = vvbuf;
  11631.     if (zzstring(s,&p,&x) < 0) {        /* e.g. for \v(\%a) */
  11632.         y = -1;
  11633.     } else {
  11634.         s = vvbuf;
  11635.         y = lookup(vartab,s,nvars,&x);
  11636.     }
  11637.     cx = y;                             /* y is too generic */
  11638. #ifndef NODIAL
  11639.     m = (mdmtyp > 0) ? modemp[mdmtyp] : NULL; /* For \v(m_xxx) variables */
  11640. #endif /* NODIAL */
  11641.  
  11642.     debug(F101,"nvlook y","",y);
  11643.  
  11644.     switch (y) {
  11645.       case VN_ARGC:                     /* ARGC */
  11646.         sprintf(vvbuf,"%d",maclvl < 0 ? topargc : macargc[maclvl]); /* SAFE */
  11647.         return(vvbuf);
  11648.  
  11649.       case VN_ARGS:                     /* ARGS */
  11650.         sprintf(vvbuf,"%d",xargs);      /* SAFE */
  11651.         return(vvbuf);
  11652.  
  11653.       case VN_COUN:                     /* COUNT */
  11654.         sprintf(vvbuf,"%d",count[cmdlvl]); /* SAFE */
  11655.         return(vvbuf);
  11656.  
  11657.       case VN_DATE:                     /* DATE */
  11658.         ztime(&p);                      /* Get "asctime" string */
  11659.         if (p == NULL || *p == NUL) return(NULL);
  11660.         vvbuf[0] = p[8];                /* dd */
  11661.         vvbuf[1] = p[9];
  11662.         vvbuf[2] = SP;
  11663.         vvbuf[3] = p[4];                /* mmm */
  11664.         vvbuf[4] = p[5];
  11665.         vvbuf[5] = p[6];
  11666.         vvbuf[6] = SP;
  11667.         for (x = 20; x < 24; x++)       /* yyyy */
  11668.           vvbuf[x - 13] = p[x];
  11669.         vvbuf[11] = NUL;
  11670.         return(vvbuf);
  11671.  
  11672.       case VN_NDAT:                     /* Numeric date */
  11673.         ckstrncpy(vvbuf,zzndate(),VVBUFL);
  11674.         return(vvbuf);
  11675.  
  11676.       case VN_DIRE:                     /* DIRECTORY */
  11677.         s = zgtdir();                   /* Get current directory */
  11678.         if (!s)
  11679. #ifdef UNIXOROSK
  11680.           s = "./";
  11681. #else
  11682. #ifdef VMS
  11683.           s = "[]";
  11684. #else
  11685.           s = "";
  11686. #endif /* VMS */
  11687. #endif /* UNIXOROSK */
  11688.         ckstrncpy(vvbuf,s,VVBUFL);
  11689.         s = vvbuf;
  11690. #ifdef UNIXOROSK
  11691.         x = strlen(s);
  11692.         if (x < VVBUFL - 1) {
  11693.             if (s[x-1] != '/') {
  11694.                 s[x] = '/';
  11695.                 s[x+1] = NUL;
  11696.             }
  11697.         }
  11698. #endif /* UNIXOROSK */
  11699.         return(s);
  11700.  
  11701.       case VN_FILE:                     /* filespec */
  11702.         return(fspec);
  11703.  
  11704.       case VN_HOST:                     /* host name */
  11705.         if (*myhost) {                  /* If known */
  11706.             return(myhost);             /* return it. */
  11707.         } else {                        /* Otherwise */
  11708.             ckstrncpy(vvbuf,"unknown",VVBUFL); /* just say "unknown" */
  11709.             return(vvbuf);
  11710.         }
  11711.  
  11712.       case VN_SYST:                     /* System type */
  11713. #ifdef UNIX
  11714.         ckstrncpy(vvbuf,"UNIX",VVBUFL);
  11715. #else
  11716. #ifdef VMS
  11717.         ckstrncpy(vvbuf,"VMS",VVBUFL);
  11718. #else
  11719. #ifdef OSK
  11720.         ckstrncpy(vvbuf,"OS9/68K",VVBUFL);
  11721. #else
  11722. #ifdef AMIGA
  11723.         ckstrncpy(vvbuf,"Amiga",VVBUFL);
  11724. #else
  11725. #ifdef MAC
  11726.         ckstrncpy(vvbuf,"Macintosh",VVBUFL);
  11727. #else
  11728. #ifdef OS2
  11729. #ifdef NT
  11730.         ckstrncpy(vvbuf,"WIN32",VVBUFL) ;
  11731. #else /* NT */
  11732.         ckstrncpy(vvbuf,"OS/2",VVBUFL);
  11733. #endif /* NT */
  11734. #else
  11735. #ifdef datageneral
  11736.         ckstrncpy(vvbuf,"AOS/VS",VVBUFL);
  11737. #else
  11738. #ifdef GEMDOS
  11739.         ckstrncpy(vvbuf,"Atari_ST",VVBUFL);
  11740. #else
  11741. #ifdef STRATUS
  11742.         ckstrncpy(vvbuf,"Stratus_VOS",VVBUFL);
  11743. #else
  11744.         ckstrncpy(vvbuf,"unknown",VVBUFL);
  11745. #endif /* STRATUS */
  11746. #endif /* GEMDOS */
  11747. #endif /* datageneral */
  11748. #endif /* OS2 */
  11749. #endif /* MAC */
  11750. #endif /* AMIGA */
  11751. #endif /* OSK */
  11752. #endif /* VMS */
  11753. #endif /* UNIX */
  11754.         return(vvbuf);
  11755.  
  11756.       case VN_SYSV:                     /* System herald */
  11757. #ifdef IKSD
  11758. #ifdef CK_LOGIN
  11759.         if (inserver && isguest)
  11760.           return("");
  11761. #endif /* CK_LOGIN */
  11762. #endif /* IKSD */
  11763.         for (x = y = 0; x < VVBUFL; x++) {
  11764.             if (ckxsys[x] == SP && y == 0) continue;
  11765.             vvbuf[y++] = (char) ((ckxsys[x] == SP) ? '_' : ckxsys[x]);
  11766.         }
  11767.         vvbuf[y] = NUL;
  11768.         return(vvbuf);
  11769.     } /* Break up long switch statements... */
  11770.  
  11771.     switch(y) {
  11772.       case VN_TIME:                     /* TIME. Assumes that ztime returns */
  11773.         ztime(&p);                      /* "Thu Feb  8 12:00:00 1990" */
  11774.         if (p == NULL || *p == NUL)     /* like asctime()! */
  11775.           return("");
  11776.         for (x = 11; x < 19; x++)       /* copy hh:mm:ss */
  11777.           vvbuf[x - 11] = p[x];         /* to vvbuf */
  11778.         vvbuf[8] = NUL;                 /* terminate */
  11779.         return(vvbuf);                  /* and return it */
  11780.  
  11781.       case VN_NTIM:                     /* Numeric time */
  11782.         ztime(&p);                      /* "Thu Feb  8 12:00:00 1990" */
  11783.         if (p == NULL || *p == NUL)     /* like asctime()! */
  11784.           return(NULL);
  11785.         z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
  11786.         sprintf(vvbuf,"%ld",z);         /* SAFE */
  11787.         return(vvbuf);
  11788.  
  11789. #ifdef CK_TTYFD
  11790.       case VN_TTYF:                     /* TTY file descriptor */
  11791.         sprintf(vvbuf,"%d",             /* SAFE */
  11792. #ifdef VMS
  11793.                 vmsttyfd()
  11794. #else
  11795.                 ttyfd
  11796. #endif /* VMS */
  11797.                 );
  11798.         return(vvbuf);
  11799. #endif /* CK_TTYFD */
  11800.  
  11801.       case VN_VERS:                     /* Numeric Kermit version number */
  11802.         sprintf(vvbuf,"%ld",vernum);    /* SAFE */
  11803.         return(vvbuf);
  11804.  
  11805.       case VN_XVNUM:                    /* Product-specific version number */
  11806.         sprintf(vvbuf,"%ld",xvernum);   /* SAFE */
  11807.         return(vvbuf);
  11808.  
  11809.       case VN_HOME:                     /* Home directory */
  11810.         return(homepath());
  11811.  
  11812.       case VN_IBUF:                     /* INPUT buffer */
  11813.         return((char *)inpbuf);
  11814.  
  11815.       case VN_ICHR:                     /* INPUT character */
  11816.         inchar[1] = NUL;
  11817.         return((char *)inchar);
  11818.  
  11819.       case VN_ICNT:                     /* INPUT character count */
  11820.         sprintf(vvbuf,"%d",incount);    /* SAFE */
  11821.         return(vvbuf);
  11822.  
  11823.       case VN_SPEE: {                   /* Transmission SPEED */
  11824.           long t;
  11825.           t = ttgspd();
  11826.           if (t < 0L)
  11827.             sprintf(vvbuf,"unknown");   /* SAFE */
  11828.           else
  11829.             sprintf(vvbuf,"%ld",t);     /* SAFE */
  11830.           return(vvbuf);
  11831.       }
  11832.  
  11833.       case VN_SUCC:                     /* SUCCESS flag */
  11834.         /* Note inverted sense */
  11835.         sprintf(vvbuf,"%d",(success == 0) ? 1 : 0); /* SAFE */
  11836.         return(vvbuf);
  11837.  
  11838.       case VN_LINE: {                   /* LINE */
  11839. #ifdef DEBUG
  11840.           if (deblog) {
  11841.               debug(F111,"\\v(line) local",ttname,local);
  11842.               debug(F111,"\\v(line) inserver","",inserver);
  11843. #ifdef TNCODE
  11844.               debug(F111,"\\v(line) tcp_incoming","",tcp_incoming);
  11845. #endif /* TNCODE */
  11846. #ifdef CK_TAPI
  11847.               debug(F111,"\\v(line) tttapi","",tttapi);
  11848. #endif /* CK_TAPI */
  11849.           }
  11850. #endif /* DEBUG */
  11851.  
  11852. #ifdef CK_TAPI
  11853.           if (tttapi) {                 /* If I have made a TAPI connection */
  11854.               int i;                    /* return the TAPI device name */
  11855.               for (i = 0; i < ntapiline; i++) {
  11856.                   if (!strcmp(ttname,tapilinetab[i].kwd)) {
  11857.                       p = _tapilinetab[i].kwd;
  11858.                       return(p);
  11859.                   }
  11860.               }
  11861.           }
  11862. #endif /* CK_TAPI */
  11863. #ifndef NOXFER
  11864.           if (inserver                  /* If I am a TCP server */
  11865. #ifdef TNCODE
  11866.               || tcp_incoming
  11867. #endif /* TNCODE */
  11868.               )
  11869. #ifdef TCPSOCKET
  11870.             p = ckgetpeer();            /* return peer name */
  11871.           else
  11872. #endif /* TCPSOCKET */
  11873. #endif /* NOXFER */
  11874.           if (local)                    /* Otherwise if in local mode */
  11875.             p = (char *) ttname;        /* return SET LINE / SET HOST name */
  11876.           else                          /* Otherwise */
  11877.             p = "";                     /* return empty string */
  11878.           if (!p)                       /* In case ckgetpeer() returns */
  11879.             p = "";                     /* null pointer... */
  11880.           debug(F110,"\\v(line) p",p,0);
  11881.           if (!*p)
  11882.             p = (char *) ttname;
  11883.           return(p);
  11884.       }
  11885.       case VN_PROG:                     /* Program name */
  11886.         return("C-Kermit");
  11887.  
  11888.     } /* Break up long switch statements... */
  11889.  
  11890.     switch(y) {
  11891.       case VN_RET:                      /* Value of most recent RETURN */
  11892.         debug(F111,"\\v(return)",mrval[maclvl+1],maclvl+1);
  11893.         p = mrval[maclvl+1];
  11894.         if (p == NULL) p = "";
  11895.         return(p);
  11896.  
  11897.       case VN_FFC:                      /* Size of most recent file */
  11898.         sprintf(vvbuf, "%s", ckfstoa(ffc)); /* SAFE */
  11899.         return(vvbuf);
  11900.  
  11901.       case VN_TFC:                      /* Size of most recent file group */
  11902.         sprintf(vvbuf, "%s", ckfstoa(tfc)); /* SAFE */
  11903.         return(vvbuf);
  11904.  
  11905.       case VN_CPU:                      /* CPU type */
  11906. #ifdef IKSD
  11907. #ifdef CK_LOGIN
  11908.         if (inserver && isguest)
  11909.           return("");
  11910. #endif /* CK_LOGIN */
  11911. #endif /* IKSD */
  11912. #ifdef OS2
  11913.          {
  11914.             char * getcpu(void) ;
  11915.             return getcpu();
  11916.          }
  11917. #else /* OS2 */
  11918. #ifdef CKCPU
  11919.         return(CKCPU);                  /* Traditionally, compile-time value */
  11920. #else
  11921. #ifdef CK_UTSNAME
  11922.         {                               /* But if none, try runtime value */
  11923.             extern char unm_mch[];
  11924.             return((char *)unm_mch);
  11925.         }
  11926. #else
  11927.         return("unknown");
  11928. #endif /* CK_UTSNAME */
  11929. #endif /* CKCPU */
  11930. #endif /* OS2 */
  11931.  
  11932.       case VN_CMDL:                     /* Command level */
  11933.         sprintf(vvbuf, "%d", cmdlvl);   /* SAFE */
  11934.         return(vvbuf);
  11935.  
  11936.       case VN_DAY:                      /* Day of week */
  11937.         ztime(&p);
  11938.         if (p != NULL && *p != NUL)     /* ztime() succeeded. */
  11939.           ckstrncpy(vvbuf,p,4);
  11940.         else
  11941.           vvbuf[0] = NUL;               /* ztime() failed. */
  11942.         return(vvbuf);                  /* Return what we got. */
  11943.  
  11944.       case VN_NDAY: {                   /* Numeric day of week */
  11945.           long k;
  11946.           z = mjd(zzndate());           /* Get modified Julian date */
  11947.           k = (((int)(z % 7L)) + 3) % 7; /* Get day number */
  11948.           sprintf(vvbuf,"%ld",k);       /* SAFE */
  11949.           return(vvbuf);
  11950.       }
  11951.  
  11952.       case VN_LCL:                      /* Local (vs remote) mode */
  11953.         ckstrncpy(vvbuf, local ? "1" : "0",VVBUFL);
  11954.         return(vvbuf);
  11955.  
  11956.       case VN_CMDS:                     /* Command source */
  11957.         if (cmdstk[cmdlvl].src == CMD_KB)
  11958.           ckstrncpy(vvbuf,"prompt",VVBUFL);
  11959.         else if (cmdstk[cmdlvl].src == CMD_MD)
  11960.           ckstrncpy(vvbuf,"macro",VVBUFL);
  11961.         else if (cmdstk[cmdlvl].src == CMD_TF)
  11962.           ckstrncpy(vvbuf,"file",VVBUFL);
  11963.         else
  11964.           ckstrncpy(vvbuf,"unknown",VVBUFL);
  11965.         return(vvbuf);
  11966.  
  11967.       case VN_CMDF:                     /* Current command file name */
  11968. #ifdef COMMENT                          /* (see comments above) */
  11969.         if (tfnam[tlevel]) {            /* (near dblbs declaration) */
  11970.             dblbs(tfnam[tlevel],vvbuf,VVBUFL);
  11971.             return(vvbuf);
  11972.         } else return("");
  11973. #else
  11974.         if (tlevel < 0)
  11975.           return("");
  11976.         else
  11977.           return(tfnam[tlevel] ? tfnam[tlevel] : "");
  11978. #endif /* COMMENT */
  11979.  
  11980.       case VN_MAC:                      /* Current macro name */
  11981.         return((maclvl > -1) ? m_arg[maclvl][0] : "");
  11982.  
  11983.       case VN_EXIT:
  11984.         sprintf(vvbuf,"%d",xitsta);     /* SAFE */
  11985.         return(vvbuf);
  11986.  
  11987.     } /* Break up long switch statements... */
  11988.  
  11989.     switch(y) {
  11990.       case VN_PRTY: {                   /* Parity */
  11991.           char *ss;
  11992.           switch (parity) {
  11993.             case 0:   ss = "none";  break;
  11994.             case 'e': ss = "even";  break;
  11995.             case 'm': ss = "mark";  break;
  11996.             case 'o': ss = "odd";   break;
  11997.             case 's': ss = "space"; break;
  11998.             default:  ss = "unknown"; break;
  11999.           }
  12000.           ckstrncpy(vvbuf,ss,VVBUFL);
  12001.           return(vvbuf);
  12002.       }
  12003.  
  12004.       case VN_DIAL:
  12005.         sprintf(vvbuf,"%d",             /* SAFE */
  12006. #ifndef NODIAL
  12007.                 dialsta
  12008. #else
  12009.                 -1
  12010. #endif /* NODIAL */
  12011.                 );
  12012.         return(vvbuf);
  12013.  
  12014. #ifdef OS2
  12015.       case VN_KEYB:
  12016.         ckstrncpy(vvbuf,conkbg(),VVBUFL);
  12017.         return(vvbuf);
  12018.       case VN_SELCT: {
  12019. #ifndef NOLOCAL
  12020.           const char * selection = GetSelection();
  12021.           return( (char *) (selection ? selection : "" )) ;
  12022. #else
  12023.           return("");
  12024. #endif /* NOLOCAL */
  12025.       }
  12026. #endif /* OS2 */
  12027.  
  12028. #ifndef NOXFER
  12029.       case VN_CPS:
  12030.         sprintf(vvbuf,"%ld",tfcps);     /* SAFE */
  12031.         return(vvbuf);
  12032. #endif /* NOXFER */
  12033.  
  12034.       case VN_MODE:                     /* File transfer mode */
  12035.         switch (binary) {
  12036.           case XYFT_T: ckstrncpy(vvbuf,"text",VVBUFL); break;
  12037.           case XYFT_B:
  12038.           case XYFT_U: ckstrncpy(vvbuf,"binary",VVBUFL); break;
  12039.           case XYFT_I: ckstrncpy(vvbuf,"image",VVBUFL); break;
  12040.           case XYFT_L: ckstrncpy(vvbuf,"labeled",VVBUFL); break;
  12041.           case XYFT_M: ckstrncpy(vvbuf,"macbinary",VVBUFL); break;
  12042.           default:     ckstrncpy(vvbuf,"unknown",VVBUFL);
  12043.         }
  12044.         return(vvbuf);
  12045.  
  12046. #ifdef CK_REXX
  12047.       case VN_REXX:
  12048.         return(rexxbuf);
  12049. #endif /* CK_REXX */
  12050.  
  12051.       case VN_NEWL:                     /* System newline char or sequence */
  12052. #ifdef UNIX
  12053.         ckstrncpy(vvbuf,"\n",VVBUFL);
  12054. #else
  12055. #ifdef datageneral
  12056.         ckstrncpy(vvbuf,"\n",VVBUFL);
  12057. #else
  12058. #ifdef OSK
  12059.         ckstrncpy(vvbuf,"\15",VVBUFL);  /* Remember, these are octal... */
  12060. #else
  12061. #ifdef MAC
  12062.         ckstrncpy(vvbuf,"\15",VVBUFL);
  12063. #else
  12064. #ifdef OS2
  12065.         ckstrncpy(vvbuf,"\15\12",VVBUFL);
  12066. #else
  12067. #ifdef STRATUS
  12068.         ckstrncpy(vvbuf,"\n",VVBUFL);
  12069. #else
  12070. #ifdef VMS
  12071.         ckstrncpy(vvbuf,"\15\12",VVBUFL);
  12072. #else
  12073. #ifdef AMIGA
  12074.         ckstrncpy(vvbuf,"\n",VVBUFL);
  12075. #else
  12076. #ifdef GEMDOS
  12077.         ckstrncpy(vvbuf,"\n",VVBUFL);
  12078. #else
  12079.         ckstrncpy(vvbuf,"\n",VVBUFL);
  12080. #endif /* GEMDOS */
  12081. #endif /* AMIGA */
  12082. #endif /* VMS */
  12083. #endif /* STRATUS */
  12084. #endif /* OS2 */
  12085. #endif /* MAC */
  12086. #endif /* OSK */
  12087. #endif /* datageneral */
  12088. #endif /* UNIX */
  12089.         return(vvbuf);
  12090.  
  12091.       case VN_ROWS:                     /* ROWS */
  12092.       case VN_COLS:                     /* COLS */
  12093.         ckstrncpy(vvbuf,(cx == VN_ROWS) ? "24" : "80",VVBUFL); /* Default */
  12094. #ifdef CK_TTGWSIZ
  12095. #ifdef OS2
  12096.         if (tt_cols[VTERM] < 0 || tt_rows[VTERM] < 0)
  12097.           ttgwsiz();
  12098.         sprintf(vvbuf,"%d",             /* SAFE */
  12099.                 (cx == VN_ROWS) ? tt_rows[VTERM] : tt_cols[VTERM]);
  12100. #else /* OS2 */
  12101.         if (ttgwsiz() > 0)              /* Get window size */
  12102.           if (tt_cols > 0 && tt_rows > 0) /* sets tt_rows, tt_cols */
  12103.             sprintf(vvbuf,"%d",         /* SAFE */
  12104.                     (cx == VN_ROWS) ? tt_rows : tt_cols);
  12105. #endif /* OS2 */
  12106. #endif /* CK_TTGWSIZ */
  12107.         return(vvbuf);
  12108.  
  12109.       case VN_TTYP:
  12110. #ifdef NOTERM
  12111.         ckstrncpy(vvbuf,"unknown",VVBUFL);
  12112. #else
  12113. #ifdef OS2
  12114.         sprintf(vvbuf, "%s",            /* SAFE */
  12115.                 (tt_type >= 0 && tt_type <= max_tt) ?
  12116.                 tt_info[tt_type].x_name :
  12117.                 "unknown"
  12118.                 );
  12119. #else
  12120. #ifdef MAC
  12121.         ckstrncpy(vvbuf,"vt320",VVBUFL);
  12122. #else
  12123.         p = getenv("TERM");
  12124.         ckstrncpy(vvbuf,p ? p : "unknown",VVBUFL+1);
  12125. #endif /* MAC */
  12126. #endif /* OS2 */
  12127. #endif /* NOTERM */
  12128.         return(vvbuf);
  12129.  
  12130.       case VN_MINP:                     /* MINPUT */
  12131.         sprintf(vvbuf, "%d", m_found);  /* SAFE */
  12132.         return(vvbuf);
  12133.     } /* Break up long switch statements... */
  12134.  
  12135.     switch(y) {
  12136.       case VN_CONN:                     /* CONNECTION */
  12137.         if (!local) {
  12138.           ckstrncpy(vvbuf,"remote",VVBUFL);
  12139.         } else {
  12140.             if (!network)
  12141.               ckstrncpy(vvbuf,"serial",VVBUFL);
  12142. #ifdef TCPSOCKET
  12143.             else if (nettype == NET_TCPB || nettype == NET_TCPA) {
  12144.                 if (ttnproto == NP_TELNET)
  12145.                   ckstrncpy(vvbuf,"tcp/ip_telnet",VVBUFL);
  12146. #ifdef CK_SSL
  12147.                 else if (ttnproto == NP_SSL || ttnproto == NP_SSL_RAW)
  12148.                   ckstrncpy(vvbuf,"tcp/ip_ssl",VVBUFL);
  12149.                 else if (ttnproto == NP_TLS || ttnproto == NP_SSL_RAW)
  12150.                   ckstrncpy(vvbuf,"tcp/ip_tls",VVBUFL);
  12151. #endif /* CK_SSL */
  12152.                 else
  12153.                   ckstrncpy(vvbuf,"tcp/ip",VVBUFL);
  12154.             }
  12155. #endif /* TCPSOCKET */
  12156. #ifdef SSHBUILTIN
  12157.             else if (nettype == NET_SSH)
  12158.                   ckstrncpy(vvbuf,"tcp/ip_ssh",VVBUFL);
  12159. #endif /* SSHBUILTIN */
  12160. #ifdef ANYX25
  12161.             else if (nettype == NET_SX25 ||
  12162.                      nettype == NET_VX25 ||
  12163.                      nettype == NET_IX25
  12164.                      )
  12165.               ckstrncpy(vvbuf,"x.25",VVBUFL);
  12166. #endif /* ANYX25 */
  12167. #ifdef DECNET
  12168.             else if (nettype == NET_DEC) {
  12169.                 if (ttnproto == NP_LAT)
  12170.                   ckstrncpy(vvbuf,"decnet_lat",VVBUFL);
  12171.                 else if ( ttnproto == NP_CTERM )
  12172.                   ckstrncpy(vvbuf,"decnet_cterm",VVBUFL);
  12173.                 else
  12174.                   ckstrncpy(vvbuf,"decnet",VVBUFL);
  12175.             }
  12176. #endif /* DECNET */
  12177. #ifdef SUPERLAT
  12178.             else if (nettype == NET_SLAT)
  12179.               ckstrncpy(vvbuf,"superlat",VVBUFL);
  12180. #endif /* SUPERLAT */
  12181. #ifdef NETFILE
  12182.             else if (nettype == NET_FILE)
  12183.               ckstrncpy(vvbuf,"local_file",VVBUFL);
  12184. #endif /* NETFILE */
  12185. #ifdef NETCMD
  12186.             else if (nettype == NET_CMD)
  12187.               ckstrncpy(vvbuf,"pipe",VVBUFL);
  12188. #endif /* NETCMD */
  12189. #ifdef NETPTY
  12190.             else if (nettype == NET_PTY)
  12191.               ckstrncpy(vvbuf,"pseudoterminal",VVBUFL);
  12192. #endif /* NETPTY */
  12193. #ifdef NETDLL
  12194.             else if (nettype == NET_DLL)
  12195.               ckstrncpy(vvbuf,"dynamic_link_library",VVBUFL);
  12196. #endif /* NETDLL */
  12197.  
  12198. #ifdef NPIPE
  12199.             else if (nettype == NET_PIPE)
  12200.               ckstrncpy(vvbuf,"named_pipe",VVBUFL);
  12201. #endif /* NPIPE */
  12202. #ifdef CK_NETBIOS
  12203.             else if (nettype == NET_BIOS)
  12204.               ckstrncpy(vvbuf,"netbios",VVBUFL);
  12205. #endif /* CK_NETBIOS */
  12206.             else
  12207.               ckstrncpy(vvbuf,"unknown",VVBUFL);
  12208.         }
  12209.         return(vvbuf);
  12210.  
  12211. #ifndef NOXFER
  12212.       case VN_SYSI:                     /* System ID, Kermit code */
  12213.         return((char *)cksysid);
  12214. #endif /* NOXFER */
  12215.  
  12216. #ifdef OS2
  12217.       case VN_SPA: {
  12218.           unsigned long space = zdskspace(0);
  12219.           if (space > 0 && space < 1024)
  12220.             sprintf(vvbuf,"-1");
  12221.           else
  12222.             sprintf(vvbuf,"%lu",space); /* SAFE */
  12223.           return(vvbuf);
  12224.       }
  12225. #endif /* OS2 */
  12226.  
  12227. #ifndef NOXFER
  12228.       case VN_QUE: {
  12229.           extern char querybuf[];
  12230.           return(querybuf);
  12231.       }
  12232. #endif /* NOXFER */
  12233.  
  12234. #ifndef NOCSETS
  12235.       case VN_CSET:
  12236. #ifdef OS2
  12237.         sprintf(vvbuf,"cp%d",os2getcp()); /* SAFE */
  12238. #else
  12239.         ckstrncpy(vvbuf,fcsinfo[fcharset].keyword,VVBUFL+1);
  12240. #endif /* OS2 */
  12241.         return(vvbuf);
  12242. #endif /* NOCSETS */
  12243.  
  12244. #ifdef OS2
  12245.       case VN_EXEDIR:
  12246.         return(exedir);
  12247.       case VN_STAR:
  12248.         return(startupdir);
  12249. #else
  12250.       case VN_EXEDIR:
  12251.         return(exedir ? exedir : "");
  12252. #ifdef VMSORUNIX
  12253.       case VN_STAR:
  12254.         return(startupdir);
  12255. #endif /* VMSORUNIX */
  12256. #endif /* OS2 */
  12257.  
  12258.       case VN_INI:
  12259.         return(inidir);
  12260.  
  12261.       case VN_MDM:
  12262.         return(gmdmtyp());
  12263.  
  12264.       case VN_EVAL:
  12265.         return(evalbuf);
  12266.  
  12267. #ifndef NODIAL
  12268.       case VN_D_CC:                     /* DIAL COUNTRY-CODE */
  12269.         return(diallcc ? diallcc : "");
  12270.  
  12271.       case VN_D_AC:                     /* DIAL AREA-CODE */
  12272.         return(diallac ? diallac : "");
  12273.  
  12274.       case VN_D_IP:                     /* DIAL INTERNATIONAL-PREFIX */
  12275.         return(dialixp ? dialixp : "");
  12276.  
  12277.       case VN_D_LP:                     /* DIAL LD-PREFIX */
  12278.         return(dialldp ? dialldp : "");
  12279.  
  12280.       case VN_D_LCP:                    /* DIAL LOCAL-PREFIX */
  12281.         return(diallcp ? diallcp : "");
  12282.  
  12283.       case VN_D_PXX:                    /* DIAL PBX-EXCHANGE that matched */
  12284.         return(matchpxx ? matchpxx : "");
  12285. #else
  12286.       case VN_D_CC:                     /* DIAL COUNTRY-CODE */
  12287.       case VN_D_AC:                     /* DIAL AREA-CODE */
  12288.       case VN_D_IP:                     /* DIAL INTERNATIONAL-PREFIX */
  12289.       case VN_D_LP:                     /* DIAL LD-PREFIX */
  12290.       case VN_D_LCP:                    /* DIAL LOCAL-PREFIX */
  12291.       case VN_D_PXX:                    /* DIAL PBX-EXCHANGE */
  12292.         return("");
  12293. #endif /* NODIAL */
  12294.       case VN_UID:
  12295. #ifdef UNIX
  12296.         {
  12297.             extern char * whoami();     /* From ckufio.c... */
  12298. #ifdef IKSD
  12299.             if (inserver)
  12300.               return((char *)uidbuf);
  12301.             else
  12302. #endif /* IKSD */
  12303.               if (uidbuf[0])
  12304.                 return((char *)uidbuf);
  12305.               else
  12306.                 return(whoami());
  12307.         }
  12308. #else
  12309.         return((char *)uidbuf);
  12310. #endif /* UNIX */
  12311.     } /* Break up long switch statements... */
  12312.  
  12313.     switch(y) {
  12314.       case VN_PWD:
  12315. #ifdef OS2
  12316.         if (activecmd == XXOUT || activecmd == XXLNOUT) {
  12317.             ckstrncpy(vvbuf,pwbuf,VVBUFL);
  12318.             ck_encrypt((char *)vvbuf);
  12319.             return((char *)vvbuf);
  12320.         } else
  12321. #endif /* OS2 */
  12322.           return((char *)pwbuf);
  12323.  
  12324.       case VN_PRM:
  12325.         return((char *)prmbuf);
  12326.  
  12327.       case VN_PROTO:
  12328. #ifdef NOXFER
  12329.         return("none");
  12330. #else
  12331. #ifdef CK_XYZ
  12332.         return(ptab[protocol].p_name);
  12333. #else
  12334.         return("kermit");
  12335. #endif /* CK_XYZ */
  12336. #endif /* NOXFER */
  12337.  
  12338. #ifndef NOXFER
  12339. #ifdef CK_TMPDIR
  12340.       case VN_DLDIR:
  12341.         return(dldir ? dldir : "");
  12342. #endif /* CK_TMPDIR */
  12343. #endif /* NOXFER */
  12344.  
  12345. #ifndef NODIAL
  12346.       case VN_M_INI:                    /* Modem init string */
  12347.         return(dialini ? dialini : (m ? m->wake_str : ""));
  12348.  
  12349.       case VN_M_DCM:                    /* Modem dial command */
  12350.         return(dialcmd ? dialcmd : (m ? m->dial_str : ""));
  12351.  
  12352.       case VN_M_DCO:                    /* Modem data compression on */
  12353.         return(dialdcon ? dialdcon : (m ? m->dc_on_str : ""));
  12354.  
  12355.       case VN_M_DCX:                    /* Modem data compression off */
  12356.         return(dialdcoff ? dialdcoff : (m ? m->dc_off_str : ""));
  12357.  
  12358.       case VN_M_ECO:                    /* Modem error correction on */
  12359.         return(dialecon ? dialecon : (m ? m->ec_on_str : ""));
  12360.  
  12361.       case VN_M_ECX:                    /* Modem error correction off */
  12362.         return(dialecoff ? dialecoff : (m ? m->ec_off_str : ""));
  12363.  
  12364.       case VN_M_AAO:                    /* Modem autoanswer on */
  12365.         return(dialaaon ? dialaaon : (m ? m->aa_on_str : ""));
  12366.  
  12367.       case VN_M_AAX:                    /* Modem autoanswer off */
  12368.         return(dialaaoff ? dialaaoff : (m ? m->aa_off_str : ""));
  12369.  
  12370.       case VN_M_HUP:                    /* Modem hangup command */
  12371.         return(dialhcmd ? dialhcmd : (m ? m->hup_str : ""));
  12372.  
  12373.       case VN_M_HWF:                    /* Modem hardware flow command */
  12374.         return(dialhwfc ? dialhwfc : (m ? m->hwfc_str : ""));
  12375.  
  12376.       case VN_M_SWF:                    /* Modem software flow command */
  12377.         return(dialswfc ? dialswfc : (m ? m->swfc_str : ""));
  12378.  
  12379.       case VN_M_NFC:                    /* Modem no flow-control command */
  12380.         return(dialnofc ? dialnofc : (m ? m->nofc_str : ""));
  12381.  
  12382.       case VN_M_PDM:                    /* Modem pulse dialing mode */
  12383.         return(dialpulse ? dialpulse : (m ? m->pulse : ""));
  12384.  
  12385.       case VN_M_TDM:                    /* Modem tone dialing mode */
  12386.         return(dialtone ? dialtone : (m ? m->tone : ""));
  12387.  
  12388.       case VN_M_NAM:                    /* Modem full name */
  12389.         return(dialname ? dialname : (m ? m->name : ""));
  12390. #else
  12391.       case VN_M_INI:                    /* Modem init string */
  12392.       case VN_M_DCM:                    /* Modem dial command */
  12393.       case VN_M_DCO:                    /* Modem data compression on */
  12394.       case VN_M_DCX:                    /* Modem data compression off */
  12395.       case VN_M_ECO:                    /* Modem error correction on */
  12396.       case VN_M_ECX:                    /* Modem error correction off */
  12397.       case VN_M_AAO:                    /* Modem autoanswer on */
  12398.       case VN_M_AAX:                    /* Modem autoanswer off */
  12399.       case VN_M_HUP:                    /* Modem hangup command */
  12400.       case VN_M_HWF:                    /* Modem hardware flow command */
  12401.       case VN_M_SWF:                    /* Modem software flow command */
  12402.       case VN_M_NFC:                    /* Modem no flow-control command */
  12403.       case VN_M_PDM:                    /* Modem pulse dialing mode */
  12404.       case VN_M_TDM:                    /* Modem tone dialing mode */
  12405.       case VN_M_NAM:
  12406.         return("");
  12407. #endif /* NODIAL */
  12408.  
  12409.       case VN_ISTAT:                    /* INPUT status */
  12410.         sprintf(vvbuf, "%d", instatus); /* SAFE */
  12411.         return(vvbuf);
  12412.  
  12413.       case VN_TEMP:                     /* Temporary directory */
  12414.         if (tempdir) {
  12415.             p = tempdir;
  12416.         } else {
  12417. #ifdef OS2
  12418. #ifdef NT
  12419.             p = getenv("K95TMP");
  12420. #else
  12421.             p = getenv("K2TMP");
  12422. #endif /* NT */
  12423.             if ( !p )
  12424. #endif /* OS2 */
  12425.               p = getenv("CK_TMP");
  12426.             if (!p) p = getenv("TMPDIR");
  12427.             if (!p) p = getenv("TEMP");
  12428.             if (!p) p = getenv("TMP");
  12429.  
  12430. #ifdef OS2ORUNIX
  12431.             if (p) {
  12432.                 int len = strlen(p);
  12433.                 if (p[len-1] != '/'
  12434. #ifdef OS2
  12435.                     && p[len-1] != '\\'
  12436. #endif /* OS2 */
  12437.                      ) {
  12438.                     static char foo[CKMAXPATH];
  12439.                     ckstrncpy(foo,p,CKMAXPATH);
  12440.                     ckstrncat(foo,"/",CKMAXPATH);
  12441.                     p = foo;
  12442.                 }
  12443.             } else
  12444. #else /* OS2ORUNIX */
  12445.             if (!p)
  12446. #endif /* OS2ORUNIX */
  12447. #ifdef UNIX                             /* Systems that have a standard */
  12448.               p = "/tmp/";              /* temporary directory... */
  12449. #else
  12450. #ifdef datageneral
  12451.               p = ":TMP:";
  12452. #else
  12453.               p = "";
  12454. #endif /* datageneral */
  12455. #endif /* UNIX */
  12456.         }
  12457.         ckstrncpy(vvbuf,p,VVBUFL);
  12458.         p = vvbuf;
  12459.  
  12460. /* This needs generalizing for VOS, AOS/VS, etc... */
  12461.  
  12462.         while (*p) {
  12463. #ifdef OS2
  12464.             if (*p == '\\') *p = '/';
  12465. #endif /* OS2 */
  12466.             p++;
  12467.         }
  12468. #ifndef VMS
  12469.         if (p > vvbuf) {
  12470.             char c =                    /* Directory termination character */
  12471. #ifdef MAC
  12472.               ':'
  12473. #else
  12474. #ifdef datageneral
  12475.               ':'
  12476. #else
  12477. #ifdef STRATUS
  12478.               '>'
  12479. #else
  12480.               '/'
  12481. #endif /* STRATUS */
  12482. #endif /* datageneral */
  12483. #endif /* MAC */
  12484.                 ;
  12485.  
  12486.             if (*(p-1) != c) {
  12487.                 *p++ = c;
  12488.                 *p = NUL;
  12489.             }
  12490.         }
  12491. #endif /* VMS */
  12492.         return(vvbuf);
  12493.     } /* Break up long switch statements... */
  12494.  
  12495.     switch(y) {
  12496.       case VN_ERRNO:                    /* Error number */
  12497. #ifdef VMS
  12498.         {
  12499.             extern int vms_lasterr;
  12500.             sprintf(vvbuf, "%d", vms_lasterr); /* SAFE */
  12501.         }
  12502. #else
  12503.         sprintf(vvbuf, "%d", errno);    /* SAFE */
  12504. #endif /* VMS */
  12505.         return(vvbuf);
  12506.  
  12507.       case VN_ERSTR:                    /* Error string */
  12508.         ckstrncpy(vvbuf,ck_errstr(),VVBUFL);
  12509.         return(vvbuf);
  12510.  
  12511. #ifndef NOXFER
  12512.       case VN_RPSIZ:                    /* RECEIVE packet-length */
  12513.         sprintf(vvbuf,"%d",urpsiz);     /* SAFE */
  12514.         return(vvbuf);
  12515.  
  12516.       case VN_WINDO:                    /* WINDOW slots */
  12517.         sprintf(vvbuf,"%d",wslotr);     /* SAFE */
  12518.         return(vvbuf);
  12519. #endif /* NOXFER */
  12520.  
  12521.       case VN_TFLN:                     /* TAKE-file line number */
  12522.         if (tlevel > -1) {
  12523.             sprintf(vvbuf, "%d", tfline[tlevel]); /* SAFE */
  12524.             return(vvbuf);
  12525.         } else
  12526.           return("0");
  12527.  
  12528.       case VN_MDMSG:                    /* DIALRESULT */
  12529. #ifndef NODIAL
  12530.         return((char *)modemmsg);
  12531. #else
  12532.         return("");
  12533. #endif /* NODIAL */
  12534.  
  12535.       case VN_DNUM:                     /* DIALNUMBER */
  12536. #ifndef NODIAL
  12537.         return(dialnum ? (char *) dialnum : "");
  12538. #else
  12539.         return("");
  12540. #endif /* NODIAL */
  12541.  
  12542.       case VN_APC:
  12543.         sprintf(vvbuf, "%d",            /* SAFE */
  12544. #ifdef CK_APC
  12545.                 apcactive
  12546. #else
  12547.                 0
  12548. #endif /* CK_APC */
  12549.                 );
  12550.         return((char *)vvbuf);
  12551.  
  12552. #ifdef OS2
  12553. #ifndef NOKVERBS
  12554.       case VN_TRMK:
  12555.           sprintf(vvbuf, "%d", keymac); /* SAFE */
  12556.         return((char *)vvbuf);
  12557. #endif /* NOKVERBS */
  12558. #endif /* OS2 */
  12559.  
  12560.       case VN_IPADDR:
  12561. #ifdef TCPSOCKET
  12562. #ifndef OSK
  12563.       /* This dumps core on OS-9 for some reason, but only if executed */
  12564.       /* before we have made a TCP connection.  This is obviously not */
  12565.       /* the ideal fix. */
  12566.         if (!myipaddr[0])
  12567.           getlocalipaddr();
  12568. #endif /* OSK */
  12569. #endif /* TCPSOCKET */
  12570.         ckstrncpy(vvbuf,
  12571. #ifdef TCPSOCKET
  12572.                 (char *)myipaddr,
  12573. #else
  12574.                 "",
  12575. #endif /* TCPSOCKET */
  12576.                 VVBUFL);
  12577.         return((char *)vvbuf);
  12578.  
  12579. #ifndef NOXFER
  12580.       case VN_CRC16:                    /* CRC-16 of most recent transfer */
  12581.         sprintf(vvbuf,"%d",crc16);      /* SAFE */
  12582.         return(vvbuf);
  12583. #endif /* NOXFER */
  12584.  
  12585. #ifdef CK_PID
  12586.       case VN_PID:
  12587. #ifdef IKSD
  12588. #ifdef CK_LOGIN
  12589.         if (inserver && isguest)
  12590.           return("");
  12591. #endif /* CK_LOGIN */
  12592. #endif /* IKSD */
  12593.         return(ckgetpid());
  12594. #endif /* CK_PID */
  12595.  
  12596. #ifndef NOXFER
  12597.       case VN_FNAM: {                   /* \v(filename) */
  12598.           extern char filnam[], ofn1[], *sfspec, *rrfspec;
  12599.           char * tmp;
  12600.           switch (what) {               /* File transfer is in progress */
  12601. #ifdef NEWFTP
  12602.             case (W_FTP|W_RECV):
  12603.             case (W_FTP|W_SEND):
  12604.               return((char *)filnam);
  12605. #endif /* NEWFTP */
  12606.             case W_RECV:
  12607.             case W_REMO:
  12608.               return((char *)ofn1);
  12609.             default:                    /* Most recent file transferred */
  12610.               if (filnam[0]) {          /* (if any) */
  12611.                   return((char *)filnam);
  12612.               } else if (lastxfer & W_SEND && sfspec) {
  12613.                   if (fnspath == PATH_OFF)
  12614.                     zstrip(sfspec,&tmp);
  12615.                   else
  12616.                     tmp = sfspec;
  12617.                   return(tmp);
  12618.               } else if (lastxfer & W_RECV && rrfspec) {
  12619.                   if (fnrpath == PATH_OFF)
  12620.                     zstrip(rrfspec,&tmp);
  12621.                   else
  12622.                     tmp = rrfspec;
  12623.                   return(tmp);
  12624.               } else
  12625.                 return("");
  12626.           }
  12627.       }
  12628.       case VN_FNUM:                     /* \v(filenum) */
  12629.         sprintf(vvbuf,"%ld",filcnt);    /* SAFE */
  12630.         return((char *)vvbuf);
  12631. #endif /* NOXFER */
  12632.  
  12633. #ifdef PEXITSTAT
  12634.       case VN_PEXIT: {
  12635.           extern int pexitstat;
  12636.           sprintf(vvbuf,"%d",pexitstat); /* SAFE */
  12637.           return((char *)vvbuf);
  12638.       }
  12639. #endif /* PEXITSTAT */
  12640.  
  12641. #ifndef NOXFER
  12642.       case VN_P_8BIT:
  12643.         vvbuf[0] = parity ? ebq : NUL;
  12644.         vvbuf[1] = NUL;
  12645.         return((char *)vvbuf);
  12646.  
  12647.       case VN_P_CTL: {
  12648.           extern CHAR myctlq;
  12649.           vvbuf[0] = myctlq;
  12650.           vvbuf[1] = NUL;
  12651.           return((char *)vvbuf);
  12652.       }
  12653.       case VN_P_RPT: {
  12654.           extern int rptena;
  12655.           vvbuf[0] = rptena ? rptq : NUL;
  12656.           vvbuf[1] = NUL;
  12657.           return((char *)vvbuf);
  12658.       }
  12659. #endif /* NOXFER */
  12660.  
  12661. #ifdef OS2
  12662.       case VN_REGN:
  12663.         return(get_reg_name());
  12664.       case VN_REGO:
  12665.         return(get_reg_corp());
  12666.       case VN_REGS:
  12667.         return(get_reg_sn());
  12668. #endif /* OS2 */
  12669.     } /* Break up long switch statements... */
  12670.  
  12671.     switch(y) {
  12672.       case VN_XPROG:
  12673. #ifdef OS2
  12674. #ifdef NT
  12675. #ifdef KUI
  12676.         return("K-95G");
  12677. #else
  12678.         return("K-95");
  12679. #endif /* KUI */
  12680. #else
  12681.         return("K/2");
  12682. #endif /* NT */
  12683. #else
  12684.         return("C-Kermit");
  12685. #endif /* OS2 */
  12686.  
  12687.       case VN_EDITOR:
  12688. #ifdef NOFRILLS
  12689.         return("");
  12690. #else
  12691. #ifdef NOPUSH
  12692.         return("");
  12693. #else
  12694.         {
  12695.             extern char editor[];
  12696.             char *ss;
  12697.             if (!editor[0]) {
  12698.                 ss = getenv("EDITOR");
  12699.                 if (ss) {
  12700.                     ckstrncpy(editor,ss,CKMAXPATH);
  12701.                 }
  12702.             }
  12703.             debug(F110,"\\v(editor)",editor,0);
  12704.             return(editor[0] ? (char *)editor : "");
  12705.         }
  12706. #endif /* NOPUSH */
  12707. #endif /* NOFRILLS */
  12708.  
  12709.       case VN_EDOPT:
  12710. #ifdef NOFRILLS
  12711.         return("");
  12712. #else
  12713. #ifdef NOPUSH
  12714.         return("");
  12715. #else
  12716.         {
  12717.             extern char editopts[];
  12718.             return(editopts[0] ? (char *)editopts : "");
  12719.         }
  12720. #endif /* NOPUSH */
  12721. #endif /* NOFRILLS */
  12722.  
  12723.       case VN_EDFILE:
  12724. #ifdef NOFRILLS
  12725.         return("");
  12726. #else
  12727. #ifdef NOPUSH
  12728.         return("");
  12729. #else
  12730.         {
  12731.             extern char editfile[];
  12732.             return(editfile[0] ? (char *)editfile : "");
  12733.         }
  12734. #endif /* NOPUSH */
  12735. #endif /* NOFRILLS */
  12736.  
  12737. #ifdef BROWSER
  12738.       case VN_BROWSR: {
  12739.           extern char browser[];
  12740.           if (!browser[0]) {
  12741.               s = getenv("BROWSER");
  12742.               if (s) ckstrncpy(browser,s,CKMAXPATH);
  12743.           }
  12744.           return(browser[0] ? (char *)browser : "");
  12745.       }
  12746.       case VN_BROPT: {
  12747.           extern char browsopts[];
  12748.           return(browsopts[0] ? (char *)browsopts : "");
  12749.       }
  12750.       case VN_URL: {
  12751.           extern char browsurl[];
  12752.           return(browsurl[0] ? (char *)browsurl : "");
  12753.       }
  12754. #endif /* BROWSER */
  12755.       case VN_HERALD:
  12756.         return((char *)versio);
  12757.  
  12758.       case VN_TEST: {                   /* test */
  12759.           extern char * ck_s_test, * ck_s_tver;
  12760.           if (!ck_s_test) ck_s_test = "";
  12761.           if (!ck_s_tver) ck_s_tver = "";
  12762.           if (*ck_s_test) {
  12763.               ckstrncpy(vvbuf,ck_s_test,VVBUFL);
  12764.               if (*ck_s_tver) {
  12765.                   ckstrncat(vvbuf,".",VVBUFL);
  12766.                   ckstrncat(vvbuf,ck_s_tver,VVBUFL);
  12767.               }
  12768.           } else
  12769.             ckstrncpy(vvbuf,"0",VVBUFL);
  12770.           return((char *)vvbuf);
  12771.       }
  12772.  
  12773. #ifndef NOXFER
  12774.       case VN_XFSTAT:                   /* xferstatus */
  12775.         x = xferstat;                   /* Like success */
  12776.         if (x > -1) x = (x == 0) ? 1 : 0; /* External value is reversed */
  12777.         sprintf(vvbuf,"%d",x);          /* SAFE */
  12778.         return((char *)vvbuf);
  12779.  
  12780.       case VN_XFMSG:                    /* xfermsg */
  12781.         return((char *)epktmsg);
  12782.  
  12783. #ifndef NOMSEND
  12784.       case VN_SNDL: {                   /* sendlist */
  12785.           extern int filesinlist;
  12786.           sprintf(vvbuf,"%d",filesinlist); /* SAFE */
  12787.           return((char *)vvbuf);
  12788.       }
  12789. #endif /* NOMSEND */
  12790. #endif /* NOXFER */
  12791.  
  12792. #ifdef CK_TRIGGER
  12793.       case VN_TRIG: {
  12794.           extern char * triggerval;
  12795.           return(triggerval ? triggerval : "");
  12796.       }
  12797. #endif /* CK_TRIGGER */
  12798. #ifdef OS2MOUSE
  12799. #ifdef OS2
  12800.       case VN_MOU_X: {
  12801.           extern int MouseCurX;
  12802.           sprintf(vvbuf,"%d",MouseCurX); /* SAFE */
  12803.           return((char *)vvbuf);
  12804.       }
  12805.       case VN_MOU_Y: {
  12806.           extern int MouseCurY;
  12807.           sprintf(vvbuf,"%d",MouseCurY); /* SAFE */
  12808.           return((char *)vvbuf);
  12809.       }
  12810. #endif /* OS2 */
  12811. #endif /* OS2MOUSE */
  12812.       case VN_PRINT: {
  12813.           extern int printpipe;
  12814.           extern char * printername;
  12815. #ifdef PRINTSWI
  12816.           extern int noprinter;
  12817.           if (noprinter) return("");
  12818. #endif /* PRINTSWI */
  12819.           ckmakmsg(vvbuf,VVBUFL,
  12820.                    printpipe ? "|" : "",
  12821.                    printername ? printername :
  12822. #ifdef OS2
  12823.                    "PRN",
  12824. #else
  12825.                    "(default)",
  12826. #endif /* OS2 */
  12827.                    NULL,
  12828.                    NULL
  12829.                    );
  12830.           return((char *)vvbuf);
  12831.       }
  12832.     } /* Break up long switch statements... */
  12833.  
  12834.     switch(y) {
  12835.       case VN_ESC:                      /* Escape character */
  12836.         sprintf(vvbuf,"%d",escape);     /* SAFE */
  12837.         return((char *)vvbuf);
  12838.  
  12839.       case VN_INTIME:
  12840.         sprintf(vvbuf,"%ld",inetime);   /* SAFE */
  12841.         return((char *)vvbuf);
  12842.  
  12843.       case VN_INTMO:
  12844.         sprintf(vvbuf,"%d",inwait);     /* SAFE */
  12845.         return((char *)vvbuf);
  12846.  
  12847.       case VN_SECURE:
  12848.         if (0
  12849. #ifdef SSHBUILTIN
  12850.             || IS_SSH()
  12851. #endif /* SSHBUILTIN */
  12852. #ifdef CK_ENCRYPTION
  12853.             || ck_tn_encrypting() && ck_tn_decrypting()
  12854. #endif /* CK_ENCRYPTION */
  12855. #ifdef CK_SSL
  12856.             || tls_active_flag || ssl_active_flag
  12857. #endif /* CK_SSL */
  12858.             )
  12859.           return("1");
  12860.         else
  12861.           return("0");
  12862.  
  12863.       case VN_AUTHN:
  12864. #ifdef CK_AUTHENTICATION
  12865.         {
  12866.             extern char szUserNameAuthenticated[];
  12867.             return((char *)szUserNameAuthenticated);
  12868.         }
  12869. #else /* CK_AUTHENTICATION */
  12870.         return((char *)"");
  12871. #endif /* CK_AUTHENTICATION */
  12872.  
  12873.       case VN_AUTHS:
  12874. #ifdef CK_AUTHENTICATION
  12875.         switch (ck_tn_auth_valid()) {
  12876.           case AUTH_UNKNOWN:
  12877.             return((char *)"unknown");
  12878.           case AUTH_OTHER:
  12879.             return((char *)"other");
  12880.           case AUTH_USER:
  12881.             return((char *)"user");
  12882.           case AUTH_VALID:
  12883.             return((char *)"valid");
  12884.           case AUTH_REJECT:
  12885.           default:
  12886.             return((char *)"rejected");
  12887.         }
  12888. #else /* CK_AUTHENTICATION */
  12889.         return((char *)"rejected");
  12890. #endif /* CK_AUTHENTICATION */
  12891.  
  12892.       case VN_AUTHT:
  12893. #ifdef CK_AUTHENTICATION
  12894. #ifdef CK_SSL
  12895.         if ((ssl_active_flag || tls_active_flag) &&
  12896.             ck_tn_auth_valid() == AUTH_VALID &&
  12897.             (sstelnet ? (!TELOPT_U(TELOPT_AUTHENTICATION)) :
  12898.                         (!TELOPT_ME(TELOPT_AUTHENTICATION))) ||
  12899.              ck_tn_authenticated() == AUTHTYPE_NULL ||
  12900.              ck_tn_authenticated() == AUTHTYPE_AUTO)
  12901.           return("X_509_CERTIFICATE");
  12902.         else
  12903. #endif /* CK_SSL */
  12904.           return(AUTHTYPE_NAME(ck_tn_authenticated()));
  12905. #else /* CK_AUTHENTICATION */
  12906.         return((char *)"NULL");
  12907. #endif /* CK_AUTHENTICATION */
  12908.  
  12909. #ifdef CK_KERBEROS
  12910.       case VN_K4PRN: {
  12911.           extern char * krb4_d_principal;
  12912.           if (krb4_d_principal)
  12913.             ckstrncpy(vvbuf,krb4_d_principal,VVBUFL+1);
  12914.           else
  12915.             *vvbuf = NUL;
  12916.           return((char *)vvbuf);
  12917.       }
  12918.       case VN_K5PRN: {
  12919.           extern char * krb5_d_principal;
  12920.           if (krb5_d_principal)
  12921.             ckstrncpy(vvbuf,krb5_d_principal,VVBUFL+1);
  12922.           else
  12923.             *vvbuf = NUL;
  12924.           return((char *)vvbuf);
  12925.       }
  12926.       case VN_K4RLM: {
  12927.           extern char * krb4_d_realm;
  12928.           if (krb4_d_realm) {
  12929.               ckstrncpy(vvbuf,krb4_d_realm,VVBUFL+1);
  12930.           } else {
  12931.               char * s = ck_krb4_getrealm();
  12932.               ckstrncpy(vvbuf,s ? s : "",VVBUFL+1);
  12933.           }
  12934.           return((char *)vvbuf);
  12935.       }
  12936.       case VN_K4SRV: {
  12937.           extern char * krb4_d_srv;
  12938.           if (krb4_d_srv)
  12939.             ckstrncpy(vvbuf,krb4_d_srv,VVBUFL+1);
  12940.           else
  12941.             ckstrncpy(vvbuf,"rcmd",VVBUFL);
  12942.           return((char *)vvbuf);
  12943.       }
  12944.       case VN_K5RLM: {
  12945.           extern char * krb5_d_realm;
  12946.           extern char * krb5_d_cc;
  12947.           if (krb5_d_realm) {
  12948.               ckstrncpy(vvbuf,krb5_d_realm,VVBUFL+1);
  12949.           } else {
  12950.               char * s = ck_krb5_getrealm(krb5_d_cc);
  12951.               ckstrncpy(vvbuf,s,VVBUFL+1);
  12952.           }
  12953.           return((char *)vvbuf);
  12954.       }
  12955.       case VN_K5CC: {
  12956.           extern char * krb5_d_cc;
  12957.           if (krb5_d_cc)
  12958.             ckstrncpy(vvbuf,krb5_d_cc,VVBUFL+1);
  12959.           else
  12960.             ckstrncpy(vvbuf,ck_krb5_get_cc_name(),VVBUFL+1);
  12961.           return((char *)vvbuf);
  12962.       }
  12963.       case VN_K5SRV: {
  12964.           extern char * krb5_d_srv;
  12965.           if (krb5_d_srv)
  12966.             ckstrncpy(vvbuf,krb5_d_srv,VVBUFL+1);
  12967.           else
  12968.             ckstrncpy(vvbuf,"host",VVBUFL);
  12969.           return((char *)vvbuf);
  12970.       }
  12971.       case VN_K4ENO: {
  12972.         extern char * krb4_errno;
  12973.         sprintf(vvbuf,"%d",krb4_errno); /* SAFE */
  12974.         return((char *)vvbuf);
  12975.       }
  12976.       case VN_K5ENO: {
  12977.         extern char * krb5_errno;
  12978.         sprintf(vvbuf,"%d",krb5_errno); /* SAFE */
  12979.         return((char *)vvbuf);
  12980.       }
  12981.       case VN_K4EMSG: {
  12982.         extern char * krb4_errmsg;
  12983.         ckstrncpy(vvbuf,krb4_errmsg?krb4_errmsg:"",VVBUFL+1);
  12984.         return((char *)vvbuf);
  12985.       }
  12986.       case VN_K5EMSG: {
  12987.         extern char * krb5_errmsg;
  12988.         ckstrncpy(vvbuf,krb5_errmsg,VVBUFL+1);
  12989.         return((char *)vvbuf);
  12990.       }
  12991. #endif /* CK_KERBEROS */
  12992. #ifdef CK_SSL
  12993.       case VN_X509_S:
  12994.         if (ssl_active_flag)
  12995.           ckstrncpy(vvbuf,ssl_get_subject_name(ssl_con),VVBUFL+1);
  12996.         else if (tls_active_flag)
  12997.           ckstrncpy(vvbuf,ssl_get_subject_name(tls_con),VVBUFL+1);
  12998.         else
  12999.           ckstrncpy(vvbuf,"",VVBUFL+1);
  13000.         return((char *)vvbuf);
  13001.       case VN_X509_I:
  13002.         if (ssl_active_flag)
  13003.           ckstrncpy(vvbuf,ssl_get_issuer_name(ssl_con),VVBUFL+1);
  13004.         else if (tls_active_flag)
  13005.           ckstrncpy(vvbuf,ssl_get_issuer_name(tls_con),VVBUFL+1);
  13006.         else
  13007.           ckstrncpy(vvbuf,"",VVBUFL+1);
  13008.         return((char *)vvbuf);
  13009. #endif /* CK_SSL */
  13010.  
  13011.       case VN_OSNAM:
  13012. #ifdef IKSD
  13013. #ifdef CK_LOGIN
  13014.         if (inserver && isguest)
  13015.           return("");
  13016. #endif /* CK_LOGIN */
  13017. #endif /* IKSD */
  13018. #ifdef CK_UTSNAME
  13019.         {
  13020.             extern char unm_nam[];
  13021.             return((char *)unm_nam);
  13022.         }
  13023. #else
  13024.         for (x = y = 0; x < VVBUFL; x++) {
  13025.             if (ckxsys[x] == SP && cx == 0) continue;
  13026.             vvbuf[y++] = (char) ((ckxsys[x] == SP) ? '_' : ckxsys[x]);
  13027.         }
  13028.         vvbuf[y] = NUL;
  13029.         return(vvbuf);
  13030. #endif /* CK_UTSNAME */
  13031.  
  13032.       case VN_OSVER: {
  13033. #ifdef CK_UTSNAME
  13034.           extern char unm_ver[];
  13035. #ifdef IKSD
  13036. #ifdef CK_LOGIN
  13037.           if (inserver && isguest)
  13038.             return("");
  13039. #endif /* CK_LOGIN */
  13040. #endif /* IKSD */
  13041.           return((char *)unm_ver);
  13042. #else
  13043.           return("");
  13044. #endif /* CK_UTSNAME */
  13045.       }
  13046.  
  13047.       case VN_OSREL: {
  13048. #ifdef CK_UTSNAME
  13049.           extern char unm_rel[];
  13050. #ifdef IKSD
  13051. #ifdef CK_LOGIN
  13052.           if (inserver && isguest)
  13053.             return("");
  13054. #endif /* CK_LOGIN */
  13055. #endif /* IKSD */
  13056.           return((char *)unm_rel);
  13057. #else
  13058.           return("");
  13059. #endif /* CK_UTSNAME */
  13060.       }
  13061.     } /* Break up long switch statements... */
  13062.  
  13063.     switch(y) {
  13064.       case VN_NAME: {
  13065.           extern char * myname;
  13066.           return(myname);
  13067.       }
  13068.  
  13069.       case VN_MODL: {
  13070. #ifdef CK_UTSNAME
  13071.           extern char unm_mod[], unm_mch[];
  13072.           int y = VVBUFL - 1;
  13073.           char * s = unm_mod;
  13074. #endif /* CK_UTSNAME */
  13075. #ifdef IKSD
  13076. #ifdef CK_LOGIN
  13077.           if (inserver && isguest)
  13078.             return("");
  13079. #endif /* CK_LOGIN */
  13080. #endif /* IKSD */
  13081.  
  13082. #ifdef COMMENT                          /* was HPUX */
  13083.           if (!unm_mod[0] && !nopush)
  13084.             zzstring("\\fcommand(model)",&s,&y);
  13085. /*
  13086.    Another possibility would be:
  13087.      "\\fcommand(ksh -c 'whence model 1>&- && model || uname -m')"
  13088.    But that would depend on having ksh.
  13089. */
  13090. #else
  13091. #ifdef OSF32                            /* Digital UNIX 3.2 and higher... */
  13092. /* Note: Ultrix has /etc/sizer, but it is not publicly executable. */
  13093. /* sizer -c outputs 'cpu:<tab><tab>"DECxxxx"' */
  13094.           if (!unm_mod[0]) {
  13095.               char * p;
  13096.               int flag = 0;
  13097.               zzstring("\\fcommand(/usr/sbin/sizer -c)",&s,&y);
  13098.               debug(F110,"DU model",unm_mod,0);
  13099.               s = unm_mod;
  13100.               p = unm_mod;
  13101.               while (*p) {              /* Extract the part in quotes */
  13102.                   if (*p == '"') {
  13103.                       if (flag)
  13104.                         break;
  13105.                       flag = 1;
  13106.                       p++;
  13107.                       continue;
  13108.                   }
  13109.                   if (flag)
  13110.                     *s++ = *p;
  13111.                   p++;
  13112.               }
  13113.               *s = NUL;
  13114.           }
  13115. #endif /* OSF32 */
  13116. #endif /* COMMENT */
  13117.  
  13118. #ifdef CK_UTSNAME
  13119.           if (unm_mod[0])
  13120.             return((char *)unm_mod);
  13121.           else
  13122.             return((char *)unm_mch);
  13123. #else
  13124.           return("");
  13125. #endif /* CK_UTSNAME */
  13126.       }
  13127.  
  13128. #ifdef IBMX25
  13129.       /* X.25 variables (local and remote address) */
  13130.       case VN_X25LA:
  13131.         if (!local_nua[0] && !x25local_nua(local_nua))
  13132.           *vvbuf = NULL;
  13133.         else
  13134.           ckstrncpy(vvbuf,local_nua,VVBUFL+1);
  13135.         return((char *)vvbuf);
  13136.  
  13137.       case VN_X25RA:
  13138.         if (!remote_nua[0])
  13139.           *vvbuf = NULL;
  13140.         else
  13141.           ckstrncpy(vvbuf,remote_nua,VVBUFL+1);
  13142.         return((char *)vvbuf);
  13143. #endif /* IBMX25 */
  13144.  
  13145. #ifndef NODIAL
  13146.       case VN_PDSFX: {
  13147.           extern char pdsfx[];
  13148.           return((char *)pdsfx);
  13149.       }
  13150.       case VN_DTYPE: {
  13151.           extern int dialtype;
  13152.           sprintf(vvbuf,"%d",dialtype); /* SAFE */
  13153.           return((char *)vvbuf);
  13154.       }
  13155. #endif /* NODIAL */
  13156.  
  13157. #ifdef UNIX
  13158.       case VN_LCKPID: {
  13159.           extern char lockpid[];
  13160.           return((char *)lockpid);
  13161.       }
  13162. #endif /* UNIX */
  13163.  
  13164. #ifndef NOXFER
  13165.       case VN_BLK:
  13166.         sprintf(vvbuf,"%d",bctr);       /* SAFE */
  13167.         return((char *)vvbuf);
  13168.  
  13169.       case VN_TFTIM:
  13170.         sprintf(vvbuf,                  /* SAFE */
  13171. #ifdef GFTIMER
  13172.                 "%ld", (long)(fptsecs + 0.5)
  13173. #else
  13174.                 "%d", tsecs
  13175. #endif /* GFTIMER */
  13176.                 );
  13177.         return((char *)vvbuf);
  13178. #endif /* NOXFER */
  13179.  
  13180.       case VN_HWPAR:
  13181.       case VN_SERIAL: {
  13182.           int sb;
  13183.           char c, * ss;
  13184.           extern int stopbits;
  13185.           vvbuf[0] = NUL;
  13186.           if (hwparity && local && !network)
  13187.             ss = parnam((char)hwparity);
  13188.           else
  13189.             ss = parnam((char)parity);
  13190.           if (cx == VN_HWPAR) {
  13191.               ckstrncpy(vvbuf,ss,VVBUFL);
  13192.               return((char *)vvbuf);
  13193.           }
  13194.           c = ss[0];
  13195.           if (islower(c)) c = toupper(c);
  13196.           sb = stopbits;
  13197.           if (sb < 1)
  13198.             sb = (speed > 0 && speed <= 110L) ? 2 : 1;
  13199.           if (hwparity)
  13200.             sprintf(vvbuf," 8%c%d",c,sb); /* SAFE */
  13201.           else if (parity)
  13202.             sprintf(vvbuf," 7%c%d",c,sb); /* SAFE */
  13203.           else
  13204.             sprintf(vvbuf," 8N%d",sb);  /* SAFE */
  13205.           return((char *)vvbuf);
  13206.       }
  13207.  
  13208. #ifdef UNIX
  13209.       case VN_LCKDIR: {
  13210. #ifndef NOUUCP
  13211.           extern char * uucplockdir;
  13212.           ckstrncpy(vvbuf,uucplockdir,VVBUFL);
  13213.           x = strlen(vvbuf);
  13214.           if (x > 0) {
  13215.               if (vvbuf[x-1] != '/') {
  13216.                   vvbuf[x] = '/';
  13217.                   vvbuf[x+1] = NUL;
  13218.               }
  13219.           }
  13220. #else
  13221.           vvbuf[0] = NUL;
  13222. #endif /* NOUUCP */
  13223.           return((char *)vvbuf);
  13224.       }
  13225. #endif /* UNIX */
  13226.     } /* Break up long switch statements... */
  13227.  
  13228.     switch(y) {
  13229. #ifndef NODIAL
  13230.       case VN_DM_LP:
  13231.       case VN_DM_SP:
  13232.       case VN_DM_PD:
  13233.       case VN_DM_TD:
  13234.       case VN_DM_WA:
  13235.       case VN_DM_WD:
  13236.       case VN_DM_HF:
  13237.       case VN_DM_WB:
  13238.       case VN_DM_RC: {
  13239.           extern char * getdm();
  13240.           ckstrncpy(vvbuf,getdm(y),VVBUFL);
  13241.           return((char *)vvbuf);
  13242.       }
  13243. #endif /* NODIAL */
  13244.  
  13245.       case VN_TY_LN:
  13246.       case VN_TY_LC: {
  13247.           extern int typ_lines;
  13248.           sprintf(vvbuf,"%d",typ_lines); /* SAFE */
  13249.           return((char *)vvbuf);
  13250.       }
  13251.       case VN_TY_LM: {
  13252.           extern int typ_mtchs;
  13253.           sprintf(vvbuf,"%d",typ_mtchs); /* SAFE */
  13254.           return((char *)vvbuf);
  13255.       }
  13256.       case VN_MACLVL:
  13257.         sprintf(vvbuf,"%d",maclvl);     /* SAFE */
  13258.         return((char *)vvbuf);
  13259.     } /* Break up long switch statements... */
  13260.  
  13261.     switch(y) {
  13262. #ifndef NOLASTFILE
  13263.       case VN_LASTFIL: {
  13264.       extern char * lastfile;
  13265.       return(lastfile ? lastfile : "");
  13266.       }
  13267. #endif    /* NOLASTFILE */
  13268. #ifndef NOXFER
  13269.       case VN_XF_BC:
  13270.         sprintf(vvbuf,"%d",crunched);   /* SAFE */
  13271.         return((char *)vvbuf);
  13272.  
  13273.       case VN_XF_TM:
  13274.         sprintf(vvbuf,"%d",timeouts);   /* SAFE */
  13275.         return((char *)vvbuf);
  13276.  
  13277.       case VN_XF_RX:
  13278.         sprintf(vvbuf,"%d",retrans);    /* SAFE */
  13279.         return((char *)vvbuf);
  13280. #endif /* NOXFER */
  13281.  
  13282.       case VN_MS_CD:                    /* Modem signals */
  13283.       case VN_MS_CTS:
  13284.       case VN_MS_DSR:
  13285.       case VN_MS_DTR:
  13286.       case VN_MS_RI:
  13287.       case VN_MS_RTS: {
  13288.           int x, z = -1;
  13289.           x = ttgmdm();                 /* Try to get them */
  13290.           if (x > -1) {
  13291.               switch (y) {
  13292.                 case VN_MS_CD:  z = (x & BM_DCD) ? 1 : 0; break;
  13293.                 case VN_MS_DSR: z = (x & BM_DSR) ? 1 : 0; break;
  13294.                 case VN_MS_CTS: z = (x & BM_CTS) ? 1 : 0; break;
  13295. #ifdef MAC
  13296.                 case VN_MS_DTR: z = (x & BM_DTR) ? 1 : 0; break;
  13297. #else
  13298. #ifndef STRATUS
  13299.                 case VN_MS_RI:  z = (x & BM_RNG) ? 1 : 0; break;
  13300. #ifndef NT
  13301.                 case VN_MS_DTR: z = (x & BM_DTR) ? 1 : 0; break;
  13302.                 case VN_MS_RTS: z = (x & BM_RTS) ? 1 : 0; break;
  13303. #endif /* NT */
  13304. #endif /* STRATUS */
  13305. #endif /* MAC */
  13306.               }
  13307.           }
  13308.           sprintf(vvbuf,"%d",z);        /* SAFE */
  13309.           return((char *)vvbuf);
  13310.       }
  13311.       case VN_MATCH:                    /* INPUT MATCH */
  13312.         return(inpmatch ? inpmatch : "");
  13313.  
  13314. #ifdef CKFLOAT
  13315.       case VN_ISCALE:            /* INPUT SCALE-FACTOR */
  13316.         return(inpscale ? inpscale : "1.0");
  13317. #endif    /* CKFLOAT */
  13318.  
  13319.       case VN_SLMSG: {                  /* SET LINE / HOST message */
  13320.           extern char * slmsg;
  13321.           vvbuf[0] = NUL;
  13322.           if (slmsg)
  13323.             ckstrncpy(vvbuf,slmsg,VVBUFL);
  13324.          return(vvbuf);
  13325.       }
  13326.  
  13327.       case VN_TXTDIR:                   /* TEXTDIR */
  13328.         return(k_info_dir ? k_info_dir : "");
  13329.  
  13330. #ifdef FNFLOAT
  13331.       case VN_MA_PI:
  13332.         return(math_pi);
  13333.  
  13334.       case VN_MA_E:
  13335.         return(math_e);
  13336.  
  13337.       case VN_MA_PR:
  13338.         sprintf(vvbuf,"%d",fp_digits);  /* SAFE */
  13339.         return(vvbuf);
  13340. #endif /* FNFLOAT */
  13341.  
  13342.       case VN_CMDBL:
  13343.         sprintf(vvbuf,"%d",CMDBL);      /* SAFE */
  13344.         return(vvbuf);
  13345.  
  13346. #ifdef CKCHANNELIO
  13347.       case VN_FERR: {
  13348.           extern int z_error;
  13349.           sprintf(vvbuf,"%d",z_error);  /* SAFE */
  13350.           return(vvbuf);
  13351.       }
  13352.       case VN_FMAX: {
  13353.           extern int z_maxchan;
  13354.           sprintf(vvbuf,"%d",z_maxchan); /* SAFE */
  13355.           return(vvbuf);
  13356.       }
  13357.       case VN_FCOU: {
  13358.           extern int z_filcount;
  13359.           sprintf(vvbuf,"%d",z_filcount); /* SAFE */
  13360.           return(vvbuf);
  13361.       }
  13362. #endif /* CKCHANNELIO */
  13363.  
  13364. #ifndef NODIAL
  13365.       case VN_DRTR: {
  13366.           extern int dialcount;
  13367.           sprintf(vvbuf,"%d",dialcount); /* SAFE */
  13368.           return(vvbuf);
  13369.       }
  13370. #endif /* NODIAL */
  13371.  
  13372. #ifndef NOLOGDIAL
  13373. #ifndef NOLOCAL
  13374.       case VN_CXTIME:
  13375.         sprintf(vvbuf,"%ld",dologshow(0)); /* SAFE */
  13376.         return(vvbuf);
  13377. #endif /* NOLOCAL */
  13378. #endif /* NOLOGDIAL */
  13379.  
  13380.       case VN_BYTE:
  13381.         sprintf(vvbuf,"%d",byteorder);  /* SAFE */
  13382.         return(vvbuf);
  13383.  
  13384.       case VN_KBCHAR:
  13385.         vvbuf[0] = NUL;
  13386.         vvbuf[1] = NUL;
  13387.         if (kbchar > 0)
  13388.           vvbuf[0] = (kbchar & 0xff);
  13389.         return(vvbuf);
  13390.  
  13391.       case VN_TTYNAM: {
  13392. #ifdef HAVECTTNAM
  13393.           extern char cttnam[];
  13394.           return((char *)cttnam);
  13395. #else
  13396.           return(CTTNAM);
  13397. #endif /* HAVECTTNAM */
  13398.       }
  13399.  
  13400.       case VN_PROMPT:
  13401.         return(cmgetp());
  13402.  
  13403.       case VN_BUILD: {
  13404.           extern char * buildid;
  13405.           return(buildid);
  13406.       }
  13407.  
  13408. #ifndef NOSEXP
  13409.       case VN_SEXP: {
  13410.           extern char * lastsexp;
  13411.           return(lastsexp ? lastsexp : "");
  13412.       }
  13413.       case VN_VSEXP: {
  13414.           extern char * sexpval;
  13415.           return(sexpval ? sexpval : "");
  13416.       }
  13417.       case VN_LSEXP: {
  13418.           extern int sexpdep;
  13419.           ckstrncpy(vvbuf,ckitoa(sexpdep),VVBUFL);
  13420.           return(vvbuf);
  13421.       }
  13422. #endif /* NOSEXP */
  13423.  
  13424. #ifdef GFTIMER
  13425.       case VN_FTIME: {
  13426.           CKFLOAT f;
  13427.           ztime(&p);
  13428.           if (p == NULL || *p == NUL)
  13429.             return(NULL);
  13430.           z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
  13431.           f = (CKFLOAT)z + ((CKFLOAT)ztusec) / 1000000.0;
  13432.           sprintf(vvbuf,"%f",f);        /* SAFE */
  13433.           return(vvbuf);
  13434.       }
  13435. #endif /* GFTIMER */
  13436.  
  13437. #ifndef NOHTTP
  13438.       case VN_HTTP_C: {                 /* HTTP Code */
  13439.           extern int http_code;
  13440.           return(ckitoa(http_code));
  13441.       }
  13442.       case VN_HTTP_N:                   /* HTTP Connected */
  13443.         return( http_isconnected() ? "1" : "0");
  13444.       case VN_HTTP_H:                   /* HTTP Host */
  13445.         return( (char *)http_host() );
  13446.       case VN_HTTP_M: {                 /* HTTP Message */
  13447.           extern char http_reply_str[];
  13448.           return((char *)http_reply_str);
  13449.       }
  13450.       case VN_HTTP_S:                   /* HTTP Security */
  13451.         return((char *)http_security());
  13452. #endif /* NOHTTP */
  13453.  
  13454. #ifdef NEWFTP
  13455.       case VN_FTP_B:
  13456.         return((char *)ftp_cpl_mode());
  13457.       case VN_FTP_D:
  13458.         return((char *)ftp_dpl_mode());
  13459.       case VN_FTP_Z:
  13460.         return((char *)ftp_authtype());
  13461.       case VN_FTP_C: {
  13462.           extern int ftpcode;
  13463.           return(ckitoa(ftpcode));
  13464.       }
  13465.       case VN_FTP_M: {
  13466.           extern char ftp_reply_str[];
  13467.           if (isdigit(ftp_reply_str[0]) &&
  13468.               isdigit(ftp_reply_str[1]) &&
  13469.               isdigit(ftp_reply_str[2]) &&
  13470.               ftp_reply_str[3] == ' ')
  13471.             return(&ftp_reply_str[4]);
  13472.           else
  13473.             return(ftp_reply_str);
  13474.       }
  13475.       case VN_FTP_S: {
  13476.           extern char ftp_srvtyp[];
  13477.           return((char *)ftp_srvtyp);
  13478.       }
  13479.       case VN_FTP_H: {
  13480.           extern char * ftp_host;
  13481.           return(ftp_host ? ftp_host : "");
  13482.       }
  13483.       case VN_FTP_X: {                  /* FTP Connected */
  13484.           extern int ftpisconnected();
  13485.           return(ftpisconnected() ? "1" : "0");
  13486.       }
  13487.       case VN_FTP_L: {                  /* FTP Logged in */
  13488.           extern int ftpisloggedin();
  13489.           return(ftpisloggedin() ? "1" : "0");
  13490.       }
  13491.       case VN_FTP_G: {                  /* FTP GET-PUT-REMOTE */
  13492.           extern int ftpget;
  13493.           char * s = "";
  13494.           switch (ftpget) {
  13495.             case 0: s = "kermit"; break;
  13496.             case 1: s = "ftp"; break;
  13497.             case 2: s = "auto"; break;
  13498.           }
  13499.           return(s);
  13500.       }
  13501. #endif /* NEWFTP */
  13502.  
  13503. #ifndef NOLOCAL
  13504.       case VN_CX_STA: {                 /* CONNECT status */
  13505.           extern int cx_status;
  13506.           return(ckitoa(cx_status));
  13507.       }
  13508. #endif /* NOLOCAL */
  13509.       case VN_NOW:                      /* Timestamp */
  13510.         return(ckcvtdate(p,0));
  13511.  
  13512.       case VN_HOUR:                     /* Hour of the day */
  13513.         ztime(&p);                      /* "Thu Feb  8 12:00:00 1990" */
  13514.         if (!p) p = "";
  13515.         if (!*p) return(p);
  13516.         vvbuf[0] = p[11];
  13517.         vvbuf[1] = p[12];
  13518.         vvbuf[2] = NUL;
  13519.         return(vvbuf);                  /* and return it */
  13520.  
  13521.       case VN_BITS:            /* Bits (16, 32, 64) */
  13522.     if (sizeof(long) > 4)
  13523.       return(ckitoa(8*sizeof(long)));
  13524.     else
  13525.       return(ckitoa(8*sizeof(int)));
  13526.  
  13527.       case VN_LOG_CON:            /* \v(...) for log files */
  13528. #ifdef CKLOGDIAL
  13529.         return(diafil);
  13530. #else 
  13531.         return("");
  13532. #endif
  13533.       case VN_LOG_PKT:
  13534. #ifndef NOXFER
  13535.         return(pktfil);
  13536. #else
  13537.         return("");
  13538. #endif
  13539.       case VN_LOG_SES:
  13540. #ifndef NOLOCAL
  13541.         return(sesfil);
  13542. #else
  13543.         return("");
  13544. #endif
  13545.       case VN_LOG_TRA:
  13546. #ifdef TLOG
  13547.         return(trafil);
  13548. #else
  13549.         return("");
  13550. #endif
  13551.       case VN_LOG_DEB:
  13552. #ifdef DEBUG
  13553.         return(debfil);
  13554. #else
  13555.         return("");
  13556. #endif
  13557.     }
  13558.  
  13559. #ifndef NODIAL
  13560.     switch (y) {                        /* Caller ID values */
  13561.       extern char
  13562.         * callid_date, * callid_time, * callid_name,
  13563.         * callid_nmbr, * callid_mesg;
  13564.  
  13565.       case VN_CI_DA:
  13566.         return(callid_date ? callid_date : "");
  13567.  
  13568.       case VN_CI_TI:
  13569.         return(callid_time ? callid_time : "");
  13570.  
  13571.       case VN_CI_NA:
  13572.         return(callid_name ? callid_name : "");
  13573.  
  13574.       case VN_CI_NU:
  13575.         return(callid_nmbr ? callid_nmbr : "");
  13576.  
  13577.       case VN_CI_ME:
  13578.         return(callid_mesg ? callid_mesg : "");
  13579.  
  13580.     } /* End of variable-name switches */
  13581. #endif /* NODIAL */
  13582.  
  13583. #ifdef NT
  13584.     switch (y) {
  13585.       case VN_PERSONAL:
  13586.         p = (char *)GetPersonal();
  13587.         if (p) {
  13588.             GetShortPathName(p,vvbuf,VVBUFL);
  13589.             return(vvbuf);
  13590.         }
  13591.         return("");
  13592.       case VN_DESKTOP:
  13593.           p = (char *)GetDesktop();
  13594.           if (p) {
  13595.               GetShortPathName(p,vvbuf,VVBUFL);
  13596.               return(vvbuf);
  13597.           }
  13598.           return("");
  13599.       case VN_COMMON:
  13600.         p = (char *)GetAppData(1);
  13601.         if (p) {
  13602.             ckmakmsg(vvbuf,VVBUFL,p,"Kermit 95/",NULL,NULL);
  13603.             GetShortPathName(vvbuf,vvbuf,VVBUFL);
  13604.             return(vvbuf);
  13605.         }
  13606.         return("");
  13607.       case VN_APPDATA:
  13608.         p = (char *)GetAppData(0);
  13609.         if (p) {
  13610.             ckmakmsg(vvbuf,VVBUFL,p,"Kermit 95/",NULL,NULL);
  13611.             GetShortPathName(vvbuf,vvbuf,VVBUFL);
  13612.             return(vvbuf);
  13613.         }
  13614.         return("");
  13615.     }
  13616. #endif /* NT */
  13617.  
  13618. #ifdef TN_COMPORT
  13619.     switch (y) {
  13620.       case VN_TNC_SIG: {
  13621.         p = (char *) tnc_get_signature();
  13622.         ckstrncpy(vvbuf,p ? p : "",VVBUFL);
  13623.         return(vvbuf);
  13624.       }
  13625.     }
  13626. #endif /* TN_COMPORT */
  13627.  
  13628. #ifdef KUI
  13629.     switch (y) {
  13630.       case VN_GUI_RUN: {
  13631.       extern HWND getHwndKUI();
  13632.       if ( IsIconic(getHwndKUI()) )
  13633.             return("minimized");
  13634.       if ( IsZoomed(getHwndKUI()) )
  13635.             return("maximized");
  13636.       return("restored");
  13637.       }
  13638.       case VN_GUI_XP:
  13639.         sprintf(vvbuf,"%d",get_gui_window_pos_x());  /* SAFE */
  13640.         return(vvbuf);
  13641.       case VN_GUI_YP:
  13642.         sprintf(vvbuf,"%d",get_gui_window_pos_y());  /* SAFE */
  13643.         return(vvbuf);
  13644.       case VN_GUI_XR:
  13645.         sprintf(vvbuf,"%d",GetSystemMetrics(SM_CXSCREEN));  /* SAFE */
  13646.         return(vvbuf);
  13647.       case VN_GUI_YR:
  13648.         sprintf(vvbuf,"%d",GetSystemMetrics(SM_CYSCREEN));  /* SAFE */
  13649.         return(vvbuf);
  13650.       case VN_GUI_FNM:
  13651.           if ( ntermfont > 0 ) {
  13652.               int i;
  13653.               for (i = 0; i < ntermfont; i++) {
  13654.                   if (tt_font == term_font[i].kwval) {
  13655.                       ckstrncpy(vvbuf,term_font[i].kwd,VVBUFL);
  13656.                       return(vvbuf);
  13657.                   }
  13658.               }
  13659.           }
  13660.           return("(unknown)");
  13661.       case VN_GUI_FSZ:
  13662.           ckstrncpy(vvbuf,ckitoa(tt_font_size/2),VVBUFL);
  13663.           if ( tt_font_size % 2 )
  13664.               ckstrncat(vvbuf,".5",VVBUFL);
  13665.           return(vvbuf);
  13666.     }
  13667. #endif /* KUI */
  13668.  
  13669.     fnsuccess = 0;
  13670.     if (fnerror) {
  13671.         fnsuccess = 0;
  13672.     }
  13673.     if (fndiags) {
  13674.         if (!embuf)
  13675.           ckstrncpy(embuf,"<ERROR:NO_SUCH_VARIABLE>",EMBUFLEN);
  13676.         printf("?%s\n",embuf);
  13677.         return((char *)embuf);
  13678.     } else
  13679.       return("");
  13680. }
  13681. #endif /* NOSPL */
  13682.  
  13683.  
  13684. /*
  13685.   X X S T R I N G  --  Expand variables and backslash codes.
  13686.  
  13687.     int xxtstring(s,&s2,&n);
  13688.  
  13689.   Expands \ escapes via recursive descent.
  13690.   Argument s is a pointer to string to expand (source).
  13691.   Argument s2 is the address of where to put result (destination).
  13692.   Argument n is the length of the destination string (to prevent overruns).
  13693.   Returns -1 on failure, 0 on success,
  13694.     with destination string null-terminated and s2 pointing to the
  13695.     terminating null, so that subsequent characters can be added.
  13696. */
  13697.  
  13698. #define XXDEPLIM 100                    /* Recursion depth limit */
  13699. /*
  13700.   In Windows the stack is limited to 256K so big character arrays like
  13701.   vnambuf can't be on the stack in recursive functions like zzstring().
  13702.   But that's no reason use malloc() in Unix or VMS, which don't have
  13703.   this kind of restriction.
  13704. */
  13705. #ifdef DVNAMBUF                /* Dynamic vnambuf[] */
  13706. #undef DVNAMBUF                /* Clean slate */
  13707. #endif /* DVNAMBUF */
  13708.  
  13709. #ifndef NOSPL                /* Only if SPL included */
  13710. #ifdef OS2                /* Only for K95 */
  13711. #define DVNAMBUF
  13712. #endif /* OS2 */
  13713. #endif /* NOSPL */
  13714.  
  13715. int
  13716. zzstring(s,s2,n) char *s; char **s2; int *n; {
  13717.     int x,                              /* Current character */
  13718.         y,                              /* Worker */
  13719.         pp,                             /* Paren level */
  13720.         kp,                             /* Brace level */
  13721.         argn,                           /* Function argument counter */
  13722.         n2,                             /* Local copy of n */
  13723.         d,                              /* Array dimension */
  13724.         vbi,                            /* Variable id (integer form) */
  13725.         argl,                           /* String argument length */
  13726.         nx;                             /* Save original length */
  13727.  
  13728.     char vb,                            /* Variable id (char form) */
  13729.         *vp,                            /* Pointer to variable definition */
  13730.         *new,                           /* Local pointer to target string */
  13731. #ifdef COMMENT
  13732.         *old,                           /* Save original target pointer */
  13733. #endif /* COMMENT */
  13734.         *p,                             /* Worker */
  13735.         *q,                             /* Worker */
  13736.         *s3;                            /* Worker */
  13737.     int  x3;                            /* Worker */
  13738.     char *r  = (char *)0;               /* For holding function args */
  13739.     char *r2 = (char *)0;
  13740.     char *r3p;
  13741.  
  13742. #ifndef NOSPL
  13743. #ifdef DVNAMBUF
  13744.     char * vnambuf = NULL;              /* Buffer for variable/function name */
  13745. #else /* DVNAMBUF */
  13746.     char vnambuf[VNAML];                /* Buffer for variable/function name */
  13747. #endif /* DVNAMBUF */
  13748.     char *argp[FNARGS];                 /* Pointers to function args */
  13749. #endif /* NOSPL */
  13750.  
  13751.     static int depth = 0;               /* Call depth, avoid overflow */
  13752.  
  13753.     n2 = *n;                            /* Make local copies of args */
  13754.     nx = n2;
  13755.  
  13756. #ifdef COMMENT
  13757.     /* This is always 32K in BIGBUFOK builds */
  13758.     if (depth == 0)
  13759.       debug(F101,"zzstring top-level n","",n2);
  13760. #endif    /* COMMENT */
  13761.  
  13762.     new = *s2;                          /* for one less level of indirection */
  13763. #ifdef COMMENT
  13764.     old = new;
  13765. #endif /* COMMENT */
  13766.  
  13767. #ifndef NOSPL
  13768.     ispattern = 0;                      /* For \fpattern() */
  13769.     isjoin = 0;                /* For \fjoin() */
  13770. #endif /* NOSPL */
  13771.     depth++;                            /* Sink to a new depth */
  13772.     if (depth > XXDEPLIM) {             /* Too deep? */
  13773.         printf("?definition is circular or too deep\n");
  13774.         debug(F101,"zzstring fail","",depth);
  13775.         depth = 0;
  13776.         *new = NUL;
  13777.         return(-1);
  13778.     }
  13779.     if (!s || !new) {                   /* Watch out for null pointers */
  13780.         debug(F101,"zzstring fail 2","",depth);
  13781.         if (new)
  13782.           *new = NUL;
  13783.         depth = 0;
  13784.         return(-1);
  13785.     }
  13786.     s3 = s;
  13787.     argl = 0;
  13788.     while (*s3++) argl++;              /* Get length of source string */
  13789.     debug(F010,"zzstring entry",s,0);
  13790.     if (argl == 0) {                    /* Empty string */
  13791.         debug(F111,"zzstring empty arg",s,argl);
  13792.         depth = 0;
  13793.         *new = NUL;
  13794.         return(0);
  13795.     }
  13796.     if (argl < 0) {                     /* Watch out for garbage */
  13797.         debug(F101,"zzstring fail 3","",depth);
  13798.         *new = NUL;
  13799.         depth = 0;
  13800.         return(-1);
  13801.     }
  13802. #ifdef DVNAMBUF
  13803.     debug(F100,"vnambuf malloc...","",0);
  13804.     vnambuf = malloc(VNAML);
  13805.     if (vnambuf == NULL) {
  13806.         printf("?Out of memory");
  13807.         return(-1);
  13808.     }
  13809.     debug(F100,"vnambuf malloc ok","",0);
  13810. #endif /* DVNAMBUF */
  13811.  
  13812.     while ((x = *s)) {                  /* Loop for all characters */
  13813.         if (x != CMDQ) {                /* Is it the command-quote char? */
  13814.             *new++ = *s++;              /* No, normal char, just copy */
  13815.             if (--n2 < 0) {             /* and count it, careful of overflow */
  13816.                 debug(F101,"zzstring overflow 1","",depth);
  13817.                 depth = 0;
  13818. #ifdef DVNAMBUF
  13819.                 if (vnambuf) free(vnambuf);
  13820. #endif /* DVNAMBUF */
  13821.                 return(-1);
  13822.             }
  13823.             continue;
  13824.         }
  13825.  
  13826. /* We have the command-quote character. */
  13827.  
  13828.         x = *(s+1);                     /* Get the following character. */
  13829.         if (isupper(x)) x = tolower(x);
  13830.         switch (x) {                    /* Act according to variable type */
  13831. #ifndef NOSPL
  13832.           case 0:                       /* It's a lone backslash */
  13833.             *new++ = *s++;
  13834.             if (--n2 < 0) {
  13835.                 debug(F101,"zzstring overflow 2","",0);
  13836. #ifdef DVNAMBUF
  13837.                 if (vnambuf) free(vnambuf);
  13838. #endif /* DVNAMBUF */
  13839.                 return(-1);
  13840.             }
  13841.             break;
  13842.           case '%':                     /* Variable */
  13843.             s += 2;                     /* Get the letter or digit */
  13844.             vb = *s++;                  /* and move source pointer past it */
  13845.             vp = NULL;                  /* Assume definition is empty */
  13846.             if (vb >= '0' && vb <= '9') { /* Digit for macro arg */
  13847.                 if (maclvl < 0)         /* Digit variables are global */
  13848.                   vp = g_var[vb];       /* if no macro is active */
  13849.                 else                    /* otherwise */
  13850.                   vp = m_arg[maclvl][vb - '0']; /* they're on the stack */
  13851.             } else if (vb == '*') {     /* Macro args string */
  13852. #ifdef COMMENT
  13853.                 /* This doesn't take changes into account */
  13854.                 vp = (maclvl >= 0) ? m_line[maclvl] : topline;
  13855.                 if (!vp) vp = "";
  13856. #else
  13857.         char * ss = new;
  13858.                 if (zzstring("\\fjoin(&_[],,1)",&new,&n2) < 0) {
  13859. #ifdef DVNAMBUF
  13860.             if (vnambuf) free(vnambuf);
  13861. #endif /* DVNAMBUF */
  13862.             return(-1);
  13863.         }
  13864.         debug(F110,"zzstring \\%*",ss,0);
  13865.                 break;
  13866. #endif /* COMMENT */
  13867.             } else {
  13868.                 if (isupper(vb)) vb += ('a'-'A');
  13869.                 vp = g_var[vb];         /* Letter for global variable */
  13870.             }
  13871.             if (!vp) vp = "";
  13872. #ifdef COMMENT
  13873.             if (vp) {                   /* If definition not empty */
  13874. #endif /* COMMENT */
  13875.                 debug(F010,"zzstring %n vp",vp,0);
  13876.                 if (zzstring(vp,&new,&n2) < 0) { /* call self to evaluate it */
  13877.                     debug(F101,"zzstring fail 6","",depth);
  13878. #ifdef DVNAMBUF
  13879.                     if (vnambuf) free(vnambuf);
  13880. #endif /* DVNAMBUF */
  13881.                     return(-1);         /* Pass along failure */
  13882.                 }
  13883. #ifdef COMMENT
  13884.             } else {
  13885.                 debug(F110,"zzstring %n vp","(NULL)",0);
  13886.                 n2 = nx;
  13887.                 new = old;
  13888.                 *new = NUL;
  13889.             }
  13890. #endif /* COMMENT */
  13891.             break;
  13892.           case '&':                     /* An array reference */
  13893.             x = arraynam(s,&vbi,&d);    /* Get name and subscript */
  13894.             debug(F111,"zzstring arraynam",s,x);
  13895.             if (x < 0) {
  13896.                 debug(F101,"zzstring fail 7","",depth);
  13897. #ifdef DVNAMBUF
  13898.                 if (vnambuf) free(vnambuf);
  13899. #endif /* DVNAMBUF */
  13900.                 return(-1);
  13901.             }
  13902.             pp = 0;                     /* Bracket counter */
  13903.             while (*s) {                /* Advance source pointer... */
  13904.                 if (*s == '[') pp++;
  13905.                 if (*s == ']' && --pp == 0) break;
  13906.                 s++;
  13907.             }
  13908.             if (*s == ']') s++;         /* ...past the closing bracket. */
  13909.  
  13910.             x = chkarray(vbi,d);        /* Array is declared? */
  13911.             debug(F101,"zzstring chkarray","",x);
  13912.             if (x > 0) {
  13913. #ifdef COMMENT
  13914.                 char * s1 = NULL;
  13915. #endif /* COMMENT */
  13916.                 vbi -= ARRAYBASE;       /* Convert name to index */
  13917.  
  13918. #ifdef COMMENT
  13919.                 if (vbi == 0) {         /* Argument vector array */
  13920.                     extern char ** toparg, ** m_xarg[];
  13921.                     extern int n_xarg[];
  13922.                     if (maclvl < 0) {
  13923.                         if (topargc >= d) {
  13924.                             s1 = toparg[d];
  13925.                         }
  13926.                     } else {
  13927.                         if (n_xarg[maclvl] >= d) {
  13928.                             s1 = m_xarg[maclvl][d];
  13929.                         }
  13930.                     }
  13931.                     if (s1) {
  13932.                         if (zzstring(s1,&new,&n2) < 0) { /* evaluate */
  13933.                             debug(F101,"zzstring fail 7.5","",depth);
  13934. #ifdef DVNAMBUF
  13935.                             if (vnambuf) free(vnambuf);
  13936. #endif /* DVNAMBUF */
  13937.                             return(-1); /* Pass along failure */
  13938.                         }
  13939.                     } else {
  13940.                         /* old = new; */
  13941.                         n2 = nx;
  13942.                     }
  13943.                 } else
  13944. #endif /* COMMENT */
  13945.                   if (a_dim[vbi] >= d) { /* If subscript in range */
  13946.                     char **ap;
  13947. #ifndef COMMENT
  13948.                     debug(F110,"zzstring a_ptr[vbi]",a_ptr[vbi],0);
  13949.                     debug(F110,"zzstring a_ptr[vbi][d]",a_ptr[vbi][d],0);
  13950. #endif /* COMMENT */
  13951.                     ap = a_ptr[vbi];    /* get data pointer */
  13952.                     if (ap) {           /* and if there is one */
  13953.                         if (ap[d]) {    /* If definition not empty */
  13954.                             debug(F111,"zzstring ap[d]",ap[d],d);
  13955.                             if (zzstring(ap[d],&new,&n2) < 0) { /* evaluate */
  13956.                                 debug(F101,"zzstring fail 8","",depth);
  13957. #ifdef DVNAMBUF
  13958.                                 if (vnambuf) free(vnambuf);
  13959. #endif /* DVNAMBUF */
  13960.                                 return(-1); /* Pass along failure */
  13961.                             }
  13962.                         }
  13963.                     } else {
  13964.                         /* old = new; */
  13965.                         n2 = nx;
  13966.                     }
  13967.                 }
  13968.         }
  13969.             break;
  13970.  
  13971.           case 'f':                     /* A builtin function */
  13972.             q = vnambuf;                /* Copy the name */
  13973.             y = 0;                      /* into a separate buffer */
  13974.             s += 2;                     /* point past 'F' */
  13975.             while (y++ < VNAML) {
  13976.                 if (*s == '(') { s++; break; } /* Look for open paren */
  13977.                 if ((*q = *s) == NUL) break;   /* or end of string */
  13978.                 s++; q++;
  13979.             }
  13980.             *q = NUL;                   /* Terminate function name */
  13981.             if (y >= VNAML) {           /* Handle pathological case */
  13982.                 while (*s && (*s != '(')) /* of very long string entered */
  13983.                   s++;                    /* as function name. */
  13984.                 if (*s == ')') s++;       /* Skip past it. */
  13985.             }
  13986.             r = r2 = malloc(argl+2);    /* And make a place to copy args */
  13987.             /* debug(F101,"zzstring r2","",r2); */
  13988.             if (!r2) {                  /* Watch out for malloc failure */
  13989.                 debug(F101,"zzstring fail 9","",depth);
  13990.                 *new = NUL;
  13991.                 depth = 0;
  13992. #ifdef DVNAMBUF
  13993.                 if (vnambuf) free(vnambuf);
  13994. #endif /* DVNAMBUF */
  13995.                 return(-1);
  13996.             }
  13997.             if (r3) free(r3); /* And another to copy literal arg string */
  13998.             r3 = malloc(argl+2);
  13999.             /* debug(F101,"zzstring r3","",r3); */
  14000.             if (!r3) {
  14001.                 debug(F101,"zzstring fail 10","",depth);
  14002.                 depth = 0;
  14003.                 *new = NUL;
  14004.                 if (r2) free(r2);
  14005. #ifdef DVNAMBUF
  14006.                 if (vnambuf) free(vnambuf);
  14007. #endif /* DVNAMBUF */
  14008.                 return(-1);
  14009.             } else
  14010.               r3p = r3;
  14011.             argn = 0;                   /* Argument counter */
  14012.             argp[argn++] = r;           /* Point to first argument */
  14013.             y = 0;                      /* Completion flag */
  14014.             pp = 1;                     /* Paren level (already have one). */
  14015.             kp = 0;
  14016.             while (1) {                 /* Copy each argument, char by char. */
  14017.                 *r3p++ = *s;            /* This is a literal copy for \flit */
  14018.                 if (!*s) break;
  14019.  
  14020.                 if (*s == '{') {        /* Left brace */
  14021.                     kp++;
  14022.                 }
  14023.                 if (*s == '}') {        /* Right brace */
  14024.                     kp--;
  14025.                 }
  14026.                 if (*s == '(' && kp <= 0) { /* Open paren not in brace */
  14027.                     pp++;               /* Count it */
  14028.                 }
  14029.                 *r = *s;                /* Now copy resulting byte */
  14030.                 if (!*r)                /* If NUL, done. */
  14031.                   break;
  14032.                 if (*r == ')' && kp <= 0) { /* Closing paren, count it. */
  14033.                     if (--pp == 0) {    /* Final one? */
  14034.                         *r = NUL;       /* Make it a terminating null */
  14035.                         *(r3p - 1) = NUL;
  14036.                         s++;            /* Point past it in source string */
  14037.                         y = 1;          /* Flag we've got all the args */
  14038.                         break;          /* Done with while loop */
  14039.                     }
  14040.                 }
  14041.                 if (*r == ',' && kp <= 0) { /* Comma */
  14042.                     if (pp == 1) {          /* If not within ()'s, */
  14043.                         if (argn >= FNARGS) { /* Too many args */
  14044.                             s++; r++;   /* Keep collecting flit() string */
  14045.                             continue;
  14046.                         }
  14047.                         *r = NUL;           /* New arg, skip past comma */
  14048.                         argp[argn++] = r+1; /* In range, point to new arg */
  14049.                     }                   /* Otherwise just skip past  */
  14050.                 }
  14051.                 s++; r++;               /* Advance pointers */
  14052.             }
  14053.             if (!y)                     /* If we didn't find closing paren */
  14054.               argn = -1;
  14055. #ifdef DEBUG
  14056.             if (deblog) {
  14057.                 char buf[24];
  14058.                 debug(F111,"zzstring function name",vnambuf,y);
  14059.                 debug(F010,"zzstring function r3",r3,0);
  14060.                 for (y = 0; y < argn; y++) {
  14061.                     sprintf(buf,"arg %2d ",y);
  14062.                     debug(F010,buf,argp[y],0);
  14063.                 }
  14064.             }
  14065. #endif /* DEBUG */
  14066.             vp = fneval(vnambuf,argp,argn,r3); /* Evaluate the function. */
  14067.             if (vp) {                      /* If definition not empty */
  14068.                 while ((*new++ = *vp++)) { /* copy it to output string */
  14069.                     if (--n2 < 0) {        /* watch out for overflow */
  14070.                         debug(F101,"zzstring fail 12","",depth);
  14071.                         if (r2) { free(r2); r2 = NULL; }
  14072.                         if (r3) { free(r3); r3 = NULL; }
  14073. #ifdef DVNAMBUF
  14074.                         if (vnambuf) free(vnambuf);
  14075. #endif /* DVNAMBUF */
  14076.                         return(-1);
  14077.                     }
  14078.                 }
  14079.                 new--;                  /* Back up over terminating null */
  14080.                 n2++;                   /* to allow for further deposits. */
  14081.             }
  14082.             if (r2) { free(r2); r2 = NULL; }
  14083.             if (r3) { free(r3); r3 = NULL; }
  14084.             break;
  14085.           case '$':                     /* An environment variable */
  14086.           case 'v':                     /* Or a named builtin variable. */
  14087.           case 'm':                     /* Or a macro /long variable */
  14088.           case 's':                     /* 196 Macro substring */
  14089.           case ':':                     /* 196 \-variable substring */
  14090.             pp = 0;
  14091.             p = s+2;                    /* $/V/M must be followed by (name) */
  14092.             if (*p != '(') {            /* as in \$(HOME) or \V(count) */
  14093.                 *new++ = *s++;          /* If not, just copy it */
  14094.                 if (--n2 < 0) {
  14095.                     debug(F101,"zzstring overflow 3","",depth);
  14096. #ifdef DVNAMBUF
  14097.                     if (vnambuf) free(vnambuf);
  14098. #endif /* DVNAMBUF */
  14099.                     return(-1);
  14100.                 }
  14101.                 break;
  14102.             }
  14103.             pp++;
  14104.             p++;                        /* Point to 1st char of name */
  14105.             q = vnambuf;                /* Copy the name */
  14106.             y = 0;                      /* into a separate buffer */
  14107.             while (y++ < VNAML) {       /* Watch out for name too long */
  14108.                 if (*p == '(') {        /* Parens can be nested... */
  14109.                     pp++;
  14110.                 } else if (*p == ')') { /* Name properly terminated with ')' */
  14111.                     pp--;
  14112.                     if (pp == 0) {
  14113.                         p++;            /* Move source pointer past ')' */
  14114.                         break;
  14115.                     }
  14116.                 }
  14117.                 if ((*q = *p) == NUL)   /* String ends before ')' */
  14118.                   break;
  14119.                 p++; q++;               /* Advance pointers */
  14120.             }
  14121.             *q = NUL;                   /* Terminate the variable name */
  14122.             if (y >= VNAML) {           /* Handle pathological case */
  14123.                 while (*p && (*p != ')')) /* of very long string entered */
  14124.                   p++;                    /* as variable name. */
  14125.                 if (*p == ')') p++;       /* Skip ahead to the end of it. */
  14126.             }
  14127.             s = p;                      /* Adjust global source pointer */
  14128.             s3 = vnambuf;
  14129.             x3 = 0;
  14130.             while (*s3++) x3++;
  14131.             p = malloc(x3 + 1);         /* Make temporary space */
  14132.             if (p) {                    /* If we got the space */
  14133.                 vp = vnambuf;           /* Point to original */
  14134.                 strcpy(p,vp);           /* (safe) Make a copy of it */
  14135.                 y = VNAML;              /* Length of name buffer */
  14136.                 zzstring(p,&vp,&y);     /* Evaluate the copy */
  14137.                 free(p);                /* Free the temporary space */
  14138.                 p = NULL;
  14139.             }
  14140.             debug(F110,"zzstring vname",vnambuf,0);
  14141.             q = NULL;
  14142.             if (x == '$') {             /* Look up its value */
  14143.                 vp = getenv(vnambuf);   /* This way for environment variable */
  14144.             } else if (x == 'm' || x == 's' || x == ':') { /* Macro / substr */
  14145.                 int k, x1 = -1, x2 = -1;
  14146.         CHAR c = NUL; 
  14147.                 k = strlen(vnambuf);
  14148.                 /* \s(name[n:m]) -- Compact substring notation */
  14149.                 if ((x == 's' || x == ':') && (k > 1)) { /* Substring wanted */
  14150.                     if (vnambuf[k-1] == ']') {
  14151.                         int i;
  14152.                         for (i = k-1; i > 0; i--) {
  14153.                             if (vnambuf[i] == '[') {
  14154.                 int j = i+1; /* Point past open bracket */
  14155.                 /* Skip past any sign */
  14156.                 if (vnambuf[j] == '-' || vnambuf[j] == '+')
  14157.                   j++;
  14158.                 for (; j < k; j++) {
  14159.                     if (!isdigit(vnambuf[j])) {
  14160.                     c = vnambuf[j];
  14161.                     vnambuf[j] = NUL;
  14162.                     x1 = atoi(&vnambuf[i+1]);
  14163.                     vnambuf[j] = c;
  14164.                     j++;
  14165.                     break;
  14166.                     }
  14167.                 }
  14168.                 if (x1 < 1)
  14169.                   x1 = 1;
  14170.                 x1--;    /* Adjust start pos to 0-base */
  14171.                 if (c == ':' || c == '-')
  14172.                   x2 = atoi(&vnambuf[j]);
  14173.                 vnambuf[i] = NUL;
  14174.                 break;
  14175.                             }
  14176.                         }
  14177.                     }
  14178.                 }
  14179.                 if (x == ':') {
  14180.                     vp = vnambuf;
  14181.                 } else {
  14182.             y = isaarray(vnambuf) ?
  14183.             mxxlook(mactab,vnambuf,nmac) :
  14184.             mxlook(mactab,vnambuf,nmac);
  14185.                     if (y > -1) {    /* Got definition */
  14186.                         vp = mactab[y].mval;
  14187.                     } else {
  14188.                         vp = NULL;
  14189.                     }
  14190.                 }
  14191.         debug(F111,"zzstring vp",vp,(vp==NULL)?0:strlen(vp));
  14192.  
  14193.                 if (vp) {
  14194.                     if ((x == 's' || x == ':') && (k > 1)) {
  14195.                         /* Compact substring notation */
  14196.                         if (x2 == 0) {  /* Length */
  14197.                             vp = NULL;
  14198.                         } else if (x1 > -1) { /* Start */
  14199.                             k = strlen(vp);
  14200.                 /* If it's off the end, result is empty */
  14201.                             if (x1 > k) { 
  14202.                                 vp = NULL;
  14203.                             } else if (k > 0) {
  14204.                 /* Stay in bounds */
  14205.                 if (c == '-' && x2 > k)
  14206.                   x2 = k;
  14207.                 if (c == ':' && x1 + x2 > k)
  14208.                   x2 = -1;
  14209.                                 if ((q = malloc(k+1))) {
  14210.                                     strcpy(q,vp); /* safe */
  14211.                     if (c == ':') { /* start:length */
  14212.                     if ((x2 > -1) && ((x1 + x2) <= k)) {
  14213.                         q[x1+x2] = NUL;
  14214.                     }
  14215.                     debug(F000,"XXX q",q,c);
  14216.                     } else if (c == '-') { /* start-endpos */
  14217.                     if (x1 >= x2) {
  14218.                         q[x1 = 0] = NUL;
  14219.                     } else if (x2 < k && x2 > -1) {
  14220.                         q[x2] = NUL;
  14221.                     }
  14222.                     debug(F000,"XXX q",q,c);
  14223.                     }
  14224.                     vp = q+x1;
  14225.                                 } else vp = NULL;
  14226.                             } else vp = NULL;
  14227.                         }
  14228.  
  14229.             debug(F110,"XXX vnambuf",vnambuf,0);
  14230.             debug(F000,"XXX c","",c);
  14231.             debug(F101,"XXX x1","",x1);
  14232.             debug(F101,"XXX x2","",x2);
  14233.             debug(F110,"XXX result",vp,0);
  14234. #ifdef DEBUG
  14235.                         if (deblog) {
  14236.                             if (!vp) {
  14237.                             } else {
  14238.                                 k = strlen(vp);
  14239.                             }
  14240.                         }
  14241. #endif /* DEBUG */
  14242.                     }
  14243.                 }
  14244.             } else {                    /* or */
  14245.                 vp = nvlook(vnambuf);   /* this way for builtin variable */
  14246.             }
  14247.             if (vp) {                   /* If definition not empty */
  14248.                 while ((*new++ = *vp++)) /* copy it to output string. */
  14249.                   if (--n2 < 0) {
  14250.                       if (q) free(q);
  14251.                       debug(F101,"zzstring overflow 4","",depth);
  14252. #ifdef DVNAMBUF
  14253.                       if (vnambuf) free(vnambuf);
  14254. #endif /* DVNAMBUF */
  14255.                       return(-1);
  14256.                   }
  14257.                 new--;                  /* Back up over terminating null */
  14258.                 n2++;                   /* to allow for further deposits. */
  14259.             }
  14260.             if (q) {
  14261.                 free(q);
  14262.                 q = NULL;
  14263.             }
  14264.             break;
  14265. #endif /* NOSPL */                      /* Handle \nnn even if NOSPL. */
  14266.  
  14267. #ifndef NOKVERBS
  14268.         case 'K':
  14269.         case 'k': {
  14270.             extern struct keytab kverbs[];
  14271.             extern int nkverbs;
  14272. #define K_BUFLEN 30
  14273.             char kbuf[K_BUFLEN + 1];    /* Key verb name buffer */
  14274.             int x, y, z, brace = 0;
  14275.             s += 2;
  14276. /*
  14277.   We assume that the verb name is {braced}, or it extends to the end of the
  14278.   string, s, or it ends with a space, control character, or backslash.
  14279. */
  14280.             p = kbuf;                   /* Copy verb name into local buffer */
  14281.             x = 0;
  14282.             if (*s == '{')  {
  14283.                 s++;
  14284.                 brace++;
  14285.             }
  14286.             while ((x++ < K_BUFLEN) && (*s > SP) && (*s != CMDQ)) {
  14287.                 if (brace && *s == '}') {
  14288.                     s++;
  14289.                     break;
  14290.                 }
  14291.                 *p++ = *s++;
  14292.             }
  14293.             brace = 0;
  14294.             *p = NUL;                   /* Terminate. */
  14295.             p = kbuf;                   /* Point back to beginning */
  14296.             debug(F110,"zzstring kverb",p,0);
  14297.             y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */
  14298.             debug(F101,"zzstring lookup",0,y);
  14299.             if (y > -1) {
  14300.                 dokverb(VCMD,y);
  14301. #ifndef NOSPL
  14302.             } else {                    /* Is it a macro? */
  14303.                 y = mxlook(mactab,p,nmac);
  14304.                 if (y > -1) {
  14305.                     debug(F111,"zzstring mxlook",p,y);
  14306.                     if ((z = dodo(y,NULL,cmdstk[cmdlvl].ccflgs)) > 0) {
  14307.                         if (cmpush() > -1) {  /* Push command parser state */
  14308.                             extern int ifc;
  14309.                             int ifcsav = ifc; /* Push IF condition on stack */
  14310.                             y = parser(1);    /* New parser to execute macro */
  14311.                             cmpop();          /* Pop command parser */
  14312.                             ifc = ifcsav;     /* Restore IF condition */
  14313.                             if (y == 0) {     /* No errors, ignore actions */
  14314.                                 p = mrval[maclvl+1]; /* If OK set return val */
  14315.                                 if (p == NULL) p = "";
  14316.                             }
  14317.                         } else {                /* Can't push any more */
  14318.                             debug(F101,"zzstring pushed too deep","",depth);
  14319.                             printf(
  14320.                                "\n?Internal error: zzstring stack overflow\n"
  14321.                                    );
  14322.                             while (cmpop() > -1);
  14323.                             p = "";
  14324.                         }
  14325.                     }
  14326.                 }
  14327. #endif /* NOSPL */
  14328.             }
  14329.             break;
  14330.         }
  14331. #endif /* NOKVERBS */
  14332.  
  14333.         default:                        /* Maybe it's a backslash code */
  14334.           y = xxesc(&s);                /* Go interpret it */
  14335.           if (y < 0) {                  /* Upon failure */
  14336.               *new++ = (char) x;        /* Just quote the next character */
  14337.               s += 2;                   /* Move past the pair */
  14338.               n2 -= 2;
  14339.               if (n2 < 0) {
  14340.                   debug(F101,"zzstring overflow 5","",depth);
  14341. #ifdef DVNAMBUF
  14342.                   if (vnambuf) free(vnambuf);
  14343. #endif /* DVNAMBUF */
  14344.                   return(-1);
  14345.               }
  14346.               continue;                 /* and go back for more */
  14347.           } else {
  14348.               *new++ = (char) y;        /* else deposit interpreted value */
  14349.               if (--n2 < 0) {
  14350.                   debug(F101,"zzstring overflow 6","",depth);
  14351. #ifdef DVNAMBUF
  14352.                   if (vnambuf) free(vnambuf);
  14353. #endif /* DVNAMBUF */
  14354.                   return(-1);
  14355.               }
  14356.           }
  14357.         }
  14358.     }
  14359.     *new = NUL;                         /* Terminate the new string */
  14360.     debug(F010,"zzstring while exit",*s2,0);
  14361.  
  14362.     depth--;                            /* Adjust stack depth gauge */
  14363.     *s2 = new;                          /* Copy results back into */
  14364.     *n = n2;                            /* the argument addresses */
  14365.     debug(F101,"zzstring ok","",depth);
  14366. #ifdef DVNAMBUF
  14367.     if (vnambuf) free(vnambuf);
  14368. #endif /* DVNAMBUF */
  14369.     return(0);                          /* and return. */
  14370. }
  14371. #endif /* NOICP */
  14372.