home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / cku196.zip / ckuus4.c < prev    next >
C/C++ Source or Header  |  1999-12-31  |  400KB  |  11,574 lines

  1. #include "ckcsym.h"
  2.  
  3. /*  C K U U S 4 --  "User Interface" for C-Kermit, part 4  */
  4.  
  5. /*
  6.   Author: Frank da Cruz <fdc@columbia.edu>,
  7.   Columbia University Academic Information Systems, New York City.
  8.  
  9.   Copyright (C) 1985, 2000,
  10.     Trustees of Columbia University in the City of New York.
  11.     All rights reserved.  See the C-Kermit COPYING.TXT file or the
  12.     copyright text in the ckcmai.c module for disclaimer and permissions.
  13. */
  14.  
  15. /*
  16.   File ckuus4.c -- Functions moved from other ckuus*.c modules to even
  17.   out their sizes.
  18. */
  19. #include "ckcdeb.h"
  20. #include "ckcasc.h"
  21. #include "ckcker.h"
  22. #include "ckuusr.h"
  23. #include "ckuver.h"
  24. #include "ckcnet.h"                     /* Network symbols */
  25. #include "ckcxla.h"                     /* Character sets */
  26.  
  27. #ifdef CK_AUTHENTICATION
  28. #include "ckuath.h"
  29. #endif /* CK_AUTHENTICATION */
  30. #ifdef CK_SSL
  31. #include "ck_ssl.h"
  32. #endif /* CK_SSL */
  33.  
  34. #ifdef VMS
  35. #include <errno.h>                      /* For \v(errno) */
  36. extern char * ckvmserrstr(unsigned long);
  37. #ifndef OLD_VMS
  38. #include <lib$routines.h>               /* Not for VAX C 2.4 */
  39. #else
  40. #include <libdef.h>
  41. #endif /* OLD_VMS */
  42. _PROTOTYP(int vmsttyfd, (void) );
  43. #endif /* VMS */
  44.  
  45. #ifdef OS2
  46. #ifndef NT
  47. #define INCL_NOPM
  48. #define INCL_VIO                        /* Needed for ckocon.h */
  49. #include <os2.h>
  50. #undef COMMENT
  51. #else
  52. #include <windows.h>
  53. #include <tapi.h>
  54. #include "ckntap.h"
  55. #define APIRET ULONG
  56. #endif /* NT */
  57. #include "ckocon.h"
  58. #include "ckoetc.h"
  59. int StartedFromDialer = 0;
  60. HWND hwndDialer = 0;
  61. LONG KermitDialerID = 0;
  62. #ifdef putchar
  63. #undef putchar
  64. #endif /* putchar */
  65. #define putchar(x) conoc(x)
  66. #ifdef CK_PID
  67. #include <process.h>
  68. #endif /* CK_PID */
  69. #endif /* OS2 */
  70.  
  71. extern xx_strp xxstring;
  72.  
  73. #ifdef DEC_TCPIP
  74. #include <descrip>
  75. #include <dvidef>
  76. #include <dcdef>
  77. #endif /* DEC_TCPIP */
  78.  
  79. #ifdef FNFLOAT
  80. #include <math.h>                       /* Floating-point functions */
  81. #endif /* FNFLOAT */
  82.  
  83. extern int quiet, network, xitsta, escape, nopush, xferstat,
  84.   exitonclose, tn_exit, ttnproto, autodl, flow, byteorder;
  85.  
  86. extern char * k_info_dir;
  87.  
  88. #ifndef MAC
  89. #ifndef AMIGA
  90. extern int ttyfd;
  91. #endif /* MAC */
  92. #endif /* AMIGA */
  93.  
  94. #ifdef TNCODE
  95. extern int tn_nlm, tn_b_nlm, tn_b_xfer, tn_sb_bug;
  96. extern int tn_rem_echo;
  97. extern int tn_b_meu, tn_b_ume;
  98. #endif /* TNCODE */
  99.  
  100. char * xferfile = NULL;
  101. int xferlog = 0;
  102.  
  103. extern int local, xargc, stayflg, rcflag, bgset, cfilef,
  104.   inserver, srvcdmsg, success;
  105.  
  106. extern char cmdfil[], *versio, *ckxsys, **xargv;
  107. #ifdef DEBUG
  108. extern char debfil[];                   /* Debug log file name */
  109. #endif /* DEBUG */
  110.  
  111. extern int noinit;
  112.  
  113. #ifndef NOICP                           /* Most of this file... */
  114.  
  115. #ifndef AMIGA
  116. #ifndef MAC
  117. #include <signal.h>
  118. #endif /* MAC */
  119. #endif /* AMIGA */
  120.  
  121. #ifdef STRATUS                          /* Stratus Computer, Inc.  VOS */
  122. #ifdef putchar
  123. #undef putchar
  124. #endif /* putchar */
  125. #define putchar(x) conoc(x)
  126. #ifdef getchar
  127. #undef getchar
  128. #endif /* getchar */
  129. #define getchar(x) coninc(0)
  130. #endif /* STRATUS */
  131.  
  132.  
  133. #ifdef ANYX25
  134. extern int revcall, closgr, cudata;
  135. int x25ver;
  136. extern char udata[];
  137. #ifndef IBMX25
  138. extern int npadx3;
  139. extern CHAR padparms[];
  140. extern struct keytab padx3tab[];
  141. #endif /* !IBMX25 */
  142. #ifdef IBMX25
  143. /* global variables only available for IBM X.25 - possibly interesting for
  144.  * other implementations
  145.  */
  146. extern x25addr_t local_nua;
  147. extern x25addr_t remote_nua;
  148. #endif /* IBMX25 */
  149. #endif /* ANYX25 */
  150.  
  151. #ifdef NETCONN
  152. #ifndef NODIAL
  153. extern int nnetdir;
  154. extern char *netdir[];
  155. #endif /* NODIAL */
  156. extern char ipaddr[];
  157.  
  158. #ifdef CK_NETBIOS
  159. extern unsigned short netbiosAvail;
  160. extern unsigned long NetbeuiAPI;
  161. extern unsigned char NetBiosName[];
  162. extern unsigned char NetBiosAdapter;
  163. extern unsigned char NetBiosLSN;
  164. #endif /* CK_NETBIOS */
  165.  
  166. #ifdef TCPSOCKET
  167. extern char myipaddr[];
  168. extern int tcp_rdns;
  169. #ifdef CK_DNS_SRV
  170. extern int tcp_dns_srv;
  171. #endif /* CK_DNS_SRV */
  172.  
  173. #ifndef NOTCPOPTS
  174. #ifdef SOL_SOCKET
  175. #ifdef SO_LINGER
  176. extern int tcp_linger;
  177. extern int tcp_linger_tmo;
  178. #endif /* SO_LINGER */
  179. #ifdef SO_DONTROUTE
  180. extern int tcp_dontroute;
  181. #endif /* SO_DONTROUTE */
  182. #ifdef TCP_NODELAY
  183. extern int tcp_nodelay;
  184. #endif /* TCP_NODELAY */
  185. #ifdef SO_SNDBUF
  186. extern int tcp_sendbuf;
  187. #endif /* SO_SNDBUF */
  188. #ifdef SO_RCVBUF
  189. extern int tcp_recvbuf;
  190. #endif /* SO_RCVBUF */
  191. #ifdef SO_KEEPALIVE
  192. extern int tcp_keepalive;
  193. #endif /* SO_KEEPALIVE */
  194. #endif /* SOL_SOCKET */
  195. #endif /* NOTCPOPTS */
  196. #endif /* TCPSOCKET */
  197. #endif /* NETCONN */
  198.  
  199. extern char * floname[];
  200.  
  201. #ifndef NOSPL
  202. extern int fndiags;                     /* Function diagnostics on/off */
  203. int ispattern = 0;
  204. #ifdef CK_APC
  205. extern int apcactive;                   /* Nonzero = APC command was rec'd */
  206. extern int apcstatus;                   /* Are APC commands being processed? */
  207. #ifdef DCMDBUF
  208. extern char *apcbuf;                    /* APC command buffer */
  209. #else
  210. extern char apcbuf[];
  211. #endif /* DCMDBUF */
  212. #endif /* CK_APC */
  213.  
  214. extern char evalbuf[];                  /* EVALUATE result */
  215. extern char uidbuf[], pwbuf[], prmbuf[];
  216. _PROTOTYP( static char * fneval, (char *, char * [], int, char * ) );
  217. _PROTOTYP( static VOID myflsh, (void) );
  218. _PROTOTYP( static char * getip, (char *) );
  219.  
  220. static char hexdigits[16] = {
  221.     '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
  222. };
  223. extern char * tempdir;
  224.  
  225. #ifdef CK_REXX
  226. extern char rexxbuf[];
  227. #endif /* CK_REXX */
  228.  
  229. extern int tfline[];
  230.  
  231. /* These need to be internationalized... */
  232.  
  233. static
  234. char *wkdays[] = {
  235.     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  236. };
  237. #endif /* NOSPL */
  238.  
  239. char *months[] = {
  240.     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  241.     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  242. };
  243.  
  244. #ifdef OS2
  245. _PROTOTYP (int os2getcp, (void) );
  246. #ifdef TCPSOCKET
  247. extern char tcpname[];
  248. #endif /* TCPSOCKET */
  249. extern char startupdir[],exedir[];
  250. extern int tcp_avail;
  251. #ifdef DECNET
  252. extern int dnet_avail;
  253. #endif /* DECNET */
  254. #ifdef SUPERLAT
  255. extern int slat_avail;
  256. #endif /* SUPERLAT */
  257.  
  258. extern int tt_type, max_tt;
  259. extern struct tt_info_rec tt_info[];
  260. extern int tt_rows[], tt_cols[];
  261. #else /* OS2 */
  262. extern int tt_rows, tt_cols;
  263. #endif /* OS2 */
  264.  
  265. #ifdef CK_TAPI
  266. extern int tttapi;
  267. extern int tapipass;
  268. extern struct keytab * tapilinetab;
  269. extern struct keytab * _tapilinetab;
  270. extern int ntapiline;
  271. #endif /* CK_TAPI */
  272.  
  273. #ifdef VMS
  274. extern char startupdir[];
  275. #endif /* VMS */
  276.  
  277. #ifdef UNIX
  278. extern char startupdir[];
  279. #endif /* UNIX */
  280.  
  281. extern struct keytab colxtab[];
  282. extern int ncolx;
  283.  
  284. extern char ttname[], *zinptr, *kermrc;
  285. extern char inidir[];
  286.  
  287. extern int activecmd, remonly, cmd_rows, cmd_cols, parity, seslog,
  288.   sessft, sosi, hwparity, tsecs, xargs, zincnt, tlevel, insilence, cmdmsk,
  289.   timint, timef, inbufsize, dialog, binary, carrier, cdtimo, cmask, duplex,
  290.   fmask, inecho, nettype, nmac, turnch, turn, kbchar;
  291.  
  292. #ifndef NOXFER
  293. extern CHAR eol,  mypadc, mystch, padch, seol, stchr, * epktmsg, feol;
  294. extern char *cksysid;
  295. extern struct ck_p ptab[];
  296. extern int
  297.   protocol, prefixing, xfrbel, xfrcan, xfrint, xfrchr, xfrnum, pktpaus,
  298.   lscapr, lscapu, xfermode, dest, slostart, maxrps, maxsps, maxtry, mypadn,
  299.   npad, pkttim, bigrbsiz, bigsbsiz, keep, atcapr, autopar, bctr, bctu,
  300.   crunched, ckdelay, ebq, ebqflg, pktlog, retrans, rpackets, rptflg, rptq,
  301.   rtimo, spackets, spsiz, spsizf, spsizr, timeouts, fncact, fncnv, urpsiz,
  302.   wmax, wslotn, wslotr, fdispla, spmax, fnrpath, fnspath, crc16;
  303. #endif /* NOXFER */
  304.  
  305. #ifdef OS2
  306. extern int zxpn;
  307. extern int viewonly;
  308. #endif /* OS2 */
  309.  
  310. #ifndef NOXFER
  311. #ifdef GFTIMER
  312. extern CKFLOAT fptsecs, fpxfsecs;
  313. #endif /* GFTIMER */
  314. extern long xfsecs, tfcps;
  315.  
  316. #ifdef CK_TMPDIR
  317. extern char *dldir;
  318. #endif /* CK_TMPDIR */
  319. #endif /* NOXFER */
  320.  
  321. #ifdef RECURSIVE
  322. extern int recursive;
  323. #endif /* RECURSIVE */
  324.  
  325. #ifdef VMS
  326.   extern int frecl;
  327. #endif /* VMS */
  328.  
  329. extern long
  330.   ffc, filcnt, rptn, speed, tfc, tlci, tlco, ccu, ccp, vernum, xvernum;
  331.  
  332. #ifndef NOSPL
  333. extern char fspec[], myhost[];
  334. #endif /* NOSPL */
  335.  
  336. extern char *tfnam[];                   /* Command file names */
  337.  
  338. #ifdef DCMDBUF
  339. extern struct cmdptr *cmdstk;
  340. extern char *line, *tmpbuf;
  341. #else
  342. extern struct cmdptr cmdstk[];
  343. extern char line[], tmpbuf[], kermrcb[];
  344. #endif /* DCMDBUF */
  345.  
  346. extern char pktfil[],                   /* Packet log file name */
  347. #ifdef TLOG
  348.   trafil[],                             /* Transaction log file name */
  349. #endif /* TLOG */
  350.   sesfil[];                             /* Session log file name */
  351.  
  352. #ifndef NOXMIT                          /* TRANSMIT command variables */
  353. extern char xmitbuf[];
  354. extern int xmitf, xmitl, xmitx, xmits, xmitw, xmitt;
  355. #endif /* NOXMIT */
  356.  
  357. extern int cmdlvl;
  358.  
  359. #ifndef NOSPL
  360. /* Script programming language items */
  361. extern char **a_ptr[];                  /* Arrays */
  362. extern int a_dim[];
  363. static char * inpmatch = NULL;
  364. extern char * inpbuf, inchar[];         /* Buffers for INPUT and REINPUT */
  365. extern char *inpbp;                     /* And pointer to same */
  366. static char *r3 = (char *)0;
  367. extern int incount;                     /* INPUT character count */
  368. extern int m_found;                     /* MINPUT result */
  369. extern int maclvl;                      /* Macro invocation level */
  370. extern struct mtab *mactab;             /* Macro table */
  371. extern char *mrval[];
  372. extern int macargc[], topargc;
  373. extern char *m_line[];
  374. extern char *m_arg[MACLEVEL][10]; /* You have to put in the dimensions */
  375. extern char *g_var[GVARS];        /* for external 2-dimensional arrays. */
  376. #ifdef DCMDBUF
  377. extern int *count, *inpcas;
  378. #else
  379. extern int count[], inpcas[];
  380. #endif /* DCMDBUF */
  381. #endif /* NOSPL */
  382.  
  383. #ifdef UNIX
  384. extern int haslock;                     /* For UUCP locks */
  385. extern char flfnam[];
  386. #ifndef USETTYLOCK
  387. extern char lock2[];
  388. #endif /* USETTYLOCK */
  389. #endif /* UNIX */
  390.  
  391. #ifdef OS2ORUNIX
  392. extern int maxnam, maxpath;             /* Longest name, path length */
  393. #endif /* OS2ORUNIX */
  394.  
  395. extern int mdmtyp, mdmsav;
  396.  
  397. #ifndef NODIAL
  398. /* DIAL-related variables */
  399. extern char modemmsg[];
  400. extern MDMINF *modemp[];                /* Pointers to modem info structs */
  401. extern int nmdm, dialhng, dialtmo, dialksp, dialdpy, dialsrt, dialmhu, dialsta;
  402. extern int dialrtr, dialint, dialrstr, dialcon, dialcq, dialfld;
  403. extern int mdmspd, dialec, dialdc, dialmth, dialmauto, dialesc;
  404. extern char *dialnum,   *dialini,  *dialdir[], *dialcmd,  *dialnpr,
  405.  *dialdcon, *dialdcoff, *dialecon, *dialecoff, *dialhcmd, *diallac,
  406.  *dialhwfc, *dialswfc,  *dialnofc, *dialpulse, *dialtone, *dialname,
  407.  *dialaaon, *dialaaoff, *dialmac;
  408. extern char *diallcc,   *dialixp,  *dialixs,   *dialldp,  *diallds,
  409.  *dialpxi,  *dialpxo,   *dialsfx,  *dialtfp;
  410. extern char *diallcp,   *diallcs;
  411. extern int ntollfree, ndialpxx, nlocalac;
  412. extern char *dialtfc[], *diallcac[], *dialpxx[], *matchpxx;
  413. extern int ndialpucc, ndialtocc;
  414. extern char *dialtocc[], *dialpucc[];
  415. extern int ndialdir, dialcnf, dialcvt, dialidt, dialpace;
  416. extern long dialmax, dialcapas;
  417.  
  418. extern struct keytab mdmtab[];
  419.  
  420. #ifdef BIGBUFOK
  421. #define ARGBUFSIZ 8191
  422. #else
  423. #define ARGBUFSIZ 1023
  424. #endif /* BIGBUFOK */
  425.  
  426. #ifdef BIGBUFOK
  427. extern char * dialmsg[];
  428. #endif /* BIGBUFOK */
  429.  
  430. #endif /* NODIAL */
  431.  
  432. #ifndef NOCSETS
  433. /* Translation stuff */
  434. extern int fcharset, tcharset, tslevel, language, nlng, tcsr, tcsl;
  435. extern struct keytab lngtab[];
  436. extern struct csinfo fcsinfo[], tcsinfo[];
  437. extern struct langinfo langs[];
  438. #ifdef CK_ANSIC
  439. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
  440. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
  441. #else
  442. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */
  443. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */
  444. #endif /* CK_ANSIC */
  445. #ifdef UNICODE
  446.     extern int ucsbom, ucsorder;
  447. #endif /* UNICODE */
  448. #endif /* NOCSETS */
  449.  
  450. #ifndef NOSPL
  451. /* Built-in variable names, maximum length VNAML (20 characters) */
  452.  
  453. struct keytab vartab[] = {
  454.     "_line",     VN_TFLN,  CM_INV,      /* 192 */
  455. #ifdef OS2
  456.     "_regname",  VN_REGN,  CM_INV,      /* 1.1.12 */
  457.     "_regorg",   VN_REGO,  CM_INV,      /* 1.1.12 */
  458.     "_regnum",   VN_REGS,  CM_INV,      /* 1.1.12 */
  459. #endif /* OS2 */
  460.     "apcactive", VN_APC,   CM_INV,      /* 192 */
  461.     "argc",      VN_ARGC,  0,
  462.     "args",      VN_ARGS,  0,
  463.     "authname",  VN_AUTHN, 0,           /* 196 */
  464.     "authstate", VN_AUTHS, 0,           /* 195 */
  465.     "authtype",  VN_AUTHT, 0,           /* 195 */
  466.     "blockcheck",VN_BLK,   0,           /* 195 */
  467. #ifdef BROWSER
  468.     "browser",   VN_BROWSR,0,           /* 193 */
  469.     "browsopts", VN_BROPT, 0,           /* 193 */
  470.     "browsurl",  VN_URL,   0,           /* 193 */
  471. #endif /* BROWSER */
  472.     "byteorder", VN_BYTE,  0,           /* 195 */
  473. #ifndef NOCSETS
  474.     "charset",   VN_CSET,  0,           /* 192 */
  475. #endif /* NOCSETS */
  476.     "cmdbufsize",VN_CMDBL, 0,           /* 195 */
  477.     "cmdfile",   VN_CMDF,  0,
  478.     "cmdlevel",  VN_CMDL,  0,
  479.     "cmdsource", VN_CMDS,  0,
  480.     "cols",      VN_COLS,  0,           /* 190 */
  481.     "connection",VN_CONN,  0,           /* 190 */
  482.     "count",     VN_COUN,  0,
  483. #ifndef NOXFER
  484.     "cps",       VN_CPS,   0,           /* 190 */
  485. #endif /* NOXFER */
  486.     "cpu",       VN_CPU,   0,
  487. #ifndef NOXFER
  488.     "crc16",     VN_CRC16, 0,           /* 192 */
  489.     "ctty",      VN_TTYNAM,0,           /* 196 */
  490. #endif /* NOXFER */
  491.     "cx_time",   VN_CXTIME,0,           /* 195 */
  492. #ifndef NODIAL
  493.     "d$ac",      VN_D_AC,  0,           /* 192 */
  494.     "d$cc",      VN_D_CC,  0,           /* 192 */
  495.     "d$ip",      VN_D_IP,  0,           /* 192 */
  496.     "d$lc",      VN_D_LCP, 0,           /* 193 */
  497.     "d$lcp",     VN_D_LCP, CM_INV,      /* 193 */
  498.     "d$lp",      VN_D_LP,  0,           /* 192 */
  499.     "d$px",      VN_D_PXX, 0,           /* 195 */
  500.     "d$pxx",     VN_D_PXX, CM_INV,      /* 195 */
  501. #endif /* NODIAL */
  502.     "date",      VN_DATE,  0,
  503.     "day",       VN_DAY,   0,
  504. #ifndef NODIAL
  505.     "dialcount", VN_DRTR,  0,           /* 195 */
  506.     "dialnumber",VN_DNUM,  0,           /* 192 */
  507.     "dialresult",VN_MDMSG, 0,           /* 192 */
  508.     "dialstatus",VN_DIAL,  0,           /* 190 */
  509.     "dialsuffix",VN_PDSFX, 0,           /* 193 */
  510.     "dialtype",  VN_DTYPE, 0,           /* 193 */
  511. #endif /* NODIAL */
  512.     "directory", VN_DIRE,  0,
  513. #ifndef NODIAL
  514.     "dm_lp",     VN_DM_LP, 0,           /* 195 */
  515.     "dm_sp",     VN_DM_SP, 0,           /* 195 */
  516.     "dm_pd",     VN_DM_PD, 0,           /* 195 */
  517.     "dm_td",     VN_DM_TD, 0,           /* 195 */
  518.     "dm_wa",     VN_DM_WA, 0,           /* 195 */
  519.     "dm_wd",     VN_DM_WD, 0,           /* 195 */
  520.     "dm_rc",     VN_DM_RC, 0,           /* 195 */
  521. #endif /* NODIAL */
  522. #ifndef NOXFER
  523.     "download",  VN_DLDIR, 0,           /* 192 */
  524. #endif /* NOXFER */
  525.     "editor",    VN_EDITOR,0,
  526.     "editfile",  VN_EDFILE,0,
  527.     "editopts",  VN_EDOPT, 0,
  528.     "errno",     VN_ERRNO, 0,           /* 192 */
  529.     "errstring", VN_ERSTR, 0,           /* 192 */
  530.     "escape",    VN_ESC,   0,           /* 193 */
  531.     "evaluate",  VN_EVAL,  0,           /* 190 */
  532. #ifdef OS2
  533.     "exedir",    VN_EXEDIR,0,           /* 192 */
  534. #endif /* OS2 */
  535.     "exitstatus",VN_EXIT,  0,
  536. #ifdef CKCHANNELIO
  537.     "f_count",   VN_FCOU,  0,           /* 195 */
  538.     "f_error",   VN_FERR,  0,           /* 195 */
  539.     "f_max",     VN_FMAX,  0,           /* 195 */
  540.     "fileerror", VN_FERR,  CM_INV,      /* 195 */
  541.     "filemax",   VN_FERR,  CM_INV,      /* 195 */
  542. #endif /* CKCHANNELIO */
  543.     "filename",  VN_FNAM,  0,           /* 193 */
  544.     "filenumber",VN_FNUM,  0,           /* 193 */
  545.     "filespec",  VN_FILE,  0,
  546.     "fsize",     VN_FFC,   0,           /* 190 */
  547.     "ftype",     VN_MODE,  0,           /* 190 */
  548.     "herald",    VN_HERALD,0,
  549.     "home",      VN_HOME,  0,
  550.     "host",      VN_HOST,  0,
  551.     "hwparity",  VN_HWPAR, 0,           /* 195 */
  552.     "input",     VN_IBUF,  0,
  553.     "inchar",    VN_ICHR,  0,
  554.     "incount",   VN_ICNT,  0,
  555.     "inidir",    VN_INI,   0,           /* 192 */
  556.     "inmatch",   VN_MATCH, 0,           /* 196 */
  557.     "instatus",  VN_ISTAT, 0,           /* 192 */
  558.     "intime",    VN_INTIME,0,           /* 193 */
  559.     "inwait",    VN_INTMO, 0,           /* 195 */
  560.     "ipaddress", VN_IPADDR,0,           /* 192 */
  561.     "kbchar",    VN_KBCHAR,0,           /* 196 */
  562. #ifdef OS2
  563.     "keyboard",  VN_KEYB,  0,
  564. #endif /* OS2 */
  565. #ifdef CK_KERBEROS
  566.     "krb4errmsg",    VN_K4EMSG,0,
  567.     "krb4errno",     VN_K4ENO, 0,
  568.     "krb4principal", VN_K4PRN, 0,
  569.     "krb4realm",     VN_K4RLM, 0,
  570.     "krb4service",   VN_K4SRV, 0,
  571.     "krb5cc",        VN_K5CC,  0,
  572.     "krb5errmsg",    VN_K5EMSG,0,
  573.     "krb5errno",     VN_K5ENO, 0,
  574.     "krb5principal", VN_K5PRN, 0,
  575.     "krb5realm",     VN_K5RLM, 0,
  576.     "krb5service",   VN_K5SRV, 0,
  577. #endif /* CK_KERBEROS */
  578.     "line",      VN_LINE,  0,
  579.     "local",     VN_LCL,   0,
  580. #ifdef UNIX
  581.     "lockdir",   VN_LCKDIR,0,           /* 195 */
  582.     "lockpid",   VN_LCKPID,0,           /* 195 */
  583. #endif /* UNIX */
  584.     "maclevel",  VN_MACLVL,0,           /* 195 */
  585.     "macro",     VN_MAC,   0,
  586. #ifdef FNFLOAT
  587.     "math_e",    VN_MA_E,  0,           /* 195 */
  588.     "math_pi",   VN_MA_PI, 0,           /* 195 */
  589.     "math_precision", VN_MA_PR, 0,      /* 195 */
  590. #endif /* FNFLOAT */
  591.     "minput",    VN_MINP,  0,           /* 192 */
  592.     "model",     VN_MODL,  0,           /* 193 */
  593.     "modem",     VN_MDM,   0,
  594. #ifdef OS2
  595.     "mousecurx", VN_MOU_X, 0,           /* K95 1.1.14 */
  596.     "mousecury", VN_MOU_Y, 0,           /* K95 1.1.14 */
  597. #endif /* OS2 */
  598. #ifndef NODIAL
  599.     "m_aa_off",  VN_M_ECX, 0,           /* all 192... */
  600.     "m_aa_on",   VN_M_AAO, 0,
  601.     "m_dc_off",  VN_M_DCX, 0,
  602.     "m_dc_on",   VN_M_DCO, 0,
  603.     "m_dial",    VN_M_DCM, 0,
  604.     "m_ec_off",  VN_M_ECX, 0,
  605.     "m_ec_on",   VN_M_ECO, 0,
  606.     "m_fc_hw",   VN_M_HWF, 0,
  607.     "m_fc_no",   VN_M_NFC, 0,
  608.     "m_fc_sw",   VN_M_SWF, 0,
  609.     "m_hup",     VN_M_HUP, 0,
  610.     "m_init",    VN_M_INI, 0,
  611.     "m_name",    VN_M_NAM, 0,           /* 195 */
  612.     "m_pulse",   VN_M_PDM, 0,
  613.     "m_sig_cd",  VN_MS_CD, 0,           /* 195 */
  614.     "m_sig_cts", VN_MS_CTS,0,           /* 195 */
  615.     "m_sig_dsr", VN_MS_DSR,0,           /* 195 */
  616.     "m_sig_dtr", VN_MS_DTR,0,           /* 195 */
  617.     "m_sig_ri",  VN_MS_RI, 0,           /* 195 */
  618.     "m_sig_rts", VN_MS_RTS,0,           /* 195 */
  619.     "m_tone",    VN_M_TDM, 0,
  620. #endif /* NODIAL */
  621.     "name",      VN_NAME,  0,
  622.     "ndate",     VN_NDAT,  0,
  623.     "nday",      VN_NDAY,  0,
  624.     "newline",   VN_NEWL,  0,
  625.     "ntime",     VN_NTIM,  0,
  626.     "osname",    VN_OSNAM, 0,           /* 193 */
  627.     "osrelease", VN_OSREL, 0,           /* 193 */
  628.     "osversion", VN_OSVER, 0,           /* 193 */
  629. #ifndef NOXFER
  630.     "packetlen", VN_RPSIZ, 0,           /* 192 */
  631. #endif /* NOXFER */
  632.     "parity",    VN_PRTY,  0,           /* 190 */
  633.     "password",  VN_PWD,   CM_INV,      /* 192 */
  634. #ifdef PEXITSTAT
  635.     "pexitstat", VN_PEXIT, 0,           /* 193 */
  636. #endif /* PEXITSTAT */
  637. #ifdef CK_PID
  638.     "pid",       VN_PID,   0,           /* 193 */
  639. #endif /* CK_PID */
  640.     "platform",  VN_SYSV,  0,
  641.     "printer",   VN_PRINT, 0,           /* 193 */
  642.     "program",   VN_PROG,  0,
  643.     "prompt",    VN_PRM,   CM_INV,      /* 192 */
  644. #ifndef NOXFER
  645.     "protocol",  VN_PROTO, 0,           /* 192 */
  646.     "p_8bit",    VN_P_8BIT,0,           /* 193 */
  647.     "p_ctl",     VN_P_CTL, 0,           /* 193 */
  648.     "p_rpt",     VN_P_RPT, 0,           /* 193 */
  649.     "query",     VN_QUE,   0,           /* 190 */
  650. #endif /* NOXFER */
  651.     "return",    VN_RET,   0,
  652. #ifdef CK_REXX
  653.     "rexx",      VN_REXX,  0,           /* 190 */
  654. #endif /* CK_REXX */
  655.     "rows",      VN_ROWS,  0,           /* 190 */
  656. #ifdef OS2
  657.     "select",    VN_SELCT, 0,           /* 192 */
  658. #endif /* OS2 */
  659.     "sendlist",  VN_SNDL,  0,
  660.     "serial",    VN_SERIAL,0,           /* 195 */
  661.     "setlinemsg",VN_SLMSG, 0,           /* 195 */
  662.     "speed",     VN_SPEE,  0,
  663. #ifdef OS2
  664.     "space",     VN_SPA,   0,
  665.     "startup",   VN_STAR,  0,           /* 190 */
  666. #else
  667. #ifdef UNIX
  668.     "startup",   VN_STAR,  0,           /* 193 */
  669. #else
  670. #ifdef VMS
  671.     "startup",   VN_STAR,  0,           /* 193 */
  672. #endif /* VMS */
  673. #endif /* UNIX */
  674. #endif /* OS2 */
  675.     "status",    VN_SUCC,  0,
  676. #ifndef NOXFER
  677.     "sysid",     VN_SYSI,  0,
  678. #endif /* NOXFER */
  679.     "system",    VN_SYST,  0,
  680.     "terminal",  VN_TTYP,  0,
  681. #ifdef OS2
  682.     "termkey",   VN_TRMK,  CM_INV,      /* 192 */
  683. #endif /* OS2 */
  684.     "test",      VN_TEST,  0,           /* 193 */
  685.     "textdir",   VN_TXTDIR,0,           /* 195 */
  686. #ifndef NOXFER
  687.     "tfsize",    VN_TFC,   0,
  688.     "tftime",    VN_TFTIM, 0,           /* 195 */
  689. #endif /* NOXFER */
  690.     "time",      VN_TIME,  0,
  691.     "tmpdir",    VN_TEMP,  0,           /* 192 */
  692. #ifdef CK_TRIGGER
  693.     "trigger",   VN_TRIG,  0,           /* 193 */
  694. #endif /* CK_TRIGGER */
  695. #ifdef CK_TTYFD
  696.     "ttyfd",     VN_TTYF,  0,
  697. #endif /* CK_TTYFD */
  698.     "ty_ln",     VN_TY_LN, 0,           /* 195 */
  699.     "ty_lc",     VN_TY_LC, 0,           /* 195 */
  700.     "ty_lm",     VN_TY_LM, 0,           /* 195 */
  701. #ifdef BROWSER
  702.     "url",       VN_URL,   CM_INV,      /* 193 */
  703. #endif /* BROWSER */
  704.     "userid",    VN_UID,   0,           /* 192 */
  705.     "version",   VN_VERS,  0,
  706. #ifndef NOXFER
  707.     "window",    VN_WINDO, 0,           /* 192 */
  708. #endif /* NOXFER */
  709. #ifdef IBMX25
  710.     "x25local_nua", VN_X25LA, 0,        /* 193 */
  711.     "x25remote_nua", VN_X25RA, 0,       /* 193 */
  712. #endif /* IBMX25 */
  713. #ifdef CK_SSL
  714.     "x509_issuer",  VN_X509_I, 0,
  715.     "x509_subject", VN_X509_S, 0,
  716. #endif /* CK_SSL */
  717. #ifndef NOXFER
  718.     "xferstatus",VN_XFSTAT,0,           /* 193 */
  719.     "xfermsg",   VN_XFMSG, 0,           /* 193 */
  720.     "xfer_badpacket", VN_XF_BC, 0,      /* 195 */
  721.     "xfer_timeout",   VN_XF_TM, 0,      /* 195 */
  722.     "xfer_retransmit",VN_XF_RX, 0,      /* 195 */
  723. #endif /* NOXFER */
  724.     "xprogram",  VN_XPROG, 0,           /* 193 */
  725.     "xversion",  VN_XVNUM, 0            /* 192 */
  726. };
  727. int nvars = (sizeof(vartab) / sizeof(struct keytab));
  728. #endif /* NOSPL */
  729.  
  730. #ifndef NOSPL
  731. struct keytab fnctab[] = {              /* Function names */
  732. #ifdef OS2
  733.     ".oox",       FN_OOX, CM_INV,       /* ... */
  734. #endif /* OS2 */
  735.  
  736. #ifdef CKCHANNELIO
  737.     "_eof",       FN_FEOF,   0,
  738.     "_errmsg",    FN_FERMSG, 0,
  739.     "_getblock",  FN_FGBLK,  0,
  740.     "_getchar",   FN_FGCHAR, 0,
  741.     "_getline",   FN_FGLINE, 0,
  742.     "_handle",    FN_FILNO,  0,
  743.     "_line",      FN_NLINE,  0,
  744.     "_pos",       FN_FPOS,   0,
  745.     "_putblock",  FN_FPBLK,  0,
  746.     "_putchar",   FN_FPCHAR, 0,
  747.     "_putline",   FN_FPLINE, 0,
  748.     "_status",    FN_FSTAT,  0,
  749. #endif /* CKCHANNELIO */
  750.  
  751.     "aaconvert",  FN_AADUMP, 0,         /* Associative Array conversion */
  752.     "absolute",   FN_ABS,  0,           /* Absolute value */
  753.     "arraylook",  FN_ALOOK,0,           /* Array lookup */
  754.     "b64decode",  FN_FMB64,0,           /* Base-64 conversion */
  755.     "b64encode",  FN_TOB64,0,           /* ... */
  756.     "basename",   FN_BSN,  0,           /* Basename */
  757.     "break",      FN_BRK,  0,           /* Break (as in Snobol) */
  758.     "ca",         FN_CAP,  CM_INV|CM_ABR, /* Abbreviation for capitablize */
  759.     "cap",        FN_CAP,  CM_INV|CM_ABR, /* Abbreviation for capitablize */
  760.     "capitalize", FN_CAP,  0,           /* First Letter -> uppercase */
  761.     "caps",       FN_CAP,  CM_INV,      /* ditto */
  762.     "character",  FN_CHR,  0,           /* Character from code */
  763.     "checksum",   FN_CHK,  0,           /* Checksum */
  764.     "code",       FN_COD,  0,           /* Code from character */
  765. #ifndef NOPUSH
  766.     "command",    FN_CMD,  0,           /* Output from a command */
  767. #endif /* NOPUSH */
  768.     "contents",   FN_CON,  0,           /* Definition (contents) of variable */
  769.     "crc16",      FN_CRC,  0,           /* CRC-16 */
  770. #ifdef OS2
  771.     "crypt",      FN_CRY, CM_INV,
  772. #endif /* OS2 */
  773.     "cvtdate",    FN_DTIM, 0,           /* Convert free date/time to std */
  774. #ifdef ZFCDAT
  775.     "date",       FN_FD,   0,           /* File modification/creation date */
  776. #endif /* ZFCDAT */
  777.     "day",        FN_DAY,  0,           /* Day of week */
  778.     "dayofyear",  FN_JDATE,0,           /* Date to Day of Year */
  779.     "definition", FN_DEF,  0,           /* Return definition of given macro */
  780. #ifndef NODIAL
  781.     "dialconvert",FN_PNCVT,0,           /* Convert portable phone number */
  782. #endif /* NODIAL */
  783.     "dimension",  FN_DIM,  0,           /* Dimension of array */
  784.     "directories",FN_DIR,  0,           /* List of directories */
  785.     "dirname",    FN_DNAM, 0,           /* Directory part of filename */
  786.     "doy",        FN_JDATE,CM_INV,      /* Date to Day of Year */
  787.     "doy2date",   FN_DATEJ,0,           /* Day of Year to date */
  788. #ifdef FN_ERRMSG
  789.     "errstring",  FN_ERRMSG,0,          /* Error code to message */
  790. #endif /* FN_ERRMSG */
  791.     "evaluate",   FN_EVA,  0,           /* Evaluate given arith expression */
  792.     "execute",    FN_EXE,  0,           /* Execute given macro */
  793.     "files",      FN_FC,   0,           /* File count */
  794. #ifdef FNFLOAT
  795.     "fpabsolute", FN_FPABS, 0,          /* Floating-point absolute value */
  796.     "fpadd",      FN_FPADD, 0,          /* FP add */
  797.     "fpcosine",   FN_FPCOS, 0,          /* FP cosine */
  798.     "fpdivide",   FN_FPDIV, 0,          /* FP divide */
  799.     "fpexp",      FN_FPEXP, 0,          /* FP e to the x */
  800.     "fpint",      FN_FPINT, 0,          /* FP to integer */
  801.     "fplog10",    FN_FPLOG, 0,          /* FP base-10 logarithm */
  802.     "fplogn",     FN_FPLN,  0,          /* FP natural logarithm */
  803.     "fpmaximum",  FN_FPMAX, 0,          /* FP maxinum */
  804.     "fpminimum",  FN_FPMIN, 0,          /* FP mininum */
  805.     "fpmodulus",  FN_FPMOD, 0,          /* FP modulus */
  806.     "fpmultiply", FN_FPMUL, 0,          /* FP multiply */
  807.     "fpraise",    FN_FPPOW, 0,          /* FP raise to a power */
  808.     "fpround",    FN_FPROU, 0,          /* FP round */
  809.     "fpsine",     FN_FPSIN, 0,          /* FP sine */
  810.     "fpsqrt",     FN_FPSQR, 0,          /* FP square root */
  811.     "fpsubtract", FN_FPSUB, 0,          /* FP subtract */
  812.     "fptangent",  FN_FPTAN, 0,          /* FP tangent */
  813. #endif /* FNFLOAT */
  814.     "hex2ip",     FN_HEX2IP,0,          /* Hex to IP address */
  815.     "hex2n",      FN_HEX2N, CM_INV,     /* Hex to decimal number */
  816.     "hexify",     FN_HEX,   0,          /* Hexify (string) */
  817.     "index",      FN_IND,   0,          /* Index (string search) */
  818.     "ip2hex",     FN_IP2HEX,0,          /* IP address to hex */
  819.     "ipaddress",  FN_IPA,   0,          /* Find and return IP address */
  820.     "jdate",      FN_JDATE, CM_INV,     /* Date to Day of Year */
  821. #ifdef CK_KERBEROS
  822.     "krbflags",      FN_KRB_FG, 0,      /* Kerberos functions */
  823.     "krbisvalid",    FN_KRB_IV, 0,
  824.     "krbnextticket", FN_KRB_NX, 0,
  825.     "krbtickets",    FN_KRB_TK, 0,
  826.     "krbtimeleft",   FN_KRB_TT, 0,
  827. #endif /* CK_KERBEROS */
  828.     "left",       FN_LEF,  0,           /* Leftmost n characters of string */
  829.     "length",     FN_LEN,  0,           /* Return length of argument */
  830.     "literal",    FN_LIT,  0,           /* Return argument literally */
  831.     "lop",        FN_STL,  0,           /* Lop */
  832.     "lower",      FN_LOW,  0,           /* Return lowercased argument */
  833.     "lpad",       FN_LPA,  0,           /* Return left-padded argument */
  834.     "ltrim",      FN_LTR,  0,           /* Left-Trim */
  835.     "maximum",    FN_MAX,  0,           /* Return maximum of two arguments */
  836.     "minimim",    FN_MIN,  0,           /* Return minimum of two arguments */
  837.     "mjd",        FN_MJD,  0,           /* Date to Modified Julian Date */
  838.     "mjd2date",   FN_MJD2, 0,           /* MJD to Date */
  839.     "modulus",    FN_MOD,  CM_INV,      /* Return modulus of two arguments */
  840.     "n2hex",      FN_2HEX, CM_INV,      /* Number to hex */
  841.     "n2octal",    FN_2OCT, CM_INV,      /* Number to octal */
  842.     "n2time",     FN_N2TIM,0,           /* Number to hh:mm:ss */
  843.     "nday",       FN_NDAY, 0,           /* Numeric day of week */
  844.     "nextfile",   FN_FIL,  0,           /* Next file in list */
  845.     "ntime",      FN_NTIM, 0,           /* Time to seconds since midnight */
  846.     "oct2n",      FN_OCT2N,CM_INV,      /* Octal to decimal number */
  847.     "pathname",   FN_FFN,  0,           /* Full file name */
  848.     "pattern",    FN_PATTERN, 0,        /* Pattern (for INPUT) */
  849. #ifdef CK_PERMS
  850.     "permissions",FN_PERM, 0,           /* Permissions of file */
  851. #else
  852.     "permissions",FN_PERM, CM_INV,      /* Permissions of file */
  853. #endif /* CK_PERMS */
  854.     "radix",      FN_RADIX,0,           /* Radix conversion */
  855. #ifndef NORANDOM
  856.     "random",     FN_RAND, 0,           /* Random number */
  857. #endif /* NORANDOM */
  858. #ifndef NOPUSH
  859.     "rawcommand", FN_RAW,  0,           /* Output from a command (raw) */
  860. #endif /* NOPUSH */
  861. #ifdef RECURSIVE
  862.     "rdirectories", FN_RDIR, 0,         /* Recursive directory list */
  863.     "rfiles",       FN_RFIL, 0,         /* Recursive file list */
  864. #endif /* RECURSIVE */
  865.     "rep",        FN_REP, CM_INV|CM_ABR,
  866.     "repeat",     FN_REP,  0,           /* Repeat argument given # of times */
  867.     "replace",    FN_RPL,  0,           /* Replace characters in string */
  868.     "reverse",    FN_REV,  0,           /* Reverse the argument string */
  869.     "right",      FN_RIG,  0,           /* Rightmost n characters of string */
  870.     "rindex",     FN_RIX,  0,           /* Right index */
  871.     "rpad",       FN_RPA,  0,           /* Right-pad the argument */
  872.     "rsearch",    FN_RSEARCH, 0,        /* R-L Search for pattern in string */
  873. #ifdef OS2
  874.     "scrncurx",   FN_SCRN_CX,  0,       /* Screen Cursor X Pos */
  875.     "scrncury",   FN_SCRN_CY,  0,       /* Screen Cursor Y Pos */
  876.     "scrnstr",    FN_SCRN_STR, 0,       /* Screen String */
  877. #endif /* OS2 */
  878.     "search",     FN_SEARCH, 0,         /* L-R Search for pattern in string */
  879.     "size",       FN_FS,   0,           /* File size */
  880.     "span",       FN_SPN,  0,           /* Span - like Snobol */
  881.     "split",      FN_SPLIT,0,           /* Split string into words */
  882.     "stripb",     FN_STB,  0,           /* Strip enclosing braces/brackets */
  883.     "stripn",     FN_STN,  0,           /* Strip n chars */
  884.     "stripx",     FN_STX,  0,           /* Strip "extension" */
  885.     "substring",  FN_SUB,  0,           /* Extract substring from argument */
  886.     "tablelook",  FN_TLOOK,0,           /* Table lookup */
  887.     "time",       FN_TIME, 0,           /* Free-format time to hh:mm:ss */
  888.     "tod2secs",   FN_NTIM, CM_INV,      /* Time-of-day-to-secs-since-midnite */
  889.     "trim",       FN_TRM,  0,           /* Trim */
  890.     "unhexify",   FN_UNH,  0,           /* Unhexify */
  891.     "upper",      FN_UPP,  0,           /* Return uppercased argument */
  892.     "verify",     FN_VER,  0,           /* Verify */
  893.     "word",       FN_WORD, 0,           /* Extract a word */
  894.     "", 0, 0
  895. };
  896. int nfuncs = (sizeof(fnctab) / sizeof(struct keytab)) - 1;
  897. #endif /* NOSPL */
  898.  
  899. #ifndef NOSPL                           /* Buffer for expansion of */
  900. #ifdef BIGBUFOK                         /* built-in variables. */
  901. #define VVBUFL 1024
  902. #else
  903. #define VVBUFL 256
  904. #endif /* BIGBUFOK */
  905. char vvbuf[VVBUFL+1];
  906. #endif /* NOSPL */
  907.  
  908. struct keytab disptb[] = {              /* Log file disposition */
  909.     "append",    1,  0,
  910.     "new",       0,  0
  911. };
  912.  
  913. #ifdef FNFLOAT
  914.  
  915. /* I N I T F L O A T  --  Deduce floating-point precision by inspection */
  916.  
  917. int fp_rounding = 0;                /* Nonzero if printf("%f") rounds */
  918. int fp_digits = 0;                  /* Digits of floating point precision */
  919.  
  920. #ifdef COMMENT
  921. /* For looking at internal floating-point representations */
  922. static char fp_xbuf[128];
  923. static char *
  924. tohex(s, n) CHAR * s; int n; {
  925.     int x;
  926.     char * p = fp_xbuf;
  927.     while (n-- > 0) {
  928.         x = (*s >> 4) & 0x0f;
  929.         *p++ = hexdigits[x];
  930.         x = *s++ & 0x0f;
  931.         *p++ = hexdigits[x];
  932.     }
  933.     *p = NUL;
  934.     return((char *)fp_xbuf);
  935. }
  936. #endif /* COMMENT */
  937.  
  938. VOID
  939. initfloat() {
  940.     char buf[256];
  941.     int i, x, y;
  942. #ifdef COMMENT
  943.     /* For looking at internal floating-point representations */
  944.     double a[] = { 0.0, 0.5, 0.05, 0.005, 0.0005, 0.00005, 0.5e-20,
  945.                      1.0, -1.0, 2.0, -2.0, 3.0, -3.0, 4.0, -4.0 };
  946.     int n = sizeof(a) / sizeof(double);
  947.     union blah {
  948.         CHAR xbuf[32];
  949.         double f;
  950.     } u;
  951. #endif /* COMMENT */
  952.  
  953.     sprintf(buf,"%0.250f",(10.0 / 3.0));
  954.     for (i = 2; i < 250 && buf[i] == '3'; i++) ;
  955.     x = i - 1;
  956.     debug(F111,"initfloat 10.0/3.0",buf,x);
  957.     sprintf(buf,"%0.250f",(4.0 / 9.0));
  958.     for (i = 2; i < 250 && buf[i] == '4'; i++) ;
  959.     y = i - 1;
  960.     debug(F111,"initfloat 4.0/9.0",buf,y);
  961.     fp_digits = (x < y) ? x : y;
  962.     sprintf(buf,"%0.6f",(7.0 / 9.0));
  963.     if (buf[7] == '8') fp_rounding = 1;
  964.     debug(F111,"initfloat 7.0/9.0",buf,fp_rounding);
  965.     debug(F101,"initfloat precision","",fp_digits);
  966. #ifdef COMMENT
  967.     for (i = 0; i < n; i++) {
  968.         memset(u.xbuf,0,32);
  969.         u.f = a[i];
  970.         sprintf(buf,"initfloat %f", u.f);
  971.         debug(F110,buf,tohex(u.xbuf,8),0);
  972.     }
  973. #endif /* COMMENT */
  974. }
  975. #endif /* FNFLOAT */
  976.  
  977. /*
  978.   P R E S C A N -- A quick look through the command-line options for
  979.   items that must be handled before the initialization file is executed.
  980. */
  981. #ifdef NT
  982. extern int StartedFromDialer;
  983. #endif /* NT */
  984. #ifdef OS2
  985. extern int k95stdio;
  986. unsigned long startflags = 0L;
  987. #endif /* OS2 */
  988.  
  989. static char *
  990. findinpath(arg) char * arg; {
  991. #ifdef OS2
  992.     extern char startupdir[], exedir[], inidir[];
  993.     char * scriptenv, * keymapenv;
  994.     int len;
  995. #endif /* OS2 */
  996. #ifdef DCMDBUF
  997.     extern char * cmdbuf;
  998. #else
  999.     extern char cmdbuf[];
  1000. #endif /* DCMDBUF */
  1001.     char takepath[4096];
  1002.     char * s;
  1003.     int x, z;
  1004.  
  1005.     /* Set up search path... */
  1006. #ifdef OS2
  1007. #ifdef NT
  1008.     scriptenv = getenv("K95SCRIPTS");
  1009.     keymapenv = getenv("K95KEYMAPS");
  1010. #else /* NT */
  1011.     scriptenv = getenv("K2SCRIPTS");
  1012.     keymapenv = getenv("K2KEYMAPS");
  1013. #endif /* NT */
  1014.     if (!scriptenv)
  1015.       scriptenv = getenv("CK_SCRIPTS");
  1016.     if (!scriptenv)
  1017.       scriptenv = "";
  1018.     if (!keymapenv)
  1019.       keymapenv = getenv("CK_KEYMAPS");
  1020.     if (!keymapenv)
  1021.       keymapenv = "";
  1022.  
  1023.     debug(F110,"startupdir",startupdir,0);
  1024.     debug(F110,"inidir",inidir,0);
  1025.     debug(F110,"exedir",exedir,0);
  1026.     len = strlen(scriptenv) + strlen(keymapenv) + 3*strlen(startupdir)
  1027.         + 3*strlen(inidir) + 3*strlen(zhome()) + 3*strlen(exedir)
  1028.         + 4*strlen("SCRIPTS/") + 4*strlen("KEYMAPS/") + 16;
  1029.  
  1030.     if (len >= 4096) {
  1031.         takepath[0] = '\0';
  1032.         debug(F111,"findinpath error - path length too long","len",len);
  1033.     } else
  1034.       sprintf(takepath,
  1035.           /* semicolon-separated path list */
  1036.           "%s%s%s%s%s;%s%s;%s%s;%s;%s%s;%s%s;%s;%s%s;%s%s",
  1037.           scriptenv,
  1038.           (scriptenv[0] && scriptenv[strlen(scriptenv)-1]==';')?"":";",
  1039.           keymapenv,
  1040.           (keymapenv[0] && keymapenv[strlen(keymapenv)-1]==';')?"":";",
  1041.           startupdir,
  1042.           startupdir, "SCRIPTS/",
  1043.           startupdir, "KEYMAPS/",
  1044.           inidir,
  1045.           inidir, "SCRIPTS/",
  1046.           inidir, "KEYMAPS/",
  1047.           zhome(),
  1048.           zhome(), "SCRIPTS/",
  1049.           zhome(), "KEYMAPS/",
  1050.           exedir,
  1051.           exedir, "SCRIPTS/",
  1052.           exedir, "KEYMAPS/"
  1053.           );
  1054. #else /* not OS2 */
  1055. #ifndef NOSPL
  1056.     z = 1024;                           /* Look in home directory */
  1057.     s = takepath;
  1058.     zzstring("\\v(home)",&s,&z);
  1059. #else
  1060.     takepath[0] = '\0';
  1061. #endif /* NOSPL */
  1062. #endif /* OS2 */
  1063. /*
  1064.   All the logic for searching the take path is in the command parser.
  1065.   So even though we aren't parsing commands, we initialize and call the
  1066.   parser from here, with the purported filename stuffed into the command
  1067.   buffer, followed by some carriage returns to make the parser return.
  1068.   If the file is not found, or otherwise not accessible, the parser prints
  1069.   an appropriate message, and then we just exit.
  1070. */
  1071.     cmdini();                           /* Allocate command buffers etc */
  1072.     cmini(0);                           /* Initialize them */
  1073.     /* Stuff filename into command buf with braces in case of spaces */
  1074.     sprintf(cmdbuf,"{%s}",arg);
  1075.     debug(F110,"prescan cmdbuf",cmdbuf,0);
  1076.     strcat(cmdbuf,"\r\r");              /* And some carriage returns */
  1077.     if (cmifip("","",&s,&x,0,takepath,xxstring) < 0)
  1078.       return(NULL);
  1079.     cmres();
  1080.     return(s);
  1081. }
  1082.  
  1083. static int tr_int;                      /* Flag if TRANSMIT interrupted */
  1084.  
  1085. #ifndef MAC
  1086. SIGTYP
  1087. #ifdef CK_ANSIC
  1088. trtrap(int foo)                         /* TRANSMIT interrupt trap */
  1089. #else
  1090. trtrap(foo) int foo;                    /* TRANSMIT interrupt trap */
  1091. #endif /* CK_ANSIC */
  1092. /* trtrap */ {
  1093. #ifdef __EMX__
  1094.     signal(SIGINT, SIG_ACK);
  1095. #endif
  1096.     tr_int = 1;                         /* (Need arg for ANSI C) */
  1097.     SIGRETURN;
  1098. }
  1099. #endif /* MAC */
  1100. #endif /* NOICP */
  1101.  
  1102. int arg_x = 0;
  1103. static int x_prescan = 0;
  1104.  
  1105. /*
  1106.   The argument y once meant something but I can't imagine what so now
  1107.   it's ignored.  (Prior to 22 Aug 98, prescan() was called twice by main(),
  1108.   and the arg differentiated the two calls.  But this caused all sorts of
  1109.   problems & confusion, so I commented out the second call.  This issue might
  1110.   need to be revisited.)
  1111. */
  1112. VOID
  1113. prescan(dummy) int dummy; {             /* Arg is ignored. */
  1114.     extern int howcalled;
  1115.     int yargc; char **yargv;
  1116.     char x;
  1117.     char *yp;
  1118.     int z;
  1119.  
  1120.     if (x_prescan)                      /* Only run once */
  1121.       return;
  1122.     x_prescan = 1;
  1123.  
  1124.     yargc = xargc;                      /* Make copy of arg vector */
  1125.     yargv = xargv;
  1126.  
  1127. #ifndef NOICP
  1128. #ifdef DCMDBUF
  1129.     if (!kermrc)
  1130.       if (!(kermrc = (char *) malloc(KERMRCL+1)))
  1131.         fatal("prescan: no memory for kermrc");
  1132. #endif /* DCMDBUF */
  1133.     ckstrncpy(kermrc,KERMRC,KERMRCL);   /* Default init file name */
  1134. #endif /* NOICP */
  1135.  
  1136. #ifdef IKSD
  1137.     if (howcalled == I_AM_IKSD)         /* Internet Kermit Service daemon */
  1138.       inserver = 1;                     /* (See inserver section of ckcmai) */
  1139.     else
  1140. #endif /* IKSD */
  1141.       if (howcalled != I_AM_KERMIT)     /* I'm called "telnet" or... */
  1142.         return;
  1143.  
  1144. /* Command line options for Kermit */
  1145.  
  1146. #ifndef NOCMDL
  1147. #ifndef NOICP
  1148.     if (yargc > 1
  1149.         && *yargv[1] != '-'
  1150.         && strcmp(yargv[1],"=")
  1151. #ifdef KERBANG
  1152.         && strcmp(yargv[1],"+")
  1153. #endif /* KERBANG */
  1154.         ) { /* Filename as 1st argument */
  1155.         char *s;
  1156.         int x, y;
  1157.  
  1158.         x = isabsolute(yargv[1]);
  1159.  
  1160.         if (!x)                         /* If not absolute */
  1161.           s = findinpath(yargv[1]);
  1162.         else
  1163.           s = yargv[1];
  1164.         if (!s)
  1165.           doexit(BAD_EXIT,xitsta);
  1166.         zfnqfp(s,CKMAXPATH,cmdfil);     /* In case of CD in file */
  1167.         yargc -= 1;                     /* Skip past the filename */
  1168.         yargv += 1;                     /* Otherwise we'll get an error */
  1169.     }
  1170. #endif /* NOICP */
  1171.  
  1172.     while (--yargc > 0) {               /* Go through command-line args */
  1173.         yargv++;
  1174.         yp = *yargv+1;                  /* Pointer for bundled args */
  1175.         if (**yargv == '=')             /* Same rules as cmdlin()... */
  1176.           return;
  1177.         debug(F110,"prescan *yargv",*yargv,0);
  1178.  
  1179. #ifndef NOICP
  1180. #ifdef KERBANG
  1181.         if (!strcmp(*yargv,"+")) {
  1182.             char * s;
  1183.             yargv++;
  1184.             noinit = 1;
  1185.             if (!*yargv)
  1186.               return;
  1187.             cfilef = 1;
  1188.             s = findinpath(*yargv);
  1189.             if (s) {
  1190.                 zfnqfp(s,CKMAXPATH,cmdfil);
  1191.                 return;
  1192.             } else
  1193.               doexit(BAD_EXIT,xitsta);
  1194.         }
  1195. #endif /* KERBANG */
  1196. #endif /* NOICP */
  1197.         if (!strcmp(*yargv,"--"))       /* getopt() conformance */
  1198.           return;
  1199. #ifdef VMS
  1200.         else if (**yargv == '/')
  1201.           continue;
  1202. #endif /* VMS */
  1203.         else if (**yargv == '-') {      /* Got an option (begins with dash) */
  1204.             x = *(*yargv+1);            /* Get option letter */
  1205.             while (x) {                 /* Allow for bundled options */
  1206.                 debug(F000,"prescan arg","",x);
  1207.                 switch (x) {
  1208. #ifndef NOICP
  1209.                   case '+':
  1210.                   case '-':
  1211.                     if (doxarg(yargv,1) < 0) {
  1212.                         fatal("Extended argument error");
  1213.                     }
  1214.                     yargv++, yargc--;
  1215.                     yp = *yargv;
  1216.                     break;
  1217. #endif /* NOICP */
  1218.  
  1219.                   case '7':             /* Undocumented... */
  1220.                     sstelnet = 1;       /* (because it doesn't work) */
  1221.                     break;
  1222. #ifdef IKSD
  1223.                   case 'A': {
  1224.                       char * p;
  1225.                       inserver = 1;     /* Flag that we are doing this */
  1226.                       srvcdmsg = 2;     /* Preset this */
  1227.                       /* See inserver section of ckcmai.c for more settings */
  1228. #ifdef NT
  1229.                       if (*(yp+1)) {
  1230.                           fatal("invalid argument bundling after -A");
  1231.                       }
  1232.  
  1233.                       /* Support for Pragma Systems Telnet/Terminal Servers */
  1234.                       p = getenv("PRAGMASYS_INETD_SOCK");
  1235.                       if (p && atoi(p) != 0) {
  1236.                           ttname[0] = '$';
  1237.                           ckstrncpy(&ttname[1],p,TTNAMLEN-1);
  1238.                           break;
  1239.                       }
  1240.                       yargv++, yargc--;
  1241.                       if (yargc < 1 || **yargv == '-') {
  1242.                           fatal("-A argument missing");
  1243.                       } else {
  1244.                           ttname[0] = '$';
  1245.                           ckstrncpy(&ttname[1],*yargv,TTNAMLEN-1);
  1246.                       }
  1247. #endif /* NT */
  1248.                       break;
  1249.                   }
  1250. #endif /* IKSD */
  1251.  
  1252. #ifdef OS2
  1253.                   case 'W':
  1254.                     if (*(yp+1))
  1255.                       fatal("invalid argument bundling after -W");
  1256.                     yargv++, yargc--;
  1257.                     if (yargc < 1)
  1258.                       fatal("Window handle missing");
  1259. #ifdef COMMENT
  1260.                     if (dummy) {
  1261.                         yargv++, yargc--;
  1262.                         break;
  1263.                     } else {
  1264. #endif /* COMMENT */
  1265.                         hwndDialer = (HWND) atol(*yargv);
  1266.                         StartedFromDialer = 1;
  1267.                         yargv++, yargc--;
  1268.                         KermitDialerID = atol(*yargv) ;
  1269. #ifdef COMMENT
  1270.                     }
  1271. #endif /* COMMENT */
  1272.                     break;
  1273.  
  1274.                   case '#':             /* K95 initialization options */
  1275.                     if (*(yp+1)) {
  1276.                         fatal("invalid argument bundling");
  1277.                     }
  1278.                     yargv++, yargc--;
  1279.                     if (yargc < 1)
  1280.                       fatal("-# argument missing");
  1281.                     startflags |= atol(*yargv);
  1282.                     break;
  1283. #endif /* OS2 */
  1284.  
  1285. #ifndef NOSPL
  1286.                   case 'M':                             /* My User Name */
  1287.                     if (*(yp+1)) {
  1288.                         fatal("invalid argument bundling");
  1289.                     }
  1290.                     yargv++, yargc--;
  1291.                     if ((yargc < 1) || (**yargv == '-')) {
  1292.                         fatal("missing username");
  1293.                     }
  1294.                     if ((int)strlen(*yargv) > UIDBUFLEN) {
  1295.                         fatal("username too long");
  1296.                     }
  1297. #ifdef IKSD
  1298.                     if (!inserver)
  1299. #endif /* IKSD */
  1300.                       ckstrncpy(uidbuf,*yargv,UIDBUFLEN);
  1301.                     break;
  1302. #endif /* NOSPL */
  1303.                   case 'R':             /* Remote-only advisory */
  1304. #ifdef CK_IFRO
  1305.                     remonly = 1;
  1306. #endif /* CK_IFRO */
  1307.                     break;
  1308.                   case 'S':             /* STAY */
  1309.                     stayflg = 1;
  1310.                     break;
  1311.                   case 'h':
  1312.                     noinit = 1;
  1313. #ifdef OS2
  1314.                     startflags |= 2;    /* No network DLLs */
  1315.                     startflags |= 4;    /* No TAPI DLLs */
  1316.                     startflags |= 8;    /* No Security DLLs */
  1317.                     startflags |= 16;   /* No Zmodem DLLs */
  1318. #endif /* OS2 */
  1319.                     break;
  1320. #ifndef NOICP
  1321.                   case 'Y':             /* No init file */
  1322.                     noinit = 1;
  1323.                     break;
  1324. #endif /* NOICP */
  1325.                   case 'd':             /* = SET DEBUG ON */
  1326. #ifdef DEBUG
  1327.                     if (!deblog) {
  1328.                         extern int debtim;
  1329.                         deblog = debopn("debug.log",0);
  1330.                         /* debtim = 1; */
  1331.                     }
  1332. #endif /* DEBUG */
  1333.                     break;
  1334.                   case 'x':             /* Server */
  1335.                     arg_x = 1;          /* Note in advance */
  1336.                     break;
  1337. #ifndef NOICP
  1338.                   case 'y':             /* Alternative init file */
  1339.                     yargv++, yargc--;
  1340.                     if (yargc < 1) fatal("missing name in -y");
  1341.             /* Replace init file name */
  1342.                     ckstrncpy(kermrc,*yargv,KERMRCL);
  1343.                     rcflag = 1;         /* Flag that this has been done */
  1344.                     debug(F111,"prescan kermrc",kermrc,rcflag);
  1345.                     break;
  1346. #endif /* NOICP */
  1347.                   case 'z':             /* = SET BACKGROUND OFF */
  1348.                     bgset = 0;
  1349.                     break;
  1350. #ifdef CK_NETBIOS
  1351.                   case 'N':
  1352.                     {
  1353.                         int n ;
  1354.                         yargv++, yargc--;
  1355. #ifdef COMMENT
  1356.                         if (y)
  1357.                           break;
  1358. #endif /* COMMENT */
  1359.                         if (strlen(*yargv) != 1 || (*yargv)[0] == 'X') {
  1360.                             NetBiosAdapter = -1;
  1361.                         } else {
  1362.                             n = atoi(*yargv);
  1363.                             if (n >= 0 && n <= 9)
  1364.                               NetBiosAdapter = n;
  1365.                             else
  1366.                               NetBiosAdapter = -1;
  1367.                         }
  1368.                     }
  1369.                     break;
  1370. #endif /* CK_NETBIOS */
  1371.                   default:
  1372.                     break;
  1373.                 }
  1374.                 if (!yp)
  1375.                   break;
  1376.                 x = *++yp;              /* See if options are bundled */
  1377.             }
  1378.         }
  1379.     }
  1380. #endif /* NOCMDL */
  1381. }
  1382.  
  1383. /*  G E T T C S  --  Get Transfer (Intermediate) Character Set  */
  1384.  
  1385. /*
  1386.   Given two file character sets, this routine picks out the appropriate
  1387.   "transfer" character set to use for translating between them.
  1388.   The transfer character set number is returned.
  1389.  
  1390.   Translation between two file character sets is done, for example,
  1391.   by the CONNECT, TRANSMIT, and TRANSLATE commands.
  1392.  
  1393.   Translation between Kanji character sets is not yet supported.
  1394. */
  1395. int
  1396. gettcs(cs1,cs2) int cs1, cs2; {
  1397. #ifdef NOCSETS                          /* No character-set support */
  1398.     return(0);                          /* so no translation */
  1399. #else
  1400.     int tcs = TC_TRANSP;
  1401. #ifdef KANJI
  1402. /* Kanji not supported yet */
  1403.     if (fcsinfo[cs1].alphabet == AL_JAPAN ||
  1404.         fcsinfo[cs2].alphabet == AL_JAPAN )
  1405.       tcs = TC_TRANSP;
  1406.     else
  1407. #endif /* KANJI */
  1408. #ifdef CYRILLIC
  1409. /*
  1410.   I can't remember why we don't test both sets here, but I think there
  1411.   must have been a reason...
  1412. */
  1413.       if (fcsinfo[cs2].alphabet == AL_CYRIL)
  1414.         tcs = TC_CYRILL;
  1415.       else
  1416. #endif /* CYRILLIC */
  1417. #ifdef HEBREW
  1418.           if (fcsinfo[cs1].alphabet == AL_HEBREW ||
  1419.               fcsinfo[cs2].alphabet == AL_HEBREW )
  1420.             tcs = TC_HEBREW;
  1421.           else
  1422. #endif /* HEBREW */
  1423. #ifdef GREEK
  1424.           if (fcsinfo[cs1].alphabet == AL_GREEK ||
  1425.               fcsinfo[cs2].alphabet == AL_GREEK )
  1426.             tcs = TC_GREEK;
  1427.           else
  1428. #endif /* GREEK */
  1429.  
  1430.             /* Roman sets ... */
  1431.  
  1432. #ifdef LATIN2                           /* East European */
  1433.         if (cs1 == FC_2LATIN  || cs2 == FC_2LATIN || /* Latin-2 */
  1434.             cs1 == FC_CP852   || cs2 == FC_CP852  || /* CP852 */
  1435.             cs1 == FC_CP1250  || cs2 == FC_CP1250 || /* Windows Latin-2 */
  1436.             cs1 == FC_MAZOVIA || cs2 == FC_MAZOVIA)  /* Polish Mazovia */
  1437.           tcs = TC_2LATIN;
  1438.         else
  1439. #endif /* LATIN2 */
  1440.                                         /* West European Euro-aware */
  1441.           if (cs1 == FC_CP858 || cs1 == FC_9LATIN ||
  1442.               cs2 == FC_CP858 || cs2 == FC_9LATIN)
  1443.             tcs = TC_9LATIN;
  1444.           else                          /* Traditional West European */
  1445.             tcs = TC_1LATIN;
  1446.     return(tcs);
  1447. #endif /* NOCSETS */
  1448. }
  1449.  
  1450. #ifndef NOLOCAL
  1451. /*  D O C O N E C T  --  Do the connect command  */
  1452. /*
  1453.   q = 0 means issue normal informational message about how to get back, etc.
  1454.   q != 0 means to skip the message.
  1455. */
  1456.  
  1457. int
  1458. doconect(q) int q; {
  1459.     int x, z;                           /* Return code */
  1460.     extern int what;
  1461. #ifdef CK_AUTODL
  1462.     extern CHAR ksbuf[];
  1463. #endif /* CK_AUTODL */
  1464. #ifndef NOKVERBS                        /* Keyboard macro material */
  1465.     extern int keymac, keymacx;
  1466. #endif /* NOKVERBS */
  1467.     extern int justone;
  1468.     int qsave;                          /* For remembering "quiet" value */
  1469. #ifdef OS2
  1470.     extern int term_io;
  1471.     extern int display_demo;
  1472.     int term_io_save;
  1473. #endif /* OS2 */
  1474.     int is_tn = 0;
  1475.  
  1476. #ifdef IKSD
  1477.     if (inserver) {
  1478.         if (!quiet)
  1479.           printf("?Sorry, IKSD cannot CONNECT.\r\n");
  1480.         return(success = 0);
  1481.     }
  1482. #endif /* IKSD */
  1483.  
  1484.     is_tn =
  1485. #ifdef TNCODE
  1486.       (local && network && ttnproto == NP_TELNET) || (!local && sstelnet)
  1487. #else
  1488.         0
  1489. #endif /* TNCODE */
  1490.           ;
  1491. /*
  1492.   Saving, changing, and restoring the global "quiet" variable around calls
  1493.   to conect() to control whether the verbose CONNECT message is printed is
  1494.   obviously less elegant than passing a parameter to conect(), but we do it
  1495.   this way to avoid the need to change all of the ck?con.c modules.  NOTE:
  1496.   it is important to restore the value immediately upon return in case there
  1497.   is an autodownload or APC.
  1498. */
  1499.     qsave = quiet;                      /* Save it */
  1500.     if (!quiet && q > -1)
  1501.       quiet = q;                        /* Use argument temporarily */
  1502.     conres();                           /* Put console back to normal */
  1503.     debug(F101,"doconect justone 1","",justone);
  1504. #ifdef CK_AUTODL
  1505.     ksbuf[0] = NUL;                     /* Autodownload packet buffer */
  1506. #endif /* CK_AUTODL */
  1507. #ifdef OS2
  1508.     display_demo = 1;                   /* Remember to display demo */
  1509. #endif /* OS2 */
  1510.  
  1511. #ifdef IKS_OPTION
  1512.     if (is_tn && TELOPT_U(TELOPT_KERMIT) && ttchk() >= 0
  1513. #ifdef OS2
  1514.        && !viewonly
  1515. #endif /* OS2 */
  1516.         ) {
  1517.         /* If the remote side is in a state of IKS START-SERVER    */
  1518.         /* we request that the state be changed.  We will detect   */
  1519.         /* a failure to adhere to the request when we call ttinc() */
  1520.         if (!iks_wait(KERMIT_REQ_STOP,0) && !tcp_incoming) {
  1521.             if (!quiet) {
  1522.                 printf("\r\nEnter Client/Server Mode...  Use:\r\n\r\n");
  1523.                 printf(
  1524. " REMOTE LOGIN <user> <password> to log in to the server if necessary.\r\n");
  1525.                 printf(" SEND and GET for file transfer.\r\n");
  1526.                 printf(" REMOTE commands for file management.\r\n");
  1527.                 printf(" FINISH to terminate Client/Server mode.\r\n");
  1528.                 printf(" BYE to terminate and close connection.\r\n");
  1529.                 printf(" REMOTE HELP for additional information.\r\n\r\n");
  1530.             }
  1531.             quiet = qsave;
  1532.             return(0);      /* Failure */
  1533.         }
  1534.     }
  1535.  
  1536.     /* Let our peer know our state. */
  1537. #ifdef CK_AUTODL
  1538.     if (is_tn && TELOPT_ME(TELOPT_KERMIT)
  1539. #ifdef OS2
  1540.         && !viewonly
  1541. #endif /* OS2 */
  1542.          ) {
  1543.         if (autodl && !TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
  1544.             tn_siks(KERMIT_START);      /* Send Kermit-Server Start */
  1545.         } else if (!autodl && TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
  1546.             tn_siks(KERMIT_STOP);
  1547.         }
  1548.     }
  1549. #else /* CK_AUTODL */
  1550.     if (TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
  1551.         tn_siks(KERMIT_STOP);
  1552.     }
  1553. #endif /* CK_AUTODL */
  1554. #endif /* IKS_OPTION */
  1555.  
  1556.     debug(F101,"doconect flow","",flow);
  1557.     x = conect();                       /* Connect the first time */
  1558.  
  1559. #ifdef IKS_OPTION
  1560.     if (TELOPT_U(TELOPT_KERMIT) &&
  1561.         TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
  1562.         !tcp_incoming && !quiet && ttchk() >= 0
  1563.         ) {
  1564.         printf("\r\nEnter Client/Server Mode...  Use:\r\n\r\n");
  1565.         printf(
  1566. " REMOTE LOGIN <user> <password> to log in to the server if necessary.\r\n");
  1567.         printf(" SEND and GET for file transfer.\r\n");
  1568.         printf(" REMOTE commands for file management.\r\n");
  1569.         printf(" FINISH to terminate Client/Server mode.\r\n");
  1570.         printf(" BYE to terminate and close connection.\r\n");
  1571.         printf(" REMOTE HELP for additional information.\r\n\r\n");
  1572.     }
  1573. #endif /* IKS_OPTION */
  1574.  
  1575.     quiet = qsave;                      /* Restore "quiet" value */
  1576.     debug(F101,"doconect justone 2","",justone);
  1577.  
  1578. #ifdef NETCONN
  1579.     if (network && tn_exit && ttchk() < 0)
  1580.       doexit(GOOD_EXIT,xitsta);         /* Exit with good status */
  1581. #endif /* NETCONN */
  1582.  
  1583. #ifdef OS2ORUNIX
  1584.     /* Exit on disconnect if the port is not open or carrier detect */
  1585.     if (exitonclose && (ttchk() < 0))
  1586.       doexit(GOOD_EXIT,xitsta);
  1587. #endif /* OS2ORUNIX */
  1588.  
  1589. #ifdef CKCONINTB4CB
  1590.     /* The order makes a difference in HP-UX 8.00. */
  1591.     /* The other order makes it think it's in the background when it */
  1592.     /* returns from CONNECT (Apr 1999). */
  1593.     setint();
  1594.     concb((char)escape);                /* Restore console for commands */
  1595. #else
  1596.     /* This is how it has always been so better leave it */
  1597.     /* this way for all non-HP-UX-8.00 builds. */
  1598.     concb((char)escape);                /* Restore console for commands */
  1599.     setint();
  1600. #endif /* CKCONINTB4CB */
  1601.  
  1602. #ifdef OS2
  1603.     term_io_save = term_io;             /* Disable I/O by emulator */
  1604.     term_io = 0;
  1605. #endif /* OS2 */
  1606.  
  1607. #ifdef CK_APC
  1608. /*
  1609.   If an APC command was received during CONNECT mode, we define it now
  1610.   as a macro, execute the macro, and then return to CONNECT mode.
  1611.   We do this in a WHILE loop in case additional APCs come during subsequent
  1612.   CONNECT sessions.
  1613. */
  1614.     debug(F101,"doconect apcactive","",apcactive);
  1615.     debug(F101,"doconect success","",success);
  1616.  
  1617.     while (x > 0 && (apcactive == APC_LOCAL ||
  1618.            (apcactive == APC_REMOTE && apcstatus != APC_OFF))) {
  1619.         debug(F101,"doconect justone 3","",justone);
  1620.         if (mlook(mactab,"_apc_commands",nmac) == -1) {
  1621.             debug(F110,"doconect about to execute APC",apcbuf,0);
  1622.             domac("_apc_commands",apcbuf,cmdstk[cmdlvl].ccflgs|CF_APC);
  1623.             delmac("_apc_commands");
  1624. #ifdef DEBUG
  1625.         } else {
  1626.             debug(F100,"doconect APC in progress","",0);
  1627. #endif /* DEBUG */
  1628.         }
  1629.         debug(F101,"doconect apcactive after domac","",apcactive);
  1630.         if (!apcactive) {               /* In case CLEAR APC was in APC */
  1631.             debug(F101,"doconect quit APC loop: apcactive","",apcactive);
  1632.             break;
  1633.         }
  1634.         /* Also don't reconnect if autodownload failed - very confusing! */
  1635.         /* Let them view the local screen to see what happened. */
  1636. #ifndef NOXFER
  1637.         debug(F101,"doconect xferstat","",xferstat);
  1638.         if (apcactive == APC_LOCAL & !xferstat) {
  1639.             debug(F101,"doconect quit APC loop: xferstat","",xferstat);
  1640.             apcactive = APC_INACTIVE;
  1641.             break;
  1642.         }
  1643. #endif /* NOXFER */
  1644. #ifdef OS2
  1645.         msleep(250);
  1646. #endif /* OS2 */
  1647.         debug(F101,"doconect justone 4","",justone);
  1648.         qsave = quiet;                  /* Do this again... */
  1649.         if (!quiet && q > -1)
  1650.           quiet = q;
  1651. #ifdef CK_AUTODL
  1652.         ksbuf[0] = NUL;
  1653. #endif /* CK_AUTODL */
  1654. #ifdef IKS_OPTION
  1655. #ifdef CK_AUTODL
  1656.         if (is_tn &&
  1657.             TELOPT_ME(TELOPT_KERMIT) &&
  1658.             !TELOPT_SB(TELOPT_KERMIT).kermit.me_start &&
  1659.             autodl
  1660. #ifdef CK_APC
  1661.             && !apcactive
  1662. #endif /* CK_APC */
  1663. #ifdef OS2
  1664.             && !viewonly
  1665. #endif /* OS2 */
  1666.             ) {
  1667.             tn_siks(KERMIT_START);      /* Send Kermit-Server Start */
  1668.         }
  1669. #endif /* CK_AUTODL */
  1670. #endif /* IKS_OPTION */
  1671.         x = conect();                   /* Re-CONNECT. */
  1672.  
  1673. #ifdef COMMENT
  1674. #ifdef IKS_OPTION
  1675. #ifdef CK_AUTODL
  1676.         if (is_tn && TELOPT_ME(TELOPT_KERMIT) && autodl
  1677. #ifdef CK_APC
  1678.             && !apcactive
  1679. #endif /* CK_APC */
  1680. #ifdef OS2
  1681.             && !viewonly
  1682. #endif /* OS2 */
  1683.             ) {
  1684.             tn_siks(KERMIT_STOP);       /* Send Kermit-Server Stop */
  1685.         }
  1686. #endif /* CK_AUTODL */
  1687. #endif /* IKS_OPTION */
  1688. #endif /* COMMENT */
  1689. #ifdef OS2
  1690.         term_io = term_io_save;
  1691. #endif /* OS2 */
  1692.         quiet = qsave;
  1693.         debug(F101,"doconect justone 5","",justone);
  1694. #ifdef NETCONN
  1695.         if (network && ttchk() < 0) {
  1696.             if (tn_exit || exitonclose)
  1697.               doexit(GOOD_EXIT,xitsta);
  1698.             else
  1699.               break;
  1700.         }
  1701. #endif /* NETCONN */
  1702.  
  1703. #ifdef OS2ORUNIX
  1704.         /* If connection dropped */
  1705.         if (ttchk() < 0) {
  1706.             concb((char)escape);        /* Restore console. */
  1707.             if (exitonclose)
  1708.               doexit(GOOD_EXIT,xitsta);
  1709.             else
  1710.               break;
  1711.         }
  1712. #endif /* OS2ORUNIX */
  1713.     }                                   /* Loop back for more. */
  1714. #endif /* CK_APC */
  1715.  
  1716. #ifndef NOKVERBS
  1717.     if ((keymac > 0) && (keymacx > -1)) { /* Executing a keyboard macro? */
  1718.         /* Set up the macro and return */
  1719.         /* Do not clear the keymac flag */
  1720.         return(dodo(keymacx,NULL,CF_KMAC|cmdstk[cmdlvl].ccflgs));
  1721.     }
  1722. #endif /* NOKVERBS */
  1723. #ifdef OS2
  1724.     term_io = term_io_save;
  1725. #endif /* OS2 */
  1726. #ifdef CKCONINTB4CB
  1727.     /* The order makes a difference in HP-UX 8.00. */
  1728.     /* The other order makes it think it's in the background when it */
  1729.     /* returns from CONNECT (Apr 1999). */
  1730.     setint();
  1731.     concb((char)escape);                /* Restore console for commands */
  1732. #else
  1733.     /* This is how it has always been so better leave it */
  1734.     /* this way for all non-HP-UX-8.00 builds. */
  1735.     concb((char)escape);                /* Restore console for commands */
  1736.     setint();
  1737. #endif /* CKCONINTB4CB */
  1738.     what = W_COMMAND;                   /* Back in command mode. */
  1739.     return(x);                          /* Done. */
  1740. }
  1741. #endif /* NOLOCAL */
  1742.  
  1743. #ifndef NOICP
  1744. #ifdef COMMENT
  1745. /*
  1746.   It seemed that this was needed for OS/2, in which \v(cmdfile) and other
  1747.   file-oriented variables or functions can return filenames containing
  1748.   backslashes, which are subsequently interpreted as quotes rather than
  1749.   directory separators (e.g. see commented section for VN_CMDF below).
  1750.   But the problem can't be cured at this level.  Example:
  1751.  
  1752.     type \v(cmdfile)
  1753.  
  1754.   Without doubling, the filename is parsed correctly, but then when passed
  1755.   to UNIX 'cat' through the shell, the backslash is removed, and then cat
  1756.   can't open the file.  With doubling, the filename is not parsed correctly
  1757.   and the TYPE command fails immediately with a "file not found" error.
  1758. */
  1759. /*
  1760.   Utility routine to double all backslashes in a string.
  1761.   s1 is pointer to source string, s2 is pointer to destination string,
  1762.   n is length of destination string, both NUL-terminated.
  1763.   Returns 0 if OK, -1 if not OK (destination string too short).
  1764. */
  1765. int
  1766. dblbs(s1,s2,n) char *s1, *s2; int n; {
  1767.     int i = 0;
  1768.     while (*s1) {
  1769.         if (*s1 == '\\') {
  1770.             if (++i > n) return(-1);
  1771.             *s2++ = '\\';
  1772.         }
  1773.         if (++i > n) return(-1);
  1774.         *s2++ = *s1++;
  1775.     }
  1776.     *s2 = NUL;
  1777.     return(0);
  1778. }
  1779. #endif /* COMMENT */
  1780.  
  1781. char *
  1782. gmdmtyp() {                             /* Get modem type */
  1783. #ifndef NODIAL
  1784.     int i, x;
  1785.     x = mdmtyp;
  1786.     if (x < 0)                          /* In case of network dialing */
  1787.       x = mdmsav;
  1788.     if (x < 1)
  1789.       return("none");
  1790.     else
  1791.       for (i = 0; i < nmdm; i++)
  1792.         if ((mdmtab[i].kwval == x) && (mdmtab[i].flgs == 0))
  1793.           return(mdmtab[i].kwd);
  1794. #endif /* NODIAL */
  1795.     return("none");
  1796. }
  1797.  
  1798. #ifndef NOXMIT
  1799. #ifndef NOLOCAL
  1800. /*  T R A N S M I T  --  Raw upload  */
  1801.  
  1802. /*  Obey current line, duplex, parity, flow, text/binary settings. */
  1803. /*  Returns 0 upon apparent success, 1 on obvious failure.  */
  1804.  
  1805. /***
  1806.  Things to add:
  1807.  . Make both text and binary mode obey set file bytesize.
  1808.  . Maybe allow user to specify terminators other than CR?
  1809.  . Maybe allow user to specify prompts other than single characters?
  1810.  . Make STATISTICS also work for TRANSMIT.
  1811.  . If TRANSMIT is done without echo, make some kind of (optional) display.
  1812.  . Make the same optimization for binary-mode transmit that was done for
  1813.    text-mode (in the no-echo / no-prompt / no-pause case).
  1814. ***/
  1815.  
  1816. /*  T R A N S M I T  --  Raw upload  */
  1817.  
  1818. /*  s is the filename, t is the turnaround (prompt) character  */
  1819.  
  1820. /*
  1821.   Maximum number of characters to buffer.
  1822.   Must be less than LINBUFSIZ
  1823. */
  1824. #ifdef OS2
  1825. #define XMBUFS 4096                     /* For compatibility with XYZmodem */
  1826. #else /* OS2 */
  1827. #define XMBUFS 1024
  1828. #endif /* OS2 */
  1829.  
  1830. #ifdef TNCODE
  1831. #ifndef IAC
  1832. #define IAC 255
  1833. #endif /* IAC */
  1834. #endif /* TNCODE */
  1835.  
  1836. #define OUTXBUFSIZ 15
  1837. static CHAR inxbuf[OUTXBUFSIZ+1];       /* Host-to-screen expansion buffer */
  1838. static int inxcount = 0;                /* and count */
  1839. static CHAR outxbuf[OUTXBUFSIZ+1];      /* Keyboard-to-host expansion buf */
  1840. static int outxcount = 0;               /* and count */
  1841.  
  1842. /*  T R A N S M I T  --  Unguarded non-protocol file transmission  */
  1843. /*
  1844.   Call with:
  1845.     char * s:   Name of file to transmit.
  1846.     char t:     Turnaround char for text-mode transmission (normally LF).
  1847.     int xlate:  nonzero = charset translation for text-mode xfer, 0 = skip.
  1848.     int binary: nonzero = transmit in binary mode, 0 = in text mode.
  1849. */
  1850. int
  1851. #ifdef CK_ANSIC
  1852. transmit(char * s, char t, int xlate, int binary)
  1853. #else
  1854. transmit(s,t,xlate,binary) char *s; char t; int xlate, binary;
  1855. #endif /* CK_ANSIC */
  1856. /* transmit */ {
  1857. #ifdef MAC
  1858.     extern char sstate;
  1859.     int count = 100;
  1860. #else
  1861. #ifdef OS2
  1862. #ifdef NT
  1863.     SIGTYP (* oldsig)(int);             /* For saving old interrupt trap. */
  1864. #else /* NT */
  1865.     SIGTYP (* volatile oldsig)(int);
  1866. #endif /* NT */
  1867.  
  1868. #else /* OS2 */
  1869.     SIGTYP (* oldsig)();
  1870. #endif /* OS2 */
  1871. #endif /* MAC */
  1872.     int eof = 0;                        /* End of File flag */
  1873.     int eol = 0;                        /* End of Line flag */
  1874.     int rc = 1;                         /* Return code. 0=fail, 1=succeed. */
  1875.     int myflow;                         /* Local copy of global flow... */
  1876.     int is_tn = 0;                      /* Do Telnet negotiations */
  1877.     int xbufsiz = XMBUFS;               /* Size of TRANSMIT buffer */
  1878.     int k, x, c, i;                     /* Int workers... */
  1879.     int control = 0;                    /* Echo loop control */
  1880.     long nbytes = 0;                    /* File byte count */
  1881.     long zz;                            /* Long worker */
  1882.     char *p;                            /* Char * worker */
  1883.  
  1884. #ifdef PIPESEND
  1885.     extern int pipesend;
  1886. #endif /* PIPESEND */
  1887.  
  1888. #ifndef NOCSETS
  1889.     int tcs = TC_TRANSP;                /* Intermediate (xfer) char set */
  1890.     int langsv = L_USASCII;             /* Save current language */
  1891.     int unicode = 0;
  1892.     int tcssize = 0;
  1893.  
  1894. #ifdef CK_ANSIC /* ANSI C prototypes... */
  1895.     CHAR (*sxo)(CHAR);
  1896.     CHAR (*rxo)(CHAR);
  1897.     CHAR (*sxi)(CHAR);
  1898.     CHAR (*rxi)(CHAR);
  1899. #else /* Not ANSI C... */
  1900.     CHAR (*sxo)();
  1901.     CHAR (*rxo)();
  1902.     CHAR (*sxi)();
  1903.     CHAR (*rxi)();
  1904. #endif /* CK_ANSIC */
  1905. #ifdef UNICODE
  1906.     union ck_short uc;
  1907.     int bomorder = 0;
  1908. #ifdef CK_ANSIC
  1909.     extern int (*xl_ufc[MAXFCSETS+1])(USHORT);  /* Unicode to FCS */
  1910.     extern USHORT (*xl_fcu[MAXFCSETS+1])(CHAR); /* FCS to Unicode */
  1911.     extern int (*xuf)(USHORT);
  1912.     extern USHORT (*xfu)(CHAR);
  1913. #else
  1914.     extern int (*xl_ufc[MAXFCSETS+1])();
  1915.     extern USHORT (*xl_fcu[MAXFCSETS+1])();
  1916.     extern int (*xuf)();
  1917.     extern USHORT (*xfu)();
  1918. #endif /* CK_ANSIC */
  1919. #endif /* UNICODE */
  1920. #endif /* NOCSETS */
  1921.  
  1922.     debug(F101,"xmit t","",t);
  1923.     debug(F101,"xmit xlate","",xlate);
  1924.     debug(F101,"xmit binary","",binary);
  1925.  
  1926. #ifdef PIPESEND
  1927.     if (pipesend) {
  1928.         if (nopush) return(-2);
  1929.         if (zxcmd(ZIFILE,s) < 1) {
  1930.             printf("?Can't start command: %s\n",s);
  1931.             return(0);
  1932.         }
  1933.     } else
  1934. #endif /* PIPESEND */
  1935.     if (zopeni(ZIFILE,s) == 0) {        /* Open the file to be transmitted */
  1936.         printf("?Can't open file %s\n",s);
  1937.         return(0);
  1938.     }
  1939.     x = -1;                             /* Open the communication channel */
  1940.     if (ttopen(ttname,&x,mdmtyp,cdtimo) < 0) {  /* (no harm if already open) */
  1941.         printf("Can't open device %s\n",ttname);
  1942.         return(0);
  1943.     }
  1944.     zz = x ? speed : -1L;
  1945.     if (binary) {                       /* Binary file transmission */
  1946.         myflow = (flow == FLO_XONX) ? FLO_NONE : flow;
  1947.  
  1948.         if (ttvt(zz,myflow) < 0) {      /* So no Xon/Xoff! */
  1949.             printf("Can't condition line\n");
  1950.             return(0);
  1951.         }
  1952.     } else {
  1953.         if (ttpkt(zz,flow,parity) < 0) { /* Put the line in "packet mode" */
  1954.             printf("Can't condition line\n"); /* so Xon/Xoff will work, etc. */
  1955.             return(0);
  1956.         }
  1957.     }
  1958.     is_tn =
  1959. #ifdef TNCODE
  1960.       (local && network && (ttnproto == NP_TELNET)) || (!local && sstelnet)
  1961. #else
  1962.         0
  1963. #endif /* TNCODE */
  1964.           ;
  1965.  
  1966. #ifndef NOCSETS
  1967. /* Set up character set translations */
  1968.  
  1969.     tcs = 0;                            /* "Transfer" or "Other" charset */
  1970.     sxo = rxo = NULL;                   /* Initialize byte-to-byte functions */
  1971.     sxi = rxi = NULL;
  1972.     unicode = 0;                        /* Assume Unicode won't be involved */
  1973.     if (!binary && xlate) {             /* Set up charset translations */
  1974. /*
  1975.   In the SENDING direction, we are converting from the local file's
  1976.   character-set (fcharset) to the remote terminal charset (tcsr).  In the
  1977.   RECEIVING direction (echoing) we are converting from the remote end of the
  1978.   terminal charset (tcsr) to its local end (tcsl), which is not necessarily
  1979.   the same as the file character-set.  Especially when the file character
  1980.   set is UCS-2, which is not a valid terminal character set.  The various
  1981.   combinations are represented in this table:
  1982.  
  1983.   FCS = File Character Set
  1984.   RCS = Remote Terminal Character Set
  1985.   CCS = Console (Local Terminal) Character Set
  1986.  
  1987.    8   4   2   1
  1988.   FCS FCS RCS CCS
  1989.   UCS UTF UTF UTF
  1990.    0   0   0   0   =   0   =   No translation
  1991.    0   0   0   1   =   1   =   FCS -> RCS, Echo RCS -> UTF
  1992.    0   0   1   0   =   2   =   FCS -> UTF, Echo UTF -> CCS
  1993.    0   0   1   1   =   3   =   FCS -> UTF, Echo no translation
  1994.  
  1995.    0   1   0   0   =   4   =   UTF -> RCS, Echo RCS -> CCS
  1996.    0   1   0   1   =   5   =   UTF -> RCS, Echo RCS -> UTF
  1997.    0   1   1   0   =   6   =   UTF -> UTF, Echo UTF -> CCS
  1998.    0   1   1   1   =   7   =   No translation
  1999.  
  2000.    1   0   0   0   =   8   =   UCS -> RCS, Echo RCS -> CCS
  2001.    1   0   0   1   =   9   =   UCS -> RCS, Echo RCS -> UTF
  2002.    1   0   1   0   =  10   =   UCS -> UTF, Echo UTF -> CCS
  2003.    1   0   1   1   =  11   =   UCS -> UTF, Echo no translation
  2004. */
  2005. #ifdef UNICODE
  2006.         xfu = NULL;                     /* Unicode translation functions */
  2007.         xuf = NULL;
  2008.         bomorder = ucsorder;            /* UCS-2 byte order */
  2009.  
  2010.         if (fcharset == FC_UCS2)        /* File charset is UCS-2 */
  2011.           unicode |= 8;
  2012.         else if (fcharset == FC_UTF8)   /* File charset is UTF-8 */
  2013.           unicode |= 4;
  2014.         if (tcsr == FC_UTF8)            /* Remote term charset is UTF-8 */
  2015.           unicode |= 2;
  2016.         if (tcsl == FC_UTF8)            /* Local term charset is UTF-8 */
  2017.           unicode |= 1;
  2018. #endif /* UNICODE */
  2019. /*
  2020.   When Unicode not involved -- TCS is the intermediate (xfer) set, and:
  2021.   sxo = File-to-Intermediate charset function
  2022.   rxo = Intermediate-to-Remote-Terminal charset function
  2023.   sxi = Remote-Terminal-to-Intermediate
  2024.   rxi = Intermediate-to-Local-Terminal
  2025. */
  2026.         tcs = gettcs(tcsr,fcharset);    /* Get intermediate set. */
  2027.         sxo = xls[tcs][fcharset];       /* translation function */
  2028.         rxo = xlr[tcs][tcsr];           /* pointers for output functions */
  2029.         sxi = xls[tcs][tcsr];           /* and for input functions. */
  2030.         rxi = xlr[tcs][tcsl];
  2031. /*
  2032.   At this point we have unicode nonzero if Unicode is involved in the
  2033.   conversion, and to 0 if it is.
  2034.   The following is to prevent use of zmstuff() and zdstuff() by translation
  2035.   functions (stuffing works with file i/o, not with communication i/o).
  2036. */
  2037.         langsv = language;              /* Save current SET LANGUAGE */
  2038.         language = L_USASCII;           /* No language-specific translations */
  2039.     }
  2040. #endif /* NOCSETS */
  2041.  
  2042.     i = 0;                              /* Beginning of buffer. */
  2043. #ifndef MAC
  2044. #ifndef AMIGA
  2045.     oldsig = signal(SIGINT, trtrap);    /* Save current interrupt trap. */
  2046. #endif /* AMIGA */
  2047. #endif /* MAC */
  2048.     tr_int = 0;                         /* Have not been interrupted (yet). */
  2049.     rc = 1;                             /* Return code presumed good. */
  2050. #ifdef VMS
  2051.     conres();
  2052. #endif /* VMS */
  2053.  
  2054. #ifndef NOCSETS
  2055.     debug(F101,"XMIT unicode","",unicode);
  2056. #ifdef UNICODE
  2057.     debug(F101,"XMIT bomorder","",bomorder);
  2058. #endif /* UNICODE */
  2059. #endif /* NOCSETS */
  2060.  
  2061.     c = 0;                              /* Initial condition */
  2062.     while (c > -1 && !eof) {            /* Loop for all characters in file */
  2063.         eol = 0;
  2064. #ifdef MAC
  2065.         /*
  2066.          * It is expensive to run the miniparser so don't do it for
  2067.          * every character.
  2068.          */
  2069.         if (--count < 0) {
  2070.             count = 100;
  2071.             miniparser(1);
  2072.             if (sstate == 'a') {
  2073.                 sstate = '\0';
  2074.                 goto xmitfail;
  2075.             }
  2076.         }
  2077. #else /* Not MAC */
  2078.         if (tr_int) {                   /* Interrupted? */
  2079.             printf("^C...\n");          /* Print message */
  2080.             goto xmitfail;
  2081.         }
  2082. #endif /* MAC */
  2083.         c = zminchar();                 /* Get a file character */
  2084.         debug(F000,"XMIT zminchar","",c);
  2085.         if (c < -1) {                   /* Other error */
  2086.             printf("?Input error\n");
  2087.             goto xmitfail;
  2088.         } else if (c > -1) {
  2089.             nbytes++;
  2090.             c &= fmask;                 /* Apply SET FILE BYTESIZE mask */
  2091.         } else if (c == -1) {
  2092.             eof = 1;
  2093.             debug(F101,"XMIT eof","",eof);
  2094.         }
  2095.         if (binary) {                   /* If binary file, */
  2096.             if (c == -1)                /* break if error, */
  2097.               goto xmitexit;
  2098.             if (ttoc(dopar((char) c)) < 0) { /* else just send the char */
  2099.                 printf("?Can't transmit character\n");
  2100.                 goto xmitfail;
  2101.             }
  2102. #ifdef TNCODE
  2103.             if (c == IAC && is_tn)      /* Quote Telnet IAC */
  2104.               ttoc((char)IAC);
  2105. #endif /* TNCODE */
  2106.  
  2107.             if (xmitw)                  /* Pause if requested */
  2108.               msleep(xmitw);
  2109.  
  2110.             if (xmitx) {                /* SET TRANSMIT ECHO ON? */
  2111.                 if (duplex) {           /* Yes, for half duplex */
  2112. #ifdef OS2
  2113.                     /* Echo to emulator */
  2114.                     scriptwrtbuf((USHORT)(c & cmdmsk));
  2115. #endif /* OS2 */
  2116.                     if (conoc((char)(c & cmdmsk)) < 0) /* echo locally. */
  2117.                       goto xmitfail;
  2118.                 } else {                /* For full duplex, */
  2119.                     int i, n;           /* display whatever is there. */
  2120.                     n = ttchk();        /* See how many chars are waiting */
  2121.                     if (n < 0) {        /* Connection dropped? */
  2122.                         printf("?Connection lost\n");
  2123.                         goto xmitfail;
  2124.                     }
  2125.                     for (i = 0; i < n; i++) { /* Read and echo that many. */
  2126.                         x = ttinc(xmitt); /* Timed read just in case. */
  2127.                         if (x > -1) {   /* If no timeout */
  2128.                             if (parity) x &= 0x7f; /* display the char, */
  2129. #ifdef OS2
  2130.                             /* Echo to emulator */
  2131.                             scriptwrtbuf((USHORT)x);
  2132. #endif /* OS2 */
  2133.                             if (conoc((char)(x & cmdmsk)) < 0) {
  2134.                                 printf("?Output error\n");
  2135.                                 goto xmitfail;
  2136.                             }
  2137.                         } else if (x == -2) {
  2138.                             printf("Connection closed.\n");
  2139.                             ttclos(1);
  2140.                             goto xmitfail;
  2141.                         } else if (x == -3) {
  2142.                             printf(
  2143.                             "Session Limit exceeded - closing connection.\n"
  2144.                                    );
  2145.                             ttclos(1);
  2146.                             goto xmitfail;
  2147.                         } else {
  2148.                             printf("?Communications error\n");
  2149.                             goto xmitfail;
  2150.                         }
  2151.                     }
  2152.                 }
  2153.             } else ttflui();            /* Not echoing, just flush input. */
  2154.  
  2155.         } else {                        /* Text mode, line at a time. */
  2156. #ifdef UNICODE
  2157.             if (fcharset == FC_UCS2 && xlate) { /* Special for UCS-2 */
  2158.                 char xbuf[8];
  2159.                 x = 1 - (nbytes & 1);   /* Odd or even byte */
  2160.                 if (x == 0)             /* Note: 1 = the 1st, 0 = 2nd, etc */
  2161.                   uc.x_short = 0;
  2162.                 if (bomorder)           /* Little Endian */
  2163.                   x = 1 - x;            /* Save byte in appropriate half */
  2164.                 debug(F101,"XMIT UCS2 x","",x);
  2165.                 uc.x_char[x] = (CHAR) (c & 0xff);
  2166.                 if (nbytes & 1)         /* First byte, go back for next */
  2167.                   continue;
  2168.                 if (nbytes == 2) {      /* UCS-2 Byte Order Mark */
  2169.                     if (uc.x_short == (USHORT) 0xfeff) {
  2170.                         debug(F100,"XMIT UCS2 BOM FEFF","",bomorder);
  2171.                         continue;
  2172.                     } else if (uc.x_short == (USHORT) 0xfffe) {
  2173.                         bomorder = 1 - bomorder;
  2174.                         debug(F100,"XMIT UCS2 BOM FFFE (swap)","",bomorder);
  2175.                         continue;
  2176.                     }
  2177.                 }
  2178.                 sprintf(xbuf,"%04X",uc.x_short);
  2179.                 debug(F111,"XMIT UCS2",xbuf,uc.x_short);
  2180.                 if (nbytes & 1)         /* Special eol test for UCS-2 */
  2181.                   if (uc.x_short == '\n')
  2182.                     eol = 1;
  2183. #ifdef COMMENT
  2184.                 if (uc.x_short == 0x2028 || uc.x_short == 0x2029)
  2185.                     eol = 1;
  2186. #endif /* COMMENT */
  2187.             } else
  2188. #endif /* UNICODE */
  2189.               if (c == '\n') {          /* Normal eol test otherwise */
  2190.                   eol = 1;
  2191.             }
  2192.             if (eol) {                  /* End of line? */
  2193.                 int stuff = -1;
  2194.                 debug(F101,"XMIT eol length","",i);
  2195.                 if (i == 0) {           /* Blank line? */
  2196.                     if (xmitf)          /* Yes, insert fill if asked. */
  2197.                       line[i++] = dopar((char) xmitf);
  2198.                 }
  2199.                 if (i == 0 || ((char) line[i-1]) != ((char) dopar(CR)))
  2200.                   line[i++] = dopar(CR); /* Terminate it with CR */
  2201.                 if (xmitl) {
  2202.                     stuff = LF;
  2203. #ifdef TNCODE
  2204.                 } else if (is_tn && (tn_nlm != TNL_CR)) {
  2205.                     /* TELNET NEWLINE ON/OFF/RAW */
  2206.                     stuff = (tn_nlm == TNL_CRLF) ? LF : NUL;
  2207. #endif /* TNCODE */
  2208.                 }
  2209.                 if (stuff > -1)
  2210.                   line[i++] = dopar((char)stuff);
  2211.                 line[i] = NUL;
  2212.                 debug(F111,"XMIT eol line",line,i);
  2213.  
  2214.             } else if (c != -1) {       /* Not a newline, regular character */
  2215.                 int k, x;
  2216.                 outxbuf[0] = c;         /* In case of no translation */
  2217.                 outxcount = 1;          /* Assume result is one byte */
  2218. #ifndef NOCSETS
  2219.                 switch (unicode) {
  2220.                   case 0:               /* No Unicode involved */
  2221.                   case 1:
  2222.                     if (xlate) {        /* If not /TRANSPARENT */
  2223.                         /* Local-to-intermediate */
  2224.                         if (sxo) c = (*sxo)((char)c);
  2225.                         /* Intermediate-to-remote */
  2226.                         if (rxo) c = (*rxo)((char)c);
  2227.                         outxbuf[0] = c;
  2228.                     }
  2229.                     break;
  2230. #ifdef UNICODE
  2231.                   case 2:               /* Local byte to UTF-8 */
  2232.                   case 3:
  2233.                     xfu = xl_fcu[fcharset];
  2234.                     tcssize = fcsinfo[fcharset].size;
  2235.                     outxcount =
  2236.                       b_to_u((CHAR)c,outxbuf,OUTXBUFSIZ,tcssize);
  2237.                     break;
  2238.                   case 4:               /* Local UTF-8 to remote byte */
  2239.                   case 5:
  2240.                     xuf = xl_ufc[tcsr];
  2241.                     x = u_to_b((CHAR)c); /* Convert to byte */
  2242.                     if (x == -1) {      /* If more input bytes needed */
  2243.                         continue;       /* go back and get them */
  2244.                     } else if (x == -2) { /* LS or PS (shouldn't happen) */
  2245.                         outxbuf[0] = CR;
  2246.                     } else if (x == -9) { /* UTF-8 error */
  2247.                         outxbuf[0] = '?'; /* Insert error char */
  2248.                         outxbuf[1] = u_to_b2(); /* Insert next char */
  2249.                         outxcount = 2;
  2250.                     } else {
  2251.                         outxbuf[0] =    /* Otherwise store result */
  2252.                           (unsigned)(x & 0xff);
  2253.                     }
  2254.                     break;
  2255.                   case 6:               /* UTF-8 to UTF-8 */
  2256.                   case 7:
  2257.                     break;
  2258.                   case 8:               /* UCS-2 to byte */
  2259.                   case 9:
  2260.                     xuf = xl_ufc[tcsr];
  2261.                     outxbuf[0] = (*xuf)(uc.x_short);
  2262.                     break;
  2263.                   case 10:
  2264.                   case 11: {            /* UCS-2 to UTF-8 */
  2265.                       int j;
  2266.                       CHAR * buf = NULL;
  2267.                       x = ucs2_to_utf8(uc.x_short,&buf);
  2268.                       if (x < 0) {
  2269.                           outxbuf[0] = 0xff; /* (= U+FFFD) */
  2270.                           outxbuf[1] = 0xbd;
  2271.                           x = 2;
  2272.                       }
  2273.                       for (j = 0; j < x; j++)
  2274.                         outxbuf[j] = buf[j];
  2275.                       outxcount = x;
  2276.                       break;
  2277.                   }
  2278. #endif /* UNICODE */
  2279.                 }
  2280. #endif /* NOCSETS */
  2281.                 outxbuf[outxcount] = NUL;
  2282.                 debug(F111,"XMIT outxbuf",outxbuf,outxcount);
  2283. /*
  2284.   Now the input character (1 or more bytes) is translated into the output
  2285.   expansion buffer (1 or more bytes); outxcount = number of bytes to add to
  2286.   the TRANSMIT line buffer, which we do here, taking care of parity, SI/SO
  2287.   processing, and quoting Telnet IACs.
  2288. */
  2289.                 for (k = 0; k < outxcount; k++) {
  2290.                     c = outxbuf[k];
  2291.                     if (xmits && parity && (c & 0200)) { /* If shifting */
  2292.                         line[i++] = dopar(SO); /* needs to be done, */
  2293.                         line[i++] = dopar((char)c); /* do it here, */
  2294.                         line[i++] = dopar(SI); /* crudely. */
  2295.                     } else {
  2296.                         line[i++] = dopar((char)c);
  2297. #ifdef TNCODE
  2298.                         if (c == IAC && is_tn)
  2299.                           line[i++] = IAC;
  2300. #endif /* TNCODE */
  2301.                     }
  2302.                 }
  2303.             }
  2304. /*
  2305.   Send characters if buffer full, or at end of line, or at end of file.
  2306.   (End of line only if echoing, waiting for a prompt, or pausing.)
  2307. */
  2308.             debug(F000,"XMIT c",ckitoa(i),c);
  2309.             if (i >= xbufsiz || eof || (eol && (xmitx || xmitw || t))) {
  2310.                 p = line;
  2311.                 line[i] = '\0';
  2312.                 debug(F111,"transmit buf",p,i);
  2313.                 if (ttol((CHAR *)p,i) < 0) { /* try to send it. */
  2314.                     printf("Can't TRANSMIT buffer\n");
  2315.                     rc = 0;
  2316.                     break;
  2317.                 }
  2318.                 i = 0;                  /* Reset buffer pointer. */
  2319. /*
  2320.   Now we handle the echo.  If the user wants to see it, or if we have to
  2321.   wait for the turnaround character, t.  If the echo is being displayed,
  2322.   and terminal character-set translation is required, we do it here.
  2323. */
  2324.                 if (duplex && xmitx) {  /* If local echo, echo it */
  2325.                     if (parity || cmdmsk == 0x7f) { /* Strip hi bits */
  2326.                         char *ss = line;             /* if necessary */
  2327.                         while (*ss) {
  2328.                             *ss &= 0x7f;
  2329.                             ss++;
  2330.                         }
  2331.                     }
  2332. #ifdef OS2
  2333.                     {                   /* Echo to emulator */
  2334.                         char *ss = p;
  2335.                         while (*ss) {
  2336.                             scriptwrtbuf((USHORT)*ss);
  2337.                             ss++;
  2338.                         }
  2339.                     }
  2340. #endif /* OS2 */
  2341.                     if (conoll(p) < 0)
  2342.                       goto xmitfail;
  2343.                 }
  2344.                 if (xmitw)              /* Sleep TRANSMIT PAUSE interval */
  2345.                   msleep(xmitw);
  2346.  
  2347.                 control = 0;            /* Readback loop control */
  2348.                 if (t != 0 && eol)      /* TRANSMIT PROMPT given and at EOL */
  2349.                   control |= 1;
  2350.                 if (xmitx && !duplex)   /* Echo desired and is remote */
  2351.                   control |= 2;
  2352.  
  2353.                 if (control) {          /* Do this if reading back the echo */
  2354.                     int n;
  2355.                     x = 0;
  2356.                     while (1) {
  2357.                         if (control & 1) { /* Termination criterion */
  2358.                             if (x == t)    /* for turnaround */
  2359.                               break;
  2360.                         } else if (control & 2) { /* And for echoing */
  2361.                             if ((n = ttchk()) < 1)
  2362.                               break;
  2363.                         }
  2364.                         if ((x = ttinc(xmitt)) < 0) { /* Read with timeout */
  2365.                             switch (x) {
  2366.                               case -2:
  2367.                                 printf("Connection closed.\n");
  2368.                                 ttclos(1);
  2369.                                 goto xmitfail;
  2370.                               case -3:
  2371.                                 printf(
  2372.                               "Session Limit exceeded - closing connection.\n"
  2373.                                        );
  2374.                                 ttclos(1); /* full thru... */
  2375.                                 goto xmitfail;
  2376.                               default:
  2377.                                 printf("?Timeout\n");
  2378.                                 goto xmitfail;
  2379.                             }
  2380.                         }
  2381.                         if (x > -1 && (control & 2)) { /* Echo any echoes */
  2382.                             if (parity)
  2383.                               x &= 0x7f;
  2384.                             c = x;
  2385. #ifdef OS2
  2386.                             scriptwrtbuf((USHORT)x);
  2387. #endif /* OS2 */
  2388.                             inxbuf[0] = c;
  2389.                             inxcount = 1;
  2390. #ifndef NOCSETS
  2391.                             switch (unicode & 3) { /* Remote bits */
  2392.                               case 0:
  2393.                                 if (xlate) {
  2394.                                     if (sxi) c = (*sxi)((CHAR)c);
  2395.                                     if (rxi) c = (*rxi)((CHAR)c);
  2396.                                     inxbuf[0] = c;
  2397.                                 }
  2398.                                 break;
  2399. #ifdef UNICODE
  2400.                               case 1:   /* Remote Byte to local UTF-8 */
  2401.                                 xfu = xl_fcu[tcsr];
  2402.                                 tcssize = fcsinfo[tcsr].size;
  2403.                                 inxcount =
  2404.                                   b_to_u((CHAR)c,
  2405.                                          inxbuf,
  2406.                                          OUTXBUFSIZ,
  2407.                                          tcssize
  2408.                                          );
  2409.                                 break;
  2410.                               case 2:   /* Remote UTF-8 to local Byte */
  2411.                                 xuf = xl_ufc[tcsl];
  2412.                                 x = u_to_b((CHAR)c);
  2413.                                 if (x < 0)
  2414.                                   continue;
  2415.                                 inxbuf[0] = (unsigned)(x & 0xff);
  2416.                                 break;
  2417.                               case 3:   /* UTF-8 to UTF-8 */
  2418.                                 break;
  2419. #endif /* UNICODE */
  2420.                             }
  2421. #endif /* NOCSETS */
  2422.                             inxbuf[inxcount] = NUL;
  2423.                             if (conxo(inxcount,(char *)inxbuf) < 0)
  2424.                               goto xmitfail;
  2425.                         }
  2426.                     }
  2427.                 } else                  /* Not echoing */
  2428.                   ttflui();             /* Just flush input buffer */
  2429.             } /* End of buffer-dumping block */
  2430.         } /* End of text mode */
  2431.         if (eof) {
  2432.             rc = 1;
  2433.             goto xmitexit;
  2434.         }
  2435.     } /* End of character-reading loop */
  2436.  
  2437.   xmitfail:                             /* Failure exit point */
  2438.     rc = 0;
  2439.  
  2440.   xmitexit:                             /* General exit point */
  2441.     if (rc > 0) {
  2442.         if (*xmitbuf) {                 /* Anything to send at EOF? */
  2443.             p = xmitbuf;                /* Yes, point to string. */
  2444.             while (*p)                  /* Send it. */
  2445.               ttoc(dopar(*p++));        /* Don't worry about echo here. */
  2446.         }
  2447.     }
  2448.  
  2449. #ifndef AMIGA
  2450. #ifndef MAC
  2451.     signal(SIGINT,oldsig);              /* Put old signal action back. */
  2452. #endif /* MAC */
  2453. #endif /* AMIGA */
  2454. #ifdef VMS
  2455.     concb(escape);                      /* Put terminal back, */
  2456. #endif /* VMS */
  2457.     zclose(ZIFILE);                     /* Close file, */
  2458. #ifndef NOCSETS
  2459.     language = langsv;                  /* restore language, */
  2460. #endif /* NOCSETS */
  2461.     ttres();                            /* and terminal modes, */
  2462.     return(rc);                         /* and return successfully. */
  2463. }
  2464. #endif /* NOLOCAL */
  2465. #endif /* NOXMIT */
  2466.  
  2467. #ifndef NOCSETS
  2468.  
  2469. _PROTOTYP( CHAR (*sxx), (CHAR) );       /* Local translation function */
  2470. _PROTOTYP( CHAR (*rxx), (CHAR) );       /* Local translation function */
  2471. _PROTOTYP( CHAR zl1as, (CHAR) );        /* Latin-1 to ascii */
  2472. _PROTOTYP( CHAR xl1as, (CHAR) );        /* ditto */
  2473.  
  2474. /*  X L A T E  --  Translate a local file from one character set to another */
  2475.  
  2476. /*
  2477.   Translates input file (fin) from character set csin to character set csout
  2478.   and puts the result in the output file (fout).  The two character sets are
  2479.   file character sets from fcstab.
  2480. */
  2481.  
  2482. int
  2483. xlate(fin, fout, csin, csout) char *fin, *fout; int csin, csout; {
  2484.  
  2485. #ifndef MAC
  2486. #ifdef OS2
  2487. #ifdef NT
  2488.     SIGTYP (* oldsig)(int);             /* For saving old interrupt trap. */
  2489.     extern int wherex[], wherey[];
  2490.     extern int k95stdout;
  2491.     extern unsigned char colorcmd;
  2492. #else /* NT */
  2493.     SIGTYP (* volatile oldsig)(int);    /* For saving old interrupt trap. */
  2494. #endif /* NT */
  2495. #else /* OS2 */
  2496.     SIGTYP (* oldsig)();
  2497. #endif /* OS2 */
  2498. #endif /* MAC */
  2499. #ifdef CK_ANSIC
  2500.     int (*fn)(char);                    /* Output function pointer */
  2501. #else
  2502.     int (*fn)();
  2503. #endif /* CK_ANSIC */
  2504.     extern int xlatype;
  2505.     int filecode;                       /* Code for output file */
  2506.     int scrnflg = 0;
  2507.  
  2508.     int z = 1;                          /* Return code. */
  2509.     int x, c, tcs;                      /* Workers */
  2510.     int bytewise = 0;
  2511.  
  2512.     ffc = 0L;
  2513.  
  2514.     if (zopeni(ZIFILE,fin) == 0) {      /* Open the file to be translated */
  2515.         printf("?Can't open input file %s\n",fin);
  2516.         return(0);
  2517.     }
  2518. #ifdef MAC
  2519. /*
  2520.   If user specified no output file, it goes to the screen.  For the Mac,
  2521.   this must be done a special way (result goes to a new window); the Mac
  2522.   doesn't have a "controlling terminal" device name.
  2523. */
  2524.     filecode = !strcmp(fout,CTTNAM) ? ZCTERM : ZOFILE;
  2525. #else
  2526. #ifdef VMS
  2527.     filecode = !strcmp(fout,CTTNAM) ? ZCTERM : ZMFILE;
  2528. #else
  2529. #ifdef OS2
  2530.     filecode = (!stricmp(fout,"con") || !stricmp(fout,"con:")) ?
  2531.         ZCTERM : ZMFILE;
  2532. #else /* OS2 */
  2533.     filecode = ZOFILE;
  2534. #endif /* OS2 */
  2535. #endif /* VMS */
  2536. #endif /* MAC */
  2537.     if (zopeno(filecode,fout,NULL,NULL) == 0) { /* And the output file */
  2538.         printf("?Can't open output file %s\n",fout);
  2539.         return(0);
  2540.     }
  2541. #ifndef AMIGA
  2542. #ifndef MAC
  2543.     oldsig = signal(SIGINT, trtrap);    /* Save current interrupt trap. */
  2544. #endif /* MAC */
  2545. #endif /* AMIGA */
  2546.  
  2547.     scrnflg = (filecode == ZCTERM);     /* Set output function */
  2548.     if (scrnflg)
  2549.       fn = NULL;
  2550.     else if (filecode == ZMFILE)
  2551.       fn = putmfil;
  2552.     else
  2553.       fn = putfil;
  2554.  
  2555.     tr_int = 0;                         /* Have not been interrupted (yet). */
  2556.     z = 1;                              /* Return code presumed good. */
  2557.  
  2558.     if (!scrnflg && !quiet)
  2559.       printf("%s (%s) => %s (%s)\n\n", /* Say what we're doing. */
  2560.              fin, fcsinfo[csin].keyword,
  2561.              fout,fcsinfo[csout].keyword
  2562.              );
  2563.  
  2564. #ifndef UNICODE
  2565. /*
  2566.   Non-Unicode picks the "most appropriate" transfer character set as the
  2567.   intermediate set, which results in loss of any characters that the source
  2568.   and target sets have in common, but are lacking from the intermediate set.
  2569. */
  2570. #ifdef KANJI
  2571.     /* Special handling for Japanese... */
  2572.  
  2573.     if (fcsinfo[csin].alphabet == AL_JAPAN ||
  2574.          fcsinfo[csout].alphabet == AL_JAPAN) {
  2575.         USHORT eu;
  2576.         int c, x, y;
  2577.  
  2578.         xpnbyte(-1,0,0,NULL);           /* Reset output machine */
  2579.         xlatype = XLA_JAPAN;
  2580.  
  2581.         while ((c = xgnbyte(FC_JEUC,csin)) > -1) { /* Get an EUC byte */
  2582.             if (tr_int) {               /* Interrupted? */
  2583.                 printf("^C...\n");      /* Print message */
  2584.                 z = 0;
  2585.                 break;
  2586.             }
  2587.             /* Send EUC byte to output machine */
  2588.             if ((x = xpnbyte(c,TC_JEUC,csout,fn)) < 0) {
  2589.                 z = -1;
  2590.                 break;
  2591.             }
  2592.         }
  2593.         goto xxlate;
  2594.     }
  2595. #endif /* KANJI */
  2596.  
  2597.     /* Regular bytewise conversion... */
  2598.  
  2599.     tcs = gettcs(csin,csout);           /* Get intermediate set. */
  2600.     if (csin == csout) {                /* Input and output sets the same? */
  2601.         sxx = rxx = NULL;               /* If so, no translation. */
  2602.     } else {                            /* Otherwise, set up */
  2603.         if (tcs < 0 || tcs > MAXTCSETS ||
  2604.             csin < 0 || csin > MAXFCSETS ||
  2605.             csout < 0 || csout > MAXFCSETS) {
  2606.             debug(F100,"XLATE csets out of range","",0);
  2607.             sxx = rxx = NULL;
  2608.         } else {
  2609.             sxx = xls[tcs][csin];       /* translation function */
  2610.             rxx = xlr[tcs][csout];      /* pointers. */
  2611.             if (rxx == zl1as) rxx = xl1as;
  2612.         }
  2613.     }
  2614.     while ((c = zminchar()) != -1) { /* Loop for all characters in file */
  2615.         if (tr_int) {                   /* Interrupted? */
  2616.             printf("^C...\n");          /* Print message */
  2617.             z = 0;
  2618.             break;
  2619.         }
  2620.         if (sxx) c = (*sxx)((CHAR)c);   /* From fcs1 to tcs */
  2621.         if (rxx) c = (*rxx)((CHAR)c);   /* from tcs to fcs2 */
  2622.         if (zchout(filecode,(char)c) < 0) { /* Output xlated character */
  2623.             z = -1;
  2624.             break;
  2625.         }
  2626.     }
  2627.     goto xxlate;                        /* Done. */
  2628.  
  2629. #else  /* UNICODE */
  2630. /*
  2631.    Use Unicode as the intermediate character set.  It's simple and gives
  2632.    little or no loss, but the overhead is a bit higher.
  2633. */
  2634.     initxlate(csin,csout);              /* Set up translation functions */
  2635.  
  2636. #ifdef NT
  2637.     if (isunicode() &&                  /* NT console is Unicode based */
  2638.         csout == FC_UCS2 &&             /* And we're translating to UCS-2 */
  2639.         filecode == ZCTERM &&           /* for the real screen... */
  2640.         !k95stdout
  2641.         ) {
  2642.         union {
  2643.             USHORT ucs2;
  2644.             UCHAR  bytes[2];
  2645.         } output;
  2646.  
  2647.         while (1) {                     /* In this case we go two-by-two. */
  2648.             if ((c = xgnbyte(FC_UCS2,csin)) < 0)
  2649.               break;
  2650.             output.bytes[0] = c;
  2651.             if ((c = xgnbyte(FC_UCS2,csin)) < 0)
  2652.               break;
  2653.             output.bytes[1] = c;
  2654.  
  2655.             if (tr_int) {               /* Interrupted? */
  2656.                 printf("^C...\n");      /* Print message */
  2657.                 z = 0;
  2658.                 break;
  2659.             }
  2660.             VscrnWrtUCS2StrAtt(VCMD,
  2661.                                &output.ucs2,
  2662.                                1,
  2663.                                wherey[VCMD],
  2664.                                wherex[VCMD],
  2665.                                &colorcmd
  2666.                                );
  2667.         }
  2668.     } else
  2669. #endif /* NT */
  2670.  
  2671.       /* General case: Get next byte translated from fcs to UCS-2 */
  2672.  
  2673.       while ((c = xgnbyte(FC_UCS2,csin)) > -1) {
  2674.           if (tr_int) {                 /* Interrupted? */
  2675.               printf("^C...\n");        /* Print message */
  2676.               z = 0;
  2677.               break;
  2678.           }
  2679.           debug(F001,"XLATE c","",c);
  2680.  
  2681.           /* And then send UCS-2 byte to translate-and-output machine */
  2682.  
  2683.           if ((x = xpnbyte(c,TC_UCS2,csout,fn)) < 0) {
  2684.               z = -1;
  2685.               break;
  2686.           }
  2687.       }
  2688. #endif /* UNICODE */
  2689.  
  2690. #ifndef UNICODE
  2691.   xxlate:                               /* Common exit point */
  2692. #endif /* UNICODE */
  2693.  
  2694. #ifndef AMIGA
  2695. #ifndef MAC
  2696.     signal(SIGINT,oldsig);              /* Put old signal action back. */
  2697. #endif /* MAC */
  2698. #endif /* AMIGA */
  2699.     tr_int = 0;
  2700.     if (z < 0) {
  2701.         if (z == -1)
  2702.           printf("?File output error: %s\n",ck_errstr());
  2703.         z = 0;
  2704.     }
  2705.     zclose(ZIFILE);                     /* Close files */
  2706.     zclose(filecode);                   /* ... */
  2707.     return(success = z);                /* and return status. */
  2708. }
  2709. #endif /* NOCSETS */
  2710.  
  2711. static char hompthbuf[CKMAXPATH+1];
  2712.  
  2713. char *
  2714. homepath() {
  2715.     int x;
  2716.     hompthbuf[0] = NUL;
  2717. #ifdef UNIXOROSK
  2718.     x = ckstrncpy(hompthbuf,zhome(),CKMAXPATH+1);
  2719.     if (x <= 0) {
  2720.         hompthbuf[0] = '/';
  2721.         hompthbuf[1] = NUL;
  2722.     } else if (x < CKMAXPATH - 2 && hompthbuf[x-1] != '/') {
  2723.         hompthbuf[x] = '/';
  2724.         hompthbuf[x+1] = NUL;
  2725.     }
  2726.     return(hompthbuf);
  2727. #else
  2728. #ifdef STRATUS
  2729.     if (strlen(zhome()) < CKMAXPATH)
  2730.       sprintf(hompthbuf,"%s>",zhome());
  2731.     return(hompthbuf);
  2732. #else
  2733.     return(zhome());
  2734. #endif /* STRATUS */
  2735. #endif /* UNIXOROSK */
  2736. }
  2737.  
  2738. /*  D O L O G  --  Do the log command  */
  2739.  
  2740. int
  2741. dolog(x) int x; {
  2742.     int y, disp; char *s = NULL, * p = NULL;
  2743.     extern int isguest;
  2744. #ifdef ZFNQFP
  2745.     struct zfnfp * fnp;
  2746. #endif /* ZFNQFP */
  2747.  
  2748.     if (isguest) {
  2749.         printf("?Anonymous log creation not allowed\n");
  2750.         return(-9);
  2751.     }
  2752.     switch (x) {                        /* Which log... */
  2753.  
  2754. #ifdef DEBUG
  2755.       case LOGD:
  2756.         y = cmofi("Name of debugging log file","debug.log",&s,xxstring);
  2757.         break;
  2758. #endif /* DEBUG */
  2759.  
  2760.       case LOGP:
  2761.         y = cmofi("Name of packet log file","packet.log",&s,xxstring);
  2762.         break;
  2763.  
  2764. #ifndef NOLOCAL
  2765.       case LOGS:
  2766.         y = cmofi("Name of session log file","session.log",&s,xxstring);
  2767.         break;
  2768. #endif /* NOLOCAL */
  2769.  
  2770. #ifdef TLOG
  2771.       case LOGT:
  2772.         y = cmofi("Name of transaction log file","transact.log",&s,
  2773.                   xxstring);
  2774.         break;
  2775. #endif /* TLOG */
  2776.  
  2777. #ifdef CKLOGDIAL
  2778.       case LOGM: {
  2779.           int m, n;
  2780.           char mypath[CKMAXPATH+1];
  2781.           m = ckstrncpy(mypath,homepath(),CKMAXPATH);
  2782.           n = strlen(CXLOGFILE);
  2783.           if (m + n < CKMAXPATH)
  2784.             strcat(mypath,CXLOGFILE);
  2785.           else
  2786.             ckstrncpy(mypath,CXLOGFILE,CKMAXPATH);
  2787.           y = cmofi("Name of connection log file",mypath,&s,xxstring);
  2788.           break;
  2789.       }
  2790. #endif /* CKLOGDIAL */
  2791.  
  2792.       default:
  2793.         printf("\n?Unknown log designator - %d\n",x);
  2794.         return(-2);
  2795.     }
  2796.     if (y < 0) return(y);
  2797.     if (y == 2) {
  2798.         printf("?Sorry, %s is a directory name\n",s);
  2799.         return(-9);
  2800.     }
  2801. #ifdef ZFNQFP
  2802. #ifdef OS2ORUNIX
  2803.     if (*s != '|')                      /* Allow for pipes */
  2804. #else
  2805. #ifdef OSK
  2806.     if (*s != '|')
  2807. #endif /* OSK */
  2808. #endif /* OS2ORUNIX */
  2809.       if (fnp = zfnqfp(s,TMPBUFSIZ - 1,tmpbuf)) {
  2810.           if (fnp->fpath)
  2811.             if ((int) strlen(fnp->fpath) > 0)
  2812.               s = fnp->fpath;
  2813.       } /* else if error keep original string */
  2814. #endif /* ZFNQFP */
  2815.  
  2816.     ckstrncpy(line,s,LINBUFSIZ);
  2817.     s = line;
  2818. #ifdef MAC
  2819.     y = 0;
  2820. #else
  2821.  
  2822.     p = "new";
  2823. #ifdef TLOG
  2824.     if ((x == LOGT && tlogfmt == 2) || x == LOGM)
  2825.       p = "append";
  2826. #endif /* TLOG */
  2827.  
  2828.     if ((y = cmkey(disptb,2,"Disposition",p,xxstring)) < 0)
  2829.       return(y);
  2830. #endif /* MAC */
  2831.     disp = y;
  2832.     if ((y = cmcfm()) < 0) return(y);
  2833.  
  2834.     switch (x) {
  2835.  
  2836. #ifdef DEBUG
  2837.       case LOGD:
  2838.         return(deblog = debopn(s,disp));
  2839. #endif /* DEBUG */
  2840.  
  2841. #ifndef NOXFER
  2842.       case LOGP:
  2843.         return(pktlog = pktopn(s,disp));
  2844. #endif /* NOXFER */
  2845.  
  2846. #ifndef NOLOCAL
  2847.       case LOGS:
  2848.         return(seslog = sesopn(s,disp));
  2849. #endif /* NOLOCAL */
  2850.  
  2851. #ifdef TLOG
  2852.       case LOGT:
  2853.         return(tralog = traopn(s,disp));
  2854. #endif /* TLOG */
  2855.  
  2856. #ifdef CKLOGDIAL
  2857.       case LOGM:
  2858.         return(dialog = diaopn(s,disp,0));
  2859. #endif /* CKLOGDIAL */
  2860.  
  2861.       default:
  2862.         return(-2);
  2863.     }
  2864. }
  2865.  
  2866. #ifndef NOXFER
  2867. int
  2868. pktopn(s,disp) char *s; int disp; {
  2869.     static struct filinfo xx;
  2870.     int y;
  2871.  
  2872.     if (!s)
  2873.       s = "";
  2874.     if (!*s)
  2875.       return(0);
  2876.  
  2877.     debug(F111,"pktopn",s,disp);
  2878.  
  2879.     zclose(ZPFILE);
  2880.  
  2881. #ifdef OS2ORUNIX
  2882.     if (s[0] == '|') {                  /* Pipe */
  2883.         char * p = s + 1;
  2884.         debug(F110,"pktopn p",p,0);
  2885.         while (*p) {
  2886.             if (*p != ' ')
  2887.               break;
  2888.             else
  2889.               p++;
  2890.         }
  2891.         debug(F110,"pktopn pipe",p,0);
  2892.         pktlog = zxcmd(ZPFILE,p);
  2893.         debug(F101,"pktopn seslog","",seslog);
  2894.     } else {                            /* File */
  2895. #endif /* OS2ORUNIX */
  2896.         if (disp) {
  2897.             xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
  2898.             xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
  2899.             xx.lblopts = 0;
  2900.             pktlog = zopeno(ZPFILE,s,NULL,&xx);
  2901.         } else pktlog = zopeno(ZPFILE,s,NULL,NULL);
  2902.         if (!pktlog)
  2903.           printf("?%s - %s\n",s,ck_errstr());
  2904. #ifdef OS2ORUNIX
  2905.     }
  2906. #endif /* OS2ORUNIX */
  2907.     if (pktlog > 0)
  2908.       ckstrncpy(pktfil,s,CKMAXPATH+1);
  2909.     else
  2910.       *pktfil = '\0';
  2911.     return(pktlog);
  2912. }
  2913. #endif /* NOXFER */
  2914.  
  2915. int
  2916. traopn(s,disp) char *s; int disp; {
  2917. #ifdef TLOG
  2918.     static struct filinfo xx;
  2919.     int y;
  2920.  
  2921.     if (!s)
  2922.       s = "";
  2923.     if (!*s)
  2924.       return(0);
  2925.  
  2926.     debug(F111,"traopn",s,disp);
  2927.     debug(F101,"traopn tlogfmt","",tlogfmt);
  2928.  
  2929.     zclose(ZTFILE);
  2930.  
  2931. #ifdef OS2ORUNIX
  2932.     if (tlogfmt == 2) {                 /* FTP format is special... */
  2933.         if (!disp)                      /* Append? */
  2934.           if (zchki(s) > -1)            /* No - does file exist? */
  2935.             (VOID) zdelet(s);           /* Yes - delete it. */
  2936.         xferlog = 1;
  2937.         ckstrncpy(trafil,s,CKMAXPATH);
  2938.         xferfile = s;
  2939.         return(1);
  2940.     }
  2941.     if (s[0] == '|') {                  /* Pipe */
  2942.         char * p = s + 1;
  2943.         debug(F110,"traopn p",p,0);
  2944.         while (*p) {
  2945.             if (*p != ' ')
  2946.               break;
  2947.             else
  2948.               p++;
  2949.         }
  2950.         debug(F110,"traopn pipe",p,0);
  2951.         tralog = zxcmd(ZTFILE,p);
  2952.         debug(F101,"traopn tralog","",tralog);
  2953.     }
  2954. #endif /* OS2ORUNIX */
  2955.  
  2956.     if (s[0] != '|') {                  /* File */
  2957.         if (disp) {
  2958.             xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
  2959.             xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
  2960.             xx.lblopts = 0;
  2961.             tralog = zopeno(ZTFILE,s,NULL,&xx);
  2962.         } else tralog = zopeno(ZTFILE,s,NULL,NULL);
  2963.     }
  2964.     if (!tralog)
  2965.       printf("?%s - %s\n",s,ck_errstr());
  2966.     if (tralog > 0 && tlogfmt > 0) {
  2967.         ckstrncpy(trafil,s,CKMAXPATH);
  2968.         tlog(F110,"Transaction Log:",versio,0L);
  2969. #ifndef MAC
  2970.         tlog(F100,ckxsys,"",0L);
  2971. #endif /* MAC */
  2972.         ztime(&s);
  2973.         tlog(F100,s,"",0L);
  2974.     } else
  2975.       *trafil = '\0';
  2976.     return(tralog);
  2977. #else
  2978.     return(0);
  2979. #endif /* TLOG */
  2980. }
  2981.  
  2982. #ifndef NOLOCAL
  2983. int
  2984. sesopn(s,disp) char * s; int disp; {
  2985.     static struct filinfo xx;
  2986.     int y;
  2987.  
  2988.     if (!s)
  2989.       s = "";
  2990.     if (!*s)
  2991.       return(0);
  2992.  
  2993.     debug(F111,"sesopn",s,disp);
  2994.  
  2995.     zclose(ZSFILE);
  2996.  
  2997. #ifdef OS2ORUNIX
  2998.     if (s[0] == '|') {                  /* Pipe */
  2999.         char * p = s + 1;
  3000.         debug(F110,"sesopn p",p,0);
  3001.         while (*p) {
  3002.             if (*p != ' ')
  3003.               break;
  3004.             else
  3005.               p++;
  3006.         }
  3007.         debug(F110,"sesopn pipe",p,0);
  3008.         seslog = zxcmd(ZSFILE,p);
  3009.         debug(F101,"sesopn seslog","",seslog);
  3010.     } else {                            /* File */
  3011. #endif /* OS2ORUNIX */
  3012.         if (disp) {
  3013.             xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
  3014.             xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
  3015.             xx.lblopts = 0;
  3016.             seslog = zopeno(ZSFILE,s,NULL,&xx);
  3017.         } else
  3018.           seslog = zopeno(ZSFILE,s,NULL,NULL);
  3019.         if (!seslog)
  3020.           printf("?%s - %s\n",s,ck_errstr());
  3021. #ifdef OS2ORUNIX
  3022.     }
  3023. #endif /* OS2ORUNIX */
  3024.     if (seslog > 0)
  3025.       ckstrncpy(sesfil,s,CKMAXPATH+1);
  3026.     else
  3027.       *sesfil = '\0';
  3028.     return(seslog);
  3029. }
  3030. #endif /* NOLOCAL */
  3031. #endif /* NOICP */
  3032.  
  3033. int
  3034. debopn(s,disp) char *s; int disp; {
  3035. #ifdef DEBUG
  3036. #ifdef CK_UTSNAME
  3037.     extern char unm_mch[], unm_nam[], unm_rel[], unm_ver[], unm_mod[];
  3038. #endif /* CK_UTSNAME */
  3039. #ifdef OS2
  3040.     extern char ckxsystem[];
  3041. #endif /* OS2 */
  3042.     char *tp;
  3043.     static struct filinfo xx;
  3044.  
  3045.     if (!s)
  3046.       s = "";
  3047.     if (!*s)
  3048.       return(0);
  3049.  
  3050.     zclose(ZDFILE);
  3051.  
  3052. #ifdef OS2ORUNIX
  3053.     if (s[0] == '|') {                  /* Pipe */
  3054.         char * p = s + 1;
  3055.         debug(F110,"debopn p",p,0);
  3056.         while (*p) {
  3057.             if (*p != ' ')
  3058.               break;
  3059.             else
  3060.               p++;
  3061.         }
  3062.         debug(F110,"debopn pipe",p,0);
  3063.         deblog = zxcmd(ZDFILE,p);
  3064.         debug(F101,"debopn deblog","",deblog);
  3065.     } else {                            /* File */
  3066. #endif /* OS2ORUNIX */
  3067.         if (disp) {
  3068.             xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
  3069.             xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
  3070.             xx.lblopts = 0;
  3071.             deblog = zopeno(ZDFILE,s,NULL,&xx);
  3072.         } else
  3073.           deblog = zopeno(ZDFILE,s,NULL,NULL);
  3074.         if (!deblog)
  3075.           printf("?%s - %s\n",s,ck_errstr());
  3076. #ifdef OS2ORUNIX
  3077.     }
  3078. #endif /* OS2ORUNIX */
  3079.     if (deblog > 0) {
  3080.         ckstrncpy(debfil,s,CKMAXPATH+1);
  3081.         debug(F110,"Debug Log ",versio,0);
  3082. #ifndef MAC
  3083. #ifdef OS2
  3084.         debug(F110,ckxsys,ckxsystem,0);
  3085. #else /* OS2 */
  3086.         debug(F100,ckxsys,"",0);
  3087. #endif /* OS2 */
  3088. #endif /* MAC */
  3089. #ifdef CK_UTSNAME
  3090.         if (unm_mch[0]) {
  3091.             debug(F110,"uname machine",unm_mch,0);
  3092.             if (unm_mod[0])
  3093.               debug(F110,"uname model  ",unm_mod,0);
  3094.             debug(F110,"uname sysname",unm_nam,0);
  3095.             debug(F110,"uname release",unm_rel,0);
  3096.             debug(F110,"uname version",unm_ver,0);
  3097.         }
  3098. #ifdef KTARGET
  3099.     {
  3100.         char * s;            /* Makefile target */
  3101.         s = KTARGET;
  3102.         if (!s) s = "";
  3103.         if (!*s) s = "(unknown)";
  3104.         debug(F110,"build target",s,0);
  3105.     }
  3106. #endif /* KTARGET */
  3107.         deblog = 0;
  3108.         ztime(&tp);
  3109.         deblog = 1;
  3110.         debug(F100,tp,"",0);
  3111. #endif /* UTSNAME */
  3112.         debug(F101,"byteorder","",byteorder);
  3113.     } else *debfil = '\0';
  3114.     return(deblog);
  3115. #else
  3116.     return(0);
  3117. #endif /* MAC */
  3118. }
  3119.  
  3120.  
  3121. static char ndatbuf[10];
  3122.  
  3123. /*  C K D A T E  --  Returns current date/time in standard format  */
  3124.  
  3125. static char nowbuf[18];
  3126.  
  3127. char *
  3128. ckdate() {
  3129.     extern struct keytab cmonths[];
  3130.     int x;
  3131.     char * t;                   /* Substitute today's date */
  3132.     char dbuf[32];
  3133.     ztime(&t);
  3134.  
  3135. /*  012345678901234567890123 */
  3136. /*  Sat Jul  4 12:16:43 1998 */
  3137.  
  3138.     ckstrncpy(dbuf,t,32);
  3139.     t = dbuf;
  3140.     debug(F110,"ckdate dbuf",dbuf,0);
  3141.     nowbuf[0] = t[20];
  3142.     nowbuf[1] = t[21];
  3143.     nowbuf[2] = t[22];
  3144.     nowbuf[3] = t[23];
  3145.  
  3146.     nowbuf[4] = NUL;
  3147.     debug(F110,"ckdate nowbuf",nowbuf,0);
  3148.  
  3149.     t[7] = NUL;
  3150.     if ((x = lookup(cmonths,t+4,12,NULL)) < 0) {
  3151.         debug(F110,"ckdate bad month",t,0);
  3152.         return("<BAD_MONTH>");
  3153.     }
  3154.     sprintf(nowbuf+4,"%02d",x);
  3155.     nowbuf[6] = (t[8] == SP) ? '0' : t[8];
  3156.     nowbuf[7] = t[9];
  3157.     nowbuf[8] = ' ';
  3158.  
  3159.     nowbuf[9] = NUL;
  3160.     debug(F110,"ckdate nowbuf",nowbuf,0);
  3161.  
  3162.     for (x = 11; x < 19; x++) nowbuf[x-2] = t[x];
  3163.     nowbuf[17] = NUL;
  3164.     debug(F110,"ckdate nowbuf",nowbuf,0);
  3165.  
  3166.     return((char *)nowbuf);
  3167. }
  3168.  
  3169. #ifndef NOICP
  3170. #ifdef CKLOGDIAL
  3171.  
  3172. /*
  3173.   fc = 0 for initial open, meaning open, then close immediately.
  3174.   fc > 0 for subsequent opens, meaning open for use, leave open.
  3175. */
  3176. int
  3177. diaopn(s,disp,fc) char *s; int disp, fc; {
  3178.     extern char diafil[];
  3179.     static struct filinfo xx;
  3180.     int y;
  3181.  
  3182.     if (!s)
  3183.       s = "";
  3184.     if (!*s)
  3185.       return(0);
  3186.  
  3187.     debug(F110,"diaopn log",s,0);
  3188.     debug(F101,"diaopn fc",s,fc);
  3189.     debug(F101,"diaopn disp 1",s,disp);
  3190.     if (fc) disp = 1;                   /* Force append if open for use */
  3191.     debug(F101,"diaopn disp 2",s,disp);
  3192.  
  3193.     zclose(ZDIFIL);                     /* In case a log was already open */
  3194.  
  3195. #ifdef OS2ORUNIX
  3196.     if (s[0] == '|') {                  /* Pipe */
  3197.         char * p = s + 1;
  3198.         debug(F110,"diaopn p",p,0);
  3199.         while (*p) {
  3200.             if (*p != ' ')
  3201.               break;
  3202.             else
  3203.               p++;
  3204.         }
  3205.         debug(F110,"diaopn pipe",p,0);
  3206.         dialog = zxcmd(ZDIFIL,p);
  3207.         debug(F101,"diaopn dialog","",dialog);
  3208.     } else {                            /* File */
  3209. #endif /* OS2ORUNIX */
  3210.         if (disp) {
  3211.             xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
  3212.             xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
  3213.             xx.lblopts = 0;
  3214.             dialog = zopeno(ZDIFIL,s,NULL,&xx);
  3215.         } else dialog = zopeno(ZDIFIL,s,NULL,NULL);
  3216.         if (!dialog)
  3217.           printf("?%s - %s\n",s,ck_errstr());
  3218. #ifdef OS2ORUNIX
  3219.     }
  3220. #endif /* OS2ORUNIX */
  3221.     if (dialog > 0)
  3222.       ckstrncpy(diafil,s,CKMAXPATH+1);
  3223.     else
  3224.       *diafil = '\0';
  3225.     if (fc == 0)                        /* Initial open */
  3226.       zclose(ZDIFIL);                   /* close it */
  3227.     return(dialog);
  3228. }
  3229. #endif /* CKLOGDIAL */
  3230.  
  3231. #ifndef NOSHOW
  3232.  
  3233. /*  SHOW command routines */
  3234.  
  3235. char *
  3236. shoxm() {
  3237.     char * s;
  3238.     switch (binary) {
  3239.       case XYFT_T: s = "text";         break;
  3240. #ifdef VMS
  3241.       case XYFT_B: s = "binary fixed"; break;
  3242.       case XYFT_I: s = "image";        break;
  3243.       case XYFT_L: s = "labeled";      break;
  3244.       case XYFT_U: s = "binary undef"; break;
  3245. #else
  3246. #ifdef MAC
  3247.       case XYFT_B: s = "binary";       break;
  3248.       case XYFT_M: s = "macbinary";    break;
  3249. #else
  3250.       case XYFT_B: s = "binary";       break;
  3251. #ifdef CK_LABELED
  3252.       case XYFT_L: s = "labeled";      break;
  3253. #endif /* CK_LABELED */
  3254. #endif /* MAC */
  3255. #endif /* VMS */
  3256.       default: s = "unknown"; break;
  3257.     }
  3258.     return(s);
  3259. }
  3260.  
  3261. #ifndef NOXFER
  3262. VOID                                    /* SHOW TRANSFER */
  3263. shoxfer() {
  3264.     extern int docrc, usepipes;
  3265.     printf("\n");
  3266.     printf(" Transfer Bell: %s\n",showoff(xfrbel));
  3267.     printf(" Transfer Interruption: %s\n",showoff(xfrint));
  3268.     printf(" Transfer Cancellation: %s\n",showoff(xfrcan));
  3269. #ifndef NOCSETS
  3270.     printf(" Transfer Character-set: ");
  3271.     if (tcharset == TC_TRANSP)
  3272.       printf("Transparent\n");
  3273.     else
  3274.       printf("%s\n",tcsinfo[tcharset].keyword);
  3275. #endif /* NOCSETS */
  3276.     printf(" Transfer CRC-calculation: %s\n",showoff(docrc));
  3277.     printf(" Transfer Display: ");
  3278.     switch (fdispla) {
  3279.       case XYFD_N: printf("%s\n","none"); break;
  3280.       case XYFD_R: printf("%s\n","serial"); break;
  3281.       case XYFD_C: printf("%s\n","fullscreen"); break;
  3282.       case XYFD_S: printf("%s\n","crt"); break;
  3283.       case XYFD_B: printf("%s\n","brief"); break;
  3284.     }
  3285.     printf(" Transfer Locking-shift: ");
  3286.     if (lscapu == 2) {
  3287.         printf("forced");
  3288.     } else {
  3289.         printf("%s", (lscapr ? "enabled" : "disabled"));
  3290.         if (lscapr) printf(",%s%s", (lscapu ? " " : " not "), "used");
  3291.     }
  3292.     printf("\n Transfer Mode: %s\n",
  3293.            xfermode == XMODE_A ?
  3294.            "automatic" :
  3295.            "manual"
  3296.            );
  3297.     printf(" Transfer Pipes: %s\n", showoff(usepipes));
  3298.     printf(" Transfer Protocol: %s\n",ptab[protocol].p_name);
  3299.     printf(" Transfer Slow-start: %s\n",showoff(slostart));
  3300.     printf("\n");
  3301. }
  3302. #endif /* NOXFER */
  3303.  
  3304. VOID
  3305. shoflow() {
  3306.     int i, x;
  3307.     extern int cxflow[], cxtype, ncxname, nfloname;
  3308.     extern char * cxname[];
  3309.     printf("\nConnection type:      %s\n",cxname[cxtype]);
  3310.     printf("Current flow-control: %s\n", floname[flow]);
  3311.     printf("\nDefaults by connection type:\n");
  3312.     debug(F111,"shoflow cxtype",cxname[cxtype],cxtype);
  3313.     debug(F101,"shoflow flow","",flow);
  3314.     for (i = 0; i < ncxname; i++) {
  3315. #ifdef NOLOCAL
  3316.         if (i > 0) break;
  3317. #endif /* NOLOCAL */
  3318. #ifndef NETCONN
  3319.         if (i > 2) break;
  3320. #endif /* NETCONN */
  3321. #ifndef DECNET
  3322.         if (i == CXT_DECNET) continue;
  3323. #endif /* DECNET */
  3324. #ifndef DECNET
  3325. #ifndef SUPERLAT
  3326.         if (i == CXT_LAT) continue;
  3327. #endif /* SUPERLAT */
  3328. #endif /* DECNET */
  3329. #ifndef CK_NETBIOS
  3330.         if (i == CXT_NETBIOS) continue;
  3331. #endif /* CK_NETBIOS */
  3332. #ifndef NPIPE
  3333.         if (i == CXT_NPIPE) continue;
  3334. #endif /* NPIPE */
  3335. #ifndef SSH
  3336.         if (i == CXT_SSH) continue;
  3337. #endif /* SSH */
  3338. #ifndef NETCMD
  3339.         if (i == CXT_PIPE) continue;
  3340. #endif /* NETCMD */
  3341. #ifndef ANYX25
  3342.         if (i == CXT_X25) continue;
  3343. #endif /* ANYX25 */
  3344.         x = cxflow[i];
  3345.         debug(F101,"shoflow x","",x);
  3346.         if (x < nfloname)
  3347.           printf("  %-14s: %s\n",cxname[i],floname[x]);
  3348.         else
  3349.           printf("  %-14s: (%d)\n",cxname[i],x);
  3350.     }
  3351.     printf("\n");
  3352. }
  3353.  
  3354. #ifndef NOLOCAL
  3355. #ifdef ANYX25
  3356. int
  3357. shox25(n) int n; {
  3358.     if (nettype == NET_SX25) {
  3359.         printf("SunLink X.25 V%d.%d",x25ver / 10,x25ver % 10);
  3360.         if (ttnproto == NP_X3) printf(", PAD X.3, X.28, X.29 protocol,");
  3361.         printf("\n");
  3362.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3363.         printf(" Reverse charge call %s",
  3364.                revcall ? "selected" : "not selected");
  3365.         printf (", Closed user group ");
  3366.         if (closgr > -1)
  3367.           printf ("%d",closgr);
  3368.         else
  3369.           printf ("not selected");
  3370.         printf("\n");
  3371.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3372.         printf(" Call user data %s.\n", cudata ? udata : "not selected");
  3373.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3374.     } else if (nettype == NET_VX25) {
  3375.         if (ttnproto == NP_X3) printf(", PAD X.3, X.28, X.29 protocol,");
  3376.         printf("\n");
  3377.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3378.         printf(" Reverse charge call %s",
  3379.                revcall ? "selected" : "not selected");
  3380.         printf (", Closed user group [unsupported]");
  3381.         if (closgr > -1)
  3382.           printf ("%d",closgr);
  3383.         else
  3384.           printf ("not selected");
  3385.         printf (",");
  3386.         printf("\n");
  3387.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3388.         printf(" Call user data %s.\n", cudata ? udata : "not selected");
  3389.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3390.     } else if (nettype == NET_IX25) {
  3391.         printf("AIX NPI X.25\n");
  3392.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3393.         printf("\n Reverse charge call %s",
  3394.                revcall ? "selected" : "not selected");
  3395.         printf (", Closed user group [unsupported]");
  3396.         if (closgr > -1)
  3397.           printf ("%d",closgr);
  3398.         else
  3399.           printf ("not selected");
  3400.         printf (",");
  3401.         printf("\n Call user data %s.\n", cudata ? udata : "not selected");
  3402.     }
  3403.     return(n);
  3404. }
  3405.  
  3406. #ifndef IBMX25
  3407. int
  3408. shopad(n) int n; {
  3409.     int i;
  3410.     printf("\nX.3 PAD Parameters:\n");
  3411.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3412.     for (i = 0; i < npadx3; i++) {
  3413.         printf(" [%d] %s %d\n",padx3tab[i].kwval,padx3tab[i].kwd,
  3414.                padparms[padx3tab[i].kwval]);
  3415.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3416.     }
  3417.     return(n);
  3418. }
  3419. #endif /* IBMX25 */
  3420. #endif /* ANYX25 */
  3421.  
  3422. VOID
  3423. shoparc() {
  3424.     extern int reliable, stopbits, clsondisc;
  3425.     int i; char *s;
  3426.     long zz;
  3427.  
  3428.     printf("Communications Parameters:\n");
  3429.     if (network
  3430. #ifdef IKSD
  3431.          || inserver
  3432. #endif /* IKSD */
  3433.          ) {
  3434.         printf(" Host: %s%s",ttname,reliable == SET_ON ? " (reliable)" : "");
  3435.     } else {
  3436.  
  3437.         printf(" %s: %s%s, speed: ",
  3438. #ifdef OS2
  3439.                "Port",
  3440. #else
  3441.                "Line",
  3442. #endif /* OS2 */
  3443.                ttname,
  3444. #ifdef CK_TTYFD
  3445.                (local &&
  3446. #ifdef VMS
  3447.                 vmsttyfd() < 0
  3448. #else
  3449.                 ttyfd == -1
  3450. #endif /* VMS */
  3451.                 ) ?
  3452.                  " (closed)" :
  3453.                    (reliable == SET_ON ? " (reliable)" : "")
  3454. #else
  3455.                ""
  3456. #endif /* CK_TTYFD */
  3457.                );
  3458.         if (
  3459. #ifdef CK_TTYFD
  3460. #ifdef VMS
  3461.             vmsttyfd() < 0
  3462. #else
  3463.             ttyfd == -1
  3464. #endif /* VMS */
  3465.             ||
  3466. #endif /* CK_TTYFD */
  3467.             (zz = ttgspd()) < 0) {
  3468.             printf("unknown");
  3469.         } else {
  3470.             if (speed == 8880) printf("75/1200");
  3471.             else if (speed == 134) printf("134.5");
  3472.             else printf("%ld",zz);
  3473.         }
  3474.     }
  3475.     if (network
  3476. #ifdef IKSD
  3477.          || inserver
  3478. #endif /* IKSD */
  3479.          )
  3480.       printf("\n Mode: ");
  3481.     else
  3482.       printf(", mode: ");
  3483.     if (local) printf("local"); else printf("remote");
  3484.     if (network == 0
  3485. #ifdef IKSD
  3486.          && !inserver
  3487. #endif/* IKSD */
  3488.          ) {
  3489. #ifdef CK_TAPI
  3490.         if (tttapi && !tapipass )
  3491.           printf(", modem: %s","TAPI");
  3492.         else
  3493. #endif /* CK_TAPI */
  3494.         printf(", modem: %s",gmdmtyp());
  3495.     } else {
  3496. #ifdef NETCONN
  3497.        if (nettype == NET_TCPA) printf(", TCP/IP");
  3498.        if (nettype == NET_TCPB) printf(", TCP/IP");
  3499.        if (nettype == NET_DEC) {
  3500.            if (ttnproto == NP_LAT) printf(", DECnet LAT");
  3501.            else if ( ttnproto == NP_CTERM ) printf(", DECnet CTERM");
  3502.            else printf(", DECnet");
  3503.        }
  3504.        if (nettype == NET_SLAT) printf(", Meridian Technologies' SuperLAT");
  3505. #ifdef NETFILE
  3506.        if (nettype == NET_FILE) printf(", local file");
  3507. #endif /* NETFILE */
  3508. #ifdef NETCMD
  3509.        if (nettype == NET_CMD) printf(", pipe");
  3510. #endif /* NETCMD */
  3511. #ifdef NETPTY
  3512.        if (nettype == NET_PTY) printf(", psuedoterminal");
  3513. #endif /* NETPTY */
  3514. #ifdef NETDLL
  3515.        if (nettype == NET_DLL) printf(", dynamic load library");
  3516. #endif /* NETDLL */
  3517. #ifdef SSH
  3518.        if (nettype == NET_SSH) printf(", Secure Shell");
  3519. #endif /* SSH */
  3520.        if (nettype == NET_PIPE) printf(", Named Pipes");
  3521. #ifdef ANYX25
  3522.        if (shox25(0) < 0) return;
  3523. #endif /* ANYX25 */
  3524.        if (ttnproto == NP_TELNET) {
  3525.            printf(", telnet protocol");
  3526.            if (0
  3527. #ifdef CK_ENCRYPTION
  3528.                || ck_tn_encrypting() && ck_tn_decrypting()
  3529. #endif /* CK_ENCRYPTION */
  3530. #ifdef CK_SSL
  3531.                || tls_active_flag || ssl_active_flag
  3532. #endif /* CK_SSL */
  3533.                )
  3534.              printf(" (SECURE)");
  3535.        }
  3536. #ifdef RLOGCODE
  3537.        else if (ttnproto == NP_RLOGIN || ttnproto == NP_K4LOGIN ||
  3538.                 ttnproto == NP_K5LOGIN)
  3539.          printf(", rlogin protocol");
  3540.        else if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN)
  3541.          printf(", rlogin protocol (SECURE)");
  3542. #endif /* RLOGCODE */
  3543. #endif /* NETCONN */
  3544.     }
  3545.     printf("\n");
  3546.     if (hwparity && local && !network)
  3547.       s = parnam((char)hwparity);
  3548.     else
  3549.       s = parnam((char)parity);
  3550.     printf(" Parity: %s%s",hwparity ? "hardware " : "", s);
  3551. #ifndef NOLOCAL
  3552.     if (local && !network) {
  3553.         int sb;
  3554.         char c;
  3555.         c = s[0];
  3556.         if (islower(c)) c = toupper(c);
  3557.         sb = stopbits;
  3558.         if (sb < 1) {
  3559.             sb = (speed <= 110L) ? 2 : 1;
  3560.             printf(", stop-bits: (default)");
  3561.         } else {
  3562.             printf(", stop-bits: %d",sb);
  3563.         }
  3564.         if (hwparity)
  3565.           printf(" (8%c%d)",c,sb);
  3566.         else if (parity)
  3567.           printf(" (7%c%d)",c,sb);
  3568.         else
  3569.           printf(" (8N%d)",sb);
  3570.         printf("\n D");
  3571.     } else
  3572.       printf(", d");
  3573. #endif /* NOLOCAL */
  3574.  
  3575.     printf("uplex: %s, ", duplex ? "half" : "full");
  3576.     debug(F101,"shoparp flow","",flow);
  3577.     printf("flow: %s", floname[flow]);
  3578.     printf(", handshake: ");
  3579.     if (turn) printf("%d\n",turnch); else printf("none\n");
  3580. #ifdef COMMENT
  3581.     if (local && !network) {            /* SET CARRIER-WATCH */
  3582. #endif /* COMMENT */
  3583.         if (carrier == CAR_OFF) s = "off";
  3584.         else if (carrier == CAR_ON) s = "on";
  3585.         else if (carrier == CAR_AUT) s = "auto";
  3586.         else s = "unknown";
  3587.         printf(" Carrier-watch: %s", s);
  3588.         if (carrier == CAR_ON) {
  3589.             if (cdtimo) printf(", timeout: %d sec", cdtimo);
  3590.             else printf(", timeout: none");
  3591.         }
  3592. #ifdef COMMENT
  3593.     }
  3594. #endif /* COMMENT */
  3595.     printf(", close-on-disconnect: %s\n",showoff(clsondisc));
  3596.  
  3597. #ifdef UNIX
  3598. #ifndef NOUUCP
  3599.     if (local && !network && haslock && *flfnam) /* UUCP lockfile, UNIX only */
  3600.       printf(" Lockfile: %s",flfnam);
  3601. #ifndef USETTYLOCK
  3602.     if (local && !network && haslock && lock2[0])
  3603.       printf("\n Secondary lockfile: %s",lock2);
  3604. #endif /* USETTYLOCK */
  3605. #else
  3606. #ifdef QNX
  3607.     {
  3608.         extern int qnxportlock, qnxopencount();
  3609.         if (local)
  3610.           printf(" Qnx-port-lock: %s, Open count: %d\n",
  3611.                  showoff(qnxportlock),
  3612.                  qnxopencount()
  3613.                  );
  3614.         else
  3615.           printf(" Qnx-port-lock: %s\n", showoff(qnxportlock));
  3616.     }
  3617. #endif /* QNX */
  3618. #endif /* NOUUCP */
  3619. #endif /* UNIX */
  3620.     printf("\n");
  3621.  
  3622.     if (local) {
  3623.         int i;
  3624.         i = parity ? 7 : 8;
  3625.         if (i == 8) i = (cmask == 0177) ? 7 : 8;
  3626.         printf(" Terminal bytesize: %d,",i);
  3627.         printf(" escape character: %d (^%c)\n",escape,ctl(escape));
  3628.     }
  3629. }
  3630.  
  3631. #ifdef TNCODE
  3632.  
  3633. #ifdef CK_AUTHENTICATION
  3634. _PROTOTYP(int ck_tn_authenticated, (VOID));
  3635. extern int forward_flag, forwarded_tickets;
  3636. #endif /* CK_AUTHENTICATION */
  3637. #ifdef CK_ENCRYPTION
  3638. _PROTOTYP(int ck_tn_encrypting, (VOID));
  3639. _PROTOTYP(int ck_tn_decrypting, (VOID));
  3640. #endif /* CK_ENCRYPTION */
  3641.  
  3642. int
  3643. shotopt(n) int n; {
  3644.     int opt;
  3645.  
  3646.     printf("%20s %12s %12s %12s %12s\n\n",
  3647.            "Telnet Option","Me (client)","U (client)",
  3648.            "Me (server)","U (server)");
  3649.     n += 2;
  3650.     if (n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3651.  
  3652.     for ( opt = TELOPT_FIRST; opt <= TELOPT_LAST; opt++) {
  3653.         switch (opt) {
  3654.           case TELOPT_AUTHENTICATION:
  3655.           case TELOPT_ENCRYPTION:
  3656.           case TELOPT_TTYPE:
  3657.           case TELOPT_NAWS:
  3658.           case TELOPT_BINARY:
  3659.           case TELOPT_NEWENVIRON:
  3660.           case TELOPT_SNDLOC:
  3661.           case TELOPT_XDISPLOC:
  3662.           case TELOPT_SGA:
  3663.           case TELOPT_ECHO:
  3664.           case TELOPT_KERMIT:
  3665.           case TELOPT_START_TLS:
  3666.           case TELOPT_FORWARD_X:
  3667.             break;
  3668.           default:
  3669.             continue;
  3670.         }
  3671. #ifdef COMMENT
  3672.         /* Some compilers choke on this: "too many instructions generated" */
  3673.         printf("%20s %12s %12s %12s %12s\n",
  3674.                TELOPT(opt),
  3675.                TELOPT_MODE(TELOPT_DEF_C_ME_MODE(opt)),
  3676.                TELOPT_MODE(TELOPT_DEF_C_U_MODE(opt)),
  3677.                TELOPT_MODE(TELOPT_DEF_S_ME_MODE(opt)),
  3678.                TELOPT_MODE(TELOPT_DEF_S_U_MODE(opt))
  3679.                );
  3680. #else
  3681.         printf("%20s ",
  3682.                TELOPT(opt)
  3683.                );
  3684.         printf("%12s %12s ",
  3685.                TELOPT_MODE(TELOPT_DEF_C_ME_MODE(opt)),
  3686.                TELOPT_MODE(TELOPT_DEF_C_U_MODE(opt))
  3687.                );
  3688.         printf("%12s %12s\n",
  3689.                TELOPT_MODE(TELOPT_DEF_S_ME_MODE(opt)),
  3690.                TELOPT_MODE(TELOPT_DEF_S_U_MODE(opt))
  3691.                );
  3692. #endif /* COMMENT */
  3693.  
  3694.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3695.         if (sstelnet)
  3696.           printf("%20s %12s %12s %12s %12s\n",
  3697.                  "",
  3698.                  "",
  3699.                  "",
  3700.                  (TELOPT_ME(opt)?"WILL":"WONT"),
  3701.                  (TELOPT_U(opt)?"WILL":"WONT")
  3702.                  );
  3703.         else
  3704.           printf("%20s %12s %12s %12s %12s\n",
  3705.                  "",
  3706.                  (TELOPT_ME(opt)?"WILL":"WONT"),
  3707.                  (TELOPT_U(opt)?"WILL":"WONT"),
  3708.                  "",
  3709.                  ""
  3710.                  );
  3711.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3712.     }
  3713.     return(n);
  3714. }
  3715.  
  3716. int
  3717. shotel(n) int n; {
  3718.     extern int tn_duplex;
  3719. #ifdef CK_ENVIRONMENT
  3720.     extern int tn_env_flg;
  3721.     extern char tn_env_acct[];
  3722.     extern char tn_env_disp[];
  3723.     extern char tn_env_job[];
  3724.     extern char tn_env_prnt[];
  3725.     extern char tn_env_sys[];
  3726. #endif /* CK_ENVIRONMENT */
  3727. #ifdef CK_SNDLOC
  3728.     extern char * tn_loc;
  3729. #endif /* CK_SNDLOC */
  3730.     printf("SET TELNET parameters:\n echo: %s\n NVT newline-mode: ",
  3731.            tn_duplex ? "local" : "remote");
  3732.     switch (tn_nlm) {
  3733.       case TNL_CRNUL: printf("%s\n","off (cr-nul)"); break;
  3734.       case TNL_CRLF:  printf("%s\n","on (cr-lf)"); break;
  3735.       case TNL_CR:    printf("%s\n","raw (cr)"); break;
  3736.       case TNL_LF:    printf("%s\n","(lf)"); break;
  3737.     }
  3738.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3739. #ifdef CK_AUTHENTICATION
  3740.     {
  3741.         int type = ck_tn_authenticated();
  3742.         printf(" authentication: ");
  3743.         switch (sstelnet ?
  3744.                 TELOPT_U_MODE(TELOPT_AUTHENTICATION) :
  3745.                  TELOPT_ME_MODE(TELOPT_AUTHENTICATION)
  3746.                 ) {
  3747.           case TN_NG_AC: printf( "accepted " ); break;
  3748.           case TN_NG_RF: printf( "refused  " ); break;
  3749.           case TN_NG_RQ: printf( "requested"); break;
  3750.           case TN_NG_MU: printf( "required "); break;
  3751.         }
  3752.  
  3753. #ifdef CK_SSL
  3754.         if ((ssl_active_flag || tls_active_flag) &&
  3755.              ck_tn_auth_valid() == AUTH_VALID &&
  3756.              (!TELOPT_U(TELOPT_AUTHENTICATION) ||
  3757.                type == AUTHTYPE_NULL ||
  3758.                type == AUTHTYPE_AUTO))
  3759.             printf("   in use: X.509 certificate\n");
  3760.         else
  3761. #endif /* CK_SSL */
  3762.       printf("   in use: %s\n",AUTHTYPE_NAME(type));
  3763.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3764.         if (forward_flag)
  3765.           printf("  credentials forwarding requested %s\n",
  3766.                  forwarded_tickets ? "and completed" :
  3767.                  "but not completed");
  3768.         else
  3769.           printf("  credentials forwarding disabled\n");
  3770.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3771.     }
  3772. #endif /* CK_AUTHENTICATION */
  3773. #ifdef CK_ENCRYPTION
  3774.     {
  3775.         int i,x;
  3776.         int e_type = ck_tn_encrypting();
  3777.         int d_type = ck_tn_decrypting();
  3778.         char * e_str = NULL, * d_str = NULL;
  3779.         static struct keytab * tnetbl = NULL;
  3780.         static int ntnetbl = 0;
  3781.  
  3782.         x = ck_get_crypt_table(&tnetbl,&ntnetbl);
  3783.  
  3784.         for (i = 0; i < ntnetbl; i++) {
  3785.             if (e_type == tnetbl[i].kwval)
  3786.               e_str = tnetbl[i].kwd;
  3787.             if (d_type == tnetbl[i].kwval)
  3788.               d_str = tnetbl[i].kwd;
  3789.         }
  3790.         printf(" encryption: ");
  3791.         switch (TELOPT_ME_MODE(TELOPT_ENCRYPTION)) {
  3792.           /* This should be changed to report both ME and U modes */
  3793.           case TN_NG_AC: printf( "accepted " ); break;
  3794.           case TN_NG_RF: printf( "refused  " ); break;
  3795.           case TN_NG_RQ: printf( "requested"); break;
  3796.           case TN_NG_MU: printf( "required "); break;
  3797.         }
  3798.         printf("       in use: ");
  3799.         switch ((e_type ? 1 : 0) | (d_type ? 2 : 0)) {
  3800.           case 0:
  3801.             printf("plain text in both directions");
  3802.             break;
  3803.           case 1:
  3804.             printf("%s output, plain text input",e_str);
  3805.             break;
  3806.           case 2:
  3807.             printf("plain text output, %s input",d_str);
  3808.             break;
  3809.           case 3:
  3810.             printf("%s output, %s input",e_str,d_str);
  3811.             break;
  3812.         }
  3813.         printf("\n");
  3814.         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3815.     }
  3816. #endif /* CK_ENCRYPTION */
  3817. #ifdef IKS_OPTION
  3818.     printf(" kermit: ");
  3819.     switch (TELOPT_U_MODE(TELOPT_KERMIT)) {
  3820.       case TN_NG_AC: printf( "u, accepted;  " ); break;
  3821.       case TN_NG_RF: printf( "u, refused;   " ); break;
  3822.       case TN_NG_RQ: printf( "u, requested; "); break;
  3823.       case TN_NG_MU: printf( "u, required;  "); break;
  3824.     }
  3825.     switch (TELOPT_ME_MODE(TELOPT_KERMIT)) {
  3826.       case TN_NG_AC: printf( "me, accepted;  " ); break;
  3827.       case TN_NG_RF: printf( "me, refused;   " ); break;
  3828.       case TN_NG_RQ: printf( "me, requested; "); break;
  3829.       case TN_NG_MU: printf( "me, required;  "); break;
  3830.     }
  3831.     if (TELOPT_U(TELOPT_KERMIT))
  3832.       printf(" u, %s",
  3833.              TELOPT_SB(TELOPT_KERMIT).kermit.u_start ?
  3834.              "started" :
  3835.              "stopped"
  3836.              );
  3837.     else
  3838.       printf(" u, n/a");
  3839.     if (TELOPT_ME(TELOPT_KERMIT))
  3840.       printf(" me, %s;",
  3841.              TELOPT_SB(TELOPT_KERMIT).kermit.me_start ?
  3842.              "started" :
  3843.              "stopped"
  3844.              );
  3845.     else
  3846.       printf(" me, n/a;");
  3847.     printf("\n");
  3848.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3849. #endif /* IKS_OPTION */
  3850.     printf(" BINARY newline-mode: ");
  3851.     switch (tn_b_nlm) {
  3852.       case TNL_CRNUL: printf("%s\n","off (cr-nul)"); break;
  3853.       case TNL_CRLF:  printf("%s\n","on (cr-lf)"); break;
  3854.       case TNL_CR:    printf("%s\n","raw (cr)"); break;
  3855.       case TNL_LF:    printf("%s\n","(lf)"); break;
  3856.     }
  3857.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3858.     printf(" binary-mode: ");
  3859.     switch (TELOPT_U_MODE(TELOPT_BINARY)) {
  3860.       case TN_NG_AC: printf( "u, accepted;  " ); break;
  3861.       case TN_NG_RF: printf( "u, refused;   " ); break;
  3862.       case TN_NG_RQ: printf( "u, requested; "); break;
  3863.       case TN_NG_MU: printf( "u, required;  "); break;
  3864.     }
  3865.     switch (TELOPT_ME_MODE(TELOPT_BINARY)) {
  3866.       case TN_NG_AC: printf( "me, accepted; " ); break ;
  3867.       case TN_NG_RF: printf( "me, refused; " ); break;
  3868.       case TN_NG_RQ: printf( "me, requested; "); break;
  3869.       case TN_NG_MU: printf( "me, required;  "); break;
  3870.     }
  3871.     printf("u, %s; me, %s\n",
  3872.            TELOPT_U(TELOPT_BINARY) ? "BINARY" : "NVT",
  3873.            TELOPT_ME(TELOPT_BINARY) ? "BINARY" : "NVT"
  3874.            );
  3875.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3876.     printf(" binary-transfer-mode: %s\n",showoff(tn_b_xfer));
  3877.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3878.     printf(" bug binary-me-means-u-too: %s\n",showoff(tn_b_meu));
  3879.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3880.     printf(" bug binary-u-means-me-too: %s\n",showoff(tn_b_ume));
  3881.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3882.     printf(" bug sb-implies-will-do: %s\n",showoff(tn_sb_bug));
  3883.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3884.     printf(" terminal-type: ");
  3885.     if (tn_term) {
  3886.         printf("%s\n",tn_term);
  3887.     } else {
  3888.         char *p;
  3889. #ifdef OS2
  3890.         p = (tt_type >= 0 && tt_type <= max_tt) ?
  3891.           tt_info[tt_type].x_name :
  3892.             "UNKNOWN";
  3893. #else
  3894.         p = getenv("TERM");
  3895. #endif /* OS2 */
  3896.         if (p)
  3897.           printf("none (%s will be used)\n",p);
  3898.         else printf("none\n");
  3899.     }
  3900.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3901. #ifdef CK_ENVIRONMENT
  3902.     printf(" environment: %s\n", showoff(tn_env_flg));
  3903.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3904.     printf("   account: %s\n",tn_env_acct);
  3905.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3906.     printf("   display: %s\n",tn_env_disp);
  3907.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3908.     printf("   job    : %s\n",tn_env_job);
  3909.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3910.     printf("   printer: %s\n",tn_env_prnt);
  3911.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3912. #ifndef NOSPL
  3913.     printf("   user   : %s\n",uidbuf);
  3914.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3915. #endif /* NOSPL */
  3916.     printf("   system : %s\n",tn_env_sys);
  3917.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3918. #endif /* CK_ENVIRONMENT */
  3919. #ifdef CK_SNDLOC
  3920.     printf(" location: %s\n", tn_loc ? tn_loc : "(none)");
  3921.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3922. #endif /* CK_SNDLOC */
  3923.     return(n);
  3924. }
  3925. #endif /* TNCODE */
  3926.  
  3927. #ifdef CK_NETBIOS
  3928. static int
  3929. shonb(n) int n; {
  3930.     printf("NETBIOS parameters:\n");
  3931.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3932.     printf(" API       : %s\n",
  3933.            NetbeuiAPI ?
  3934.            "NETAPI.DLL - IBM Extended Services or Novell Netware Requester"
  3935.            : "ACSNETB.DLL - IBM Network Transport Services/2" ) ;
  3936.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3937.     printf(" Local Name: [%s]\n", NetBiosName);
  3938.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3939.     printf(" Adapter   : %d\n", NetBiosAdapter);
  3940.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3941.     if (NetBiosLSN > 0xFF) {
  3942.         printf(" Session   : %d\n", NetBiosLSN);
  3943.     } else {
  3944.         printf(" Session   : none active\n");
  3945.     }
  3946.     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
  3947.     return(n);
  3948. }
  3949. #endif /* CK_NETBIOS */
  3950.  
  3951. #ifndef NONET
  3952. int
  3953. shonet() {
  3954.  
  3955. #ifndef NETCONN
  3956.     printf("\nNo networks are supported in this version of C-Kermit\n");
  3957.  
  3958. #else
  3959. #ifdef NOLOCAL
  3960.     printf("\nNo networks are supported in this version of C-Kermit\n");
  3961.  
  3962. #else /* rest of this routine */
  3963.  
  3964.     int i, n = 4;
  3965.  
  3966. #ifndef NODIAL
  3967.     if (nnetdir <= 1) {
  3968.         printf("\nNetwork directory: %s\n",netdir[0] ? netdir[0] : "(none)");
  3969.         n++;
  3970.     } else {
  3971.         int i;
  3972.         printf("\nNetwork directories:\n");
  3973.         for (i = 0; i < nnetdir; i++) {
  3974.             printf("%2d. %s\n",i,netdir[i]);
  3975.             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  3976.         }
  3977.     }
  3978. #endif /* NODIAL */
  3979.  
  3980. #ifdef OS2
  3981.     printf("\nNetwork availability:\n");
  3982. #else
  3983.     printf("\nSupported networks:\n");
  3984. #endif /* OS2 */
  3985.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  3986.  
  3987. #ifdef VMS
  3988.  
  3989. #ifdef TCPWARE
  3990.     printf(" Process Software Corporation TCPware for OpenVMS");
  3991. #else
  3992. #ifdef MULTINET
  3993.     printf(" TGV MultiNet TCP/IP");
  3994. #else
  3995. #ifdef WINTCP
  3996.     printf(" WOLLONGONG WIN/TCP");
  3997. #else
  3998. #ifdef DEC_TCPIP
  3999.     {
  4000.         static $DESCRIPTOR(tcp_desc,"_TCP0:");
  4001.         int status;
  4002.         long devclass;
  4003.         static int itmcod = DVI$_DEVCLASS;
  4004.  
  4005. #ifdef COMMENT
  4006.         status = LIB$GETDVI(&itmcod, 0, &tcp_desc, &devclass);
  4007. #else
  4008.         /* Martin Zinser 9/96 */
  4009.         status = lib$getdvi(&itmcod, 0, &tcp_desc, &devclass);
  4010. #endif /* COMMENT */
  4011.         if ((status & 1) && (devclass == DC$_SCOM))
  4012.           printf(" Process Software Corporation TCPware for OpenVMS");
  4013.         else
  4014. #ifdef UCX50
  4015.           printf(" DEC TCP/IP Services for (Open)VMS 5.0");
  4016. #else
  4017.           printf(" DEC TCP/IP Services for (Open)VMS");
  4018. #endif /* UCX50 */
  4019.     }
  4020. #else
  4021. #ifdef CMU_TCPIP
  4022.     printf(" CMU-OpenVMS/IP");
  4023. #else
  4024.     printf(" None");
  4025. #endif /* CMU_TCPIP */
  4026. #endif /* DEC_TCPIP */
  4027. #endif /* WINTCP */
  4028. #endif /* MULTINET */
  4029. #endif /* TCPWARE */
  4030.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4031. #ifdef TNCODE
  4032.     printf(", TELNET protocol\n\n");
  4033.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4034.     n = shotel(n);
  4035.     if (n < 0) return(0);
  4036.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4037. #endif /* TNCODE */
  4038.     printf("\n");
  4039.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4040.  
  4041. #else /* Not VMS */
  4042.  
  4043. #ifdef SUNX25
  4044.     printf(" SunLink X.25\n");
  4045.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4046. #endif /* SUNX25 */
  4047.  
  4048. #ifdef STRATUSX25
  4049.     printf(" Stratus VOS X.25\n");
  4050.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4051. #endif /* STRATUSX25 */
  4052.  
  4053. #ifdef IBMX25
  4054.     printf(" IBM AIX X.25\n");
  4055.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4056. #endif /* IBMX25 */
  4057.  
  4058. #ifdef HPX25
  4059.     printf(" HP-UX X.25\n");
  4060.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4061. #endif /* HPX25 */
  4062.  
  4063. #ifdef DECNET
  4064. #ifdef OS2
  4065. #ifdef NT
  4066.     if (dnet_avail)
  4067.       printf(" DECnet, LAT and CTERM protocols\n");
  4068.     else
  4069.       printf(" DECnet, LAT and CTERM protocols - not available\n");
  4070.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4071. #else /* NT */
  4072.     if (dnet_avail)
  4073.       printf(" DECnet, LAT protocol\n");
  4074.     else
  4075.       printf(" DECnet, LAT protocol - not available\n");
  4076.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4077. #endif /* NT */
  4078. #else
  4079.     printf(" DECnet\n");
  4080.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4081. #endif /* OS2 */
  4082. #endif /* DECNET */
  4083.  
  4084. #ifdef NPIPE
  4085.     printf(" Named Pipes\n");
  4086.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4087. #endif /* NPIPE */
  4088.  
  4089. #ifdef CK_NETBIOS
  4090.     if (netbiosAvail)
  4091.       printf(" NETBIOS\n");
  4092.     else
  4093.       printf(" NETBIOS - not available\n");
  4094.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4095. #endif /* CK_NETBIOS */
  4096.  
  4097. #ifdef SUPERLAT
  4098.     if (slat_avail)
  4099.       printf(" SuperLAT\n");
  4100.     else
  4101.       printf(" SuperLAT - not available\n") ;
  4102.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4103. #endif /* SUPERLAT */
  4104.  
  4105. #ifdef TCPSOCKET
  4106.     if (
  4107. #ifdef OS2
  4108.         tcp_avail
  4109. #else
  4110.         1
  4111. #endif /* OS2 */
  4112.         ) {
  4113.         char ipaddr[16];
  4114.  
  4115.         if (getlocalipaddrs(ipaddr,16,0) < 0) {
  4116. #ifdef OS2ONLY
  4117.             printf(" TCP/IP via %s\n", tcpname);
  4118. #else
  4119.             printf(" TCP/IP\n");
  4120. #endif /* OS2ONLY */
  4121.             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4122.         } else {
  4123.             int i = 1;
  4124. #ifdef OS2ONLY
  4125.           printf(" TCP/IP [%16s] via %s\n", ipaddr, tcpname);
  4126. #else
  4127.           printf(" TCP/IP [%16s]\n",ipaddr);
  4128. #endif /* OS2ONLY */
  4129.             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4130.  
  4131.             while (getlocalipaddrs(ipaddr,16,i++) >= 0) {
  4132.                 printf("        [%16s]\n",ipaddr);
  4133.                 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4134.             }
  4135.         }
  4136. #ifdef TNCODE
  4137.         if (nettype == NET_TCPB) {
  4138.             printf("\n");
  4139.             n = shotel(++n);
  4140.             if (n < 0) return(0);
  4141.             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4142.         }
  4143. #endif /* TNCODE */
  4144. #ifdef OS2
  4145.     } else {
  4146.         printf(" TCP/IP - not available%s\n",tcpname[0] ? tcpname : "" );
  4147.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4148. #endif /* OS2 */
  4149.     }
  4150. #endif /* TCPSOCKET */
  4151.  
  4152. #ifdef CK_NETBIOS
  4153.     if (netbiosAvail && nettype == NET_BIOS) {
  4154.        printf("\n") ;
  4155.        if ((n = shonb(++n)) < 0) return(0);
  4156.        if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4157.     }
  4158. #endif /* CK_NETBIOS */
  4159.  
  4160. #endif /* VMS */
  4161.  
  4162.     printf("\nActive network connection:\n");
  4163.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4164.  
  4165.     if (network) {
  4166.         printf(" Host: %s",ttname);
  4167.         if ((nettype == NET_TCPA || nettype == NET_TCPB) && *ipaddr)
  4168.           printf(" [%s]",ipaddr);
  4169.     } else
  4170.       printf(" Host: none");
  4171.     printf(", via: ");
  4172.     if (nettype == NET_TCPA || nettype == NET_TCPB)
  4173.       printf("tcp/ip\n");
  4174.     else if (nettype == NET_SX25)
  4175.       printf("SunLink X.25\n");
  4176.     else if (nettype == NET_VX25)
  4177.       printf("Stratus VOS X.25\n");
  4178.     else if (nettype == NET_IX25)
  4179.       printf("IBM AIX X.25\n");
  4180.     else if (nettype == NET_HX25)
  4181.       printf("HP-UX X.25\n");
  4182.     else if (nettype == NET_DEC) {
  4183.         if ( ttnproto == NP_LAT )
  4184.           printf("DECnet LAT\n");
  4185.         else if ( ttnproto == NP_CTERM )
  4186.           printf("DECnet CTERM\n");
  4187.         else
  4188.           printf("DECnet\n");
  4189.     } else if (nettype == NET_PIPE)
  4190.       printf("Named Pipes\n");
  4191.     else if (nettype == NET_BIOS)
  4192.       printf("NetBIOS\n");
  4193.     else if (nettype == NET_SLAT)
  4194.       printf("SuperLAT\n");
  4195.  
  4196. #ifdef NETFILE
  4197.     else if ( nettype == NET_FILE )
  4198.       printf("local file\n");
  4199. #endif /* NETFILE */
  4200. #ifdef NETCMD
  4201.     else if ( nettype == NET_CMD )
  4202.       printf("pipe\n");
  4203. #endif /* NETCMD */
  4204. #ifdef NETPTY
  4205.     else if ( nettype == NET_PTY )
  4206.         printf("psuedoterminal\n");
  4207. #endif /* NETPTY */
  4208. #ifdef NETDLL
  4209.     else if ( nettype == NET_DLL )
  4210.       printf("dynamic link library\n");
  4211. #endif /* NETDLL */
  4212. #ifdef SSH
  4213.     else if ( nettype == NET_SSH )
  4214.       printf("Secure Shell\n");
  4215. #endif /* SSH */
  4216.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4217.  
  4218. #ifdef ANYX25
  4219.     if ((nettype == NET_SX25) ||
  4220.         (nettype == NET_VX25) ||
  4221.         (nettype == NET_IX25))
  4222.       if ((n = shox25(n)) < 0) return(0);
  4223. #endif /* ANYX25 */
  4224.  
  4225. #ifdef TCPSOCKET
  4226.     if (nettype == NET_TCPA || nettype == NET_TCPB) {
  4227.         printf(" Reverse DNS lookup: %s\n", showooa(tcp_rdns));
  4228.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4229.  
  4230. #ifdef CK_DNS_SRV
  4231.         printf(" DNS Service Records lookup: %s\n", showooa(tcp_dns_srv));
  4232.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4233. #endif /* CK_DNS_SRV */
  4234.  
  4235. #ifndef NOTCPOPTS
  4236. #ifdef SOL_SOCKET
  4237. #ifdef SO_KEEPALIVE
  4238.         printf(" Keepalive: %s\n", showoff(tcp_keepalive));
  4239.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4240. #endif /* SO_KEEPALIVE */
  4241.  
  4242. #ifdef SO_LINGER
  4243.         printf(" Linger: %s", tcp_linger ? "on, " : "off\n" );
  4244.         if (tcp_linger) {
  4245.             if (tcp_linger_tmo)
  4246.               printf("%d x 10 milliseconds\n",tcp_linger_tmo);
  4247.             else
  4248.               printf("no timeout\n");
  4249.         }
  4250.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4251. #endif /* SO_LINGER */
  4252.  
  4253. #ifdef SO_DONTROUTE
  4254.         printf(" DontRoute: %s\n", tcp_dontroute ? "on" : "off" );
  4255.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4256. #endif /* SO_DONTROUTE */
  4257.  
  4258. #ifdef TCP_NODELAY
  4259.         printf(" Nodelay: %s\n", showoff(tcp_nodelay));
  4260.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4261. #endif /* TCP_NODELAY */
  4262.  
  4263. #ifdef SO_SNDBUF
  4264.         if (tcp_sendbuf <= 0)
  4265.           printf(" Send buffer: (default size)\n");
  4266.         else
  4267.           printf(" Send buffer: %d bytes\n", tcp_sendbuf);
  4268.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4269. #endif /* SO_SNDBUF */
  4270. #ifdef SO_RCVBUF
  4271.         if (tcp_recvbuf <= 0)
  4272.           printf(" Receive buffer: (default size)\n");
  4273.         else
  4274.           printf(" Receive buffer: %d bytes\n", tcp_recvbuf);
  4275.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4276. #endif /* SO_RCVBUF */
  4277. #endif /* SOL_SOCKET */
  4278. #endif /* NOTCPOPTS */
  4279.     }
  4280.  
  4281. #ifdef RLOGCODE
  4282.     if (ttnproto == NP_RLOGIN) {
  4283.         printf(" LOGIN (rlogin) protocol\n");
  4284.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4285.     }
  4286. #ifdef CK_KERBEROS
  4287.     else if (ttnproto == NP_K4LOGIN) {
  4288.         printf(" Kerberos 4 LOGIN (klogin) protocol\n");
  4289.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4290.     }
  4291.     else if (ttnproto == NP_EK4LOGIN) {
  4292.         printf(" Encrypted Kerberos 4 LOGIN (eklogin) protocol\n");
  4293.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4294.     }
  4295.     else if (ttnproto == NP_K5LOGIN) {
  4296.         printf(" Kerberos 5 LOGIN (klogin) protocol\n");
  4297.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4298.     }
  4299.     else if (ttnproto == NP_EK5LOGIN) {
  4300.         printf(" Encrypted Kerberos 5 LOGIN (eklogin) protocol\n");
  4301.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4302.     }
  4303. #endif /* CK_KERBEROS */
  4304. #endif /* RLOGCODE */
  4305.  
  4306. #ifdef TNCODE
  4307.     if (ttnproto == NP_TELNET) {
  4308.         printf(" TELNET protocol\n");
  4309.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4310.         printf(" Echoing is currently %s\n",duplex ? "local" : "remote");
  4311.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4312.     }
  4313. #endif /* TNCODE */
  4314.     if (ttnproto == NP_TCPRAW) {
  4315.         printf(" Raw TCP socket\n");
  4316.         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4317.     }
  4318. #endif /* TCPSOCKET */
  4319.     printf("\n");
  4320. #endif /* NOLOCAL */
  4321. #endif /* NETCONN */
  4322.     return(0);
  4323. }
  4324. #endif /* NONET */
  4325.  
  4326. #ifndef NODIAL
  4327. VOID
  4328. shodial() {
  4329.     if (mdmtyp >= 0 || local != 0) doshodial();
  4330. }
  4331.  
  4332. VOID
  4333. shods(s) char *s; {                     /* Show a dial-related string */
  4334.     char c;
  4335.     if (s == NULL || !(*s)) {           /* Empty? */
  4336.         printf("(none)\n");
  4337.     } else {                            /* Not empty. */
  4338.         while (c = *s++)                /* Can contain controls */
  4339.           if (c == '\\')                /* a backslash */
  4340.             printf("\\\\");
  4341.           else if (c > 31 && c < 127) {
  4342.               putchar(c);
  4343.           } else
  4344.             printf("\\{%d}",c);
  4345.         printf("\n");
  4346.     }
  4347. }
  4348.  
  4349. int
  4350. doshodial() {
  4351.  
  4352.     int i, n = 2;
  4353.  
  4354.     printf(" Dial status:  %d", dialsta);
  4355.  
  4356. #ifdef BIGBUFOK
  4357.     if (dialsta > 90)
  4358.       printf(" = Unknown error");
  4359.     else if (dialsta < 0)
  4360.       printf(" = (none)");
  4361.     else if (dialsta < 30 && dialmsg[dialsta])
  4362.       printf(" = %s", dialmsg[dialsta]);
  4363. #endif /* BIGBUFOK */
  4364.     n++;
  4365.     if (ndialdir <= 1) {
  4366.         printf("\n Dial directory: %s\n",dialdir[0] ? dialdir[0] : "(none)");
  4367.     } else {
  4368.         int i;
  4369.         printf("\n Dial directories:\n");
  4370.         for (i = 0; i < ndialdir; i++)
  4371.           printf("%2d. %s\n",i+1,dialdir[i]);
  4372.         n += ndialdir;
  4373.     }
  4374.     printf(" Dial method:  ");
  4375.     if      (dialmauto)         printf("auto   ");
  4376.     else if (dialmth == XYDM_D) printf("default");
  4377.     else if (dialmth == XYDM_P) printf("pulse  ");
  4378.     else if (dialmth == XYDM_T) printf("tone   ");
  4379.     printf("         Dial sort: %s\n",dialsrt ? "on" : "off");
  4380.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4381.     printf(" Dial hangup:  %s             Dial display: %s\n",
  4382.            dialhng ? "on " : "off", dialdpy ? "on" : "off");
  4383.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4384.     if (dialrtr > 0) {
  4385.         printf(" Dial retries: %-6d          Dial interval: %d\n",
  4386.                dialrtr, dialint);
  4387.     } else {
  4388.         printf(" Dial retries: (auto)          Dial interval: %d\n", dialint);
  4389.     }
  4390.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4391.     printf(" Dial timeout: ");
  4392. #ifdef CK_TAPI
  4393.     if (tttapi && !tapipass)
  4394.         printf("(tapi)");
  4395.     else
  4396. #endif /* CK_TAPI */
  4397.     if (dialtmo > 0)
  4398.       printf("%4d sec", dialtmo);
  4399.     else
  4400.       printf("0 (auto)");
  4401.     printf("        Redial number: %s\n",dialnum ? dialnum : "(none)");
  4402.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4403.     printf(" Dial confirmation: %s        Dial convert-directory: %s\n",
  4404.            dialcnf ? "on " : "off",
  4405.            dialcvt ? ((dialcvt == 1) ? "on" : "ask") : "off");
  4406.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4407.     printf(" Dial ignore-dialtone: %s", dialidt ? "on " : "off");
  4408.     printf("     Dial pacing: %d\n",dialpace);
  4409.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4410.     printf(
  4411. " Dial prefix:                  %s\n", dialnpr ? dialnpr : "(none)");
  4412.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4413.     printf(
  4414. " Dial suffix:                  %s\n", dialsfx ? dialsfx : "(none)");
  4415.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4416.     printf(
  4417. " Dial country-code:            %-12s", diallcc ? diallcc : "(none)");
  4418.     printf("Dial connect:  %s", dialcon ? ((dialcon == 1) ? "on" : "auto")
  4419.            : "off");
  4420.     if (dialcon != CAR_OFF)
  4421.       printf(" %s", dialcq ? "quiet" : "verbose");
  4422.     printf(
  4423. "\n Dial area-code:               %-12s", diallac ? diallac : "(none)");
  4424.     n++;
  4425.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4426.     printf("Dial restrict: ");
  4427.     if (dialrstr == 5) printf("international\n");
  4428.     else if (dialrstr == 4) printf("long-distance\n");
  4429.     else if (dialrstr == 2) printf("local\n");
  4430.     else if (dialrstr == 6) printf("none\n");
  4431.     else printf("?\n");
  4432.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4433.     printf(" Dial lc-area-codes:           ");
  4434.     if (nlocalac == 0)
  4435.       printf("(none)");
  4436.     else
  4437.       for (i = 0; i < nlocalac; i++)
  4438.         printf("%s ", diallcac[i]);
  4439.     printf(
  4440. "\n Dial lc-prefix:               %s\n", diallcp ? diallcp : "(none)");
  4441.     n++;
  4442.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4443.     printf(
  4444. " Dial lc-suffix:               %s\n", diallcs ? diallcs : "(none)");
  4445.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4446.     printf(
  4447. " Dial ld-prefix:               %s\n", dialldp ? dialldp : "(none)");
  4448.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4449.     printf(
  4450. " Dial ld-suffix:               %s\n", diallds ? diallds : "(none)");
  4451.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4452.     printf(
  4453. " Dial force-long-distance      %s\n", showoff(dialfld));
  4454.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4455.     printf(
  4456. " Dial intl-prefix:             %s\n", dialixp ? dialixp : "(none)");
  4457.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4458.     printf(
  4459. " Dial intl-suffix:             %s\n", dialixs ? dialixs : "(none)");
  4460.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4461.     printf(
  4462. " Dial toll-free-area-code:     ");
  4463.     if (ntollfree == 0)
  4464.       printf("(none)");
  4465.     else
  4466.       for (i = 0; i < ntollfree; i++)
  4467.         printf("%s ", dialtfc[i]);
  4468.     printf("\n");
  4469.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4470.  
  4471.     printf(
  4472. " Dial pulse-countries:         ");
  4473.     if (ndialpucc == 0)
  4474.       printf("(none)");
  4475.     else
  4476.       for (i = 0; i < ndialpucc; i++)
  4477.         printf("%s ", dialpucc[i]);
  4478.     printf("\n");
  4479.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4480.  
  4481.     printf(
  4482. " Dial tone-countries:          ");
  4483.     if (ndialtocc == 0)
  4484.       printf("(none)");
  4485.     else
  4486.       for (i = 0; i < ndialtocc; i++)
  4487.         printf("%s ", dialtocc[i]);
  4488.     printf("\n");
  4489.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4490.  
  4491.     printf(
  4492. " Dial toll-free-prefix:        %s\n",
  4493.            dialtfp ? dialtfp :
  4494.           (dialldp ? dialldp : "(none)")
  4495.           );
  4496.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4497.     printf(
  4498. #ifdef COMMENT
  4499. " Dial pbx-exchange:            %s\n", dialpxx ? dialpxx : "(none)");
  4500. #else
  4501. " Dial pbx-exchange:            ");
  4502.     if (ndialpxx == 0)
  4503.       printf("(none)");
  4504.     else
  4505.       for (i = 0; i < ndialpxx; i++)
  4506.         printf("%s ", dialpxx[i]);
  4507.     printf("\n");
  4508. #endif /* COMMENT */
  4509.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4510.     printf(
  4511. " Dial pbx-inside-prefix:       %s\n", dialpxi ? dialpxi : "(none)");
  4512.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4513.     printf(
  4514. " Dial pbx-outside-prefix:      %s\n", dialpxo ? dialpxo : "(none)");
  4515.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  4516.     printf(
  4517. " Dial macro:                   %s\n", dialmac ? dialmac : "(none)");
  4518.     return(0);
  4519. }
  4520. #endif /* NODIAL */
  4521. #endif /* NOLOCAL */
  4522.  
  4523. /*  Show File Parameters */
  4524.  
  4525. static char *
  4526. pathval(x) int x; {
  4527.     switch (x) {
  4528.       case PATH_OFF:  return("off");
  4529.       case PATH_ABS:  return("absolute");
  4530.       case PATH_REL:  return("relative");
  4531.       case PATH_AUTO: return("auto");
  4532.       default: return("unknown");
  4533.     }
  4534. }
  4535.  
  4536. VOID
  4537. shofil() {
  4538.     char *s; int i = 0, n = 1;
  4539.     extern char * ifdnam[];
  4540. #ifdef UNIX
  4541.     extern int wildxpand;
  4542. #endif /* UNIX */
  4543.     extern char * snd_move, * snd_rename, * rcv_move, * rcv_rename;
  4544. #ifdef PATTERNS
  4545.     extern int patterns;
  4546. #endif /* PATTERNS */
  4547.     extern char * rfspec, * sfspec;
  4548. #ifdef UNIX
  4549.     extern int zobufsize, zofbuffer, zofblock;
  4550. #endif /* UNIX */
  4551. #ifdef CK_CTRLZ
  4552.     extern int eofmethod;
  4553. #endif /* CK_CTRLZ */
  4554.  
  4555.     printf("\n");
  4556.  
  4557. #ifdef VMS
  4558.     printf(" File record-Length:      %5d\n",frecl);
  4559.     n++;
  4560. #endif /* VMS */
  4561.  
  4562. #ifndef NOXFER
  4563.     printf(" Transfer mode:           %s\n",
  4564.            xfermode == XMODE_A ?
  4565.            "automatic" :
  4566.            "manual"
  4567.            );
  4568.     n++;
  4569. #ifdef PATTERNS
  4570.     printf(" File patterns:           %s", showooa(patterns));
  4571.     if (xfermode == XMODE_M && patterns)
  4572.       printf(" (but disabled by TRANSFER-MODE MANUAL)");
  4573.     else if (patterns)
  4574.       printf(" (SHOW PATTERNS for list)");
  4575.     printf("\n");
  4576.     n++;
  4577. #endif /* PATTERNS */
  4578.     if (xfermode == XMODE_A)
  4579.       printf(" Default file type:       %s\n",shoxm());
  4580.     else
  4581.       printf(" File type:               %s\n",shoxm());
  4582.     n++;
  4583.     if (fncnv == XYFN_L)
  4584.       s = "literal";
  4585.     else if (fncnv == XYFN_C)
  4586.       s = "converted";
  4587.     else
  4588.       s = "(unknown)";
  4589.     printf(" File names:              %s\n",s);
  4590.     n++;
  4591.     printf(" Send pathnames:          %s\n", pathval(fnspath));
  4592.     n++;
  4593.     printf(" Receive pathnames:       %s\n", pathval(fnrpath));
  4594.     n++;
  4595. #ifdef UNIXOROSK
  4596.     printf(" Match dot files:         %s\n", matchdot ? "yes" : "no");
  4597.     n++;
  4598. #ifdef UNIX
  4599.     printf(" Wildcard-expansion:      %s\n", wildxpand ? "shell" : "kermit");
  4600.     n++;
  4601. #endif /* UNIX */
  4602. #endif /* UNIXOROSK */
  4603.     printf(" File collision:          ");
  4604.     for (i = 0; i < ncolx; i++)
  4605.       if (colxtab[i].kwval == fncact) break;
  4606.     printf("%s\n", (i == ncolx) ? "unknown" : colxtab[i].kwd);
  4607.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4608.     printf(" File destination:        %s\n",
  4609.            (dest == DEST_D) ? "disk" :
  4610.            ((dest == DEST_S) ? "screen" :
  4611.             ((dest == DEST_N) ? "nowhere" :
  4612.             "printer"))
  4613.            );
  4614.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4615.     s = (keep >= 0 && keep <= 2) ? ifdnam[keep] : "keep";
  4616.     printf(" File incomplete:         %s\n",s);
  4617.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4618.     printf(" File bytesize:           %d\n",(fmask == 0177) ? 7 : 8);
  4619.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4620. #ifndef NOCSETS
  4621.     printf(" File character-set:      %s\n",fcsinfo[fcharset].keyword);
  4622.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4623. #ifdef UNICODE
  4624.     printf(" File UCS bom:            %s\n",showoff(ucsbom));
  4625.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4626.     printf(" File UCS byte-order:     %s-endian\n",
  4627.            ucsorder ? "little" : "big");
  4628.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4629.     printf(" Computer byteorder:      %s-endian\n",
  4630.            byteorder ? "little" : "big");
  4631.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4632. #endif /* UNICODE */
  4633. #endif /* NOCSETS */
  4634.  
  4635.     printf(" File end-of-line:        ");
  4636.     i = feol;
  4637.     switch (feol) {
  4638.       case XYFA_C: printf("%s\n","cr"); break;
  4639.       case XYFA_L: printf("%s\n","lf"); break;
  4640.       case XYFA_2: printf("%s\n","crlf"); break;
  4641.       default: printf("%d\n",i);
  4642.     }
  4643. #endif /* NOXFER */
  4644.  
  4645.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4646. #ifdef CK_CTRLZ
  4647.     printf(" File eof:                %s\n", eofmethod ? "ctrl-z" : "length");
  4648.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4649. #endif /* CK_CTRLZ */
  4650. #ifndef NOXFER
  4651. #ifdef CK_TMPDIR
  4652.     printf(" File download-directory: %s\n", dldir ? dldir : "(none)");
  4653.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4654. #ifdef COMMENT
  4655.     i = 256;
  4656.     s = line;
  4657.     zzstring("\\v(tmpdir)",&s,&i);
  4658.     printf(" Temporary directory:     %s\n", line);
  4659.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4660. #endif /* COMMENT */
  4661. #endif /* CK_TMPDIR */
  4662. #ifdef VMS
  4663.     {
  4664.     extern int vmssversions, vmsrversions;
  4665.     printf(" Send version-numbers:    %s\n",showoff(vmssversions));
  4666.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4667.     printf(" Receive version-numbers: %s\n",showoff(vmsrversions));
  4668.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4669.     }
  4670. #endif /* VMS */
  4671.     printf(" Send move-to:            %s\n",
  4672.            snd_move ? snd_move : "(none)");
  4673.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4674.     printf(" Send rename-to:          %s\n",
  4675.            snd_rename ? snd_rename : "(none)");
  4676.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4677.     printf(" Receive move-to:         %s\n",
  4678.            rcv_move ? rcv_move : "(none)");
  4679.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4680.     printf(" Receive rename-to:       %s\n",
  4681.            rcv_rename ? rcv_rename : "(none)");
  4682.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4683. #endif /* NOXFER */
  4684. #ifdef KERMRC
  4685.     printf(" Initialization file:     %s\n", noinit ? "(none)" :
  4686. #ifdef CK_SYSINI
  4687.            CK_SYSINI
  4688. #else
  4689.            kermrc
  4690. #endif /* CK_SYSINI */
  4691.            );
  4692. #endif /* KERMRC */
  4693.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4694.  
  4695.     if (k_info_dir) {
  4696.         printf(" Kermit doc files:        %s\n", k_info_dir);
  4697.         if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4698.     }
  4699.  
  4700. #ifdef UNIX
  4701.     printf(" Disk output buffer:      %d (writes are %s, %s)\n",
  4702.            zobufsize,
  4703.            zofbuffer ? "buffered" : "unbuffered",
  4704.            zofblock ? "blocking" : "nonblocking"
  4705.            );
  4706.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4707. #endif /* UNIX */
  4708. #ifdef OS2ORUNIX
  4709.     printf(" Longest filename:        %d\n", maxnam);
  4710.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4711.     printf(" Longest pathname:        %d\n", maxpath);
  4712.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4713. #endif /* OS2ORUNIX */
  4714.  
  4715.     printf(" Last file sent:          %s\n", sfspec ? sfspec : "(none)");
  4716.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4717.     printf(" Last file received:      %s\n", rfspec ? rfspec : "(none)");
  4718.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4719.     printf("\n Also see:\n");
  4720.     n++;
  4721.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  4722.     printf(" SHOW PROTOCOL, SHOW XFER");
  4723. #ifdef CK_LABELED
  4724.     printf(", SHOW LABELED");
  4725. #endif /* CK_LABELED */
  4726. #ifdef PATTERNS
  4727.     printf(", SHOW PATTERNS");
  4728. #endif /* PATTERNS */
  4729. #ifdef STREAMING
  4730.     printf(", SHOW STREAMING");
  4731. #endif /* STREAMING */
  4732. #ifndef NOCSETS
  4733.     printf(", SHOW CHARACTER-SETS");
  4734. #endif /* NOCSETS */
  4735.     printf("\n\n");
  4736. }
  4737.  
  4738. #ifndef NOXFER
  4739. VOID
  4740. shoparp() {                             /* Protocol */
  4741.     extern int docrc, skipbup;
  4742.     char *s;
  4743.  
  4744. #ifdef CK_TIMERS
  4745.     extern int rttflg;
  4746. #endif /* CK_TIMERS */
  4747.  
  4748.     printf("Protocol: %s\n",ptab[protocol].p_name);
  4749.  
  4750.     if (protocol == PROTO_K) {
  4751.         printf("\nProtocol Parameters:   Send    Receive");
  4752.         if (timef)
  4753.           printf("\n Timeout (used=%2d):%7d*%8d ", timint, rtimo, pkttim);
  4754.         else
  4755.           printf("\n Timeout (used=%2d):%7d%9d ",  timint, rtimo, pkttim);
  4756. #ifdef XFRCAN
  4757.         printf("       Cancellation:    %s",showoff(xfrcan));
  4758.         if (xfrcan)
  4759.           printf(" %d %d", xfrchr, xfrnum);
  4760. #endif /* XFRCAN */
  4761.         printf("\n Padding:      %11d%9d", npad,   mypadn);
  4762.         if (bctr == 4)
  4763.           printf("        Block Check: blank-free-2\n");
  4764.         else
  4765.           printf("        Block Check: %6d\n",bctr);
  4766.         printf(  " Pad Character:%11d%9d", padch,  mypadc);
  4767.         printf("        Delay:       %6d\n",ckdelay);
  4768.         printf(  " Pause:        %11d%9d", pktpaus, pktpaus);
  4769.         printf("        Attributes:      %s\n",showoff(atcapr));
  4770.         printf(  " Packet Start: %11d%9d", mystch, stchr);
  4771.         printf("        Max Retries: %6d\n",maxtry);
  4772.         printf(  " Packet End:   %11d%9d", seol,   eol);
  4773.         if (ebqflg)
  4774.           printf("        8th-Bit Prefix: '%c'",ebq);
  4775.         else
  4776.           printf("        8th-Bit Prefix: ('%c' but not used)",ebq);
  4777.         printf(  "\n Packet Length:%11d ", spmax);
  4778.         printf("%8d     ",  urpsiz);
  4779.         if (rptflg)
  4780.           printf("   Repeat Prefix:  '%c'",rptq);
  4781.         else
  4782.           printf("   Repeat Prefix:  ('%c' but not used)",rptq);
  4783.         printf(  "\n Maximum Length: %9d%9d", maxsps, maxrps);
  4784.         printf("        Window Size:%7d set, %d used\n",wslotr,wmax);
  4785.         printf(    " Buffer Size:  %11d%9d", bigsbsiz, bigrbsiz);
  4786.         printf("        Locking-Shift:    ");
  4787.         if (lscapu == 2) {
  4788.             printf("forced");
  4789.         } else {
  4790.             printf("%s", (lscapr ? "enabled" : "disabled"));
  4791.             if (lscapr) printf(",%s%s", (lscapu ? " " : " not "), "used");
  4792.         }
  4793.         printf("\n\n");
  4794.  
  4795.         if (!(s = ptab[protocol].h_b_init)) s = "";
  4796.         printf(" Auto-upload command (binary): %s\n", *s ? s : "(none)");
  4797.         if (!(s = ptab[protocol].h_t_init)) s = "";
  4798.         printf(" Auto-upload command (text):   %s\n", *s ? s : "(none)");
  4799.         if (!(s = ptab[protocol].h_x_init)) s = "";
  4800.         printf(" Auto-server command:          %s\n", *s ? s : "(none)");
  4801.  
  4802.         tmpbuf[0] = NUL;
  4803. #ifdef CK_TIMERS
  4804.         if (rttflg) {
  4805.             extern int mintime, maxtime;
  4806.             sprintf(tmpbuf," Packet timeouts: dynamic %d:%d",
  4807.                     mintime,
  4808.                     maxtime);
  4809.         } else {
  4810.             sprintf(tmpbuf," Packet timeouts: fixed");
  4811.         }
  4812. #endif /* CK_TIMERS */
  4813.         if (tmpbuf[0])
  4814.           printf("%-31s",tmpbuf);
  4815.         printf("Send backup: %s\n",showoff(!skipbup));
  4816.  
  4817.         printf(" Transfer mode:   %s", xfermode == XMODE_A ?
  4818.                "automatic   " :
  4819.                "manual      "
  4820.                );
  4821.         printf(" Transfer slow-start: %s, crc: %s\n",
  4822.                showoff(slostart),
  4823.                showoff(docrc)
  4824.                );
  4825. #ifdef PIPESEND
  4826.         {
  4827.             extern int usepipes;
  4828.             printf(" Transfer pipes:  %s         ",usepipes ? "on " : "off");
  4829.         }
  4830. #endif /* PIPESEND */
  4831. #ifndef NOCSETS
  4832.         printf(" Transfer character-set: ");
  4833.         if (tcharset == TC_TRANSP)
  4834.           printf("transparent\n");
  4835.         else
  4836.           printf("%s\n", tcsinfo[tcharset].keyword );
  4837. #endif /* NOCSETS */
  4838. #ifdef PIPESEND
  4839.         {
  4840.             extern char * sndfilter, * rcvfilter;
  4841.             printf(" Send filter:     %s\n", sndfilter ? sndfilter : "(none)");
  4842.             printf(" Receive filter:  %s\n", rcvfilter ? rcvfilter : "(none)");
  4843.         }
  4844. #endif /* PIPESEND */
  4845.         printf("\nAlso see:\n");
  4846.         printf(" SHOW FILE, SHOW XFER");
  4847.  
  4848. #ifdef CK_LABELED
  4849.         printf(", SHOW LABELED");
  4850. #endif /* CK_LABELED */
  4851. #ifdef PATTERNS
  4852.         printf(", SHOW PATTERNS");
  4853. #endif /* PATTERNS */
  4854. #ifdef STREAMING
  4855.         printf(", SHOW STREAMING");
  4856. #endif /* STREAMING */
  4857. #ifndef NOCSETS
  4858.         printf(", SHOW CHARACTER-SETS");
  4859. #endif /* NOCSETS */
  4860.     }
  4861.  
  4862. #ifdef CK_XYZ
  4863. #ifdef XYZ_INTERNAL
  4864.     if (protocol != PROTO_K) {
  4865.         int i;
  4866.         int x;
  4867.         printf(" File type: %s\n", binary ? "binary" : "text");
  4868.         if (protocol == PROTO_Z) {              /* Zmodem */
  4869.             printf(" Window size:   ");
  4870.             if (ptab[protocol].winsize < 1)
  4871.               printf("none\n");
  4872.             else
  4873.               printf("%d\n",wslotr);
  4874. #ifdef COMMENT
  4875.             printf(" Packet (frame) length: ");
  4876.             if (ptab[protocol].spktlen < 0)
  4877.               printf("none\n");
  4878.             else
  4879.               printf("%d\n",spmax);
  4880. #endif /* COMMENT */
  4881.         } else {
  4882.             if (ptab[protocol].spktlen >= 1000)
  4883.               printf(" 1K packets\n");
  4884.             else
  4885.               printf(" 128-byte packets\n");
  4886.         }
  4887.         printf(" Pathname stripping when sending:   %s\n",
  4888.                showoff(ptab[protocol].fnsp)
  4889.                );
  4890.         printf(" Pathname stripping when receiving: %s\n",
  4891.                showoff(ptab[protocol].fnrp)
  4892.                );
  4893.         printf(" Filename collision action:         ");
  4894.         for (i = 0; i < ncolx; i++)
  4895.           if (colxtab[i].kwval == fncact) break;
  4896.         printf("%-12s", (i == ncolx) ? "unknown" : colxtab[i].kwd);
  4897.  
  4898.         printf("\n Escape control characters:          ");
  4899.         x = ptab[protocol].prefix;
  4900.         if (x == PX_ALL)
  4901.           printf("all\n");
  4902.         else if (x == PX_CAU || x==PX_WIL)
  4903.           printf("minimal\n");
  4904.         else
  4905.           printf("none\n");
  4906.         if (!(s = ptab[protocol].h_b_init))
  4907.           s = "";
  4908.         printf(" Autoreceive command (binary): %s\n", *s ? s : "(none)");
  4909.         if (!(s = ptab[protocol].h_t_init))
  4910.           s = "";
  4911.         printf(" Autoreceive command (text):   %s\n", *s ? s : "(none)");
  4912.     }
  4913. #else
  4914.     if (protocol != PROTO_K) {
  4915.         printf("\nExecuted by external commands:\n\n");
  4916.         s = ptab[protocol].p_b_scmd;
  4917.         if (!s) s = "";
  4918.         printf(" SEND command (binary):        %s\n", *s ? s : "(none)");
  4919.         s = ptab[protocol].p_t_scmd;
  4920.         if (!s) s = "";
  4921.         printf(" SEND command (text):          %s\n", *s ? s : "(none)");
  4922.         s = ptab[protocol].p_b_rcmd;
  4923.         if (!s) s = "";
  4924.         printf(" RECEIVE command (binary):     %s\n", *s ? s : "(none)");
  4925.         s = ptab[protocol].p_t_rcmd;
  4926.         if (!s) s = "";
  4927.         printf(" RECEIVE command (text):       %s\n", *s ? s : "(none)");
  4928.         s = ptab[protocol].h_b_init;
  4929.         if (!s) s = "";
  4930.         printf(" Autoreceive command (binary): %s\n", *s ? s : "(none)");
  4931.         s = ptab[protocol].h_t_init;
  4932.         if (!s) s = "";
  4933.         printf(" Autoreceive command (text):   %s\n", *s ? s : "(none)");
  4934.     }
  4935. #endif /* XYZ_INTERNAL */
  4936. #endif /* CK_XYZ */
  4937. }
  4938. #endif /* NOXFER */
  4939.  
  4940. #ifndef NOCSETS
  4941. /* Character-set items */
  4942.  
  4943. extern int s_cset, r_cset, axcset[], afcset[];
  4944. extern struct keytab xfrmtab[];
  4945.  
  4946. VOID
  4947. shoparl() {
  4948. #ifdef COMMENT
  4949.     int i;
  4950. /* Misleading... */
  4951.     printf("\nAvailable Languages:\n");
  4952.     for (i = 0; i < MAXLANG; i++) {
  4953.         printf(" %s\n",langs[i].description);
  4954.     }
  4955. #else
  4956.     printf("\nLanguage-specific translation rules: %s\n",
  4957.            language == L_USASCII ? "none" : langs[language].description);
  4958.     shocharset();
  4959.     printf("\n\n");
  4960. #endif /* COMMENT */
  4961. }
  4962.  
  4963. VOID
  4964. shocharset() {
  4965.     int x;
  4966.     char * s = "Unknown";
  4967.     extern int xlatype;
  4968.     debug(F101,"SHOW FILE CHAR","",fcharset);
  4969.  
  4970.     printf("\n File Character-Set: %s (%s), ",
  4971.            fcsinfo[fcharset].keyword,
  4972.            fcsinfo[fcharset].name
  4973.            );
  4974.     if ((x = fcsinfo[fcharset].size) == 128)
  4975.       printf("7-bit");
  4976.     else if (x == 256)
  4977.       printf("8-bit");
  4978.     else
  4979.       printf("multibyte");
  4980.     printf("\n Transfer Character-Set");
  4981. #ifdef COMMENT
  4982.     if (tslevel == TS_L2)
  4983.       printf(": (international)");
  4984.     else
  4985. #endif /* COMMENT */
  4986.     if (tcharset == TC_TRANSP)
  4987.       printf(": Transparent");
  4988.     else
  4989.       printf(": %s (%s)",tcsinfo[tcharset].keyword, tcsinfo[tcharset].name);
  4990.     printf("\n");
  4991. #ifdef COMMENT
  4992.     switch (xlatype) {
  4993.       case XLA_NONE: s = "None"; break;
  4994.       case XLA_BYTE: s = "Byte"; break;
  4995.       case XLA_JAPAN: s = "Japanese"; break;
  4996.       case XLA_UNICODE: s = "Unicode"; break;
  4997.     }
  4998.     printf("\n Translation type: %s\n",s);
  4999. #endif /* COMMENT */
  5000.     printf(" SEND character-set-selection: %s\n",xfrmtab[s_cset].kwd);
  5001.     printf(" RECEIVE character-set-selection: %s\n",xfrmtab[r_cset].kwd);
  5002.     if (s_cset == XMODE_A || r_cset == XMODE_A)
  5003.       printf(
  5004.       " (Use SHOW ASSOCIATIONS to list automatic character-set selections.)\n"
  5005.              );
  5006. }
  5007.  
  5008. VOID
  5009. showassoc() {
  5010.     int i, k, n = 4;
  5011.     char * s;
  5012.     printf("\nFor incoming files:\n\n");
  5013.     printf("Transfer Character-Set   File Character-Set\n");
  5014.     for (i = 1; i <= MAXTCSETS; i++) {
  5015.         k = axcset[i];
  5016.         if (k < 0 || k > MAXFCSETS)
  5017.           s = "(none)";
  5018.         else
  5019.           s = fcsinfo[k].keyword;
  5020.         if (!s) s = "";
  5021.         if (!*s) s = "(none)";
  5022.         printf(" %-25s%s\n",tcsinfo[i].keyword,s);
  5023.         if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5024.     }
  5025.     printf("\nFor outbound files:\n\n");
  5026.     n += 2;
  5027.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5028.     printf("File Character-Set       Transfer Character-Set\n");
  5029.     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5030.     for (i = 0; i <= MAXFCSETS; i++) {
  5031.         k = afcset[i];
  5032.         if (k < 0 || k > MAXTCSETS)
  5033.           s = "(none)";
  5034.         else
  5035.           s = tcsinfo[k].keyword;
  5036.         if (!s) s = "";
  5037.         if (!*s) s = "(none)";
  5038.         printf(" %-25s%s\n",fcsinfo[i].keyword,s);
  5039.         if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
  5040.     }
  5041. }
  5042. #endif /* NOCSETS */
  5043.  
  5044. VOID
  5045. shopar() {
  5046.     printf("Show what?  (Type \"show ?\" for a list of possiblities.)\n");
  5047. }
  5048. #endif /* NOSHOW */
  5049.  
  5050. #ifndef NOXFER
  5051. /*  D O S T A T  --  Display file transfer statistics.  */
  5052.  
  5053. int
  5054. dostat(brief) int brief; {
  5055.     extern long filrej, peakcps;
  5056.     extern int lastspmax, streamed, cleared, streamok;
  5057.     extern char whoareu[];
  5058.     int n = 0;
  5059.     extern int docrc, interrupted, fatalio;
  5060.  
  5061. #ifdef CK_TTGWSIZ
  5062. #ifdef OS2
  5063.     if (tt_cols[VTERM] < 0 || tt_rows[VTERM] < 0)
  5064.       ttgwsiz();
  5065. #else /* OS2 */
  5066.     if (ttgwsiz() > 0) {
  5067.         if (tt_rows > 0 && tt_cols > 0) {
  5068.             cmd_rows = tt_rows;
  5069.             cmd_cols = tt_cols;
  5070.         }
  5071.     }
  5072. #endif /* OS2 */
  5073. #endif /* CK_TTGWSIZ */
  5074.  
  5075.     debug(F101,"dostat xferstat","",xferstat);
  5076.     if (xferstat < 0) {
  5077.         printf(" No file transfers yet.\n");
  5078.         return(1);
  5079.     }
  5080.     if (brief) printf("\n");
  5081.     n = 1;
  5082.     printf(" status                 : ");
  5083.     if (xferstat) printf("SUCCESS\n");
  5084.     else if (interrupted) printf("FAILURE (interrupted)\n");
  5085.     else if (fatalio) printf("FAILURE (i/o error)\n");
  5086.     else printf("FAILURE\n");
  5087.     n++;
  5088.     if (xferstat > 0) {
  5089.         if (docrc)
  5090.           printf(" crc-16 of file(s)      : %ld\n", crc16);
  5091.         else
  5092.           printf(" crc-16 of file(s)      : (disabled)\n");
  5093.         n++;
  5094.     }
  5095.     if (!xferstat && *epktmsg) {
  5096.         printf(" reason                 : %s\n", epktmsg);
  5097.         n++;
  5098.     }
  5099.     if (!brief) {
  5100.         if (whoareu[0]) {
  5101.             printf(" remote system type     : %s\n",
  5102.                    getsysid((char *)whoareu));
  5103.             n++;
  5104.         }
  5105.         printf(" files transferred      : %ld\n",filcnt - filrej);
  5106.         printf(" files not transferred  : %ld\n",filrej);
  5107.         printf(" characters last file   : %ld\n",ffc);
  5108.         printf(" total file characters  : %ld\n",tfc);
  5109.         printf(" communication line in  : %ld\n",tlci);
  5110.         printf(" communication line out : %ld\n",tlco);
  5111.         printf(" packets sent           : %d\n", spackets);
  5112.         printf(" packets received       : %d\n", rpackets);
  5113.         n += 8;
  5114.     }
  5115.     printf(" damaged packets rec'd  : %d\n", crunched);
  5116.     printf(" timeouts               : %d\n", timeouts);
  5117.     printf(" retransmissions        : %d\n", retrans);
  5118.     n += 3;
  5119.  
  5120.     if (!brief) {
  5121.         if (filcnt > 0) {
  5122.             printf(" parity                 : %s",parnam((char)parity));
  5123.             n++;
  5124.             if (autopar) { printf(" (detected automatically)"); n++; }
  5125.             printf(
  5126.                  "\n control characters     : %ld prefixed, %ld unprefixed\n",
  5127.                    ccp, ccu);
  5128.             n++;
  5129.             printf(" 8th bit prefixing      : ");
  5130.             n++;
  5131.             if (ebqflg) printf("yes [%c]\n",ebq); else printf("no\n");
  5132.             n++;
  5133.             printf(" locking shifts         : %s\n", lscapu ? "yes" : "no");
  5134.             n++;
  5135.         }
  5136.     }
  5137.     if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
  5138.     if (streamed > 0)
  5139.       printf(" window slots used      : (streaming)\n");
  5140.     else
  5141.       printf(" window slots used      : %d of %d\n", wmax, wslotr);
  5142.     if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
  5143.     printf(" reliable:              : %s%s\n",
  5144.            streamok ? "" : "not ", "negotiated");
  5145.     if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
  5146.     printf(" clearchannel:          : %s%s\n",
  5147.            cleared  ? "" : "not ", "negotiated");
  5148.     if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
  5149.  
  5150.     if (!brief) {
  5151.         printf(" packet length          : %d (send), %d (receive)\n",
  5152.                lastspmax, urpsiz);
  5153.         if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
  5154.         printf(" compression            : ");
  5155.         if (rptflg)
  5156.           printf("yes [%c] (%ld)\n",(char) rptq,rptn);
  5157.         else
  5158.           printf("no\n");
  5159.         if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
  5160.         if (bctu == 4)
  5161.           printf(" block check type used  : blank-free-2\n");
  5162.         else
  5163.           printf(" block check type used  : %d\n",bctu);
  5164.         if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
  5165.     }
  5166. #ifdef GFTIMER
  5167. #ifdef COMMENT
  5168.     printf(" elapsed time           : %0.3f sec, %s\n", fptsecs,hhmmss(tsecs));
  5169. #endif /* COMMENT */
  5170.     printf(" elapsed time           : %s (%0.3f sec)\n",
  5171.            hhmmss((long)(fptsecs + 0.5)),fptsecs);
  5172. #else
  5173. #ifdef COMMENT
  5174.     printf(" elapsed time           : %s (%d sec)\n",hhmmss(tsecs),tsecs);
  5175. #endif /* COMMENT */
  5176.     printf(" elapsed time           : %d sec, %s\n",tsecs,hhmmss(tsecs));
  5177. #endif /* GFTIMER */
  5178.     if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
  5179.     if (local && !network && !brief) {
  5180.         if (speed <= 0L) speed = ttgspd();
  5181.         if (speed > 0L) {
  5182.             if (speed == 8880)
  5183.               printf(" transmission rate      : 75/1200 bps\n");
  5184.             else
  5185.               printf(" transmission rate      : %ld bps\n",speed);
  5186.             if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
  5187.         }
  5188.     }
  5189.     if (local && !network &&    /* Only makes sense for */
  5190.         mdmtyp == 0 &&          /* direct serial connections */
  5191.         speed > 99L &&          /* when we really know the speed */
  5192.         speed != 8880L
  5193.         ) {
  5194.         int eff;
  5195.         eff = (((tfcps * 100L) / (speed / 100L)) + 5L) / 10L;
  5196.         printf(" effective data rate    : %ld cps (%d%%)\n",tfcps,eff);
  5197.     } else
  5198.       printf(" effective data rate    : %ld cps\n", tfcps);
  5199.     if (peakcps > 0L && peakcps > tfcps)
  5200.       printf(" peak data rate         : %ld cps\n", peakcps);
  5201.     if (brief)
  5202.       printf("\nUse STATISTICS /VERBOSE for greater detail.\n\n");
  5203.     return(1);
  5204. }
  5205. #endif /* NOXFER */
  5206.  
  5207. #ifndef NOSPL
  5208.  
  5209. /* The INPUT command */
  5210.  
  5211. /*
  5212.   NOTE: An INPUT timeout of 0 means to perform a nonblocking read of the
  5213.   material that has already arrived and is waiting to be read, and perform
  5214.   matches against it, without doing any further reads.  It should succeed
  5215.   or fail instantaneously.
  5216. */
  5217.  
  5218. /* Output buffering for "doinput" */
  5219.  
  5220. #ifdef pdp11
  5221. #define MAXBURST 16             /* Maximum size of input burst */
  5222. #else
  5223. #define MAXBURST 1024
  5224. #endif /* pdp11 */
  5225. #ifdef OSK
  5226. static CHAR *conbuf;            /* Buffer to hold output for console */
  5227. #else
  5228. static CHAR conbuf[MAXBURST];   /* Buffer to hold output for console */
  5229. #endif /* OSK */
  5230. static int concnt = 0;          /* Number of characters buffered */
  5231. #ifdef OSK
  5232. static CHAR *sesbuf;            /* Buffer to hold output for session log */
  5233. #else
  5234. static CHAR sesbuf[MAXBURST];   /* Buffer to hold output for session log */
  5235. #endif /* OSK */
  5236. static int sescnt = 0;          /* Number of characters buffered */
  5237.  
  5238. static VOID                             /* Flush INPUT echoing */
  5239. myflsh() {                              /* and session log output. */
  5240.     if (concnt > 0) {
  5241.         conxo(concnt, (char *) conbuf);
  5242.         concnt = 0;
  5243.     }
  5244.     if (sescnt > 0) {
  5245.         logstr((char *) sesbuf, sescnt);
  5246.         sescnt = 0;
  5247.     }
  5248. }
  5249.  
  5250. /* Execute the INPUT and MINPUT commands */
  5251.  
  5252. int instatus = -1;
  5253. long inetime = -1L;
  5254. int inwait = 0;
  5255.  
  5256. /* For returning the input sequence that matched */
  5257.  
  5258. #ifdef BIGBUFOK
  5259. #define MATCHBUFSIZ 8191
  5260. #else
  5261. #define MATCHBUFSIZ 1023
  5262. #endif /* BIGBUFOK */
  5263. static char * matchbuf = NULL;
  5264. static int matchindex = 0;
  5265. /*
  5266.   timo = How long to wait:
  5267.          < 0 = Wait forever
  5268.            0 = Don't wait
  5269.          > 0 = Wait this many seconds
  5270.   ms   = Array of strings to wait for.
  5271.   mp   = Array of flags.
  5272.          If mp[i] == 0, ms[i] is literal, else it's a pattern.
  5273. */
  5274. int
  5275. doinput(timo,ms,mp) int timo; char *ms[]; int mp[]; {
  5276.     extern int inintr;
  5277. #ifdef CK_AUTODL
  5278.     extern int inautodl;
  5279. #endif /* CK_AUTODL */
  5280.     int x, y, i, t, rt, icn, anychar, mi[MINPMAX];
  5281. #ifdef GFTIMER
  5282.     CKFLOAT fpt = 0.0;
  5283. #endif /* GFTIMER */
  5284.     int lastchar = 0;
  5285.     int waiting = 0;
  5286.     char ch, *xp, *s;
  5287.     CHAR c;
  5288. #ifdef OS2
  5289.     extern int term_io;
  5290.     int term_io_save;
  5291. #endif /* OS2 */
  5292. #ifdef TNCODE
  5293.     static int cr = 0;
  5294. #endif /* TNCODE */
  5295.     int is_tn = 0;
  5296.     int wrapped = 0;
  5297.  
  5298. #define CK_BURST
  5299. /*
  5300.   This enables the INPUT speedup code, which depends on ttchk() returning
  5301.   accurate information.  If INPUT fails with this code enabled, change the
  5302.   above "#define" to "#undef".
  5303. */
  5304. #ifdef CK_BURST
  5305.     int burst = 0;                      /* Chars remaining in input burst */
  5306. #endif /* CK_BURST */
  5307.  
  5308.     inwait = timo;                      /* For \v(inwait) */
  5309.     makestr(&inpmatch,NULL);
  5310.  
  5311.     if (!matchbuf)
  5312.       matchbuf = malloc(MATCHBUFSIZ+1);
  5313.     matchindex = 0;
  5314.  
  5315.     is_tn =
  5316. #ifdef TNCODE
  5317.         (local && network && ttnproto == NP_TELNET) || (!local && sstelnet)
  5318. #else
  5319.          0
  5320. #endif /* TNCODE */
  5321.           ;
  5322.  
  5323.     instatus = INP_IE;                  /* 3 = internal error */
  5324.     kbchar = 0;
  5325.  
  5326. #ifdef OSK
  5327.     if (conbuf == NULL) {
  5328.         if ((conbuf = (CHAR *)malloc(MAXBURST*2)) == NULL) {
  5329.             return(0);
  5330.         }
  5331.         sesbuf = conbuf + MAXBURST;
  5332.     }
  5333. #endif /* OSK */
  5334.  
  5335. #ifndef NOLOCAL
  5336.     if (local) {                        /* In local mode... */
  5337.         if ((waiting = ttchk()) < 0) {  /* check that connection is open */
  5338.             printf("?Connection %s %s is not open.\n",
  5339.                    network ? "to" : "on",
  5340.                    ttname
  5341.                    );
  5342.             instatus = INP_IO;
  5343.             return(0);
  5344.         }
  5345.         debug(F101,"doinput waiting","",waiting);
  5346.         y = ttvt(speed,flow);           /* Put line in "ttvt" mode */
  5347.         if (y < 0) {
  5348.             printf("?INPUT initialization error\n");
  5349.             instatus = INP_IO;
  5350.             return(0);                  /* Watch out for failure. */
  5351.         }
  5352.     }
  5353. #endif /* NOLOCAL */
  5354.  
  5355.     if (!ms[0]) {                       /* If we were passed a NULL pointer */
  5356.         anychar = 1;                    /*  ... */
  5357.     } else {
  5358.         y = (int)strlen(ms[0]);         /* Or if search string is empty */
  5359.         anychar = (y < 1);              /* any input character will do. */
  5360.     }
  5361.     if (!anychar && waiting == 0 && timo == 0)
  5362.       return(0);
  5363.  
  5364. #ifndef NODEBUG
  5365.     if (deblog) {
  5366.         char xbuf[24];
  5367.         debug(F101,"doinput anychar","",anychar);
  5368.         debug(F101,"doinput timo","",timo);
  5369.         debug(F101,"doinput echo","",inecho);
  5370.         debug(F101,"doinput burst","",burst);
  5371.         y = -1;
  5372.         while (ms[++y]) {
  5373.             sprintf(xbuf,"doinput string %2d",y);
  5374.             debug(F111,xbuf,ms[y],mp[y]);
  5375.         }
  5376.     }
  5377. #endif /* NODEBUG */
  5378.  
  5379. #ifdef IKS_OPTION
  5380.     if (is_tn) {
  5381.         /* If the remote side is in a state of IKS START-SERVER    */
  5382.         /* we request that the state be changed.  We will detect   */
  5383.         /* a failure to adhere to the request when we call ttinc() */
  5384.         if (TELOPT_U(TELOPT_KERMIT) &&
  5385.             TELOPT_SB(TELOPT_KERMIT).kermit.u_start)
  5386.           iks_wait(KERMIT_REQ_STOP,0);  /* Send Request-Stop */
  5387. #ifdef CK_AUTODL
  5388.         /* If we are processing packets during INPUT and we have not */
  5389.         /* sent a START message, do so now.                          */
  5390.         if (inautodl && !TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
  5391.             tn_siks(KERMIT_START);      /* Send Kermit-Server Start */
  5392.         }
  5393. #endif /* CK_AUTODL */
  5394.     }
  5395. #endif /* IKS_OPTION */
  5396.     x = 0;                              /* Return code, assume failure */
  5397.     instatus = INP_TO;                  /* Status, assume timeout */
  5398.  
  5399.     for (y = 0; y < MINPMAX; y++)
  5400.       mi[y] = 0;                        /* String pattern match position */
  5401.  
  5402.     if (!inpcas[cmdlvl]) {              /* INPUT CASE = IGNORE?  */
  5403.         y = -1;
  5404.  
  5405.         while(xp = ms[++y]) {
  5406.             while (*xp) {               /* Convert to lowercase */
  5407.                 if (isupper(*xp)) *xp = (char) tolower(*xp);
  5408.                 xp++;
  5409.             }
  5410.         }
  5411.     }
  5412.     rtimer();                           /* Reset timer. */
  5413. #ifdef GFTIMER
  5414.     rftimer();                          /* Floating-point timer too. */
  5415. #endif /* GFTIMER */
  5416.     inetime = -1L;                      /* Initialize elapsed time. */
  5417.     t = 0;                              /* Time now is 0. */
  5418.     m_found = 0;                        /* Default to timed-out */
  5419.     incount = 0;                        /* Character counter */
  5420.     rt = (timo == 0) ? 0 : 1;           /* Character-read timeout interval */
  5421.  
  5422. #ifdef OS2
  5423.     term_io_save = term_io;             /* Disable I/O by emulator */
  5424.     term_io = 0;
  5425. #endif /* OS2 */
  5426.  
  5427.     while (1) {                         /* Character-getting loop */
  5428. #ifdef CK_APC
  5429.         /* Check to see if there is an Autodown or other APC command */
  5430.         if (apcactive == APC_LOCAL ||
  5431.             (apcactive == APC_REMOTE && apcstatus != APC_OFF)) {
  5432.             if (mlook(mactab,"_apc_commands",nmac) == -1) {
  5433.                 debug(F110,"doinput about to execute APC",apcbuf,0);
  5434.                 domac("_apc_commands",apcbuf,cmdstk[cmdlvl].ccflgs|CF_APC);
  5435.                 delmac("_apc_commands");
  5436.                 apcactive = APC_INACTIVE;
  5437. #ifdef DEBUG
  5438.             } else {
  5439.                 debug(F100,"doinput APC in progress","",0);
  5440. #endif /* DEBUG */
  5441.             }
  5442.         }
  5443. #endif /* CK_APC */
  5444.  
  5445.         if (timo == 0 && waiting < 1) { /* Special exit criterion */
  5446.             instatus = INP_TO;          /* for timeout == 0 */
  5447.             break;
  5448.         }
  5449.         if (local) {                    /* One case for local */
  5450.             y = ttinc(rt);              /* Get character from comm device */
  5451.             debug(F101,"input ttinc(rt) returns","",y);
  5452.             if (y < -1) {               /* Connection failed. */
  5453.                 instatus = INP_IO;      /* Status = i/o error */
  5454. #ifdef OS2
  5455.                 term_io = term_io_save;
  5456. #endif /* OS2 */
  5457.                 switch (y) {
  5458.                   case -2:              /* Connection lost */
  5459.                     if (local && !network && carrier != CAR_OFF) {
  5460. #ifdef CKLOGDIAL
  5461.                         dologend();
  5462. #endif /* CKLOGDIAL */
  5463.                         printf("Connection closed.\n");
  5464.                         ttclos(1);
  5465.                     }
  5466.                     break;
  5467.                   case -3:
  5468. #ifdef CKLOGDIAL
  5469.                     dologend();
  5470. #endif /* CKLOGDIAL */
  5471.                     printf("Session Limit exceeded - closing connection.\n");
  5472.                     ttclos(1);
  5473.                   default:
  5474.                     break;
  5475.                 }
  5476.                 return(0);
  5477.             }
  5478.             if (inintr) {
  5479.                 if ((icn = conchk()) > 0) { /* Interrupted from keyboard? */
  5480.                     kbchar = coninc(0);
  5481.                     debug(F101,"input interrupted from keyboard","",icn);
  5482.                     while (--icn > 0) {
  5483.                         debug(F110,"doinput","absorbing",0);
  5484.                         coninc(0);      /* Yes, absorb what was typed. */
  5485.                     }
  5486.                     instatus = INP_UI;  /* Fail and remember why. */
  5487.                     break;
  5488.                 }
  5489.             }
  5490.         } else {                        /* Another for remote */
  5491.             y = coninc(rt);
  5492.             debug(F101,"input coninc(rt) returns","",y);
  5493.         }
  5494.         if (y > -1) {                   /* A character arrived */
  5495.             if (timo == 0)
  5496.               waiting--;
  5497. #ifndef OS2
  5498. #ifdef TNCODE
  5499.             /* Check for telnet protocol negotiation */
  5500.             if (is_tn) {
  5501.                 switch (y & 0xff) {
  5502.                   case IAC:
  5503.                     cr = 0;
  5504.                     myflsh();   /* Break from input burst for tn_doop() */
  5505. #ifdef CK_BURST
  5506.                     burst = 0;
  5507. #endif /* CK_BURST */
  5508.                     waiting -= 2;       /* (not necessarily...) */
  5509.                     switch (tn_doop((CHAR)(y & 0xff),duplex,ttinc)) {
  5510.                       case 2: duplex = 0; continue;
  5511.                       case 1: duplex = 1; continue;
  5512. #ifdef IKS_OPTION
  5513.                       case 4:
  5514.                         if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
  5515.                              !tcp_incoming) {
  5516.                             instatus = INP_IKS;
  5517.                             printf(
  5518. " Internet Kermit Service in SERVER mode.\n Please use REMOTE commands.\n"
  5519.                                    );
  5520.                             break;
  5521.                         }
  5522.                         continue;
  5523. #endif /* IKS_OPTION */
  5524.                       case 6:           /* TELNET DO LOGOUT received */
  5525.                       default: continue;
  5526.                     }
  5527.                   case CR:
  5528.                     cr = 1;
  5529.                     break;
  5530.                   case NUL:
  5531.                     if (!TELOPT_U(TELOPT_BINARY) && cr) {
  5532.                         cr = 0;
  5533.                         continue;
  5534.                     }
  5535.                     cr = 0;
  5536.                     break;
  5537.                   default:
  5538.                     cr = 0;
  5539.                 }
  5540.                 /* I'm echoing remote chars */
  5541.                 if (TELOPT_ME(TELOPT_ECHO) && tn_rem_echo)
  5542.                   ttoc((char)y);
  5543.             }
  5544. #endif /* TNCODE */
  5545. #ifdef CK_AUTODL
  5546.             /* Check for file transfer packets */
  5547.             if (inautodl) autodown(y);
  5548. #endif /* CK_AUTODL */
  5549. #else  /* OS2 */
  5550. #ifdef TNCODE
  5551.             /* Check for telnet protocol negotiation */
  5552.  
  5553.             if (is_tn) {
  5554.                 int tx;
  5555.                 switch (y & 0xff) {
  5556.                   case IAC:
  5557.                     myflsh();   /* Break from input burst for tn_doop() */
  5558. #ifdef CK_BURST
  5559.                     burst = 0;
  5560. #endif /* CK_BURST */
  5561. #ifdef IKS_OPTION
  5562.                     tx = scriptwrtbuf((USHORT)y);
  5563.                     if (tx == 4) {
  5564.                         if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
  5565.                             !tcp_incoming
  5566.                             ) {
  5567.                             instatus = INP_IKS;
  5568.                             printf(
  5569.   " Internet Kermit Service in SERVER mode.\n Please use REMOTE commands.\n"
  5570.                                    );
  5571.                             break;
  5572.                         }
  5573.                     } else if (tx == 6) {
  5574.                         /* TELNET DO LOGOUT received */
  5575.  
  5576.                     }
  5577. #else /* IKS_OPTION */
  5578.                     /* Handles Telnet negotiations */
  5579.                     tx = scriptwrtbuf((USHORT)y);
  5580.                     if (tx == 6) {
  5581.                         /* TELNET DO LOGOUT received */
  5582.                     }
  5583. #endif /* IKS_OPTION */
  5584.                     waiting -= 2;       /* (not necessarily...) */
  5585.                     cr = 0;
  5586.                     continue;           /* and autodownload check */
  5587.                   case CR:
  5588.                     cr = 1;
  5589.                     tx = scriptwrtbuf((USHORT)y);
  5590.                     if (tx == 6) {
  5591.                         /* TELNET DO LOGOUT received */
  5592.                     }
  5593.                     break;
  5594.                   case NUL:
  5595.                     cr = 0;
  5596.                     if (!TELOPT_U(TELOPT_BINARY) && cr)
  5597.                       continue;
  5598.                     tx = scriptwrtbuf((USHORT)y);
  5599.                     if (tx == 6) {
  5600.                         /* TELNET DO LOGOUT received */
  5601.                     }
  5602.                     break;
  5603.                   default:
  5604.                     cr = 0;
  5605.                     tx = scriptwrtbuf((USHORT)y);
  5606.                     if (tx == 6) {
  5607.                         /* TELNET DO LOGOUT received */
  5608.                     }
  5609.                 }
  5610.                 /* I'm echoing remote chars */
  5611.                 if (TELOPT_ME(TELOPT_ECHO) && tn_rem_echo)
  5612.                   ttoc((CHAR)y);
  5613.             } else
  5614. #endif /* TNCODE */
  5615.               /* Handles terminal emulation responses */
  5616.               scriptwrtbuf((USHORT)y);
  5617. #endif /* OS2 */
  5618.  
  5619.             /* Real input character to be checked */
  5620.  
  5621. #ifdef CK_BURST
  5622.             burst--;                    /* One less character waiting */
  5623.             debug(F101,"doinput burst","",burst);
  5624. #endif /* CK_BURST */
  5625.             c = (CHAR) (cmask & (CHAR) y); /* Mask off parity */
  5626.             inchar[0] = c;              /* Remember character for \v(inchar) */
  5627. #ifdef COMMENT
  5628. #ifdef CK_BURST
  5629.             /* Update "lastchar" time only once during input burst */
  5630.             if (burst <= 0)
  5631. #endif /* CK_BURST */
  5632. #endif /* COMMENT */
  5633.               lastchar = gtimer();      /* Remember when it came */
  5634.  
  5635.             if (c == '\0') {            /* NUL, we can't use it */
  5636.                 if (anychar) {          /* Except if any character will do? */
  5637.                     x = 1;              /* Yes, done. */
  5638.                     incount = 1;        /* This must be the first and only. */
  5639.                     break;
  5640.                 } else goto refill;     /* Otherwise continue INPUTting */
  5641.             }
  5642.             *inpbp++ = c;               /* Store char in circular buffer */
  5643.             incount++;                  /* Count it for \v(incount) */
  5644.  
  5645.             /* Don't NUL-terminate here - it's a circular buffer. */
  5646.  
  5647.             if (inpbp >= inpbuf + inbufsize) { /* Time to wrap around? */
  5648.                 wrapped++;
  5649.                 *inpbp = NUL ;          /* Make it null-terminated */
  5650.                 inpbp = inpbuf;         /* Yes. */
  5651.             }
  5652.             if (matchbuf) {
  5653.                 if (matchindex < MATCHBUFSIZ) {
  5654.                     matchbuf[matchindex++] = c;
  5655.                     matchbuf[matchindex] = NUL;
  5656.                 }
  5657.             }
  5658. #ifdef MAC
  5659.             {
  5660.                 extern char *ttermw;    /* fake pointer cast */
  5661.                 if (inecho) {
  5662.                     outchar(ttermw, c); /* echo to terminal window */
  5663.                     /* this might be too much overhead to do here ? */
  5664.                     updatecommand(ttermw);
  5665.                 }
  5666.             }
  5667. #else /* Not MAC */
  5668.             if (inecho) conbuf[concnt++] = c; /* Buffer console output */
  5669. #endif /* MAC */
  5670. #ifndef OS2
  5671.             if (seslog) {
  5672. #ifdef UNIX
  5673.                 if (sessft != 0 || c != '\r')
  5674. #else
  5675. #ifdef OSK
  5676.                 if (sessft != 0 || c != '\012')
  5677. #endif /* OSK */
  5678. #endif /* UNIX */
  5679.                   sesbuf[sescnt++] = c; /* Buffer session log output */
  5680.             }
  5681. #endif /* OS2 */
  5682.             if (anychar) {              /* Any character will do? */
  5683.                 x = 1;
  5684.                 break;
  5685.             }
  5686.             if (!inpcas[cmdlvl]) {      /* Ignore alphabetic case? */
  5687.                 if (isupper(c))         /* Yes, convert input char to lower */
  5688.                   c = (CHAR) tolower(c);
  5689.             }
  5690.             debug(F000,"doinput char","",c);
  5691.  
  5692.             /* Here is the matching section */
  5693.  
  5694.             y = -1;                     /* Loop thru search strings */
  5695.             while (s = ms[++y]) {       /* ...as many as we have. */
  5696.                 if (mp[y]) {            /* Pattern match? */
  5697.                     int j;
  5698.                     /* This is gross but it works... */
  5699.                     /* We could just as easily have prepended '*' to the  */
  5700.                     /* pattern and skipped the loop, except then we would */
  5701.                     /* not have any way to identify the matching string.  */
  5702.                     for (j = 0; j < matchindex; j++) {
  5703.                         if (ckmatch(s,&matchbuf[j],1,0)) {
  5704.                             matchindex = j;
  5705.                             x = 1;
  5706.                             break;
  5707.                         }
  5708.                     }
  5709.                     if (x > 0)
  5710.                       break;
  5711.                     continue;
  5712.                 }                       /* Literal match. */
  5713.                 i = mi[y];              /* Match-position in search string. */
  5714.                 debug(F000,"compare char","",(CHAR)s[i]);
  5715.                 if (c == (CHAR) s[i]) { /* Check for match */
  5716.                     i++;                /* Got one, go to next character */
  5717.                 } else {                /* Don't have a match */
  5718.                     int j;
  5719.                     for (j = i; i > 0; ) { /* Back up in search string */
  5720.                         i--; /* (Do this here to prevent compiler foulup) */
  5721.                         /* j is the length of the substring that matched */
  5722.                         if (c == (CHAR) s[i]) {
  5723.                             if (!strncmp(s,&s[j-i],i)) {
  5724.                                 i++;          /* c actually matches -- cfk */
  5725.                                 break;
  5726.                             }
  5727.                         }
  5728.                     }
  5729.                 }
  5730.                 if ((CHAR) s[i] == (CHAR) '\0') { /* Matched to end? */
  5731.                     ckstrncpy(matchbuf,ms[y],MATCHBUFSIZ);
  5732.                     matchindex = 0;
  5733.                     x = 1;              /* Yes, */
  5734.                     break;              /* done. */
  5735.                 }
  5736.                 mi[y] = i;              /* No, remember match-position */
  5737.             }
  5738.             if (x == 1) {               /* Set \v(minput) result */
  5739.                 m_found = y + 1;
  5740.                 break;
  5741.             }
  5742.         }
  5743. #ifdef CK_BURST
  5744.         else if (y <= -1 && burst > 0) {
  5745.             debug(F111,"doinput (y<=-1&&burst>0)","burst",burst);
  5746.                                         /* a timo occurred so there can't   */
  5747.             burst = 0;                  /* be data waiting; must check timo */
  5748.         }
  5749.       refill:
  5750.         if (burst <= 0) {               /* No buffered chars remaining... */
  5751.             myflsh();                   /* Flush buffered output */
  5752.             if (local) {                /* Get size of next input burst */
  5753.                 burst = ttchk();
  5754.                 if (burst < 0) {        /* ttchk() says connection is closed */
  5755.                     instatus = INP_IO;  /* Status = i/o error */
  5756. #ifdef OS2
  5757.                     term_io = term_io_save;
  5758. #endif /* OS2 */
  5759.                     printf("Fatal error - disconnected.\n");
  5760.                     ttclos(1);
  5761.                     break;
  5762.                 }
  5763.                 if (inintr) {
  5764.                     if ((icn = conchk()) > 0) { /* Interrupt from keyboard? */
  5765.                         kbchar = coninc(0);
  5766.                         debug(F101,"input interrupted from keyboard","",icn);
  5767.                         while (--icn > 0) coninc(0); /* Yes, absorb chars. */
  5768.                         break;          /* And fail. */
  5769.                     }
  5770.                 }
  5771.             } else {
  5772.                 burst = conchk();
  5773.             }
  5774.             debug(F101,"doinput burst","",burst);
  5775.             /* Prevent overflow of "conbuf" and "sesbuf" */
  5776.             if (burst > MAXBURST)
  5777.               burst = MAXBURST;
  5778.  
  5779.             /* Did not match, timer exceeded? */
  5780.             t = gtimer();
  5781.             debug(F111,"doinput gtimer","burst",t);
  5782.             debug(F101,"doinput timo","",timo);
  5783.             if ((t >= timo) && (timo > 0))
  5784.               break;
  5785.             else if (insilence > 0 && (t - lastchar) > insilence)
  5786.               break;
  5787.         } else {
  5788.             debug(F111,"doinput (burst > 0)","burst",burst);
  5789.         }
  5790. #else
  5791.         myflsh();                       /* Flush buffered output */
  5792.         /* Did not match, timer exceeded? */
  5793.         t = gtimer();
  5794.         debug(F111,"doinput gtimer","no burst",t);
  5795.         debug(F101,"doinput timo","",timo);
  5796.         if ((t >= timo) && (timo > -1))
  5797.           break;
  5798.         else if (insilence > 0 && (t - lastchar) > insilence)
  5799.           break;
  5800. #endif /* CK_BURST */
  5801.     }                                   /* Still have time left, continue. */
  5802.     myflsh();                           /* Flush buffered output. */
  5803.     if (x > 0)
  5804.       instatus = 0;
  5805. #ifdef OS2
  5806.     term_io = term_io_save;
  5807. #endif /* OS2 */
  5808. #ifdef COMMENT
  5809. #ifdef IKS_OPTION
  5810. #ifdef CK_AUTODL
  5811.     if (is_tn && TELOPT_ME(TELOPT_KERMIT) && inautodl) {
  5812.         tn_siks(KERMIT_STOP);           /* Send Kermit-Server Stop */
  5813.     }
  5814. #endif /* CK_AUTODL */
  5815. #endif /* IKS_OPTION */
  5816. #endif /* COMMENT */
  5817.  
  5818. #ifdef GFTIMER
  5819.     fpt = gftimer();                    /* Get elapsed time */
  5820.  
  5821. /* If a long is 32 bits, it would take about 50 days for this to overflow. */
  5822.  
  5823.     inetime = (int)(fpt * (CKFLOAT)1000.0);
  5824. #else
  5825.     inetime = (int)(gtimer() * 1000);
  5826. #endif /* GFTIMER */
  5827.  
  5828.     makestr(&inpmatch,&matchbuf[matchindex]); /* \v(inmatch) */
  5829.     return(x);                          /* Return the return code. */
  5830. }
  5831. #endif /* NOSPL */
  5832.  
  5833. #ifndef NOSPL
  5834. /* REINPUT Command */
  5835.  
  5836. /*
  5837.   Note, the timeout parameter is required, but ignored.  Syntax is compatible
  5838.   with MS-DOS Kermit except timeout can't be omitted.  This function only
  5839.   looks at the characters already received and does not read any new
  5840.   characters from the connection.
  5841. */
  5842. int
  5843. doreinp(timo,s,pat) int timo; char *s; int pat; {
  5844.     int x, y, i;
  5845.     char *xx, *xp, *xq = (char *)0;
  5846.     CHAR c;
  5847.  
  5848.     if (!s) s = "";
  5849.     debug(F101,"doreinput pat","",pat);
  5850.  
  5851.     y = (int)strlen(s);
  5852.     debug(F111,"doreinput search",s,y);
  5853.  
  5854.     if (y > inbufsize) {                /* If search string longer than */
  5855.         debug(F101,"doreinput inbufsize","",inbufsize);
  5856.         return(0);                      /* input buffer, fail. */
  5857.     }
  5858.     makestr(&inpmatch,NULL);
  5859.     if (!matchbuf)
  5860.       matchbuf = malloc(MATCHBUFSIZ+1);
  5861.     matchindex = 0;
  5862.  
  5863.     x = 0;                              /* Return code, assume failure */
  5864.     i = 0;                              /* String pattern match position */
  5865.  
  5866.     if (!inpcas[cmdlvl]) {              /* INPUT CASE = IGNORE?  */
  5867.         xp = malloc(y+2);               /* Make a separate copy of the */
  5868.         if (!xp) {                      /* search string. */
  5869.             printf("?malloc error 6\n");
  5870.             return(x);
  5871.         } else xq = xp;                 /* Keep pointer to beginning. */
  5872.         while (*s) {                    /* Yes, convert to lowercase */
  5873.             *xp = *s;
  5874.             if (isupper(*xp)) *xp = (char) tolower(*xp);
  5875.             xp++; s++;
  5876.         }
  5877.         *xp = NUL;                      /* Terminate it! */
  5878.         s = xq;                         /* Move search pointer to it. */
  5879.     }
  5880.     xx = *inpbp ? inpbp : inpbuf;       /* Current INPUT buffer pointer */
  5881.     do {
  5882.         c = *xx++;                      /* Get next character */
  5883.         debug(F000,"XXX","",c);
  5884.         if (!c) break;
  5885.         if (xx >= inpbuf + inbufsize)   /* Wrap around if necessary */
  5886.           xx = inpbuf;
  5887.         if (!inpcas[cmdlvl]) {          /* Ignore alphabetic case? */
  5888.             if (isupper(c)) c = (CHAR) tolower(c); /* Yes */
  5889.         }
  5890.         if (pat) {
  5891.             int j;
  5892.             if (matchbuf) {
  5893.                 if (matchindex < MATCHBUFSIZ) {
  5894.                     matchbuf[matchindex++] = c;
  5895.                     matchbuf[matchindex] = NUL;
  5896.                     debug(F111,"XXX",matchbuf,matchindex);
  5897.                 }
  5898.                 for (j = 0; j < matchindex; j++) { /* Gross but effective */
  5899.                     if (ckmatch(s,&matchbuf[j],1,0)) {
  5900.                         debug(F101,"GOT IT","",j);
  5901.                         matchindex = j;
  5902.                         x = 1;
  5903.                         break;
  5904.                     }
  5905.                 }
  5906.             }
  5907.             if (x > 0)
  5908.               break;
  5909.             continue;
  5910.         }
  5911.         debug(F000,"doreinp char","",c);
  5912.         debug(F000,"compare char","",(CHAR) s[i]);
  5913.         if (((char) c) == ((char) s[i])) { /* Check for match */
  5914.             i++;                        /* Got one, go to next character */
  5915.         } else {                        /* Don't have a match */
  5916.             int j;
  5917.             for (j = i; i > 0; ) {      /* [jrs] search backwards for it  */
  5918.                 i--;
  5919.                 if (((char) c) == ((char) s[i])) {
  5920.                     if (!strncmp(s,&s[j-i],i)) {
  5921.                         i++;
  5922.                         break;
  5923.                     }
  5924.                 }
  5925.             }
  5926.         }                               /* [jrs] or return to zero from -1 */
  5927.         if (s[i] == '\0') {             /* Matched all the way to end? */
  5928.             ckstrncpy(matchbuf,s,MATCHBUFSIZ);
  5929.             matchindex = 0;
  5930.             x = 1;                      /* Yes, */
  5931.             break;                      /* done. */
  5932.         }
  5933.     } while (xx != inpbp && x < 1);     /* Until back where we started. */
  5934.  
  5935.     if (!inpcas[cmdlvl]) if (xq) free(xq); /* Free this if it was malloc'd. */
  5936.     makestr(&inpmatch,&matchbuf[matchindex]); /* \v(inmatch) */
  5937.     return(x);                          /* Return search result. */
  5938. }
  5939.  
  5940. /*  X X S T R I N G  --  Interpret strings containing backslash escapes  */
  5941. /*  Z Z S T R I N G  --  (new name...)  */
  5942. /*
  5943.  Copies result to new string.
  5944.   strips enclosing braces or doublequotes.
  5945.   interprets backslash escapes.
  5946.   returns 0 on success, nonzero on failure.
  5947.   tries to be compatible with MS-DOS Kermit.
  5948.  
  5949.  Syntax of input string:
  5950.   string = chars | "chars" | {chars}
  5951.   chars = (c*e*)*
  5952.   where c = any printable character, ascii 32-126
  5953.   and e = a backslash escape
  5954.   and * means 0 or more repetitions of preceding quantity
  5955.   backslash escape = \operand
  5956.   operand = {number} | number | fname(operand) | v(name) | $(name) | m(name)
  5957.   number = [r]n[n[n]]], i.e. an optional radix code followed by 1-3 digits
  5958.   radix code is oO (octal), xX (hex), dD or none (decimal) (see xxesc()).
  5959. */
  5960.  
  5961. #ifndef NOFRILLS
  5962. int
  5963. yystring(s,s2) char *s; char **s2; {    /* Reverse a string */
  5964.     int x;
  5965.     static char *new;
  5966.     new = *s2;
  5967.     if (!s || !new) return(-1);         /* Watch out for null pointers. */
  5968.     if ((x = (int)strlen(s)) == 0) {    /* Recursion done. */
  5969.         *new = '\0';
  5970.         return(0);
  5971.     }
  5972.     x--;                                /* Otherwise, call self */
  5973.     *new++ = s[x];                      /* to reverse rest of string. */
  5974.     s[x] = 0;
  5975.     return(yystring(s,&new));
  5976. }
  5977. #endif /* NOFRILLS */
  5978.  
  5979. static char ipabuf[16] = { NUL };       /* IP address buffer */
  5980.  
  5981. static char *
  5982. getip(s) char *s; {
  5983.     char c=NUL;                         /* Workers... */
  5984.     int i=0, p=0, d=0;
  5985.     int state = 0;                      /* State of 2-state FSA */
  5986.  
  5987.     while (c = *s++) {
  5988.         switch(state) {
  5989.           case 0:                       /* Find first digit */
  5990.             i = 0;                      /* Output buffer index */
  5991.             ipabuf[i] = NUL;            /* Initialize output buffer */
  5992.             p = 0;                      /* Period counter */
  5993.             d = 0;                      /* Digit counter */
  5994.             if (isdigit(c)) {           /* Have first digit */
  5995.                 d = 1;                  /* Count it */
  5996.                 ipabuf[i++] = c;        /* Copy it */
  5997.                 state = 1;              /* Change state */
  5998.             }
  5999.             break;
  6000.  
  6001.           case 1:                       /* In numeric field */
  6002.             if (isdigit(c)) {           /* Have digit */
  6003.                 if (++d > 3)            /* Too many */
  6004.                   state = 0;            /* Start over */
  6005.                 else                    /* Not too many */
  6006.                   ipabuf[i++] = c;      /* Keep it */
  6007.             } else if (c == '.' && p < 3) { /* Have a period */
  6008.                 p++;                    /* Count it */
  6009.                 if (d == 0)             /* Not preceded by a digit */
  6010.                   state = 0;            /* Start over */
  6011.                 else                    /* OK */
  6012.                   ipabuf[i++] = c;      /* Keep it */
  6013.                 d = 0;                  /* Reset digit counter */
  6014.             } else if (p == 3 && d > 0) { /* Not part of address */
  6015.                 ipabuf[i] = NUL;        /* If we have full IP address */
  6016.                 return((char *)ipabuf); /* Return it */
  6017.             } else {                    /* Otherwise */
  6018.                 state = 0;              /* Start over */
  6019.                 ipabuf[0] = NUL;        /* (in case no more chars left) */
  6020.             }
  6021.         }
  6022.     }                                   /* Fall thru at end of string */
  6023.     ipabuf[i] = NUL;                    /* Maybe we have one */
  6024.     return((p == 3 && d > 0) ? (char *)ipabuf : "");
  6025. }
  6026. #endif /* NOSPL */
  6027.  
  6028. /* Date Routines */
  6029.  
  6030. /* Z J D A T E  --  Convert yyyymmdd date to Day of Year */
  6031.  
  6032. static int jdays[12] = {  0,31,59,90,120,151,181,212,243,273,304,334 };
  6033. static int ldays[12] = {  0,31,60,91,121,152,182,213,244,274,305,335 };
  6034. static char zjdbuf[12] = { NUL, NUL };
  6035. /*
  6036.   Deinde, ne in posterum a XII kalendas aprilis aequinoctium recedat,
  6037.   statuimus bissextum quarto quoque anno (uti mos est) continuari debere,
  6038.   praeterquam in centesimis annis; qui, quamvis bissextiles antea semper
  6039.   fuerint, qualem etiam esse volumus annum MDC, post eum tamen qui deinceps
  6040.   consequentur centesimi non omnes bissextiles sint, sed in quadringentis
  6041.   quibusque annis primi quique tres centesimi sine bissexto transigantur,
  6042.   quartus vero quisque centesimus bissextilis sit, ita ut annus MDCC, MDCCC,
  6043.   MDCCCC bissextiles non sint. Anno vero MM, more consueto dies bissextus
  6044.   intercaletur, februario dies XXIX continente, idemque ordo intermittendi
  6045.   intercalandique bissextum diem in quadringentis quibusque annis perpetuo
  6046.   conservetur.  - Gregorius XIII, Anno Domini MDLXXXII.
  6047. */
  6048. char *
  6049. zjdate(date) char * date; {             /* date = yyyymmdd */
  6050.     char year[5];
  6051.     char month[3];
  6052.     char day[3];
  6053.     int d, m, x, y;
  6054.     int leapday, j;
  6055.     char * time = NULL;
  6056.  
  6057.     if (!date) date = "";               /* Validate arg */
  6058.     x = strlen(date);
  6059.     if (x < 1) return("0");
  6060.     if (x < 8) return("-1");
  6061.     for (x = 0; x < 8; x++)
  6062.       if (!isdigit(date[x]))
  6063.         return("-1");
  6064.  
  6065.     if (date[8] && date[9])
  6066.       time = date + 9;
  6067.  
  6068.     year[0] = date[0];                  /* Isolate year */
  6069.     year[1] = date[1];
  6070.     year[2] = date[2];
  6071.     year[3] = date[3];
  6072.     year[4] = '\0';
  6073.  
  6074.     month[0] = date[4];                 /* Month */
  6075.     month[1] = date[5];
  6076.     month[2] = '\0';;
  6077.  
  6078.     day[0] = date[6];                   /* And day */
  6079.     day[1] = date[7];
  6080.     day[2] = '\0';
  6081.  
  6082.     leapday = 0;                        /* Assume no leap day */
  6083.     y = atoi(year);
  6084.     m = atoi(month);
  6085.     d = atoi(day);
  6086.     if (m > 2) {                        /* No Leap day before March */
  6087.         if (y % 4 == 0) {               /* If year is divisible by 4 */
  6088.             leapday = 1;                /* It's a Leap year */
  6089.             if (y % 100 == 0) {         /* Except if divisible by 100 */
  6090.                 if (y % 400 != 0)       /* but not by 400 */
  6091.                   leapday = 0;
  6092.             }
  6093.         }
  6094.     }
  6095.     j = jdays[m - 1] + d + leapday;     /* Day of year */
  6096.     if (time)
  6097.       sprintf(zjdbuf,"%04d%03d %s",y,j,time);
  6098.     else
  6099.       sprintf(zjdbuf,"%04d%03d",y,j);
  6100.     return((char *)zjdbuf);
  6101. }
  6102.  
  6103. static char jzdbuf[32];
  6104.  
  6105. /* J Z D A T E  --  Convert Day of Year to yyyyddmm date */
  6106.  
  6107. char *
  6108. jzdate(date) char * date; {             /* date = yyyyddd */
  6109.     char year[5];                       /* with optional time */
  6110.     char day[4];
  6111.     char * time = NULL, * p;
  6112.     int d, m, x, y;
  6113.     int leapday, j;
  6114.     int * zz;
  6115.  
  6116.     if (!date) date = "";               /* Validate arg */
  6117.     x = strlen(date);
  6118.  
  6119.     debug(F111,"jzdate len",date,x);
  6120.  
  6121.     if (x < 1) return("0");
  6122.     if (x < 7) return("-1");
  6123.     if (x > 8) time = date + 8;
  6124.  
  6125.     for (x = 0; x < 7; x++)
  6126.       if (!isdigit(date[x]))
  6127.         return("-1");
  6128.  
  6129.     year[0] = date[0];                  /* Isolate year */
  6130.     year[1] = date[1];
  6131.     year[2] = date[2];
  6132.     year[3] = date[3];
  6133.     year[4] = '\0';
  6134.  
  6135.     debug(F110,"jzdate year",year,0);
  6136.  
  6137.     day[0] = date[4];                   /* And day */
  6138.     day[1] = date[5];
  6139.     day[2] = date[6];
  6140.     day[3] = '\0';
  6141.  
  6142.     debug(F110,"jzdate day",day,0);
  6143.  
  6144.     j = atoi(day);
  6145.     if (j > 366)
  6146.       return("-1");
  6147.  
  6148.     leapday = 0;                        /* Assume no leap day */
  6149.     y = atoi(year);
  6150.     if (y % 4 == 0) {                   /* If year is divisible by 4 */
  6151.         leapday = 1;                    /* It's a Leap year */
  6152.         if (y % 100 == 0) {             /* Except if divisible by 100 */
  6153.             if (y % 400 != 0)           /* but not by 400 */
  6154.               leapday = 0;
  6155.         }
  6156.     }
  6157.     debug(F101,"jzdate leapday","",leapday);
  6158.     zz = leapday ? ldays : jdays;
  6159.  
  6160.     for (x = 0; x < 11; x++)
  6161.       if (j > zz[x] && j <= zz[x+1])
  6162.         break;
  6163.     m = x + 1;
  6164.  
  6165.     debug(F101,"jzdate m","",m);
  6166.  
  6167.     d = j - zz[x];
  6168.  
  6169.     debug(F101,"jzdate d","",d);
  6170.  
  6171.     if (time)
  6172.       sprintf(jzdbuf,"%04d%02d%02d %s",y,m,d,time);
  6173.     else
  6174.       sprintf(jzdbuf,"%04d%02d%02d",y,m,d);
  6175.  
  6176.     debug(F101,"jzdate jzdbuf",jzdbuf,0);
  6177.  
  6178.     p = ckcvtdate((char *)jzdbuf, 0);   /* Convert to standard form */
  6179.     ckstrncpy(jzdbuf,p,32);
  6180.     if (!time) jzdbuf[8] = NUL;         /* Remove time if not wanted */
  6181.     return((char *)jzdbuf);
  6182. }
  6183.  
  6184. /* M J D  --  Modified Julian Date */
  6185. /*
  6186.   Call with:
  6187.     Standard-format date-time string: yyyymmdd[ hh:mm:ss].
  6188.     The time, if any, is ignored.
  6189.  
  6190.   Returns:
  6191.    -1L on error, otherwise:
  6192.    The number of days since 17 Nov 1858 (as a whole number)
  6193.  
  6194.   The Modified Julian Date is defined by the International Astronomical
  6195.   Union as the true Julian date minus 2400000.5 days.  The true Julian
  6196.   date is the number days since since noon of 1 January 4713 BCE of the
  6197.   Julian proleptic calendar.
  6198. */
  6199. long
  6200. mjd(date) char * date; {
  6201.     char year[5];
  6202.     char month[3];
  6203.     char day[3];
  6204.     int x, d, m, y;
  6205.  
  6206.     if (!date) date = "";               /* Validate arg */
  6207.     x = strlen(date);
  6208.     if (x < 1) return(0L);
  6209.     if (x < 8) return(-1L);
  6210.     for (x = 0; x < 8; x++)
  6211.       if (!isdigit(date[x]))
  6212.         return(-1L);
  6213.  
  6214.     year[0] = date[0];                  /* Isolate year */
  6215.     year[1] = date[1];
  6216.     year[2] = date[2];
  6217.     year[3] = date[3];
  6218.     year[4] = '\0';
  6219.     y = atoi(year) - 1900;
  6220.  
  6221.     month[0] = date[4];                 /* Month */
  6222.     month[1] = date[5];
  6223.     month[2] = '\0';;
  6224.     m = atoi(month);
  6225.  
  6226.     day[0] = date[6];                   /* And day */
  6227.     day[1] = date[7];
  6228.     day[2] = '\0';
  6229.     d = atoi(day);
  6230.  
  6231.     if (m - 2 < 1) {                    /* Arithmetic */
  6232.         m += 9;
  6233.         y--;
  6234.     } else {
  6235.         m -= 3;
  6236.     }
  6237.     return(15078 + (1461 * y) / 4 + (153 * m + 2) / 5 + d);
  6238. }
  6239.  
  6240. static char mjd2dbuf[12];
  6241.  
  6242. /*  M J D 2 D A T E  --  Converts MJD to yyyymmdd  */
  6243.  
  6244. char *
  6245. #ifdef CK_ANSIC
  6246. mjd2date(long mjd)
  6247. #else
  6248. mjd2date(mjd) long mjd;
  6249. #endif /* CK_ANSIC */
  6250. /* mjd2date */ {
  6251.     long jd, l, n;
  6252.     int d, m, y;
  6253.     jd = (long)(mjd + 2400001L);
  6254.     l = jd + 68569;
  6255.     n = 4 * l / 146097L;
  6256.     l = l - (146097 * n + 3) / 4;
  6257.     y = 4000 * (l + 1) / 1461001L;
  6258.     l = l - 1461 * y / 4 + 31;
  6259.     m = 80 * l / 2447;
  6260.     d = l - 2447 * m / 80;
  6261.     l = m / 11;
  6262.     m = m + 2 - 12 * l;
  6263.     y = 100 * (n - 49) + y + l;
  6264.     sprintf(mjd2dbuf,"%04d%02d%02d",y,m,d);
  6265.     return((char *)mjd2dbuf);
  6266. }
  6267.  
  6268. #ifndef NOSPL
  6269. static char ** flist = (char **) NULL;  /* File list for \fnextfile() */
  6270. static int flistn = 0;                  /* Number of items in file list */
  6271.  
  6272. /*
  6273.   The function return-value buffer must be global, since fneval() returns a
  6274.   pointer to it.  fneval() is called only by zzstring(), which always copies
  6275.   the result out of this buffer to somewhere else, so it's OK to have only
  6276.   one buffer for this in most cases.  However, since function calls can be
  6277.   nested -- e.g. functions whose arguments are functions, or recursive
  6278.   functions, at some point we should convert this to an array of buffers,
  6279.   indexed by function depth (which might or might not be the same as the
  6280.   "depth" variable).  Also, since function results are potentially quite big,
  6281.   we'd need to allocate and deallocate dynamically as we descend and ascend
  6282.   function depth.  Left for a future release...
  6283. */
  6284. char fnval[FNVALL+2];                   /* Function return value  */
  6285. static int fndepth = 0;                 /* (we don't actually use this yet) */
  6286. int fnsuccess = 1;
  6287. extern int fnerror;
  6288.  
  6289. static char *                           /* Evaluate builtin functions */
  6290. fneval(fn,argp,argn,xp) char *fn, *argp[]; int argn; char * xp; {
  6291.     int i=0, j=0, k=0, len1=0, len2=0, len3=0, n=0, t=0, x=0, y=0;
  6292.     int failed = 0;                     /* Return code, 0 = ok */
  6293.     long z = 0L;
  6294.     char *bp[FNARGS + 1];               /* Pointers to malloc'd strings */
  6295.     char c = NUL;
  6296.     char *p = NULL, *s = NULL;
  6297.     char *val1 = NULL, *val2 = NULL;    /* Pointers to numeric string values */
  6298.  
  6299. #ifdef RECURSIVE
  6300.     int rsave = recursive;
  6301. #endif /* RECURSIVE */
  6302. #ifdef OS2
  6303.     int zsave = zxpn;
  6304. #endif /* OS2 */
  6305.  
  6306.     for (i = 0; i < FNARGS; i++)        /* Initialize argument pointers */
  6307.       bp[i] = NULL;
  6308. /*
  6309.   IMPORTANT: Note that argn is not an accurate count of the number of
  6310.   arguments.  We can't really tell if an argument is null until after we
  6311.   execute the code below.  So argn is really the maximum number of arguments
  6312.   we might have.  In particular note that argn is always at least 1, even
  6313.   if the function is called with empty parentheses (but don't count on it).
  6314. */
  6315.     if (!fn) fn = "";                   /* Protect against null pointers */
  6316.     debug(F111,"fneval",fn,argn);
  6317.     debug(F110,"fneval",argp[0],0);
  6318.     if (argn > FNARGS)                  /* Discard excess arguments */
  6319.       argn = FNARGS;
  6320.  
  6321.     fndepth++;
  6322.     debug(F101,"fneval fndepth","",fndepth);
  6323.     p = fnval;
  6324.     fnval[0] = NUL;
  6325.     y = lookup(fnctab,fn,nfuncs,&x);    /* Look up the function name */
  6326.     if (y < 0) {                        /* Not found */
  6327.         failed = 1;
  6328.         if (fndiags) {                  /* FUNCTION DIAGNOSTIC ON */
  6329.             int x;
  6330.             x = strlen(fn);
  6331.             switch (y) {
  6332.               case -1:
  6333.                 if (x + 32 < FNVALL)
  6334.                   sprintf(fnval,"<ERROR:NO_SUCH_FUNCTION:\\f%s()>",fn);
  6335.                 else
  6336.                   sprintf(fnval,"<ERROR:NO_SUCH_FUNCTION>");
  6337.                 break;
  6338.               case -2:
  6339.                 if (x + 26 < FNVALL)
  6340.                   sprintf(fnval,"<ERROR:NAME_AMBIGUOUS:\\f%s()>",fn);
  6341.                 else
  6342.                   sprintf(fnval,"<ERROR:NAME_AMBIGUOUS>");
  6343.                 break;
  6344.               case -3:
  6345.                 sprintf(fnval,"<ERROR:FUNCTION_NAME_MISSING:\\f()>");
  6346.                 break;
  6347.               default:
  6348.                 if (x + 26 < FNVALL)
  6349.                   sprintf(fnval,"<ERROR:LOOKUP_FAILURE:\\f%s()>",fn);
  6350.                 else
  6351.                   sprintf(fnval,"<ERROR:LOOKUP_FAILURE>");
  6352.                 break;
  6353.             }
  6354.         }
  6355.         goto fnend;                     /* Always leave via common exit */
  6356.     }
  6357. #ifdef DEBUG
  6358.     if (deblog) {
  6359.         int j;
  6360.         for (j = 0; j < argn; j++)
  6361.           debug(F111,"fneval arg",argp[j],j);
  6362.     }
  6363. #endif /* DEBUG */
  6364.     for (j = argn-1; j >= 0; j--) {     /* Uncount empty trailing args */
  6365.         if (!argp[j])
  6366.           argn--;
  6367.         else if (!*(argp[j]))
  6368.           argn--;
  6369.         else break;
  6370.     }
  6371.     debug(F101,"fneval argn","",argn);
  6372. /*
  6373.   \fliteral() and \fcontents() are special functions that do not evaluate
  6374.   their arguments, and are treated specially here.  After these come the
  6375.   functions whose arguments are evaluated in the normal way.
  6376. */
  6377.     if (y == FN_LIT) {                  /* literal(arg1) */
  6378.         debug(F110,"flit",xp,0);
  6379.         p = xp ? xp : "";               /* Return a pointer to arg itself */
  6380.         goto fnend;
  6381.     }
  6382.     if (y == FN_CON) {                  /* Contents of variable, unexpanded. */
  6383.         char c;
  6384.         if (!(p = argp[0]) || !*p) {
  6385.             failed = 1;
  6386.             p = fnval;
  6387.             if (fndiags)
  6388.               sprintf(fnval,"<ERROR:MISSING_ARG:\\fcontents()>");
  6389.             goto fnend;
  6390.         }
  6391.         p = brstrip(p);
  6392.         if (*p == CMDQ) p++;
  6393.         if ((c = *p) == '%') {          /* Scalar variable. */
  6394.             c = *++p;                   /* Get ID character. */
  6395.             p = "";                     /* Assume definition is empty */
  6396.             if (!c) {                   /* Double paranoia */
  6397.                 failed = 1;
  6398.                 p = fnval;
  6399.                 if (fndiags)
  6400.                   sprintf(fnval,"<ERROR:ARG_BAD_VARIABLE:\\fcontents()>");
  6401.                 goto fnend;
  6402.             }
  6403.             if (c >= '0' && c <= '9') { /* Digit for macro arg */
  6404.                 if (maclvl < 0)         /* Digit variables are global */
  6405.                   p = g_var[c];         /* if no macro is active */
  6406.                 else                    /* otherwise */
  6407.                   p = m_arg[maclvl][c - '0']; /* they're on the stack */
  6408.             } else if (c == '*' && maclvl >= 0) {
  6409.                 p = m_line[maclvl];
  6410.                 if (!p) p = "";
  6411.             } else {
  6412.                 if (isupper(c)) c -= ('a'-'A');
  6413.                 p = g_var[c];           /* Letter for global variable */
  6414.             }
  6415.             if (!p) p = "";
  6416.             goto fnend;
  6417.         } else if (c == '&') {                  /* Array reference. */
  6418.             int vbi, d;
  6419.             if (arraynam(p,&vbi,&d) < 0) { /* Get name and subscript */
  6420.                 failed = 1;
  6421.                 p = fnval;
  6422.                 if (fndiags)
  6423.                   sprintf(fnval,"<ERROR:ARG_BAD_ARRAY:\\fcontents()>");
  6424.                 goto fnend;
  6425.             }
  6426.             if (chkarray(vbi,d) > 0) {  /* Array is declared? */
  6427.                 vbi -= ARRAYBASE;       /* Convert name to index */
  6428.                 if (a_dim[vbi] >= d) {  /* If subscript in range */
  6429.                     char **ap;
  6430.                     ap = a_ptr[vbi];    /* get data pointer */
  6431.                     if (ap) {           /* and if there is one */
  6432.                         p = ap[d];
  6433.                         goto fnend;
  6434.                     }
  6435.                 }
  6436.             } else {
  6437.                 failed = 1;
  6438.                 p = fnval;
  6439.                 if (fndiags)
  6440.                   sprintf(fnval,"<ERROR:ARG_NOT_ARRAY:\\fcontents()>");
  6441.                 goto fnend;
  6442.             }
  6443.         } else {
  6444.             failed = 1;
  6445.             p = fnval;
  6446.             if (fndiags)
  6447.               sprintf(fnval,"<ERROR:ARG_NOT_VARIABLE:\\fcontents()>");
  6448.             goto fnend;
  6449.         }
  6450.     }
  6451.     p = fnval;                          /* Default result pointer */
  6452.     fnval[0] = NUL;                     /* Default result = empty string */
  6453.  
  6454.     for (i = 0; i < argn; i++) {        /* Loop to expand each argument */
  6455.         n = MAXARGLEN;                  /* Allow plenty of space */
  6456.         bp[i] = s = malloc(n+1);        /* Allocate space for this argument */
  6457.         if (bp[i] == NULL) {            /* Handle failure to get space */
  6458.             failed = 1;
  6459.             if (fndiags)
  6460.               sprintf(fnval,"<ERROR:MALLOC_FAILURE:\\f%s()>",fn);
  6461.             goto fnend;
  6462.         }
  6463.         p = argp[i] ? argp[i] : "";     /* Point to this argument */
  6464.  
  6465. /*
  6466.   Trim leading and trailing spaces from the original argument, before
  6467.   evaluation.  This code new to edit 184.
  6468. */
  6469.         {
  6470.             int x, j;
  6471.             x = strlen(p);
  6472.             if (*p == '{' && *(p+x-1) == '}') {
  6473.                 p[x-1] = NUL;
  6474.                 p++;
  6475.                 x -= 2;
  6476.             } else {
  6477.                 j = x - 1;              /* Trim trailing whitespace */
  6478.                 while (j > 0 && (*(p + j) == SP || *(p + j) == HT))
  6479.                   *(p + j--) = NUL;
  6480.                 while (*p == SP || *p == HT) /* Strip leading whitespace */
  6481.                   p++;
  6482.             }
  6483.         }
  6484.  
  6485. /* Now evaluate the argument */
  6486.  
  6487.         debug(F111,"fneval calling zzstring",p,n);
  6488.         t = zzstring(p,&s,&n);          /* Expand arg into new space */
  6489.         debug(F101,"fneval zzstring","",t);
  6490.         debug(F101,"fneval zzstring","",n);
  6491.         if (t < 0) {
  6492.             debug(F101,"fneval zzstring fails, arg","",i);
  6493.             failed = 1;
  6494.             if (fndiags) {
  6495.                 if (n == 0)
  6496.                   sprintf(fnval,"<ERROR:ARG_TOO_LONG:\\f%s()>",fn);
  6497.                 else
  6498.                   sprintf(fnval,"<ERROR:ARG_EVAL_FAILURE:\\f%s()>",fn);
  6499.             }
  6500.             goto fnend;
  6501.         }
  6502.         debug(F111,"fneval arg",bp[i],i);
  6503.     }
  6504.  
  6505. #ifdef DEBUG
  6506.     if (deblog) {
  6507.         int j;
  6508.         for (j = 0; j < argn; j++) {
  6509.             debug(F111,"fneval arg post eval",argp[j],j);
  6510.             debug(F111,"fneval evaluated arg",bp[j],j);
  6511.         }
  6512.     }
  6513. #endif /* DEBUG */
  6514. /*
  6515.   From this point on, bp[0..argn-1] are not NULL and all must be freed
  6516.   before returning.
  6517. */
  6518.     if (argn < 1) {                     /* Catch required args missing */
  6519.         switch (y) {
  6520.           case FN_DEF:
  6521.           case FN_EVA:
  6522.           case FN_EXE:
  6523.           case FN_CHR:
  6524.           case FN_COD:
  6525.           case FN_MAX:
  6526.           case FN_MIN:
  6527.           case FN_MOD:
  6528.           case FN_FD:
  6529.           case FN_FS:
  6530.           case FN_TOD:
  6531.           case FN_FFN:
  6532.           case FN_BSN:
  6533.           case FN_RAW:
  6534.           case FN_CMD:
  6535.           case FN_2HEX:
  6536.           case FN_2OCT:
  6537.           case FN_DNAM:
  6538. #ifdef FN_ERRMSG
  6539.           case FN_ERRMSG:
  6540. #endif /* FN_ERRMSG */
  6541. #ifdef CK_KERBEROS
  6542.           case FN_KRB_TK:
  6543.           case FN_KRB_NX:
  6544.           case FN_KRB_IV:
  6545.           case FN_KRB_TT:
  6546.           case FN_KRB_FG:
  6547. #endif /* CK_KERBEROS */
  6548.           case FN_MJD2:
  6549.           case FN_N2TIM:
  6550.           case FN_DIM:
  6551.           case FN_DATEJ:
  6552.           case FN_PNCVT:
  6553.           case FN_PERM:
  6554.           case FN_ALOOK:
  6555.           case FN_TLOOK:
  6556.           case FN_ABS:
  6557.           case FN_FPABS:
  6558.           case FN_FPEXP:
  6559.           case FN_FPLOG:
  6560.           case FN_FPLN:
  6561.           case FN_FPMOD:
  6562.           case FN_FPSQR:
  6563.           case FN_FPADD:
  6564.           case FN_FPDIV:
  6565.           case FN_FPMUL:
  6566.           case FN_FPPOW:
  6567.           case FN_FPSUB:
  6568.           case FN_FPINT:
  6569.           case FN_FPROU:
  6570.           case FN_FPSIN:
  6571.           case FN_FPCOS:
  6572.           case FN_FPTAN:
  6573.           case FN_AADUMP:
  6574.             failed = 1;
  6575.             p = fnval;
  6576.             if (fndiags)
  6577.               sprintf(fnval,"<ERROR:MISSING_ARG:\\f%s()>",fn);
  6578.             goto fnend;
  6579.         }
  6580.     }
  6581.     p = fnval;                          /* Reset these again. */
  6582.     fnval[0] = NUL;
  6583.  
  6584.     switch (y) {                        /* Do function on expanded args. */
  6585.  
  6586.       case FN_DEF:                      /* \fdefinition(arg1) */
  6587.         k = mlook(mactab,bp[0],nmac);
  6588.         p = (k > -1) ? mactab[k].mval : "";
  6589.         goto fnend;
  6590.  
  6591.       case FN_EVA:                      /* \fevaluate(arg1) */
  6592.         p = *(bp[0]) ? evalx(bp[0]) : "";
  6593.         if (!*p && fndiags) {
  6594.             failed = 1;
  6595.             p = fnval;
  6596.             if (fndiags)
  6597.               sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  6598.         }
  6599.         goto fnend;
  6600.  
  6601.       case FN_EXE:                      /* \fexecute(arg1) */
  6602.         j = (int)strlen(s = bp[0]);     /* Length of macro invocation */
  6603.         p = "";                         /* Initialize return value to null */
  6604.         if (j) {                        /* If there is a macro to execute */
  6605.             while (*s == SP) s++,j--;   /* strip leading spaces */
  6606.             p = s;                      /* remember beginning of macro name */
  6607.             for (i = 0; i < j; i++) {   /* find end of macro name */
  6608.                 if (*s == SP)
  6609.                   break;
  6610.                 s++;
  6611.             }
  6612.             if (*s == SP)       {       /* if there was a space after */
  6613.                 *s++ = NUL;             /* terminate the macro name */
  6614.                 while (*s == SP) s++;   /* skip past any extra spaces */
  6615.             } else s = "";              /* maybe there are no arguments */
  6616.             if (p && *p)
  6617.               k = mlook(mactab,p,nmac); /* Look up the macro name */
  6618.             else
  6619.               k = -1;
  6620.             if (k < 0) {
  6621.                 failed = 1;
  6622.                 p = fnval;
  6623.                 if (fndiags)
  6624.                   sprintf(fnval,"<ERROR:NO_SUCH_MACRO:\\f%s()>",fn);
  6625.                 goto fnend;
  6626.             }
  6627. /*
  6628.   This is just a WEE bit dangerous because we are copying up to 9 arguments
  6629.   into the space reserved for one.  It won't overrun the buffer, but if there
  6630.   are lots of long arguments we might lose some.  The other problem is that if
  6631.   the macro has more than 3 arguments, the 4th through last are all
  6632.   concatenated onto the third.  (The workaround is to use spaces rather than
  6633.   commas to separate them.)  Leaving it like this to avoid having to allocate
  6634.   tons more buffers.
  6635. */
  6636.             if (argn > 1) {             /* Commas used instead of spaces */
  6637.                 int i;
  6638.                 char *p = bp[0];        /* Reuse this space */
  6639.                 *p = NUL;               /* Make into dodo() arg list */
  6640.                 for (i = 1; i < argn; i++) {
  6641.                     strncat(p,bp[i],MAXARGLEN);
  6642.                     strncat(p," ",MAXARGLEN);
  6643.                 }
  6644.                 s = bp[0];              /* Point to new list */
  6645.             }
  6646.             p = "";                     /* Initialize return value */
  6647.             if (k >= 0) {               /* If macro found in table */
  6648.                 /* Go set it up (like DO cmd) */
  6649.                 if ((j = dodo(k,s,cmdstk[cmdlvl].ccflgs)) > 0) {
  6650.                     if (cmpush() > -1) { /* Push command parser state */
  6651.                         extern int ifc;
  6652.                         int ifcsav = ifc; /* Push IF condition on stack */
  6653.                         k = parser(1);  /* Call parser to execute the macro */
  6654.                         cmpop();        /* Pop command parser */
  6655.                         ifc = ifcsav;   /* Restore IF condition */
  6656.                         if (k == 0) {   /* No errors, ignore action cmds. */
  6657.                             p = mrval[maclvl+1]; /* If OK, set return value. */
  6658.                             if (p == NULL) p = "";
  6659.                         }
  6660.                     } else {            /* Can't push any more */
  6661.                         debug(F100,"fexec pushed too deep","",0);
  6662.                         printf("\n?\\fexec() too deeply nested\n");
  6663.                         while (cmpop() > -1) ;
  6664.                         p = "";
  6665.                     }
  6666.                 }
  6667.             }
  6668.         }
  6669.         goto fnend;
  6670.  
  6671. #ifdef RECURSIVE
  6672.       case FN_RDIR:                     /* \frdir..() - Recursive dir count */
  6673.       case FN_RFIL:                     /* \frfiles() - Recursive file count */
  6674.         /* recursive = 2; */            /* fall thru... */
  6675. #endif /* RECURSIVE */
  6676.       case FN_FC:                       /* \ffiles() - File count. */
  6677.       case FN_DIR: {                    /* \ffdir.() - Directory count. */
  6678.           char abuf[16], *s;
  6679.           char ** ap = NULL;
  6680.           int x, xflags = 0;
  6681.           if (matchdot)
  6682.             xflags |= ZX_MATCHDOT;
  6683.           if (y == FN_RDIR || y == FN_RFIL)
  6684.             xflags |= ZX_RECURSE;
  6685.           failed = 0;
  6686.           if (argn < 1) {
  6687.               p = "0";
  6688.               goto fnend;
  6689.           }
  6690.           if (y == FN_DIR || y == FN_RDIR) { /* Only list directories */
  6691.               xflags |= ZX_DIRONLY;
  6692. #ifdef OS2
  6693.               zxpn = 1;                 /* Use the alternate list */
  6694. #endif /* OS2 */
  6695.           } else {                      /* List only files */
  6696.               xflags |= ZX_FILONLY;
  6697. #ifdef OS2
  6698.               zxpn = 1;                 /* Use the alternate list */
  6699. #endif /* OS2 */
  6700.           }
  6701.           if (*(bp[0])) {
  6702.               k = nzxpand(bp[0],xflags);
  6703.               if (k < 0) k = 0;
  6704.               sprintf(fnval,"%d",k);
  6705.               p = fnval;
  6706.           } else
  6707.             p = "0";
  6708.  
  6709.           if (argn > 1) {               /* Assign list to array */
  6710.               fnval[0] = NUL;           /* Initial return value */
  6711.               ckstrncpy(abuf,bp[1],16); /* Get array reference */
  6712.               s = abuf;
  6713.               if (*s == CMDQ) s++;
  6714.               failed = 1;               /* Assume it's bad */
  6715.               p = fnval;                /* Point to result */
  6716.               if (fndiags)              /* Default is this error message */
  6717.                 sprintf(fnval,"<ERROR:ARG_BAD_ARRAY:\\f%s()>",fn);
  6718.               if (s[0] != '&')          /* "Address" of array */
  6719.                 goto fnend;
  6720.               if (s[2])
  6721.                 if (s[2] != '[' || s[3] != ']')
  6722.                   goto fnend;
  6723.               if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */
  6724.                 s[1] += 32;
  6725.               if ((x = dclarray(s[1],k)) < 0) /* File list plus count */
  6726.                 goto fnend;
  6727.               failed = 0;               /* Unset failure flag */
  6728.               ap = a_ptr[x];            /* Point to array we just declared */
  6729.               sprintf(fnval,"%d",k);
  6730.           }
  6731. #ifdef OS2
  6732.           if (ap) {                     /* We are making an array */
  6733.               int i;
  6734.               char tmp[16];
  6735.               ap[0] = NULL;             /* Containing number of files    */
  6736.               makestr(&(ap[0]),ckitoa(k));
  6737.  
  6738.               ckstrncpy(tmp,fnval,16);  /* Save return value */
  6739.  
  6740.               for (i = 1; i <= k; i++) { /* Fill it */
  6741.                   ap[i] = NULL;
  6742.                   znext(fnval);         /* Next filename */
  6743.                   if (!*fnval)          /* No more, done */
  6744.                     break;              /* In case a premature end */
  6745.                   makestr(&(ap[i]),fnval);
  6746.               }
  6747. #ifdef ZXREWIND
  6748.               k = zxrewind();           /* Reset the file expansion */
  6749. #else
  6750.               k = nzxpand(bp[0],xflags);
  6751. #endif /* ZXREWIND */
  6752.               ckstrncpy(fnval,tmp,FNVALL); /* Restore return value */
  6753.           }
  6754. #else /* OS2 */
  6755.           {                             /* Make copies of the list */
  6756.               int i; char tmp[16];
  6757.               if (flist) {              /* Free old file list, if any */
  6758.                   for (i = 0; flist[i]; i++) { /* and each string */
  6759.                       free(flist[i]);
  6760.                       flist[i] = NULL;
  6761.                   }
  6762.                   free(flist);
  6763.               }
  6764.               ckstrncpy(tmp,fnval,16);  /* Save our return value */
  6765.               flist = (char **) malloc((k+1) * sizeof(char *)); /* New array */
  6766.               if (flist) {
  6767.                   for (i = 0; i <= k; i++) { /* Fill it */
  6768.                       flist[i] = NULL;
  6769.                       znext(fnval);     /* Next filename */
  6770.                       if (!*fnval)      /* No more, done */
  6771.                         break;
  6772.                       makestr(&(flist[i]),fnval);
  6773.                   }
  6774.                   if (ap) {             /* If array pointer given */
  6775.                       ap[0] = NULL;
  6776.                       makestr(&(ap[0]),ckitoa(k));
  6777.                       for (i = 0; i < k; i++) { /* Copy file list to array */
  6778.                           ap[i+1] = NULL;
  6779.                           makestr(&(ap[i+1]),flist[i]);
  6780.                       }
  6781.                   }
  6782.               }
  6783.               ckstrncpy(fnval,tmp,FNVALL); /* Restore return value */
  6784.               flistn = 0;               /* Reset global list pointer */
  6785.           }
  6786. #endif /* OS2 */
  6787. #ifdef RECURSIVE
  6788.           recursive = rsave;
  6789. #endif /* RECURSIVE */
  6790. #ifdef OS2
  6791.           zxpn = zsave;
  6792. #endif /* OS2 */
  6793.       }
  6794.       goto fnend;
  6795.  
  6796.       case FN_FIL:                      /* \fnextfile() - Next file in list. */
  6797.         p = fnval;                      /* (no args) */
  6798.         *p = NUL;
  6799. #ifdef OS2
  6800.         zxpn = 1;                       /* OS/2 - use the alternate list */
  6801.         znext(p);                       /* Call system-dependent function */
  6802.         zxpn = zsave;                   /* Restore original list */
  6803. #else
  6804.         if (flist)                      /* Others, use our own list. */
  6805.           if (flist[flistn])
  6806.             p = flist[flistn++];
  6807. #endif /* OS2 */
  6808.         goto fnend;
  6809.  
  6810.     } /* Break up big switch... */
  6811.  
  6812.     switch (y) {
  6813.       case FN_IND:                      /* \findex(s1,s2,start) */
  6814.       case FN_RIX:                      /* \frindex(s1,s2,start) */
  6815.       case FN_SEARCH:                   /* \fsearch(pat,string,start) */
  6816.       case FN_RSEARCH: {                /* \frsearch(pat,string,start) */
  6817.         int i = 0, right = 0, search = 0;
  6818.         right = (y == FN_RIX || y == FN_RSEARCH);
  6819.         search = (y == FN_SEARCH || y == FN_RSEARCH);
  6820.         p = "0";
  6821.         if (argn > 1) {                 /* Only works if we have 2 or 3 args */
  6822.             int start = 0;
  6823.             int mflag = 0;
  6824.             char * pat = NULL;
  6825.             len1 = (int)strlen(pat = bp[0]); /* length of string to look for */
  6826.             len2 = (int)strlen(s = bp[1]); /* length of string to look in */
  6827.             if (search) {               /* If pattern */
  6828.                 if (len1 == 0)          /* append "*" if not already there.. */
  6829.                   mflag++;
  6830.                 else if (pat[len1-1] != '*')
  6831.                   mflag++;
  6832.                 if (mflag) {
  6833.                     char * tmp;
  6834.                     tmp = malloc(len1+2);
  6835.                     if (tmp) {
  6836.                         sprintf(tmp,"%s*",pat);
  6837.                         pat = tmp;
  6838.                     } else
  6839.                       mflag = 0;
  6840.                 }
  6841.                 len1++;
  6842.             }
  6843.             if (len1 < 1 || len2 < 1)   /* Watch out for empty strings */
  6844.               goto fnend;
  6845.             start = right ? -1 : 0;     /* Default starting position */
  6846.             if (argn > 2) {
  6847.                 val1 = *(bp[2]) ? evalx(bp[2]) : "1";
  6848.                 if (chknum(val1)) {
  6849.                     int t;
  6850.                     t = atoi(val1);
  6851.                     if (!search) {      /* Index or Rindex */
  6852.                         j = len2 - len1; /* Length difference */
  6853.                         t--;            /* Convert position to 0-based */
  6854.                         if (t < 0) t = 0;
  6855.                         start = t;
  6856.                         if (!right && start < 0) start = 0;
  6857.                     } else {            /* Search or Rsearch */
  6858.                         int x;
  6859.                         if (t < 0) t = 0;
  6860.                         if (right) {    /* Right to left */
  6861.                             if (t > len2) t = len2;
  6862.                             start = len2 - t - 1;
  6863.                             if (start < 0) {
  6864.                                 if (mflag) if (pat) free(pat);
  6865.                                 goto fnend;
  6866.                             }
  6867.                             x = len2 - t;
  6868.                             s[x] = NUL;
  6869.                         } else {        /* Left to right */
  6870.                             start = t - 1;
  6871.                             if (start < 0) start = 0;
  6872.                             if (start >= len2) {
  6873.                                 if (mflag) if (pat) free(pat);
  6874.                                 goto fnend;
  6875.                             }
  6876.                         }
  6877.                     }
  6878.                 } else {
  6879.                     failed = 1;
  6880.                     if (fndiags) {
  6881.                         sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  6882.                         p = fnval;
  6883.                     }
  6884.                     if (mflag) if (pat) free(pat);
  6885.                     goto fnend;
  6886.                 }
  6887.             }
  6888.             if (search) {               /* \fsearch() or \frsearch() */
  6889.                 if (right) {
  6890.                     if (start < 0) start = len2 - 1;
  6891.                     for (i = start;
  6892.                          i >= 0 && !ckmatch(pat,s+i,inpcas[cmdlvl],1);
  6893.                          i--) ;
  6894.                     if (i < 0) i = 0; else i++;
  6895.                 } else {
  6896.                     for (i = start;
  6897.                          i < len2 && !ckmatch(pat,s+i,inpcas[cmdlvl],1);
  6898.                          i++) ;
  6899.                     if (i == len2) i = 0; else i++;
  6900.                 }
  6901.             } else {
  6902.                 i = ckindex(pat,bp[1],start,right,inpcas[cmdlvl]);
  6903.             }
  6904.             if (mflag) if (pat) free(pat);
  6905.             sprintf(fnval,"%d",i);
  6906.             p = fnval;
  6907.         }
  6908.         goto fnend;
  6909.       }
  6910.  
  6911.       case FN_RPL:                      /* \freplace(s1,s2,s3) */
  6912.       /*
  6913.         s = bp[0] = source string
  6914.             bp[1] = match string
  6915.             bp[2] = replacement string
  6916.         p = fnval = destination (result) string
  6917.       */
  6918.         if (argn < 1)                   /* Nothing */
  6919.           goto fnend;
  6920.         if (argn < 2) {                 /* Only works if we have 2 or 3 args */
  6921.             ckstrncpy(p,bp[0],FNVALL);
  6922.         } else {
  6923.             len1 = (int)strlen(bp[0]);  /* length of string to look in */
  6924.             len2 = (int)strlen(bp[1]);  /* length of string to look for */
  6925.             len3 = (argn < 3) ? 0 : (int)strlen(bp[2]); /* Len of replacemnt */
  6926.             j = len1 - len2 + 1;
  6927.             if (j < 1 || len1 == 0 || len2 == 0) { /* Args out of whack */
  6928.                 ckstrncpy(p,bp[0],FNVALL); /* so just return original string */
  6929.                 p[FNVALL] = NUL;
  6930.             } else {
  6931.                 s = bp[0];              /* Point to beginning of string */
  6932.                 while (j--) {           /* For each character */
  6933.                     if (!ckstrcmp(bp[1],s,len2,inpcas[cmdlvl])) {
  6934.                         if (len3) {
  6935.                             strcpy(p,bp[2]);
  6936.                             p += len3;
  6937.                         }
  6938.                         s += len2;                  /* and skip past it. */
  6939.                     } else {            /* No, */
  6940.                         *p++ = *s++;    /* just copy this character */
  6941.                     }
  6942.                 }
  6943.                 *p = NUL;
  6944.                 while (*p++ = *s++);
  6945.             }
  6946.         }
  6947.         p = fnval;
  6948.         goto fnend;
  6949.  
  6950.       case FN_CHR:                      /* \fcharacter(arg1) */
  6951.         val1 = *(bp[0]) ? evalx(bp[0]) : "";
  6952.         if (chknum(val1)) {             /* Must be numeric */
  6953.             i = atoi(val1);
  6954.             if (i >= 0 && i < 256) {    /* Must be an 8-bit value */
  6955.                 p = fnval;
  6956.                 *p++ = (char) i;
  6957.                 *p = NUL;
  6958.                 p = fnval;
  6959.             } else {
  6960.                 failed = 1;
  6961.                 if (fndiags)
  6962.                   sprintf(fnval,"<ERROR:ARG_OUT_OF_RANGE:\\f%s()>",fn);
  6963.             }
  6964.         } else {
  6965.             failed = 1;
  6966.             if (fndiags)
  6967.               sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  6968.         }
  6969.         goto fnend;
  6970.  
  6971.       case FN_COD:                      /* \fcode(char) */
  6972.         if ((int)strlen(bp[0]) > 0) {
  6973.             p = fnval;
  6974.             i = *bp[0];
  6975.             sprintf(p,"%d",(i & 0xff));
  6976.         } else p = "";                  /* Can't happen */
  6977.         goto fnend;
  6978.  
  6979.       case FN_LEN:                      /* \flength(arg1) */
  6980.         if (argn > 0) {
  6981.             p = fnval;
  6982.             sprintf(p,"%d",(int)strlen(bp[0]));
  6983.         } else p = "0";
  6984.         goto fnend;
  6985.  
  6986.       case FN_LOW:                      /* \flower(arg1) */
  6987.         s = bp[0] ? bp[0] : "";
  6988.         p = fnval;
  6989.         while (*s) {
  6990.             if (isupper(*s))
  6991.               *p = (char) tolower(*s);
  6992.             else
  6993.               *p = *s;
  6994.             p++; s++;
  6995.         }
  6996.         *p = NUL;
  6997.         p = fnval;
  6998.         goto fnend;
  6999.  
  7000.       case FN_MAX:                      /* \fmax(arg1,arg2) */
  7001.       case FN_MIN:                      /* \fmin(arg1,arg2) */
  7002.       case FN_MOD:                      /* \fmod(arg1,arg2) */
  7003.         val1 = *(bp[0]) ? evalx(bp[0]) : "";
  7004.         free(bp[0]);                    /* Copy this because evalx() returns */
  7005.         bp[0] = NULL;                   /* Set it to NULL in case argn == 1 */
  7006.         if (argn > 1) {                 /* pointer to same */
  7007.             bp[0] = malloc((int)strlen(val1)+1); /* buffer next time. */
  7008.             strcpy(bp[0],val1);
  7009.             val1 = bp[0];
  7010.             val2 = *(bp[1]) ? evalx(bp[1]) : "";
  7011.             if (chknum(val1) && chknum(val2)) {
  7012.                 i = atoi(val1);
  7013.                 j = atoi(val2);
  7014.                 switch (y) {
  7015.                   case FN_MAX:
  7016.                     if (j < i) j = i;
  7017.                     break;
  7018.                   case FN_MIN:
  7019.                     if (j > i) j = i;
  7020.                     break;
  7021.                   case FN_MOD:
  7022.                     if (j == 0) {
  7023.                         failed = 1;
  7024.                         if (fndiags)
  7025.                           sprintf(fnval,"<ERROR:DIVIDE_BY_ZERO:\\f%s()>",fn);
  7026.                         else
  7027.                           fnval[0] = NUL;
  7028.                         goto fnend;
  7029.                     } else
  7030.                       j = i % j;
  7031.                 }
  7032.                 p = fnval;
  7033.                 sprintf(p,"%d",j);
  7034.             } else {
  7035.                 failed = 1;
  7036.                 if (fndiags)
  7037.                   sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  7038.             }
  7039.         } else p = val1;
  7040.         goto fnend;
  7041.     } /* Break up big switch... */
  7042.  
  7043.     switch (y) {
  7044.       case FN_SUB:                      /* \fsubstr(arg1,arg2,arg3) */
  7045.       case FN_RIG:                      /* \fright(arg1,arg2) */
  7046.       case FN_LEF:                      /* \fleft(arg1,arg2) */
  7047.         if (argn < 1)
  7048.           goto fnend;
  7049.         val1 = "";
  7050.         if (argn > 1)
  7051.           if (*(bp[1]))
  7052.             val1 =  evalx(bp[1]);
  7053.         if (bp[1]) free(bp[1]);         /* Have to copy this */
  7054.         bp[1] = malloc((int)strlen(val1)+1);
  7055.         if (!bp[1]) {
  7056.             failed = 1;
  7057.             if (fndiags)
  7058.               sprintf((p = fnval),"<ERROR:MALLOC:\\f%s()>",fn);
  7059.             goto fnend;
  7060.         }
  7061.         strcpy(bp[1],val1);
  7062.         val1 = bp[1];
  7063.         val2 = "";
  7064.         if (argn > 2)
  7065.           if (*(bp[2]))
  7066.             val2 = evalx(bp[2]);
  7067.         if (
  7068.             ((argn > 1) && (int)strlen(val1) && !rdigits(val1)) ||
  7069.             ((y == FN_SUB) &&
  7070.               ((argn > 2) && (int)strlen(val2) && !rdigits(val2)))
  7071.             ) {
  7072.             failed = 1;
  7073.             if (fndiags)
  7074.               sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  7075.         } else {
  7076.             int lx;
  7077.             p = fnval;                  /* pointer to result */
  7078.             lx = strlen(bp[0]);         /* length of arg1 */
  7079.             if (y == FN_SUB) {          /* substring */
  7080.                 k = (argn > 2) ? atoi(val2) : MAXARGLEN; /* length */
  7081.                 j = (argn > 1) ? atoi(val1) : 1; /* start pos for substr */
  7082.             } else if (y == FN_LEF) {   /* left */
  7083.                 k = (argn > 1) ? atoi(val1) : lx;
  7084.                 j = 1;
  7085.             } else {                             /* right */
  7086.                 k = (argn > 1) ? atoi(val1) : lx; /* length */
  7087.                 j = lx - k + 1;                  /* start pos for right */
  7088.                 if (j < 1) j = 1;
  7089.             }
  7090.             if (k > 0 && j <= lx) {              /* if start pos in range */
  7091.                 s = bp[0]+j-1;                   /* point to source string */
  7092.                 for (i = 0; (i < k) && (*p++ = *s++); i++) ;  /* copy */
  7093.             }
  7094.             *p = NUL;                   /* terminate the result */
  7095.             p = fnval;                  /* and point to it. */
  7096.         }
  7097.         goto fnend;
  7098.  
  7099.       case FN_UPP:                      /* \fupper(arg1) */
  7100.         s = bp[0] ? bp[0] : "";
  7101.         p = fnval;
  7102.         while (*s) {
  7103.             if (islower(*s))
  7104.               *p = (char) toupper(*s);
  7105.             else
  7106.               *p = *s;
  7107.             p++; s++;
  7108.         }
  7109.         *p = NUL;
  7110.         p = fnval;
  7111.         goto fnend;
  7112.  
  7113.       case FN_REP:                      /* \frepeat(text,number) */
  7114.         if (argn < 1)
  7115.           goto fnend;
  7116.         val1 = "1";
  7117.         if (argn > 1)
  7118.           if (*(bp[1]))
  7119.             val1 = evalx(bp[1]);
  7120.         if (chknum(val1)) {             /* Repeat count */
  7121.             n = atoi(val1);
  7122.             debug(F111,"SUNDAY frepeat n",val1,n);
  7123.             if (n > 0) {                /* Make n copies */
  7124.                 p = fnval;
  7125.                 *p = '\0';
  7126.                 k = (int)strlen(bp[0]); /* Make sure string has some length */
  7127.                 debug(F111,"SUNDAY frepeat k","",k);
  7128.                 debug(F111,"SUNDAY frepeat FNVALL","",FNVALL);
  7129.                 if (k * n >= FNVALL) {  /* But not too much... */
  7130.                     failed = 1;
  7131.                     if (fndiags)
  7132.                       sprintf(fnval,"<ERROR:RESULT_TOO_LONG:\\f%s()>",fn);
  7133.                     else
  7134.                       fnval[0] = NUL;
  7135.                     p = fnval;
  7136.                     goto fnend;
  7137.                 }
  7138.                 if (k > 0) {            /* If there is something to copy */
  7139.                     for (i = 0; i < n; i++) { /* Copy loop */
  7140.                         s = bp[0];
  7141.                         for (j = 0; j < k; j++) {
  7142.                             if ((p - fnval) >= FNVALL)
  7143.                               break;    /* shouldn't happen... */
  7144.                             else
  7145.                               *p++ = *s++;
  7146.                         }
  7147.                     }
  7148.                     *p = NUL;
  7149.                 }
  7150.             }
  7151.         } else {
  7152.             failed = 1;
  7153.             if (fndiags)
  7154.               sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  7155.         }
  7156.         p = fnval;
  7157.         goto fnend;
  7158.  
  7159. #ifndef NOFRILLS
  7160.       case FN_REV:                      /* \freverse() */
  7161.         if (argn < 1)
  7162.           goto fnend;
  7163.         yystring(bp[0],&p);
  7164.         goto fnend;
  7165. #endif /* NOFRILLS */
  7166.  
  7167.       case FN_RPA:                      /* \frpad() and \flpad() */
  7168.       case FN_LPA:
  7169.         if (argn < 1)
  7170.           goto fnend;
  7171.         val1 = "";
  7172.         if (argn > 1)
  7173.           if (*(bp[1]))
  7174.             val1 = evalx(bp[1]);
  7175.         if (argn == 1 || !*val1) {      /* If a number wasn't given */
  7176.             p = fnval;                  /* just return the original string */
  7177.             ckstrncpy(p,bp[0],FNVALL);
  7178.         } else if (chknum(val1)) {      /* Repeat count */
  7179.             char pc;
  7180.             n = atoi(val1);
  7181.             if (n >= 0) {
  7182.                 p = fnval;
  7183.                 k = (int)strlen(bp[0]); /* Length of string to be padded */
  7184.                 if (k >= n) {           /* It's already long enough */
  7185.                     ckstrncpy(p,bp[0],FNVALL);
  7186.                 } else {
  7187.                     if (n + k <= FNVALL) {
  7188.                         pc = (char) ((argn < 3) ? SP : *bp[2]);
  7189.                         if (!pc) pc = SP;
  7190.                         if (y == FN_RPA) { /* RPAD */
  7191.                             strncpy(p,bp[0],k); /* (leave it like this) */
  7192.                             p[k] = NUL;
  7193.                             p += k;
  7194.                             for (i = k; i < n; i++)
  7195.                               *p++ = pc;
  7196.                         } else {        /* LPAD */
  7197.                             n -= k;
  7198.                             for (i = 0; i < n; i++)
  7199.                               *p++ = pc;
  7200.                             strncpy(p,bp[0],k); /* (leave it like this) */
  7201.                             p[k] = NUL;
  7202.                             p += k;
  7203.                         }
  7204.                     }
  7205.                     *p = NUL;
  7206.                 }
  7207.             }
  7208.         } else {
  7209.             failed = 1;
  7210.             if (fndiags)
  7211.               sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  7212.         }
  7213.         p = fnval;
  7214.         goto fnend;
  7215.  
  7216. #ifdef ZFCDAT
  7217.       case FN_FD:                       /* \fdate(filename) */
  7218.         p = fnval;
  7219.         s = zfcdat(bp[0]);
  7220.         if (!s) s = "";
  7221.         if (!*s) {
  7222.             failed = 1;
  7223.             if (fndiags)
  7224.               sprintf(fnval,"<ERROR:FILE_NOT_FOUND:\\f%s()>",fn);
  7225.             goto fnend;
  7226.         }
  7227.         ckstrncpy(fnval,s,FNVALL);
  7228. #endif /* ZFCDAT */
  7229.         goto fnend;
  7230.  
  7231.     } /* Break up big switch... */
  7232.  
  7233.     switch (y) {
  7234.       case FN_FS:                       /* \fsize(filename) */
  7235.         p = fnval;
  7236.         z = zchki(bp[0]);
  7237.         if (z < 0) {
  7238.             failed = 1;
  7239.             if (fndiags) {
  7240.                 if (z == -1)
  7241.                   sprintf(fnval,"<ERROR:FILE_NOT_FOUND:\\f%s()>",fn);
  7242.                 else if (z == -2)
  7243.                   sprintf(fnval,"<ERROR:FILE_NOT_READABLE:\\f%s()>",fn);
  7244.                 else if (z == -3)
  7245.                   sprintf(fnval,"<ERROR:FILE_NOT_ACCESSIBLE:\\f%s()>",fn);
  7246.                 else
  7247.                   sprintf(fnval,"<ERROR:FILE_ERROR:\\f%s()>",fn);
  7248.             }
  7249.             goto fnend;
  7250.         }
  7251.         sprintf(fnval,"%ld",z);
  7252.         goto fnend;
  7253.  
  7254.       case FN_VER:                      /* \fverify() */
  7255.         p = "0";
  7256.         if (argn > 1) {                 /* Only works if we have 2 or 3 args */
  7257.             int start;
  7258.             char *s2, ch1, ch2;
  7259.             start = 0;
  7260.             if (argn > 2) {             /* Starting position specified */
  7261.                 val1 = *(bp[2]) ? evalx(bp[2]) : "0";
  7262.                 if (chknum(val1)) {
  7263.                     start = atoi(val1) /* - 1 */;
  7264.                     if (start < 0) start = 0;
  7265.                     if (start > (int)strlen(bp[1]))
  7266.                       goto verfin;
  7267.                 } else {
  7268.                     failed = 1;
  7269.                     if (fndiags)
  7270.                       sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  7271.                     goto fnend;
  7272.                 }
  7273.             }
  7274.             i = start;
  7275.             p = "0";
  7276.             for (s = bp[1] + start; *s; s++,i++) {
  7277.                 ch1 = *s;
  7278.                 if (!inpcas[cmdlvl]) if (islower(ch1)) ch1 = toupper(ch1);
  7279.                 j = 0;
  7280.                 for (s2 = bp[0]; *s2; s2++) {
  7281.                     ch2 = *s2;
  7282.                     if (!inpcas[cmdlvl]) if (islower(ch2)) ch2 = toupper(ch2);
  7283.                     if (ch1 == ch2) {
  7284.                         j = 1;
  7285.                         break;
  7286.                     }
  7287.                 }
  7288.                 if (j == 0) {
  7289.                     sprintf(fnval,"%d",i+1);
  7290.                     p = fnval;
  7291.                     break;
  7292.                 }
  7293.             }
  7294.         }
  7295.       verfin:
  7296.         goto fnend;
  7297.  
  7298.       case FN_IPA:                      /* Find and return IP address */
  7299.         if (argn > 0) {                 /* in argument string. */
  7300.             int start;
  7301.             char *s2;
  7302.             start = 0;
  7303.             if (argn > 1) {             /* Starting position specified */
  7304.                 if (chknum(bp[1])) {
  7305.                     start = atoi(bp[1]) - 1;
  7306.                     if (start < 0) start = 0;
  7307.                 } else {
  7308.                     failed = 1;
  7309.                     if (fndiags)
  7310.                       sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  7311.                     goto fnend;
  7312.                 }
  7313.             }
  7314.             p = getip(bp[0]+start);
  7315.         } else p = "";
  7316.         goto fnend;
  7317.  
  7318. #ifdef OS2
  7319.       case FN_CRY:
  7320.         p = "";
  7321.         if (argn > 0) {
  7322.             p = fnval;
  7323.             ckstrncpy(p,bp[0],FNVALL);
  7324.             ck_encrypt(p);
  7325.         }
  7326.         goto fnend;
  7327.  
  7328.       case FN_OOX:
  7329.         p = "";
  7330.         if (argn > 0)
  7331.           p = (char *) ck_oox(bp[0], (argn > 1) ? bp[1] : "");
  7332.         goto fnend;
  7333. #endif /* OS2 */
  7334.  
  7335.       case FN_HEX:                      /* \fhexify(arg1) */
  7336.         if (argn < 1)
  7337.           goto fnend;
  7338.         if ((int)strlen(bp[0]) < (FNVALL / 2)) {
  7339.             s = bp[0];
  7340.             p = fnval;
  7341.             while (*s) {
  7342.                 x = (*s >> 4) & 0x0f;
  7343.                 *p++ = hexdigits[x];
  7344.                 x = *s++ & 0x0f;
  7345.                 *p++ = hexdigits[x];
  7346.             }
  7347.             *p = NUL;
  7348.             p = fnval;
  7349.         }
  7350.         goto fnend;
  7351.  
  7352.       case FN_UNH: {                    /* \funhex(arg1) */
  7353.           int c[2], i;
  7354.           if (argn < 1)
  7355.             goto fnend;
  7356.           if ((int)strlen(bp[0]) < (FNVALL * 2)) {
  7357.               s = bp[0];
  7358.               p = fnval;
  7359.               while (*s) {
  7360.                   for (i = 0; i < 2; i++) {
  7361.                       c[i] = *s++;
  7362.                       if (!c[i]) { p = ""; goto unhexfin; }
  7363.                       if (islower(c[i])) c[i] = toupper(c[i]);
  7364.                       if (c[i] >= '0' && c[i] <= '9') {
  7365.                           c[i] -= 0x30;
  7366.                       } else if (c[i] >= 'A' && c[i] <= 'F') {
  7367.                           c[i] -= 0x37;
  7368.                       } else {
  7369.                           failed = 1;
  7370.                           if (fndiags)
  7371.                             sprintf(fnval,
  7372.                                     "<ERROR:ARG_OUT_OF_RANGE:\\f%s()>",
  7373.                                     fn
  7374.                                     );
  7375.                           goto fnend;
  7376.                       }
  7377.                   }
  7378.                   *p++ = ((c[0] << 4) & 0xf0) | (c[1] & 0x0f);
  7379.               }
  7380.               *p = NUL;
  7381.               p = fnval;
  7382.           }
  7383.         unhexfin:
  7384.           goto fnend;
  7385.       }
  7386.  
  7387.       case FN_BRK: {                    /* \fbreak() */
  7388.           char * c;                     /* Characters to break on */
  7389.           char c2, s2;
  7390.           int start = 0;
  7391.           int done = 0;
  7392.           if (argn < 1)
  7393.             goto fnend;
  7394.           if (argn > 2) {
  7395.               s = bp[2] ? bp[2] : "0";
  7396.               if (chknum(s)) {
  7397.                   start = atoi(s);
  7398.                   if (start < 0) start = 0;
  7399.                   if (start > (int)strlen(bp[0]))
  7400.                     goto brkfin;
  7401.               } else {
  7402.                   failed = 1;
  7403.                   if (fndiags)
  7404.                     sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  7405.                   goto fnend;
  7406.               }
  7407.           }
  7408.           s = bp[0] + start;            /* Source pointer */
  7409.  
  7410.           while (*s && !done) {
  7411.               s2 = *s;
  7412.               if (!inpcas[cmdlvl] && islower(s2)) s2 = toupper(s2);
  7413.               c = bp[1] ? bp[1] : "";   /* Character to break on */
  7414.               while (*c) {
  7415.                   c2 = *c;
  7416.                   if (!inpcas[cmdlvl] && islower(c2)) c2 = toupper(c2);
  7417.                   if (c2 == s2) {
  7418.                       done = 1;
  7419.                       break;
  7420.                   }
  7421.                   c++;
  7422.               }
  7423.               if (done) break;
  7424.               *p++ = *s++;
  7425.           }
  7426.           *p = NUL;                     /* terminate the result */
  7427.           p = fnval;                    /* and point to it. */
  7428.         brkfin:
  7429.           goto fnend;
  7430.       }
  7431.  
  7432.       case FN_SPN: {                    /* \fspan() */
  7433.           char *q;
  7434.           char c1, c2;
  7435.           int start = 0;
  7436.           if (argn < 1)
  7437.             goto fnend;
  7438.           if (argn > 2) {               /* Starting position */
  7439.               s = bp[2] ? bp[2] : "0";
  7440.               if (chknum(s)) {
  7441.                   start = atoi(s);
  7442.                   if (start < 0) start = 0;
  7443.               } else {
  7444.                   failed = 1;
  7445.                   if (fndiags)
  7446.                     sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  7447.                   goto fnend;
  7448.               }
  7449.           }
  7450.           s = bp[0] + start;            /* Source pointer */
  7451.           if (argn > 1 &&
  7452.               (int)strlen(bp[1]) > 0 &&
  7453.               start <= (int)strlen(bp[0])) {
  7454.               while (*s) {              /* Loop thru source string */
  7455.                   q = bp[1];            /* Span string */
  7456.                   c1 = *s;
  7457.                   if (!inpcas[cmdlvl])
  7458.                     if (islower(c1)) c1 = toupper(c1);
  7459.                   x = 0;
  7460.                   while (c2 = *q++) {
  7461.                       if (!inpcas[cmdlvl])
  7462.                         if (islower(c2)) c2 = toupper(c2);
  7463.                       if (c1 == c2) { x = 1; break; }
  7464.                   }
  7465.                   if (!x) break;
  7466.                   *p++ = *s++;
  7467.               }
  7468.               *p = NUL;                 /* Terminate and return the result */
  7469.               p = fnval;
  7470.           }
  7471.           goto fnend;
  7472.       }
  7473.     } /* Break up big switch... */
  7474.  
  7475.     switch (y) {
  7476.       case FN_TRM:                      /* \ftrim(s1[,s2]) */
  7477.       case FN_LTR:                      /* \fltrim(s1[,s2]) */
  7478.         if (argn < 1)
  7479.           goto fnend;
  7480.         if ((len1 = (int)strlen(bp[0])) > 0) {
  7481.             if (len1 > FNVALL)
  7482.               len1 = FNVALL;
  7483.             s = " \t";
  7484.             if (argn > 1)               /* Trim list given */
  7485.               s = bp[1];
  7486.             len2 = (int)strlen(s);
  7487.             if (len2 < 1) {             /* or not... */
  7488.                 s = " \t";              /* Default is to trim whitespace */
  7489.                 len2 = 2;
  7490.             }
  7491.             if (y == FN_TRM) {          /* Trim from right */
  7492.                 char * q, p2, q2;
  7493.                 ckstrncpy(fnval,bp[0],FNVALL); /* Copy string to output */
  7494.                 p = fnval + len1 - 1;   /* Point to last character */
  7495.  
  7496.                 while (p >= (char *)fnval) { /* Go backwards */
  7497.                     q = s;              /* Point to trim list */
  7498.                     p2 = *p;
  7499.                     if (!inpcas[cmdlvl])
  7500.                       if (islower(p2)) p2 = toupper(p2);
  7501.                     while (*q) {        /* Is this char in trim list? */
  7502.                         q2 = *q;
  7503.                         if (!inpcas[cmdlvl])
  7504.                           if (islower(q2)) q2 = toupper(q2);
  7505.                         if (p2 == q2) { /* Yes, null it out */
  7506.                             *p = NUL;
  7507.                             break;
  7508.                         }
  7509.                         q++;
  7510.                     }
  7511.                     if (!*q)            /* Trim list exhausted */
  7512.                       break;            /* So we're done. */
  7513.                     p--;                /* Else keep trimming */
  7514.                 }
  7515.             } else {                    /* Trim from left */
  7516.                 char * q, p2, q2;
  7517.                 p = bp[0];              /* Source */
  7518.                 while (*p) {
  7519.                     p2 = *p;
  7520.                     if (!inpcas[cmdlvl])
  7521.                       if (islower(p2)) p2 = toupper(p2);
  7522.                     q = s;
  7523.                     while (*q) {        /* Is this char in trim list? */
  7524.                         q2 = *q;
  7525.                         if (!inpcas[cmdlvl])
  7526.                           if (islower(q2)) q2 = toupper(q2);
  7527.                         if (p2 == q2) { /* Yes, point past it */
  7528.                             p++;        /* and try next source character */
  7529.                             break;
  7530.                         }
  7531.                         q++;            /* No, try next trim character */
  7532.                     }
  7533.                     if (!*q)            /* Trim list exhausted */
  7534.                       break;            /* So we're done. */
  7535.                 }
  7536.                 ckstrncpy(fnval,p,FNVALL);
  7537.             }
  7538.             p = fnval;
  7539.         } else p = "";
  7540.         goto fnend;
  7541.  
  7542.       case FN_CAP:                      /* \fcapitalize(arg1) */
  7543.         if (argn < 1)
  7544.           goto fnend;
  7545.         s = bp[0];
  7546.         p = fnval;
  7547.         x = 0;
  7548.         while (c = *s++) {
  7549.             if (isalpha(c)) {
  7550.                 if (x == 0) {
  7551.                     x = 1;
  7552.                     if (islower(c))
  7553.                       c = toupper(c);
  7554.                 } else if (isupper(c))
  7555.                   c = tolower(c);
  7556.             }
  7557.             *p++ = c;
  7558.         }
  7559.         *p = NUL;
  7560.         p = fnval;
  7561.         goto fnend;
  7562.  
  7563. #ifdef COMMENT
  7564.       case FN_TOD:                      /* Time of day to secs since midnite */
  7565.         sprintf(fnval,"%ld",tod2sec(bp[0]));
  7566.         goto fnend;
  7567. #endif /* COMMENT */
  7568.  
  7569.       case FN_FFN:                      /* Full pathname of file */
  7570.         zfnqfp(bp[0],FNVALL,p);
  7571.         if (!p) p = "";
  7572.         goto fnend;
  7573.  
  7574.       case FN_CHK: {                    /* \fchecksum() */
  7575.           long chk = 0;
  7576.           p = (argn > 0) ? bp[0] : "";
  7577.           while (*p) chk += *p++;
  7578.           sprintf(fnval,"%lu",chk);
  7579.           p = fnval;
  7580.           goto fnend;
  7581.       }
  7582.  
  7583. #ifndef NOXFER
  7584.       case FN_CRC:                      /* \fcrc16() */
  7585.         if (argn > 0)
  7586.           sprintf(fnval,"%u",chk3((CHAR *)bp[0],(int)strlen(bp[0])));
  7587.         else
  7588.           p = "0";
  7589.         goto fnend;
  7590. #endif /* NOXFER */
  7591.  
  7592.       case FN_BSN:                      /* \fbasename() */
  7593.         zstrip(bp[0],&p);
  7594.         goto fnend;
  7595.  
  7596. #ifdef OS2
  7597.       case FN_SCRN_CX:                  /* \fscrncurx() */
  7598.         p = fnval;
  7599.         sprintf(p,"%d",(int)VscrnGetCurPos(VTERM)->x);
  7600.         goto fnend;
  7601.  
  7602.       case FN_SCRN_CY:                  /* \fscrncury() */
  7603.         p = fnval;
  7604.         sprintf(p,"%d",(int)VscrnGetCurPos(VTERM)->y);
  7605.         goto fnend;
  7606.  
  7607.       case FN_SCRN_STR: {               /* \fscrnstr() */
  7608.           videoline * line = NULL;
  7609.           viocell * cells = NULL;
  7610.           int row = 0, col = 0, len = 0;
  7611.           /* NOTE: On Unicode systems, the screen contents are stored in */
  7612.           /* in Unicode.  Therefore, we should really be performing a    */
  7613.           /* conversion to the local character set.                      */
  7614.  
  7615.           if (bp[0] == NULL || bp[0][0] == '\0') {
  7616.               row = 0;
  7617.           } else {
  7618.               if (chknum(bp[0])) {
  7619.                   row = atoi(bp[0]);
  7620.                   if (row < 0)
  7621.                     row = 0;
  7622.               } else {
  7623.                   failed = 1;
  7624.                   if (fndiags)
  7625.                     sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  7626.                   goto fnend;
  7627.               }
  7628.           }
  7629.           line = VscrnGetLineFromTop( VTERM, (USHORT) row );
  7630.           if (line != NULL) {
  7631.               if (bp[1] == NULL || bp[1][0] == '\0')
  7632.                 col = 0;
  7633.               else {
  7634.                   if (chknum(bp[0])) {
  7635.                       col = atoi(bp[1]);
  7636.                       if (col < 0 || col >= line->width)
  7637.                         col = 0;
  7638.                   } else {
  7639.                       failed = 1;
  7640.                       if (fndiags)
  7641.                         sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  7642.                       goto fnend;
  7643.                   }
  7644.               }
  7645.               if (bp[2] == NULL || bp[2][0] == '\0') {
  7646.                   len = line->width - (col+1);
  7647.               } else {
  7648.                   if (!chknum(bp[2])) {
  7649.                       failed = 1;
  7650.                       if (fndiags)
  7651.                         sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  7652.                       goto fnend;
  7653.                   }
  7654.                   len = atoi(bp[2]);
  7655.                   if (len < 0 || len > line->width)
  7656.                     len = line->width;
  7657.               }
  7658.               cells = line->cells;
  7659.               for (i = 0; i < len; i++) {
  7660.                   int pos = i + col;
  7661.                   if (pos < line->width) {
  7662.                       fnval[i] = (CHAR) (cells[pos].c & 0xFF);
  7663.                       if (fnval[i] == 0)
  7664.                         fnval[i] = SP;
  7665.                   } else
  7666.                     fnval[i] = SP;
  7667.               }
  7668.               fnval[i] = '\0';
  7669.           } else {
  7670.               fnval[0] = '\0';
  7671.           }
  7672.           p = fnval;
  7673.           goto fnend;
  7674.       }
  7675. #endif /* OS2 */
  7676.  
  7677. #ifndef NOPUSH
  7678.       case FN_RAW:                      /* \frawcommand() */
  7679.       case FN_CMD: {                    /* \fcommand() */
  7680.           int x, c, n = FNVALL;
  7681.           x = 0;                        /* Completion flag */
  7682. /*
  7683.   ZIFILE can be safely used because we can't possibly be transferring a file
  7684.   while executing this function.
  7685. */
  7686.           if (!nopush && zxcmd(ZIFILE,bp[0]) > 0) { /* Open the command */
  7687.               while (n-- > -1) {        /* Read from it */
  7688.                   if ((c = zminchar()) < 0) {
  7689.                       x = 1;             /* EOF - set completion flag */
  7690.                       if (y == FN_CMD) { /* If not "rawcommand" */
  7691.                           p--;           /* remove trailing newlines */
  7692.                           while (*p == CR || *p == LF)
  7693.                             p--;
  7694.                           p++;
  7695.                       }
  7696.                       *p = NUL;         /* Terminate the string */
  7697.                       break;
  7698.                   } else                /* Command still running */
  7699.                     *p++ = c;           /* Copy the bytes */
  7700.               }
  7701.               zclose(ZIFILE);           /* Close the command */
  7702.           }
  7703.           /* Return null string if command's output was too long. */
  7704.           p = fnval;
  7705.           if (!x) {
  7706.               failed = 1;
  7707.               if (fndiags)
  7708.                 sprintf(fnval,"<ERROR:RESULT_TOO_LONG:\\f%s()>",fn);
  7709.           }
  7710.           goto fnend;
  7711.       }
  7712. #endif /* NOPUSH */
  7713.     } /* Break up big switch... */
  7714.  
  7715.     switch (y) {
  7716.       case FN_STX:                      /* \fstripx(string,c) */
  7717.         if (!(s = bp[0]))               /* Make sure there is a string */
  7718.           goto fnend;
  7719.         c = '.';                        /* Character to strip from */
  7720.         if (argn > 1) if (*bp[1]) c = *bp[1];
  7721.         n = ckstrncpy(fnval,bp[0],FNVALL);
  7722.         while (--n >= 0) {
  7723.             if (fnval[n] == c) {
  7724.                 fnval[n] = NUL;
  7725.                 break;
  7726.             }
  7727.         }
  7728.         p = fnval;
  7729.         goto fnend;
  7730.  
  7731.       case FN_STL:                      /* \flop(string,c) */
  7732.         if (!(s = bp[0]))               /* Make sure there is a string */
  7733.           goto fnend;
  7734.         c = '.';                        /* Character to strip to */
  7735.         if (argn > 1) if (*bp[1]) c = *bp[1];
  7736.         x = 0;
  7737.         while (*s++) {
  7738.             if (*(s-1) == c) {
  7739.                 x = 1;
  7740.                 break;
  7741.             }
  7742.         }
  7743.         if (!x) s = bp[0];
  7744.         ckstrncpy(fnval,s,FNVALL);
  7745.         p = fnval;
  7746.         goto fnend;
  7747.  
  7748.       case FN_STN:                      /* \fstripn(string,n) */
  7749.         if (argn < 1)                   /* Remove n chars from right */
  7750.           goto fnend;
  7751.         val1 = "0";
  7752.         if (argn > 1)
  7753.           if (*(bp[1]))
  7754.             val1 = evalx(bp[1]);
  7755.         if (!chknum(val1)) {
  7756.             failed = 1;
  7757.             if (fndiags)
  7758.               sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  7759.             goto fnend;
  7760.         }
  7761.         n = atoi(val1);
  7762.         if (n < 0) n = 0;
  7763.         k = (int)strlen(s = bp[0]) - n;
  7764.         if (k < 0) k = 0;
  7765.         p = fnval;
  7766.         while (k-- > 0)
  7767.           *p++ = *s++;
  7768.         *p = NUL;
  7769.         p = fnval;
  7770.         goto fnend;
  7771.  
  7772.       case FN_STB: {                    /* \fstripb(string,c) */
  7773.           char c2 = NUL;
  7774.           p = fnval;
  7775.           *p = NUL;
  7776.           if (!(s = bp[0]))             /* Make sure there is a string */
  7777.             goto fnend;
  7778.           if ((x = strlen(s)) < 1)
  7779.             goto fnend;
  7780.           c = NUL;                      /* Brace/bracket kind */
  7781.           if (argn > 1) if (*bp[1]) c = *bp[1];
  7782.           if (!c) c = s[0];
  7783.           if (argn > 2) if (*bp[2]) c2 = *bp[2];
  7784.           if (*s == c) {
  7785.               if (!c2) {
  7786.                   switch (c) {
  7787.                     case '(': c2 = ')'; break;
  7788.                     case '[': c2 = ']'; break;
  7789.                     case '{': c2 = '}'; break;
  7790.                     case '<': c2 = '>'; break;
  7791.                     case '"': c2 = '"'; break;
  7792.                     case 39:  c2 = 39;  break;
  7793.                     case 96:  c2 = 39;  break;
  7794.                     default:
  7795.                       if (argn == 2) {
  7796.                           c2 = c;
  7797.                       } else {
  7798.                           strncpy(fnval,s,x); /* Leave it like this */
  7799.                           fnval[x] = NUL;
  7800.                           goto fnend;
  7801.                       }
  7802.                   }
  7803.               }
  7804.               if (s[x-1] == c2) {
  7805.                   strncpy(fnval,s+1,x-2); /* Leave it like this */
  7806.                   fnval[x-2] = NUL;
  7807.                   goto fnend;
  7808.               }
  7809.           }
  7810.           strncpy(fnval,s,x);
  7811.           fnval[x] = NUL;
  7812.           goto fnend;
  7813.       }
  7814.  
  7815.       case FN_2HEX:                     /* Number to hex */
  7816.       case FN_2OCT:                     /* Number to octal */
  7817.         if (!rdigits(bp[0])) {
  7818.             failed = 1;
  7819.             if (fndiags)
  7820.               sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  7821.             goto fnend;
  7822.         }
  7823.         sprintf(fnval, y == FN_2HEX ? "%lx" : "%lo", atol(bp[0]));
  7824.         if (y == FN_2HEX && (int)(strlen(fnval)&1))
  7825.           sprintf(fnval,"0%lx",atol(bp[0]));
  7826.         p = fnval;
  7827.         goto fnend;
  7828.  
  7829.       case FN_DNAM: {                   /* Directory part of file name */
  7830.           char *s;
  7831.           zfnqfp(bp[0],FNVALL,p);       /* Get full name */
  7832.           if (!isdir(p)) {              /* Is it already a directory? */
  7833.               zstrip(p,&s);             /* No get basename */
  7834.               if (*s) {
  7835.                   x = ckindex(s,p,0,0,0); /* Pos of latter in former */
  7836.                   if (x > 0) p[x-1] = NUL;
  7837.               }
  7838.           }
  7839.           if (!p) p = "";
  7840.           goto fnend;
  7841.       }
  7842.  
  7843. #ifndef NORANDOM
  7844.       case FN_RAND:                     /* Random number */
  7845.         k = rand();
  7846.         x = 0;
  7847.         if (argn > 0) {
  7848.             if (!chknum(bp[0])) {
  7849.                 failed = 1;
  7850.                 if (fndiags)
  7851.                   sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  7852.                 goto fnend;
  7853.             }
  7854.             x = atoi(bp[0]);
  7855.         }
  7856.         sprintf(fnval,"%d", x > 0 ? k % x : (x == 0 ? 0 : (0 - (k % (-x)))));
  7857.         p = fnval;
  7858.         goto fnend;
  7859. #endif /* NORANDOM */
  7860.     } /* Break up big switch... */
  7861.  
  7862.     switch (y) {
  7863.       case FN_SPLIT:                    /* \fsplit(s1,a,s2,s3) */
  7864.       case FN_WORD: {                   /* \fword(s1,n,s2,s3) */
  7865.           int inword = 0;
  7866.           int wordnum = 0;
  7867.           int splitting = 0;
  7868.           int x, max = 0;
  7869.           int array = 0;
  7870.           int isdeclared = 0;
  7871.           char ** ap = NULL;
  7872.           char c = NUL;
  7873.           char * sep = "";
  7874.           char * notsep = "";
  7875.           char * bp0 = NULL;
  7876.           char * bp1 = NULL;
  7877.           char abuf[16];
  7878.           fnval[0] = NUL;               /* Initial return value */
  7879.           splitting = (y == FN_SPLIT);
  7880.  
  7881.           bp0 = bp[0];
  7882.           if (!bp0) bp0 = "";
  7883.           debug(F111,"fsplit bp[0]",bp0,argn);
  7884.           if (argn < 1 || !*bp0) {      /* Check args */
  7885.               strcpy(fnval,"0");        /* No string so no words; return "0" */
  7886.               debug(F100,"SPLIT A","",0);
  7887.               goto fnend;
  7888.           }
  7889.           bp1 = bp[1];
  7890.           if (!bp1) bp1 = "";
  7891.           debug(F110,"fsplit bp[1]",bp1,0);
  7892.  
  7893.           if (!splitting) {             /* \fword(): n = word number */
  7894.               val1 = "1";               /* Default is first word */
  7895.               if (argn > 1)             /* Word number supplied */
  7896.                 if (*bp1)
  7897.                   val1 = evalx(bp1);
  7898.               if (!chknum(val1)) {
  7899.                   failed = 1;
  7900.                   if (fndiags)
  7901.                     sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  7902.                   debug(F100,"SPLIT B","",0);
  7903.                   goto fnend;
  7904.               }
  7905.               n = atoi(val1);
  7906.           } else if (argn > 1 && *bp1) { /* \fsplit(): n = word count */
  7907.               ckstrncpy(abuf,bp1,16);   /* Get array reference */
  7908.               debug(F110,"fsplit abuf 1",abuf,0);
  7909.               failed = 1;               /* Assume it's bad */
  7910.               p = fnval;                /* Point to result */
  7911.               if (fndiags)              /* Default is this error message */
  7912.                 sprintf(fnval,"<ERROR:ARG_BAD_ARRAY:\\f%s()>",fn);
  7913.               if (abuf[0] != '&') {     /* "Address" of array */
  7914.                   debug(F100,"SPLIT C","",0);
  7915.                   goto fnend;           /* It's bad */
  7916.               }
  7917.               if (abuf[2]) {
  7918.                   if (abuf[2] != '[' || abuf[3] != ']') {
  7919.                       debug(F100,"SPLIT C","",0);
  7920.                       goto fnend;               /* Bad */
  7921.                   }
  7922.               }
  7923.               debug(F110,"fsplit abuf 2",abuf,0);
  7924.               if (abuf[1] > 64 && abuf[1] < 91) /* Convert upper to lower */
  7925.                 abuf[1] += 32;
  7926.               if (abuf[1] < 97 || abuf[1] > 122) { /* Check for a-z */
  7927.                   debug(F100,"SPLIT D","",0);
  7928.                   goto fnend;
  7929.               }
  7930.               debug(F110,"fsplit abuf 3",abuf,0);
  7931.               max = chkarray(abuf[1],1); /* Array is declared? */
  7932.               if (max > -1)
  7933.                 isdeclared = 1;
  7934.               array = 1;
  7935.               fnval[0] = NUL;           /* No error, erase message */
  7936.               failed = 0;               /* Unset failure flag */
  7937.               n = 0;                    /* Initialize the counter */
  7938.               c = abuf[1];              /* Remember array letter */
  7939.           }
  7940.           debug(F101,"fsplit argn","",argn);
  7941.           debug(F110,"fsplit bp[2]",bp[2],0);
  7942.           debug(F110,"fsplit bp[3]",bp[3],0);
  7943.           if (argn > 2)                 /* Have break set? */
  7944.             sep = bp[2];
  7945.           if (argn > 3)                 /* Have include set? */
  7946.             notsep = bp[3];
  7947.           if (!sep) sep = "";           /* Guard against null pointers */
  7948.           if (!notsep) notsep = "";
  7949.           if (splitting || n >= 0) {    /* Something to do? */
  7950.               if (!isdeclared) {        /* Array is not declared? */
  7951.                   max = CMDBL / 5;      /* Maximum size... */
  7952.                   if (array) {          /* Make a temporary copy... */
  7953.                       debug(F110,"fsplit declaring",abuf,0);
  7954.                       ap = (char **) malloc(max * sizeof(char **));
  7955.                       if (!ap) {
  7956.                           failed = 1;
  7957.                           if (fndiags)          /* Change message */
  7958.                             sprintf(fnval,"<ERROR:ARRAY_FAILURE:\\f%s()>",fn);
  7959.                           debug(F100,"SPLIT E","",0);
  7960.                           goto fnend;
  7961.                       }
  7962.                       debug(F110,"fsplit declared ok",abuf,0);
  7963.                   }
  7964.               }
  7965.               s = bp0;                  /* String to get word(s) from */
  7966.               p = "";                   /* Pointer to word */
  7967.               do {                      /* Loop through string */
  7968.                   if (*s < SP)          /* Current char */
  7969.                     x = 0;              /* x == 0 means "is separator" */
  7970.                   else if (*sep)        /* Break set given */
  7971.                     x = (ckstrchr(sep,*s) ? 0 : 1);
  7972.                   else                  /* Default break set */
  7973.                     x = (*s >= '0' && *s <= '9' ||
  7974.                          *s >= 'A' && *s <= 'Z' ||
  7975.                          *s >= 'a' && *s <= 'z');
  7976.                   if (x == 0 && *notsep && *s) /* Exception set */
  7977.                     x = (ckstrchr(notsep,*s) ? 1 : 0);
  7978.                   if (x) {
  7979.                       if (!inword) {    /* Character is not a separator */
  7980.                           wordnum++;
  7981.                           inword = 1;
  7982.                           p = s;
  7983.                       }
  7984.                   } else {              /* Character is a separator */
  7985.                       if (inword) {
  7986.                           inword = 0;
  7987.                           if (splitting) { /* \fsplit() */
  7988.                               if (*s)
  7989.                                 *s++ = NUL;
  7990.                               if (array) {
  7991.                                   if (wordnum > max) {
  7992. /* If too many words for array, stop successfully when array is full */
  7993. #ifdef COMMENT
  7994. /* Uncomment this section to fail if array is too small. */
  7995.                                       if (fndiags)
  7996.                                         sprintf(fnval,
  7997.                                                 "<ERROR:ARRAY_INDEX:\\f%s()>",
  7998.                                                 fn);
  7999.                                       p = fnval;
  8000.                                       failed = 1;
  8001.                                       debug(F100,"SPLIT F","",0);
  8002. #endif /* COMMENT */
  8003.                                       goto fnend;
  8004.                                   }
  8005.                                   if (isdeclared) {
  8006.                                       sprintf(abuf,"\\&%c[%d]",c,wordnum);
  8007.                                       addmac(abuf,p);
  8008.                                   } else {
  8009.                                       ap[wordnum] = NULL;
  8010.                                       makestr(&(ap[wordnum]),p);
  8011.                                   }
  8012.                               }
  8013.                               continue;
  8014.                           } else if (wordnum == n) { /* \fword() */
  8015.                               *s = NUL;
  8016.                               ckstrncpy(fnval,p,FNVALL);
  8017.                               p = fnval;
  8018.                               debug(F100,"SPLIT G","",0);
  8019.                               goto fnend;
  8020.                           } else
  8021.                             p = "";
  8022.                       }
  8023.                   }
  8024.                   if (*s)
  8025.                     s++;
  8026.               } while (*s || inword);   /* Do not quit while we are still */
  8027.                                         /* in a word.  Treat final NUL as */
  8028.                                         /* a separator.                   */
  8029.           }
  8030.           debug(F100,"fsplit do-loop done","",0);
  8031.           if (splitting) {
  8032.               sprintf(fnval,"%d",wordnum);
  8033.               if (array && !isdeclared) { /* Array was not declared. */
  8034.                   int i;
  8035.                   debug(F110,"fsplit declaring for real",abuf,0);
  8036.                   if ((x = dclarray(abuf[1],wordnum)) < 0) { /* Declare it. */
  8037.                       failed = 1;
  8038.                       debug(F100,"SPLIT H","",0);
  8039.                       goto fnend;
  8040.                   }
  8041.                   debug(F110,"fsplit declared OK",abuf,0);
  8042.                   debug(F111,"fsplit array x",abuf,x);
  8043.                   a_dim[x] = wordnum;
  8044.                   for (i = 1; i <= wordnum; i++) /* Copy pointers */
  8045.                     a_ptr[x][i] = ap[i];
  8046.                   debug(F110,"fsplit copy 1..n OK",abuf,0);
  8047.                   a_ptr[x][0] = NULL;
  8048.                   makestr(&(a_ptr[x][0]),fnval); /* Make element 0 */
  8049.                   debug(F110,"fsplit makestr 0 OK",abuf,0);
  8050.                   if (ap) free(ap);              /* Free temporary array */
  8051.                   debug(F110,"fsplit free OK",abuf,0);
  8052.               }
  8053.           }
  8054.           debug(F110,"SPLIT X",fnval,0);
  8055.           p = fnval;
  8056.           goto fnend;
  8057.       }
  8058.  
  8059.     } /* Break up big switch... */
  8060.  
  8061.     switch (y) {
  8062.  
  8063. #ifdef CK_KERBEROS
  8064.       case FN_KRB_TK:                   /* Kerberos tickets */
  8065.       case FN_KRB_NX:                   /* Kerberos next ticket */
  8066.       case FN_KRB_IV:                   /* Kerberos ticket is valid */
  8067.       case FN_KRB_FG:                   /* Kerberos Ticket flags */
  8068.       case FN_KRB_TT: {                 /* Kerberos ticket time */
  8069.           int kv = 0;                   /* Kerberos version */
  8070.           int n = 0;
  8071.           char * s = NULL;
  8072.           if (rdigits(bp[0])) {
  8073.               kv = atoi(bp[0]);
  8074.           } else {
  8075.               failed = 1;
  8076.               if (fndiags)
  8077.                 sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  8078.               goto fnend;
  8079.           }
  8080.           if (kv != 4 && kv != 5) {
  8081.               failed = 1;
  8082.               if (fndiags)
  8083.                 sprintf(fnval,"<ERROR:ARG_OUT_OF_RANGE:\\f%s()>",fn);
  8084.               goto fnend;
  8085.           }
  8086.           if ((y == FN_KRB_IV || y == FN_KRB_TT || y == FN_KRB_FG) &&
  8087.                argn < 2) {
  8088.               failed = 1;
  8089.               if (fndiags)
  8090.                 sprintf(fnval,"<ERROR:MISSING_ARG:\\f%s()>",fn);
  8091.               goto fnend;
  8092.           }
  8093.           switch (y) {
  8094.             case FN_KRB_TK:             /* Number of Kerberos tickets */
  8095. #ifdef CK_AUTHENTICATION
  8096.               switch (kv) {
  8097.                 case 4:
  8098.                   n = ck_krb4_get_tkts();
  8099.                   sprintf(fnval, "%d", (n >= 0) ? n : 0);
  8100.                   goto fnend;
  8101.                 case 5: {
  8102.                     extern char * krb5_d_cc;
  8103.                     n = ck_krb5_get_tkts(krb5_d_cc);
  8104.                     sprintf(fnval, "%d", (n >= 0) ? n : 0);
  8105.                     goto fnend;
  8106.                 }
  8107.               }
  8108. #else
  8109.               sprintf(fnval,"%d",0);    /* Some number, 0 or greater */
  8110. #endif /* CK_AUTHENTICATION */
  8111.               goto fnend;
  8112.  
  8113.             case FN_KRB_NX:             /* Kerberos next ticket */
  8114. #ifdef CK_AUTHENTICATION
  8115.               switch (kv) {
  8116.                 case 4:
  8117.                   s = ck_krb4_get_next_tkt();
  8118.                   sprintf(fnval, "%s", s ? s : "");
  8119.                   goto fnend;
  8120.                 case 5:
  8121.                   s = ck_krb5_get_next_tkt();
  8122.                   sprintf(fnval, "%s" , s ? s : "");
  8123.                   goto fnend;
  8124.               }
  8125. #else
  8126.               sprintf(fnval,"k%d next-ticket-string",kv); /* Some string */
  8127. #endif /* CK_AUTHENTICATION */
  8128.               goto fnend;
  8129.  
  8130.             case FN_KRB_IV:             /* Kerberos ticket is valid */
  8131. #ifdef CK_AUTHENTICATION
  8132.               /* Return 1 if valid, 0 if not */
  8133.               switch (kv) {
  8134.                 case 4:
  8135.                   n = ck_krb4_tkt_isvalid(bp[1]);
  8136.                   sprintf(fnval, "%d", n > 0 ? 1 : 0);
  8137.                   goto fnend;
  8138.                 case 5: {
  8139.                     extern char * krb5_d_cc;
  8140.                     n = ck_krb5_tkt_isvalid(krb5_d_cc,bp[1]);
  8141.                     sprintf(fnval,"%d", n > 0 ? 1 : 0);
  8142.                     goto fnend;
  8143.                 }
  8144.               }
  8145. #else
  8146.               sprintf(fnval,"%d",0);    /* Return 1 if valid, 0 if not */
  8147. #endif /* CK_AUTHENTICATION */
  8148.               goto fnend;
  8149.  
  8150.             case FN_KRB_TT:             /* Kerberos ticket time */
  8151. #ifdef CK_AUTHENTICATION
  8152.               switch (kv) {
  8153.                 case 4:
  8154.                   n = ck_krb4_tkt_time(bp[1]);
  8155.                   sprintf(fnval,"%d", n >= 0 ? n : 0);
  8156.                   goto fnend;
  8157.                 case 5: {
  8158.                     extern char * krb5_d_cc;
  8159.                     n = ck_krb5_tkt_time(krb5_d_cc,bp[1]);
  8160.                     sprintf(fnval,"%d", n >= 0 ? n : 0);
  8161.                     goto fnend;
  8162.                 }
  8163.               }
  8164. #else
  8165.               strcpy(fnval,"600");        /* Some time */
  8166. #endif /* CK_AUTHENTICATION */
  8167.               goto fnend;
  8168.  
  8169.             case FN_KRB_FG:             /* Kerberos ticket flags */
  8170. #ifdef CK_AUTHENTICATION
  8171.               switch (kv) {
  8172.                 case 4:
  8173.                   fnval[0] = '\0';
  8174.                   goto fnend;
  8175.                 case 5: {
  8176.                     extern char * krb5_d_cc;
  8177.                     ckstrncpy(fnval,ck_krb5_tkt_flags(krb5_d_cc,bp[1]),FNVALL);
  8178.                     goto fnend;
  8179.                 }
  8180.               }
  8181. #else
  8182.               fnval[0] = '\0';
  8183. #endif /* CK_AUTHENTICATION */
  8184.               goto fnend;
  8185.           }
  8186.           p = fnval;
  8187.           goto fnend;
  8188.       }
  8189. #endif /* CK_KERBEROS */
  8190.  
  8191. #ifdef FN_ERRMSG
  8192.       case FN_ERRMSG:
  8193.         if (rdigits(bp[0])) {
  8194.             k = atoi(bp[0]);
  8195.         } else {
  8196.             failed = 1;
  8197.             if (fndiags)
  8198.               sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  8199.             goto fnend;
  8200.         }
  8201. #ifdef VMS
  8202.         ckstrncpy(fnval,ckvmserrstr(k),FNVALL);
  8203. #else
  8204.         x = errno;
  8205.         errno = k;
  8206.         ckstrncpy(fnval,ck_errstr(),FNVALL);
  8207.         errno = x;
  8208. #endif /* VMS */
  8209.         p = fnval;
  8210.         goto fnend;
  8211. #endif /* FN_ERRMSG */
  8212.  
  8213.       case FN_DIM: {
  8214.           int x, max;
  8215.           char abuf[16], *s;
  8216.           fnval[0] = NUL;               /* Initial return value */
  8217.           ckstrncpy(abuf,bp[0],16);     /* Get array reference */
  8218.           s = abuf;
  8219.           if (*s == CMDQ) s++;
  8220.           failed = 1;                   /* Assume it's bad */
  8221.           p = fnval;                    /* Point to result */
  8222.           if (fndiags)                  /* Default is this error message */
  8223.             sprintf(fnval,"<ERROR:ARG_BAD_ARRAY:\\f%s()>",fn);
  8224.           if (s[0] != '&') {            /* "Address" of array */
  8225.               goto fnend;
  8226.           }
  8227.           if (s[2]) {
  8228.               if (s[2] != '[' || s[3] != ']') {
  8229.                   goto fnend;
  8230.               }
  8231.           }
  8232.           if (s[1] >= 64 && s[1] < 91)  /* Convert upper to lower */
  8233.             s[1] += 32;
  8234.           if (s[1] < 95 || s[1] > 122) { /* Check for a-z */
  8235.               goto fnend;                       /* Bad */
  8236.           }
  8237.           if ((max = chkarray(s[1],1)) < 1)
  8238.             max = 0;
  8239.           failed = 0;                   /* Unset failure flag */
  8240.           sprintf(fnval,"%d",max);
  8241.           goto fnend;
  8242.       }
  8243.  
  8244.     } /* Break up big switch... */
  8245.  
  8246.     switch (y) {
  8247.       case FN_JDATE:
  8248.         if (argn < 1)                   /* Check number of args */
  8249.           p = ckdate();                 /* None, get today's date-time */
  8250.         else                            /* Some */
  8251.           p = bp[0];                    /* Use first */
  8252.         p = ckcvtdate(p,0);             /* Convert to standard form */
  8253.         ckstrncpy(fnval,zjdate(p),FNVALL); /* Convert to Julian */
  8254.         p = fnval;                      /* Point to result */
  8255.         failed = 0;
  8256.         if (*p == '-') {
  8257.             failed = 1;
  8258.             if (fndiags)                /* Default is this error message */
  8259.               sprintf(fnval,"<ERROR:ARG_BAD_DATE:\\f%s()>",fn);
  8260.         }
  8261.         goto fnend;
  8262.  
  8263.       case FN_DATEJ:
  8264.         ckstrncpy(fnval,jzdate(bp[0]),FNVALL); /* Convert to yyyy<dayofyear> */
  8265.         p = fnval;                      /* Point to result */
  8266.         failed = 0;
  8267.         if (*p == '-') {
  8268.             failed = 1;
  8269.             if (fndiags)                /* Default is this error message */
  8270.               sprintf(fnval,"<ERROR:ARG_BAD_DATE:\\f%s()>",fn);
  8271.         }
  8272.         goto fnend;
  8273.  
  8274.       case FN_DTIM:                     /* \fcvtdate() */
  8275.       case FN_TIME:                     /* Free-format time to hh:mm:ss */
  8276.       case FN_NTIM:                     /* Free-format time to hh:mm:ss */
  8277.         if (argn < 1)                   /* Check number of args */
  8278.           p = ckdate();                 /* None, get today's date */
  8279.         else                            /* Some */
  8280.           p = bp[0];                    /* Use first */
  8281.         p = ckcvtdate(p,2);             /* Convert to standard form */
  8282.         if (*p == '<') {
  8283.             failed = 1;
  8284.             if (fndiags)                /* Default is this error message */
  8285.               sprintf(fnval,"<ERROR:ARG_BAD_DATE_OR_TIME:\\f%s()>",fn);
  8286.             p = fnval;
  8287.             goto fnend;
  8288.         } else if (y == FN_TIME) {
  8289.             p += 9;
  8290.         } else if (y == FN_NTIM) {
  8291.             long sec = 0L;
  8292.             p[11] = NUL;
  8293.             p[14] = NUL;
  8294.             sec = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
  8295.             sprintf(fnval,"%ld",sec);
  8296.             p = fnval;
  8297.         }
  8298.         goto fnend;
  8299.  
  8300.       case FN_MJD:                      /* Modified Julian Date */
  8301.         if (argn < 1)                   /* Check number of args */
  8302.           p = zzndate();                /* None, get today's date-time */
  8303.         else                            /* Some */
  8304.           p = bp[0];                    /* Use first */
  8305.         p = ckcvtdate(p,0);             /* Convert to standard form */
  8306.         if (*p == '-') {
  8307.             failed = 1;
  8308.             if (fndiags)                /* Default is this error message */
  8309.               sprintf(fnval,"<ERROR:ARG_BAD_DATE:\\f%s()>",fn);
  8310.             goto fnend;
  8311.         }
  8312.         sprintf(fnval,"%ld",mjd(p));    /* Convert to modified Julian date */
  8313.         p = fnval;                      /* Point to result */
  8314.         goto fnend;
  8315.  
  8316.       case FN_MJD2: {
  8317.           long k = 0L;
  8318.           int n = 0;
  8319.           p = evalx(bp[0]);
  8320.           if (*p == '-') {
  8321.               p++;
  8322.               n = 1;
  8323.           }
  8324.           if (!rdigits(p)) {
  8325.               failed = 1;
  8326.               if (fndiags)
  8327.                 sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  8328.               p = fnval;
  8329.               goto fnend;
  8330.           } else {
  8331.               k = atol(p);
  8332.               if (n) k = -k;
  8333.           }
  8334.           ckstrncpy(fnval,mjd2date(k),FNVALL); /* Convert to Date */
  8335.           p = fnval;                    /* Point to result */
  8336.           failed = 0;
  8337.           goto fnend;
  8338.       }
  8339.  
  8340. #ifndef NODIAL
  8341.       case FN_PNCVT: {                  /* Convert phone number */
  8342.           extern char * pncvt();
  8343.           failed = 0;
  8344.           p = pncvt(bp[0]);
  8345.           if (!p) p = "";
  8346.           if (!*p) {
  8347.             failed = 1;
  8348.             if (fndiags)                /* Default is this error message */
  8349.               sprintf(fnval,"<ERROR:ARG_BAD_PHONENUM:\\f%s()>",fn);
  8350.         }
  8351.         goto fnend;
  8352.       }
  8353. #endif /* NODIAL */
  8354.  
  8355.       case FN_DAY:
  8356.       case FN_NDAY:
  8357.         if (argn < 1)                   /* Check number of args */
  8358.           p = zzndate();                /* None, get today's date-time */
  8359.         else                            /* Some */
  8360.           p = bp[0];                    /* Use first */
  8361.         p = ckcvtdate(p,0);             /* Convert to standard form */
  8362.         if (*p == '-') {
  8363.             failed = 1;
  8364.             if (fndiags)                /* Default is this error message */
  8365.               sprintf(fnval,"<ERROR:ARG_BAD_DATE:\\f%s()>",fn);
  8366.             goto fnend;
  8367.         }
  8368.         failed = 0;
  8369.         z = mjd(p);                     /* Convert to modified Julian date */
  8370.         k = (((int)(z % 7L)) + 3) % 7;  /* Day of week */
  8371.         p = fnval;                      /* Point to result */
  8372.         if (y == FN_NDAY)
  8373.           sprintf(fnval,"%d",k);
  8374.         else
  8375.           ckstrncpy(fnval,wkdays[k],FNVALL);
  8376.         goto fnend;
  8377.  
  8378.       case FN_N2TIM: {                  /* Sec since midnight to hh:mm:ss */
  8379.           long k = 0L;
  8380.           int n = 0, hh, mm, ss;
  8381.           char * s = bp[0];
  8382.           if (argn < 1)                 /* If no arg substitute 0 */
  8383.             s = "0";
  8384.           p = evalx(s);                 /* Evaluate expression silently */
  8385.           if (*p == '-') {              /* Check result for minus sign */
  8386.               p++;
  8387.               n = 1;
  8388.           }
  8389.           if (!rdigits(p)) { /* Check for numeric */
  8390.               failed = 1;
  8391.               if (fndiags)
  8392.                 sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  8393.               p = fnval;
  8394.               goto fnend;
  8395.           } else {
  8396.               k = atol(p);
  8397.               if (n) k = -k;
  8398.           }
  8399.           if (k < 0) {                  /* Check for negative */
  8400.               failed = 1;
  8401.               if (fndiags)
  8402.                 sprintf(fnval,"<ERROR:ARG_OUT_OF_RANGE:\\f%s()>",fn);
  8403.               p = fnval;
  8404.               goto fnend;
  8405.           }
  8406.           hh = k / 3600L;               /* Have positive number */
  8407.           mm = (k % 3600L) / 60L;       /* break it down... */
  8408.           ss = ((k % 3600L) % 60L);
  8409.  
  8410.           sprintf(fnval,"%02d:%02d:%02d",hh,mm,ss);
  8411.           p = fnval;
  8412.           failed = 0;
  8413.           goto fnend;
  8414.       }
  8415.  
  8416.       case FN_PERM: {                   /* File permissions */
  8417.           p = fnval;
  8418.           z = zchki(bp[0]);
  8419.           if (z < 0) {
  8420.               failed = 1;
  8421.               if (fndiags) {
  8422.                   if (z == -1)
  8423.                     sprintf(fnval,"<ERROR:FILE_NOT_FOUND:\\f%s()>",fn);
  8424.                   else if (z == -2)
  8425.                     sprintf(fnval,"<ERROR:FILE_NOT_READABLE:\\f%s()>",fn);
  8426.                   else if (z == -3)
  8427.                     sprintf(fnval,"<ERROR:FILE_NOT_ACCESSIBLE:\\f%s()>",fn);
  8428.                   else
  8429.                     sprintf(fnval,"<ERROR:FILE_ERROR:\\f%s()>",fn);
  8430.               }
  8431.               goto fnend;
  8432.           }
  8433. #ifdef CK_PERMS
  8434.           ckstrncpy(fnval,ziperm(bp[0]),FNVALL);
  8435. #else
  8436.           ckstrncpy(fnval,"(unknown)",FNVALL);
  8437. #endif /* CK_PERMS */
  8438.           goto fnend;
  8439.       }
  8440.       case FN_TLOOK:
  8441.       case FN_ALOOK: {
  8442.           int i, x, hi, lo, max, cmdlen;
  8443.           char abuf[16], *s, *pat;
  8444.           char kwbuf[256];
  8445.           char delim = ':';
  8446.           failed = 1;                   /* Assume failure */
  8447.           strcpy(fnval,"-1");
  8448.           pat = bp[0];                  /* Point to search pattern */
  8449.           if (!pat) pat = "";
  8450.           cmdlen = strlen(pat);
  8451.           if (argn < 2 || cmdlen < 1) { /* Need two args */
  8452.               if (fndiags)
  8453.                 sprintf(fnval,"<ERROR:MISSING_ARG:\\f%s()>",fn);
  8454.               goto fnend;
  8455.           }
  8456.           ckstrncpy(abuf,bp[1],16);     /* Get array reference */
  8457.           if (argn > 2)
  8458.             delim = *(bp[2]);
  8459.           s = abuf;
  8460.           if ((x = arraybounds(s,&lo,&hi)) < 0) {  /* Get index and bounds */
  8461.               if (fndiags)
  8462.                 sprintf(fnval,"<ERROR:ARG_BAD_ARRAY:\\f%s()>",fn);
  8463.               goto fnend;
  8464.           }
  8465.           p = fnval;                    /* Point to result */
  8466.           max = a_dim[x];               /* Size of array */
  8467.           if (lo < 0) lo = 0;           /* Use given range if any */
  8468.           if (lo > max) lo = max;
  8469.           if (hi < 0) hi = max;
  8470.           if (hi > max) hi = max;
  8471.           failed = 0;                   /* Unset failure flag */
  8472.           if (max < 1)
  8473.             goto fnend;
  8474.           kwbuf[255] = NUL;
  8475.           for (i = lo; i <= hi; i++) {
  8476.               if (!a_ptr[x][i])
  8477.                 continue;
  8478.               if (y == FN_ALOOK) {
  8479.                   if (ckmatch(pat,a_ptr[x][i],inpcas[cmdlvl],1)) {
  8480.                       sprintf(fnval,"%d",i);
  8481.                       goto fnend;
  8482.                   }
  8483.               } else if (y == FN_TLOOK) {
  8484.                   char * aa;
  8485.                   int j = 0, v = 0, len;
  8486.                   if (i == hi)
  8487.                     break;
  8488.                   aa = a_ptr[x][i];     /* Point to this array element */
  8489.                   if (!aa) aa = "";
  8490.                   while (j < 254 && *aa) { /* Isolate keyword */
  8491.                       if (*aa == delim)
  8492.                         break;
  8493.                       kwbuf[j++] = *aa++;
  8494.                   }
  8495.                   kwbuf[j] = NUL;
  8496.                   len = j;
  8497.                   v = 0;
  8498.                   if ((len == cmdlen && !ckstrcmp(kwbuf,pat,len,0)) ||
  8499.                       ((v = !ckstrcmp(kwbuf,pat,cmdlen,0)) &&
  8500.                        ckstrcmp(a_ptr[x][i+1],pat,cmdlen,0))) {
  8501.                       sprintf(fnval,"%d",i);
  8502.                       goto fnend;
  8503.                   }
  8504.                   if (v) {              /* Ambiguous */
  8505.                       strcpy(fnval,"-2");
  8506.                       goto fnend;
  8507.                   }
  8508.               }
  8509.           }
  8510.           if (y == FN_TLOOK) {          /* tablelook() last element */
  8511.               strcpy(fnval,"-1");
  8512.               if (!ckstrcmp(a_ptr[x][hi],pat,cmdlen,0))
  8513.                 sprintf(fnval,"%d",hi);
  8514.           }
  8515.           goto fnend;
  8516.       }
  8517.       case FN_TOB64:                    /* Base-64 conversion */
  8518.       case FN_FMB64:
  8519.         p = fnval;
  8520.         *p = NUL;
  8521.         if (argn < 1)
  8522.           goto fnend;
  8523.         if (y == FN_TOB64) {
  8524.             x = b8tob64(bp[0],-1,fnval,FNVALL);
  8525.         } else {
  8526.             x = strlen(bp[0]);
  8527.             if (!(x % 4)) {
  8528.                 failed = 1;
  8529.                 sprintf(fnval,"<ERROR:ARG_INCOMPLETE:\\f%s()>",fn);
  8530.                 goto fnend;
  8531.             }
  8532.             b64tob8(NULL,0,NULL,0);     /* Reset */
  8533.             x = b64tob8(bp[0],-1,fnval,FNVALL);
  8534.             b64tob8(NULL,0,NULL,0);     /* Reset again */
  8535.         }
  8536.         if (x < 0) {
  8537.             failed = 1;
  8538.             if (fndiags) {
  8539.                 char * m = "INTERNAL_ERROR";
  8540.                 switch (x) {
  8541.                   case -1: m = "ARG_TOO_LONG"; break;
  8542.                   case -2: m = "ARG_OUT_OF_RANGE"; break;
  8543.                 }
  8544.                 sprintf(fnval,"<ERROR:%s:\\f%s()>",m,fn);
  8545.             }
  8546.         }
  8547.         goto fnend;
  8548.  
  8549.       case FN_ABS: {
  8550.           char * s;
  8551.           s = bp[0];
  8552.           if (*s == '-' || *s == '+')
  8553.             s++;
  8554.           if (!rdigits(s)) {
  8555.               if (fndiags)
  8556.                 sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  8557.               goto fnend;
  8558.           }
  8559.           ckstrncpy(fnval,s,FNVALL);
  8560.           goto fnend;
  8561.       }
  8562.  
  8563.       case FN_AADUMP: {
  8564.           char abuf[16], *s = NULL, **ap = NULL, **vp = NULL;
  8565.           char pattern[VNAML];
  8566.           int slen, i, j, k, first = -1;
  8567.           extern int xdelmac();
  8568.           p = fnval;
  8569.           if (argn < 2) {
  8570.               if (fndiags)
  8571.                 sprintf(fnval,"<ERROR:MISSING_ARG2:\\f%s()>",fn);
  8572.               goto fnend;
  8573.           }
  8574.           debug(F101,"aaconvert argn","",argn);
  8575.           s = bp[0];
  8576.           slen = strlen(s);
  8577.  
  8578.           /* Count elements so we can create the array */
  8579.  
  8580.           sprintf(pattern,"%s<*>",s);
  8581.           for (k = 0, i = 0; i < nmac; i++) {
  8582.               if (ckmatch(pattern,mactab[i].kwd,0,1)) {
  8583.                   if (first < 0)        /* Remember location of first match */
  8584.                     first = i;
  8585.                   k++;
  8586.               }
  8587.           }
  8588.           debug(F101,"aaconvert matches","",k);
  8589.           debug(F101,"aaconvert first","",first);
  8590.           fnval[0] = NUL;               /* Initial return value */
  8591.           ckstrncpy(abuf,bp[1],16);     /* Get array reference */
  8592.           s = abuf;
  8593.           if (*s == CMDQ) s++;
  8594.           p = fnval;                    /* Point to result */
  8595.           if (fndiags)                  /* Default is this error message */
  8596.             sprintf(fnval,"<ERROR:ARG_BAD_ARRAY:\\f%s()>",fn);
  8597.           if (s[0] != '&')              /* Address of array */
  8598.             goto fnend;
  8599.           if (s[2])
  8600.             if (s[2] != '[' || s[3] != ']')
  8601.               goto fnend;
  8602.           if (s[1] >= 64 && s[1] < 91)  /* Convert upper to lower */
  8603.             s[1] += 32;
  8604.           if ((x = dclarray(s[1],k)) < 0) /* Declare array to size */
  8605.             goto fnend;
  8606.           ap = a_ptr[x];                /* Point to array we just declared */
  8607.           debug(F111,"aaconvert array 1",abuf,ap);
  8608.           abuf[0] = NUL;
  8609.           if (argn > 2) {
  8610.               ckstrncpy(abuf,bp[2],16); /* Get value array reference */
  8611.               s = abuf;
  8612.               if (*s == CMDQ) s++;
  8613.               if (s[0] != '&')          /* Address of array */
  8614.                 goto fnend;
  8615.               if (s[2])
  8616.                 if (s[2] != '[' || s[3] != ']')
  8617.                   goto fnend;
  8618.               if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */
  8619.                 s[1] += 32;
  8620.               if ((x = dclarray(s[1],k)) < 0)
  8621.                 goto fnend;
  8622.               vp = a_ptr[x];            /* Point to array we just declared */
  8623.           }
  8624.           debug(F111,"aaconvert array 2",abuf,vp);
  8625.           makestr(&ap[0],ckitoa(k));
  8626.           if (vp) makestr(&vp[0],ckitoa(k));
  8627.           if (fndiags)
  8628.             sprintf(fnval,"<ERROR:ASSOCIATIVE_ARRAY:\\f%s()>",fn);
  8629.  
  8630.           /* Copy macro index & value to the arrays and then remove the */
  8631.           /* macro, so the 'first' pointer keeps indicating the next one. */
  8632.           /* We could combine the initial counting loop with this one but */
  8633.           /* then it would be harder to create the array and anyway this */
  8634.           /* function is plenty fast as it is. */
  8635.  
  8636.           for (i = 1; i <= k; ) {
  8637.               if (!ckmatch(pattern,mactab[first].kwd,0,1)) {
  8638.                   debug(F111,"aaconvert oddball",mactab[first].kwd,first);
  8639.                   first++;
  8640.                   continue;
  8641.               }
  8642.               ckstrncpy(tmpbuf,mactab[first].kwd,TMPBUFSIZ); /* Macro name */
  8643.               s = tmpbuf;                       /* Make writeable copy */
  8644.               s += slen;                        /* Isolate "index" */
  8645.               j = strlen(s) - 1;
  8646.               if (*s != '<' || *(s+j) != '>') { /* Check syntax */
  8647.                   /* This shouldn't happen */
  8648.                   debug(F111,"aaconvert ERROR",mactab[first].kwd,first);
  8649.                   goto fnend;
  8650.               }
  8651.               *(s+j) = NUL;             /* Remove final '>' */
  8652.               debug(F111,"aaconvert",s+1,i);
  8653.               makestr(&(ap[i]),s+1);    /* Set first array to index */
  8654.               if (vp)
  8655.                 makestr(&(vp[i]),mactab[first].mval); /* 2nd to value */
  8656.               if (xdelmac(first) < 0)
  8657.                 goto fnend;
  8658.               i++;
  8659.           }
  8660.           sprintf(fnval,"%d",k);        /* Return size of arrays */
  8661.           p = fnval;
  8662.           debug(F110,"aaconvert return",p,0);
  8663.           failed = 0;                   /* Unset failure flag */
  8664.           goto fnend;
  8665.       }
  8666.  
  8667.     } /* End of switch() */
  8668.  
  8669. #ifdef FNFLOAT
  8670. /*
  8671.   Floating-point functions.  To be included only if FNFLOAT is defined, which
  8672.   should happen only if CKFLOAT is also defined, and if the math library is
  8673.   linked in.  Even then, we might have float-vs-double confusion as well as
  8674.   confusion about what the final "%f" format effector is supposed to reference
  8675.   (32 bits, 64 bits, etc).  Expect trouble if CKFLOAT does not match the data
  8676.   type of math library functions or args.
  8677. */
  8678.     if (y == FN_FPABS ||                /* Floating-point functions */
  8679.         y == FN_FPADD ||
  8680.         y == FN_FPDIV ||
  8681.         y == FN_FPEXP ||
  8682.         y == FN_FPLOG ||
  8683.         y == FN_FPLN  ||
  8684.         y == FN_FPMOD ||
  8685.         y == FN_FPMAX ||
  8686.         y == FN_FPMIN ||
  8687.         y == FN_FPMUL ||
  8688.         y == FN_FPPOW ||
  8689.         y == FN_FPSQR ||
  8690.         y == FN_FPINT ||
  8691.         y == FN_FPSUB ||
  8692.         y == FN_FPROU ||
  8693.         y == FN_FPSIN ||
  8694.         y == FN_FPCOS ||
  8695.         y == FN_FPTAN) {
  8696.         CKFLOAT farg[2], fpresult = 0.0;
  8697.         char fpbuf[64], * bp0;
  8698.         double dummy;
  8699.         int sign = 0;
  8700.         int i, j, places = 0;
  8701.         int argcount = 1;
  8702.  
  8703.         failed = 1;
  8704.         p = fnval;
  8705.         bp0 = bp[0];
  8706.         if (!bp0)
  8707.           bp0 = "0";
  8708.         else if (!*bp0)
  8709.           bp0 = "0";
  8710.         if (!isfloat(bp0,0)) {
  8711.             if (fndiags)
  8712.               sprintf(fnval,"<ERROR:ARG_NOT_FLOAT:\\f%s()>",fn);
  8713.             goto fnend;
  8714.         }
  8715.         if (y == FN_FPINT) {            /* Float to int */
  8716.             failed = 0;
  8717.             ckstrncpy(fnval,bp0,FNVALL);
  8718.             for (i = 0; fnval[i]; i++) {
  8719.                 if (fnval[i] == '.') {
  8720.                     fnval[i] = NUL;
  8721.                     break;
  8722.                 }
  8723.             }
  8724.             goto fnend;
  8725.         }
  8726.         switch (y) {                    /* These need 2 args */
  8727.           case FN_FPADD:
  8728.           case FN_FPDIV:
  8729.           case FN_FPMOD:
  8730.           case FN_FPMAX:
  8731.           case FN_FPMIN:
  8732.           case FN_FPMUL:
  8733.           case FN_FPPOW:
  8734.           case FN_FPSUB:
  8735.             argcount = 2;
  8736.         }
  8737.         /* Missing arguments are supplied as 0.0 */
  8738.  
  8739.         debug(F111,fn,"argcount",argcount);
  8740.         for (i = 0; i < argcount; i++) { /* Get floating-point args */
  8741. #ifdef DEBUG
  8742.             if (deblog) {
  8743.                 sprintf(fpbuf,"bp[%d]=%s",i,bp[i] ? bp[i] : "(null)");
  8744.                 debug(F100,fpbuf,"",0);
  8745.             }
  8746. #endif /* DEBUG */
  8747.             if (!bp[i]) {
  8748.                 farg[i] = 0.0;
  8749.             } else if (!*(bp[i])) {
  8750.                 farg[i] = 0.0;
  8751.             } else if (!isfloat(bp[i],0)) {
  8752.                 if (fndiags)
  8753.                   sprintf(fnval,"<ERROR:ARG_NOT_FLOAT:\\f%s()>",fn);
  8754.                 goto fnend;
  8755.             } else {
  8756.                 farg[i] = floatval;
  8757.             }
  8758. #ifdef DEBUG
  8759.             if (deblog) {
  8760.                 sprintf(fpbuf,"farg[%d]=%f",i,farg[i]);
  8761.                 debug(F100,fpbuf,"",0);
  8762.             }
  8763. #endif /* DEBUG */
  8764.         }
  8765.         if (bp[argcount]) {             /* Get decimal places */
  8766.             char * s;
  8767.             s = bp[argcount];
  8768.             if (!s) s = "";
  8769.             if (!*s) s = "0";
  8770.             s = evalx(s);
  8771.             if (!chknum(s)) {
  8772.                 if (fndiags)
  8773.                   sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  8774.                 goto fnend;
  8775.             }
  8776.             places = atoi(s);
  8777.         }
  8778.         errno = 0;
  8779.         failed = 0;
  8780.         switch (y) {                    /* Now do the requested function */
  8781.           case FN_FPABS:                /* Floating-point absolute value */
  8782. #ifndef COMMENT
  8783.             fpresult = fabs(farg[0]);
  8784. #else
  8785.             if (farg[0] < 0.0)
  8786.               fpresult = 0.0 - farg[0];
  8787. #endif /* COMMENT */
  8788.             break;
  8789.           case FN_FPADD:                /* FP add */
  8790.             fpresult = farg[0] + farg[1];
  8791.             break;
  8792.           case FN_FPDIV:                /* FP divide */
  8793.           case FN_FPMOD:                /* FP modulus */
  8794.             if (!farg[1]) {
  8795.                 failed = 1;
  8796.                 if (fndiags)
  8797.                   sprintf(fnval,"<ERROR:DIVIDE_BY_ZERO:\\f%s()>",fn);
  8798.             } else
  8799.               fpresult = (y == FN_FPDIV) ?
  8800.                 (farg[0] / farg[1]) :
  8801.                   fmod(farg[0],farg[1]);
  8802.             break;
  8803.           case FN_FPEXP:                /* FP e to the x */
  8804.             fpresult = (CKFLOAT) exp(farg[0]);
  8805.             break;
  8806.           case FN_FPLOG:                /* FP base-10 logarithm */
  8807.           case FN_FPLN:                 /* FP natural logarithm */
  8808.             if (farg[0] < 0.0) {
  8809.                 failed = 1;
  8810.                 if (fndiags)
  8811.                   sprintf(fnval,"<ERROR:ARG_OUT_OF_RANGE:\\f%s()>",fn);
  8812.             } else
  8813.               fpresult = (y == FN_FPLOG) ? log10(farg[0]) : log(farg[0]);
  8814.             break;
  8815.           case FN_FPMUL:                /* FP multiply */
  8816.             fpresult = farg[0] * farg[1];
  8817.             break;
  8818.           case FN_FPPOW:                /* FP raise to a power */
  8819.             fpresult = modf(farg[1],&dummy);
  8820.             if ((!farg[0] && farg[1] <= 0.0) ||
  8821.                 (farg[0] < 0.0 && !fpresult)) {
  8822.                 failed = 1;
  8823.                 if (fndiags)
  8824.                   sprintf(fnval,"<ERROR:ARG_OUT_OF_RANGE:\\f%s()>",fn);
  8825.             } else
  8826.               fpresult = pow(farg[0],farg[1]);
  8827.             break;
  8828.           case FN_FPSQR:                /* FP square root */
  8829.             if (farg[0] < 0.0) {
  8830.                 failed = 1;
  8831.                 if (fndiags)
  8832.                   sprintf(fnval,"<ERROR:ARG_OUT_OF_RANGE:\\f%s()>",fn);
  8833.             } else
  8834.               fpresult = sqrt(farg[0]);
  8835.             break;
  8836.           case FN_FPSUB:                /* FP subtract */
  8837.             fpresult = farg[0] - farg[1];
  8838.             break;
  8839.           case FN_FPROU:                /* FP round */
  8840.             fpresult = farg[0];
  8841.             break;
  8842.           case FN_FPSIN:                /* FP sine */
  8843.             fpresult = (CKFLOAT) sin(farg[0]);
  8844.             break;
  8845.           case FN_FPCOS:                /* FP cosine */
  8846.             fpresult = (CKFLOAT) cos(farg[0]);
  8847.             break;
  8848.           case FN_FPTAN:                /* FP tangent */
  8849.             fpresult = (CKFLOAT) tan(farg[0]);
  8850.             break;
  8851.           case FN_FPMAX:
  8852.             fpresult = (farg[0] > farg[1]) ? farg[0] : farg[1];
  8853.             break;
  8854.           case FN_FPMIN:
  8855.             fpresult = (farg[0] < farg[1]) ? farg[0] : farg[1];
  8856.             break;
  8857.         }
  8858.  
  8859.         /* Get here with fpresult = function result */
  8860.  
  8861.         if (errno) {                    /* If range or domain error */
  8862.             failed = 1;
  8863.             if (fndiags)
  8864.               sprintf(fnval,"<ERROR:FLOATING-POINT-OP:\\f%s()>",fn);
  8865.         }
  8866.         if (failed) {                   /* and/or any other kind of error, */
  8867.             goto fnend;                 /* fail. */
  8868.         } else {
  8869.             char fbuf[16];              /* For creating printf format */
  8870.             if (!fp_rounding &&         /* If printf doesn't round, */
  8871.                 (places > 0 ||          /* round result to decimal places. */
  8872.                  (places == 0 && y == FN_FPROU)))
  8873.               fpresult += (0.5 / pow(10.0,(CKFLOAT)places));
  8874.             if (places > 0) {                   /* If places specified */
  8875.                 sprintf(fbuf,"%%0.%df",places); /* and then use it to write */
  8876.                 sprintf(fnval,fbuf,fpresult);   /* the given no. of digits */
  8877.             } else {                            /* otherwise */
  8878. #ifdef COMMENT
  8879. /*
  8880.   Here we want to print exactly fp_digits significant digits, no matter which
  8881.   side of the decimal point they are on.  That is, we want want the default
  8882.   format to show the maximum number of non-garbage digits, AND we want the last
  8883.   such digit to be rounded.  Of course there is no way to do that, since the
  8884.   digit after the last non-garbage digit is, well, garbage.  So the following
  8885.   clever ruse does no good.
  8886. */
  8887.                 int sign = 0, m = 0;
  8888.                 sprintf(fnval,"%f",fpresult);
  8889.                 if (fnval[0] == '-') sign = 1;
  8890.                 for (i = sign; i < FNVALL; i++) {
  8891.                     if (isdigit(fnval[i]))
  8892.                       m++;
  8893.                     else
  8894.                       break;
  8895.                 }
  8896.                 if (m > 1) {
  8897.                     int d = fp_digits - m;
  8898.                     if (d < 1) d = 1;
  8899.                     sprintf(fbuf,"%%%d.%df",fp_digits+sign+1,d);
  8900.                 } else {
  8901.                     sprintf(fbuf,"%%0.%df",fp_digits);
  8902.                 }
  8903.                 sprintf(fnval,fbuf,fpresult);
  8904. #else
  8905.                 sprintf(fbuf,"%%0.%df",fp_digits); /* go for max precision */
  8906.                 sprintf(fnval,fbuf,fpresult);
  8907.  
  8908. #endif /* COMMENT */
  8909.             }
  8910.             if (fnval[0] == '-') sign = 1;
  8911.         }
  8912.         debug(F111,"fpresult 1",fnval,errno); /* Check for over/underflow */
  8913.         for (i = sign; fnval[i]; i++) { /* Give requested decimal places */
  8914.             if (fnval[i] == '.')        /* First find the decimal point */
  8915.               break;
  8916.             else if (i > fp_digits + sign - 1) /* replacing garbage */
  8917.               fnval[i] = '0';           /* digits with 0... */
  8918.         }
  8919.         if (fnval[i] == '.') {          /* Have decimal point */
  8920.             int gotend = 0;
  8921.             /* d < 0 so truncate fraction */
  8922.             if (places < 0 || (places == 0 && y == FN_FPROU)) {
  8923.                 fnval[i] = NUL;
  8924.             } else if (places > 0) {    /* d > 0 so this many decimal places */
  8925.                 i++;                           /* First digit after decimal */
  8926.                 for (j = 0; j < places; j++) { /* Truncate after d decimal */
  8927.                     if (!fnval[j+i])           /* places or extend to d  */
  8928.                       gotend = 1;              /* decimal places. */
  8929.                     if (gotend || j+i+sign > fp_digits)
  8930.                       fnval[j+i] = '0';
  8931.                 }
  8932.                 fnval[j+i] = NUL;
  8933.             } else {                    /* d == 0 so Do The Right Thing */
  8934.                 for (j = (int)strlen(fnval) - 1; j > i+1; j--) {
  8935.                     if ((j - sign) > fp_digits)
  8936.                       fnval[j] = '0';
  8937.                     if (fnval[j] == '0')
  8938.                       fnval[j] = NUL;   /* Strip useless trailing 0's. */
  8939.                     else
  8940.                       break;
  8941.                 }
  8942.             }
  8943.         }
  8944.         debug(F111,"fpresult 2",fnval,errno);
  8945.         goto fnend;
  8946.     }
  8947. #endif /* FNFLOAT */
  8948.  
  8949. #ifdef CKCHANNELIO
  8950.     if (y == FN_FSTAT  ||               /* File functions */
  8951.         y == FN_FPOS   ||
  8952.         y == FN_FEOF   ||
  8953.         y == FN_FGCHAR ||
  8954.         y == FN_FGLINE ||
  8955.         y == FN_FGBLK  ||
  8956.         y == FN_FPCHAR ||
  8957.         y == FN_FPLINE ||
  8958.         y == FN_FPBLK  ||
  8959.         y == FN_NLINE  ||
  8960.         y == FN_FERMSG ||
  8961.         y == FN_FILNO) {
  8962.         int x = 0, t = 0, channel;
  8963.         long z;
  8964.         extern int z_maxchan;
  8965.  
  8966.         failed = 1;                     /* Assume failure */
  8967.         p = fnval;                      /* until we validate args */
  8968.         if (y == FN_FERMSG) {
  8969.             extern int z_error;
  8970.             if (argn < 1) {
  8971.                 x = z_error;
  8972.             } else if (chknum(bp[0])) {
  8973.                 x = atoi(bp[0]);
  8974.             } else if (fndiags)
  8975.               sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  8976.             failed = 0;
  8977.             ckstrncpy(fnval,ckferror(x),FNVALL);
  8978.             goto fnend;
  8979.         }
  8980.         if (argn < 1) {                 /* All file functions need channel */
  8981.             if (fndiags)
  8982.               sprintf(fnval,"<ERROR:MISSING_ARG:\\f%s()>",fn);
  8983.             goto fnend;
  8984.         }
  8985.         if (rdigits(bp[0])) {           /* Channel must be numeric */
  8986.             channel = atoi(bp[0]);
  8987.         } else {                        /* Fail if it isn't */
  8988.             if (fndiags)
  8989.               sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  8990.             goto fnend;
  8991.         }
  8992.         if (channel < 0 || channel > z_maxchan) { /* Check channel range */
  8993.             if (fndiags)
  8994.               sprintf(fnval,"<ERROR:ARG_OUT_OF_RANGE:\\f%s()>",fn);
  8995.             goto fnend;
  8996.         }
  8997.         x = z_getmode(channel);         /* Find out about the channel */
  8998.  
  8999.         failed = 0;                     /* Assume success from here down */
  9000.         if (y == FN_FSTAT) {            /* Status / modes of channel */
  9001.             if (x > -1)
  9002.               x &= FM_RWB;              /* Mask out irrelevant bits */
  9003.             else                        /* In this case not open is OK */
  9004.               x = 0;
  9005.             sprintf(fnval,"%d",x);      /* 0 if not open, 1-7 if open */
  9006.             goto fnend;
  9007.         } else if (x < 1) {             /* Not \f_status() so must be open */
  9008.             failed = 1;
  9009.             if (fndiags)
  9010.               sprintf(fnval,"<ERROR:FILE_NOT_OPEN:\\f%s()>",fn);
  9011.             goto fnend;
  9012.         }
  9013.         switch (y) {                    /* Do the requested function */
  9014.           case FN_FPOS:                 /* Get position */
  9015.             z = z_getpos(channel);
  9016.             sprintf(fnval,"%ld",z);
  9017.             goto fnend;
  9018.  
  9019.           case FN_NLINE:                /* Get line number */
  9020.             z = z_getline(channel);
  9021.             sprintf(fnval,"%ld",z);
  9022.             goto fnend;
  9023.  
  9024.           case FN_FEOF:                 /* Check EOF */
  9025.             t = 0;
  9026.             if (x & FM_EOF) t = 1;
  9027.             sprintf(fnval,"%d",t);
  9028.             goto fnend;
  9029.  
  9030.           case FN_FILNO:                /* Get file handle */
  9031.             x = z_getfnum(channel);
  9032.             sprintf(fnval,"%d",x);
  9033.             goto fnend;
  9034.  
  9035.           case FN_FPBLK:                /* Read or write block */
  9036.           case FN_FGBLK:
  9037.             if (argn < 2) {
  9038.                 if (fndiags)
  9039.                   sprintf(fnval,"<ERROR:MISSING_ARG:\\f%s()>",fn);
  9040.                 goto fnend;
  9041.             }
  9042.             if (rdigits(bp[1])) {
  9043.                 t = atoi(bp[1]);
  9044.             } else {
  9045.                 if (fndiags)
  9046.                   sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  9047.                 goto fnend;
  9048.             }
  9049.           case FN_FGCHAR:               /* Read or write character or line */
  9050.           case FN_FPCHAR:
  9051.           case FN_FGLINE:
  9052.           case FN_FPLINE:
  9053.             fnval[0] = NUL;
  9054.             switch (y) {
  9055.               case FN_FGCHAR: t = z_in(channel,fnval,FNVALL,1,1); break;
  9056.               case FN_FGLINE: t = z_in(channel,fnval,FNVALL,FNVALL-1,0); break;
  9057.               case FN_FGBLK:
  9058.                 if (t >= FNVALL) t = FNVALL - 1;
  9059.                 t = z_in(channel,fnval,FNVALL,t,1);
  9060.                 break;
  9061.               case FN_FPCHAR: t = z_out(channel,bp[1],1,1);  break;
  9062.               case FN_FPLINE: t = z_out(channel,bp[1],-1,0); break;
  9063.               case FN_FPBLK:  t = z_out(channel,bp[1],-1,1); break;
  9064.             }
  9065.             if (t < 0) {                /* Handle read/write error */
  9066.                 failed = 1;
  9067.                 if (fndiags && t != FX_EOF)
  9068.                   sprintf(fnval,"<ERROR:FILE_ERROR_%d:\\f%s()>",t,fn);
  9069.                 goto fnend;
  9070.             }
  9071.             if (y == FN_FGCHAR)         /* Null terminate char */
  9072.               fnval[1] = NUL;
  9073.             /* Write (put) functions return numeric status code */
  9074.             if (y == FN_FPCHAR || y == FN_FPLINE || y == FN_FPBLK)
  9075.               sprintf(fnval,"%d",t);
  9076.             goto fnend;
  9077.         }
  9078.     }
  9079. #endif /* CKCHANNELIO */
  9080.  
  9081.     if (y == FN_PATTERN) {              /* \fpattern() */
  9082.         ispattern = 1;
  9083.         if (argn > 0) {
  9084.             p = fnval;
  9085.             ckstrncpy(fnval,bp[0],FNVALL);
  9086.         } else p = "";
  9087.         goto fnend;
  9088.     }
  9089.  
  9090.     if (y == FN_HEX2N || y == FN_OCT2N) { /* \fhex2n(), \foct2n() */
  9091.         long u = 0L;
  9092.         int d, k;
  9093.         p = "0";
  9094.         if (argn < 1)
  9095.           goto fnend;
  9096.         p = ckradix(bp[0], ((y == FN_HEX2N) ? 16 : 8), 10);
  9097.         if (!p) {
  9098.             if (fndiags)
  9099.               sprintf(fnval,"<ERROR:ARG_OUT_OF_RANGE:\\f%s()>",fn);
  9100.             goto fnend;
  9101.         }
  9102.         failed = 0;
  9103.         ckstrncpy(fnval,p,FNVALL);
  9104.         p = fnval;
  9105.         goto fnend;
  9106.     }
  9107.  
  9108.     if (y == FN_HEX2IP) {
  9109.         int c[2], ip[4], i, k;
  9110.         p = "0";
  9111.         if (argn < 1)
  9112.           goto fnend;
  9113.         s = bp[0];
  9114.         if ((int)strlen(s) != 8) {
  9115.             failed = 1;
  9116.             if (fndiags)
  9117.               sprintf(fnval,
  9118.                       "<ERROR:ARG_OUT_OF_RANGE:\\f%s()>",
  9119.                       fn
  9120.                       );
  9121.             goto fnend;
  9122.         }
  9123.         p = fnval;
  9124.         for (k = 0; k < 8; k += 2) {
  9125.             for (i = 0; i < 2; i++) {
  9126.                 c[i] = *s++;
  9127.                 if (islower(c[i])) c[i] = toupper(c[i]);
  9128.                 if (c[i] >= '0' && c[i] <= '9') {
  9129.                     c[i] -= 0x30;
  9130.                 } else if (c[i] >= 'A' && c[i] <= 'F') {
  9131.                     c[i] -= 0x37;
  9132.                 } else {
  9133.                     failed = 1;
  9134.                     if (fndiags)
  9135.                       sprintf(fnval,
  9136.                               "<ERROR:ARG_OUT_OF_RANGE:\\f%s()>",
  9137.                               fn
  9138.                               );
  9139.                     goto fnend;
  9140.                 }
  9141.                 ip[k/2] = c[0] << 4 | c[1];
  9142.             }
  9143.             sprintf(p,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]);
  9144.         }
  9145.         goto fnend;
  9146.     }
  9147.     if (y == FN_IP2HEX) {
  9148.         int ip[4], i;
  9149.         char * q;
  9150.         p = "00000000";
  9151.         if (argn < 1)
  9152.           goto fnend;
  9153.         s = bp[0];
  9154.         p = fnval;
  9155.         for (i = 0; i < 3; i++) {
  9156.             q = ckstrchr(s,'.');
  9157.             if (q) {
  9158.                 *q++ = NUL;
  9159.                 ip[i] = atoi(s);
  9160.                 s = q;
  9161.             } else {
  9162.                 failed = 1;
  9163.                 if (fndiags)
  9164.                   sprintf(fnval,
  9165.                           "<ERROR:ARG_OUT_OF_RANGE:\\f%s()>",
  9166.                           fn
  9167.                           );
  9168.                 goto fnend;
  9169.             }
  9170.         }
  9171.         ip[3] = atoi(s);
  9172.         sprintf(p,"%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
  9173.         goto fnend;
  9174.     }
  9175.     if (y == FN_RADIX) {
  9176.         failed = 1;
  9177.         p = fnval;
  9178.         if (argn < 3) {
  9179.             if (fndiags)
  9180.               sprintf(fnval,"<ERROR:MISSING_ARG:\\f%s()>",fn);
  9181.             goto fnend;
  9182.         }
  9183.         if (!rdigits(bp[1]) || !rdigits(bp[2])) {
  9184.             if (fndiags)
  9185.               sprintf(fnval,"<ERROR:ARG_NOT_NUMERIC:\\f%s()>",fn);
  9186.             goto fnend;
  9187.         }
  9188.         p = ckradix(bp[0],atoi(bp[1]),atoi(bp[2]));
  9189.         if (!p) {
  9190.             if (fndiags)
  9191.               sprintf(fnval,"<ERROR:ARG_OUT_OF_RANGE:\\f%s()>",fn);
  9192.             goto fnend;
  9193.         }
  9194.         failed = 0;
  9195.         ckstrncpy(fnval,p,FNVALL);
  9196.         p = fnval;
  9197.         goto fnend;
  9198.     }
  9199.  
  9200. /* Note: when adding new functions remember to update dohfunc in ckuus2.c. */
  9201.  
  9202.     failed = 1;
  9203.     if (fndiags)
  9204.       sprintf(fnval,"<ERROR:UNKNOWN_FUNCTION:\\f%s()>",fn);
  9205.  
  9206.   fnend:
  9207.     /* Free temporary storage for aguments */
  9208.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  9209.     fndepth--;
  9210.     if (failed) {                       /* Handle failure */
  9211.         debug(F111,"fnend",fnval,errno);
  9212.         if (!p) p = "";
  9213.         if (p[0]) {
  9214.             /* In case this wasn't caught above... */
  9215.             k = strlen(p);
  9216.             if (p[0] != '<' && p[k-1] != '>') {
  9217.                 sprintf(fnval,"<ERROR:BAD_ARG:\\f%s()>",fn);
  9218.                 p = fnval;
  9219.             }
  9220.         } else {
  9221.             sprintf(fnval,"<ERROR:UNKNOWN:\\f%s()>",fn);
  9222.             p = fnval;
  9223.         }
  9224.         if (fnerror)                    /* SET FUNCTION ERROR ON */
  9225.           fnsuccess = 0;                /* Make command fail (see ckuus5.c) */
  9226.         debug(F111,"fneval failed",p,fnsuccess);
  9227.         if (fndiags)                    /* SET FUNCTION DIAGNOSTICS ON */
  9228.           printf("?%s\n",p);            /* Print error message now. */
  9229.         else
  9230.           return("");                   /* Return nothing. */
  9231.     }
  9232.     return(p);
  9233. }
  9234. #endif /* NOSPL */
  9235.  
  9236. char *
  9237. zzndate() {                             /* Returns today's date as yyyymmdd */
  9238.     char * p;
  9239.     int x;
  9240.  
  9241. /* WARNING - This will fail if asctime() returns non-English month names */
  9242.  
  9243.     ztime(&p);                          /* Get "asctime" string */
  9244.     if (p == NULL || *p == NUL) return("");
  9245.     for (x = 20; x < 24; x++)           /* yyyy */
  9246.       ndatbuf[x - 20] = p[x];
  9247.     ndatbuf[6] = (char) ((p[8] == ' ') ? '0' : p[8]);
  9248.     ndatbuf[7] = p[9];                  /* dd */
  9249.     for (x = 0; x < 12; x++)            /* mm */
  9250.       if (!strncmp(p+4,months[x],3)) break;
  9251.     if (x == 12) {
  9252.         ndatbuf[4] = ndatbuf[5] = '?';
  9253.     } else {
  9254.         x++;
  9255.         ndatbuf[4] = (char) ((x < 10) ? '0' : '1');
  9256.         ndatbuf[5] = (char) ((x % 10) + 48);
  9257.     }
  9258.     ndatbuf[8] = NUL;
  9259.     return((char *)ndatbuf);
  9260. }
  9261.  
  9262. static char ckpidbuf[32] = "????";
  9263.  
  9264. #ifdef VMS
  9265. _PROTOTYP(long zgpid,(void));
  9266. #endif /* VMS */
  9267.  
  9268. char *
  9269. ckgetpid() {                            /* Return pid as string */
  9270. #ifdef CK_PID
  9271. #ifdef OS2
  9272. #define getpid _getpid
  9273.     unsigned long zz;
  9274. #else
  9275.     long zz;
  9276. #endif /* OS2 */
  9277. #ifdef VMS
  9278.     zz = zgpid();
  9279. #else
  9280.     zz = getpid();
  9281. #endif /* VMS */
  9282.     sprintf(ckpidbuf,"%ld",zz);
  9283. #endif /* CK_PID */
  9284.     return((char *)ckpidbuf);
  9285. }
  9286.  
  9287. #ifndef NOSPL
  9288. #define EMBUFLEN 128                    /* Error message buffer length */
  9289.  
  9290. static char embuf[EMBUFLEN+1];
  9291.  
  9292. char *                                  /* Evaluate builtin variable */
  9293. nvlook(s) char *s; {
  9294.     int x, y;
  9295.     long z;
  9296.     char *p;
  9297. #ifndef NODIAL
  9298.     MDMINF * m;
  9299. #endif /* NODIAL */
  9300. #ifndef NOKVERBS                        /* Keyboard macro material */
  9301.     extern int keymac, keymacx;
  9302. #endif /* NOKVERBS */
  9303. #ifdef CK_LOGIN
  9304.     extern int isguest;
  9305. #endif /* CK_LOGIN */
  9306.     if (!s) s = "";
  9307.     x = strlen(s);
  9308.     if (fndiags) {                      /* FUNCTION DIAGNOSTIC ON */
  9309.         if (x + 32 < EMBUFLEN)
  9310.           sprintf(embuf,"<ERROR:NO_SUCH_VARIABLE:\\v(%s)>",s);
  9311.         else
  9312.           sprintf(embuf,"<ERROR:NO_SUCH_VARIABLE>");
  9313.     } else                              /* FUNCTION DIAGNOSTIC OFF */
  9314.       embuf[0] = NUL;
  9315.     x = VVBUFL;
  9316.     p = vvbuf;
  9317.     if (zzstring(s,&p,&x) < 0) {        /* e.g. for \v(\%a) */
  9318.         y = -1;
  9319.     } else {
  9320.         s = vvbuf;
  9321.         y = lookup(vartab,s,nvars,&x);
  9322.     }
  9323. #ifndef NODIAL
  9324.     m = (mdmtyp > 0) ? modemp[mdmtyp] : NULL; /* For \v(m_xxx) variables */
  9325. #endif /* NODIAL */
  9326.  
  9327.     debug(F101,"nvlook y","",y);
  9328.  
  9329.     switch (y) {
  9330.       case VN_ARGC:                     /* ARGC */
  9331.         sprintf(vvbuf,"%d",maclvl < 0 ? topargc : macargc[maclvl]);
  9332.         return(vvbuf);
  9333.  
  9334.       case VN_ARGS:                     /* ARGS */
  9335.         sprintf(vvbuf,"%d",xargs);
  9336.         return(vvbuf);
  9337.  
  9338.       case VN_COUN:                     /* COUNT */
  9339.         sprintf(vvbuf,"%d",count[cmdlvl]);
  9340.         return(vvbuf);
  9341.  
  9342.       case VN_DATE:                     /* DATE */
  9343.         ztime(&p);                      /* Get "asctime" string */
  9344.         if (p == NULL || *p == NUL) return(NULL);
  9345.         vvbuf[0] = p[8];                /* dd */
  9346.         vvbuf[1] = p[9];
  9347.         vvbuf[2] = SP;
  9348.         vvbuf[3] = p[4];                /* mmm */
  9349.         vvbuf[4] = p[5];
  9350.         vvbuf[5] = p[6];
  9351.         vvbuf[6] = SP;
  9352.         for (x = 20; x < 24; x++)       /* yyyy */
  9353.           vvbuf[x - 13] = p[x];
  9354.         vvbuf[11] = NUL;
  9355.         return(vvbuf);
  9356.  
  9357.       case VN_NDAT:                     /* Numeric date */
  9358.         ckstrncpy(vvbuf,zzndate(),VVBUFL);
  9359.         return(vvbuf);
  9360.  
  9361.       case VN_DIRE:                     /* DIRECTORY */
  9362.         s = zgtdir();                   /* Get current directory */
  9363.         if (!s)
  9364. #ifdef UNIXOROSK
  9365.           s = "./";
  9366. #else
  9367. #ifdef VMS
  9368.           s = "[]";
  9369. #else
  9370.           s = "";
  9371. #endif /* VMS */
  9372. #endif /* UNIXOROSK */
  9373.         ckstrncpy(vvbuf,s,VVBUFL);
  9374.         s = vvbuf;
  9375. #ifdef UNIXOROSK
  9376.         x = strlen(s);
  9377.         if (x < VVBUFL - 1) {
  9378.             if (s[x-1] != '/') {
  9379.                 s[x] = '/';
  9380.                 s[x+1] = NUL;
  9381.             }
  9382.         }
  9383. #endif /* UNIXOROSK */
  9384.         return(s);
  9385.  
  9386.       case VN_FILE:                     /* filespec */
  9387.         return(fspec);
  9388.  
  9389.       case VN_HOST:                     /* host name */
  9390.         if (*myhost) {                  /* If known */
  9391.             return(myhost);             /* return it. */
  9392.         } else {                        /* Otherwise */
  9393.             strcpy(vvbuf,"unknown");    /* just say "unknown" */
  9394.             return(vvbuf);
  9395.         }
  9396.  
  9397.       case VN_SYST:                     /* System type */
  9398. #ifdef UNIX
  9399.         strcpy(vvbuf,"UNIX");
  9400. #else
  9401. #ifdef VMS
  9402.         strcpy(vvbuf,"VMS");
  9403. #else
  9404. #ifdef OSK
  9405.         strcpy(vvbuf,"OS9/68K");
  9406. #else
  9407. #ifdef AMIGA
  9408.         strcpy(vvbuf,"Amiga");
  9409. #else
  9410. #ifdef MAC
  9411.         strcpy(vvbuf,"Macintosh");
  9412. #else
  9413. #ifdef OS2
  9414. #ifdef NT
  9415.         strcpy(vvbuf,"WIN32") ;
  9416. #else /* NT */
  9417.         strcpy(vvbuf,"OS/2");
  9418. #endif /* NT */
  9419. #else
  9420. #ifdef datageneral
  9421.         strcpy(vvbuf,"AOS/VS");
  9422. #else
  9423. #ifdef GEMDOS
  9424.         strcpy(vvbuf,"Atari_ST");
  9425. #else
  9426. #ifdef STRATUS
  9427.         strcpy(vvbuf,"Stratus_VOS");
  9428. #else
  9429.         strcpy(vvbuf,"unknown");
  9430. #endif /* STRATUS */
  9431. #endif /* GEMDOS */
  9432. #endif /* datageneral */
  9433. #endif /* OS2 */
  9434. #endif /* MAC */
  9435. #endif /* AMIGA */
  9436. #endif /* OSK */
  9437. #endif /* VMS */
  9438. #endif /* UNIX */
  9439.         return(vvbuf);
  9440.  
  9441.       case VN_SYSV:                     /* System herald */
  9442. #ifdef IKSD
  9443. #ifdef CK_LOGIN
  9444.         if (inserver && isguest)
  9445.           return("");
  9446. #endif /* CK_LOGIN */
  9447. #endif /* IKSD */
  9448.         for (x = y = 0; x < VVBUFL; x++) {
  9449.             if (ckxsys[x] == SP && y == 0) continue;
  9450.             vvbuf[y++] = (char) ((ckxsys[x] == SP) ? '_' : ckxsys[x]);
  9451.         }
  9452.         vvbuf[y] = NUL;
  9453.         return(vvbuf);
  9454.     } /* Break up long switch statements... */
  9455.  
  9456.     switch(y) {
  9457.       case VN_TIME:                     /* TIME. Assumes that ztime returns */
  9458.         ztime(&p);                      /* "Thu Feb  8 12:00:00 1990" */
  9459.         if (p == NULL || *p == NUL)     /* like asctime()! */
  9460.           return("");
  9461.         for (x = 11; x < 19; x++)       /* copy hh:mm:ss */
  9462.           vvbuf[x - 11] = p[x];         /* to vvbuf */
  9463.         vvbuf[8] = NUL;                 /* terminate */
  9464.         return(vvbuf);                  /* and return it */
  9465.  
  9466.       case VN_NTIM:                     /* Numeric time */
  9467.         ztime(&p);                      /* "Thu Feb  8 12:00:00 1990" */
  9468.         if (p == NULL || *p == NUL)     /* like asctime()! */
  9469.           return(NULL);
  9470.         z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
  9471.         sprintf(vvbuf,"%ld",z);
  9472.         return(vvbuf);
  9473.  
  9474. #ifdef CK_TTYFD
  9475.       case VN_TTYF:                     /* TTY file descriptor */
  9476.         sprintf(vvbuf,"%d",
  9477. #ifdef VMS
  9478.                 vmsttyfd()
  9479. #else
  9480.                 ttyfd
  9481. #endif /* VMS */
  9482.                 );
  9483.         return(vvbuf);
  9484. #endif /* CK_TTYFD */
  9485.  
  9486.       case VN_VERS:                     /* Numeric Kermit version number */
  9487.         sprintf(vvbuf,"%ld",vernum);
  9488.         return(vvbuf);
  9489.  
  9490.       case VN_XVNUM:                    /* Product-specific version number */
  9491.         sprintf(vvbuf,"%ld",xvernum);
  9492.         return(vvbuf);
  9493.  
  9494.       case VN_HOME:                     /* Home directory */
  9495.         return(homepath());
  9496.  
  9497.       case VN_IBUF:                     /* INPUT buffer */
  9498.         return((char *)inpbuf);
  9499.  
  9500.       case VN_ICHR:                     /* INPUT character */
  9501.         inchar[1] = NUL;
  9502.         return((char *)inchar);
  9503.  
  9504.       case VN_ICNT:                     /* INPUT character count */
  9505.         sprintf(vvbuf,"%d",incount);
  9506.         return(vvbuf);
  9507.  
  9508.       case VN_SPEE: {                   /* Transmission SPEED */
  9509.           long t;
  9510.           t = ttgspd();
  9511.           if (t < 0L)
  9512.             sprintf(vvbuf,"unknown");
  9513.           else
  9514.             sprintf(vvbuf,"%ld",t);
  9515.           return(vvbuf);
  9516.       }
  9517.  
  9518.       case VN_SUCC:                     /* SUCCESS flag */
  9519.         sprintf(vvbuf,"%d",(success == 0) ? 1 : 0); /* Note inverted sense */
  9520.         return(vvbuf);
  9521.  
  9522.       case VN_LINE: {                   /* LINE */
  9523. #ifdef DEBUG
  9524.           if (deblog) {
  9525.               debug(F111,"\v(line) local",ttname,local);
  9526.               debug(F111,"\v(line) inserver","",inserver);
  9527. #ifdef TNCODE
  9528.               debug(F111,"\v(line) tcp_incoming","",tcp_incoming);
  9529. #endif /* TNCODE */
  9530. #ifdef CK_TAPI
  9531.               debug(F111,"\v(line) tttapi","",tttapi);
  9532. #endif /* CK_TAPI */
  9533.           }
  9534. #endif /* DEBUG */
  9535.  
  9536. #ifdef CK_TAPI
  9537.           if (tttapi) {                 /* If I have made a TAPI connection */
  9538.               int i;                    /* return the TAPI device name */
  9539.               for (i = 0; i < ntapiline; i++) {
  9540.                   if (!strcmp(ttname,tapilinetab[i].kwd)) {
  9541.                       p = _tapilinetab[i].kwd;
  9542.                       return(p);
  9543.                   }
  9544.               }
  9545.           }
  9546. #endif /* CK_TAPI */
  9547. #ifndef NOXFER
  9548.           if (inserver                  /* If I am a TCP server */
  9549. #ifdef TNCODE
  9550.               || tcp_incoming
  9551. #endif /* TNCODE */
  9552.               )
  9553. #ifdef TCPSOCKET
  9554.             p = ckgetpeer();            /* return peer name */
  9555.           else
  9556. #endif /* TCPSOCKET */
  9557. #endif /* NOXFER */
  9558.           if (local)                    /* Otherwise if in local mode */
  9559.             p = (char *) ttname;        /* return SET LINE / SET HOST name */
  9560.           else                          /* Otherwise */
  9561.             p = "";                     /* return empty string */
  9562.           if (!p)                       /* In case ckgetpeer() returns */
  9563.             p = "";                     /* null pointer... */
  9564.           debug(F110,"\v(line) p",p,0);
  9565.           if (!*p)
  9566.             p = (char *) ttname;
  9567.           return(p);
  9568.       }
  9569.       case VN_PROG:                     /* Program name */
  9570.         return("C-Kermit");
  9571.  
  9572.     } /* Break up long switch statements... */
  9573.  
  9574.     switch(y) {
  9575.       case VN_RET:                      /* Value of most recent RETURN */
  9576.         debug(F111,"\\v(return)",mrval[maclvl+1],maclvl+1);
  9577.         p = mrval[maclvl+1];
  9578.         if (p == NULL) p = "";
  9579.         return(p);
  9580.  
  9581.       case VN_FFC:                      /* Size of most recent file */
  9582.         sprintf(vvbuf, "%ld", ffc);
  9583.         return(vvbuf);
  9584.  
  9585.       case VN_TFC:                      /* Size of most recent file group */
  9586.         sprintf(vvbuf, "%ld", tfc);
  9587.         return(vvbuf);
  9588.  
  9589.       case VN_CPU:                      /* CPU type */
  9590. #ifdef IKSD
  9591. #ifdef CK_LOGIN
  9592.         if (inserver && isguest)
  9593.           return("");
  9594. #endif /* CK_LOGIN */
  9595. #endif /* IKSD */
  9596. #ifdef OS2
  9597.          {
  9598.             char * getcpu(void) ;
  9599.             return getcpu();
  9600.          }
  9601. #else /* OS2 */
  9602. #ifdef CKCPU
  9603.         return(CKCPU);                  /* Traditionally, compile-time value */
  9604. #else
  9605. #ifdef CK_UTSNAME
  9606.         {                               /* But if none, try runtime value */
  9607.             extern char unm_mch[];
  9608.             return((char *)unm_mch);
  9609.         }
  9610. #else
  9611.         return("unknown");
  9612. #endif /* CK_UTSNAME */
  9613. #endif /* CKCPU */
  9614. #endif /* OS2 */
  9615.  
  9616.       case VN_CMDL:                     /* Command level */
  9617.         sprintf(vvbuf, "%d", cmdlvl);
  9618.         return(vvbuf);
  9619.  
  9620.       case VN_DAY:                      /* Day of week */
  9621.         ztime(&p);
  9622.         if (p != NULL && *p != NUL)     /* ztime() succeeded. */
  9623.           ckstrncpy(vvbuf,p,4);
  9624.         else
  9625.           vvbuf[0] = NUL;               /* ztime() failed. */
  9626.         return(vvbuf);                  /* Return what we got. */
  9627.  
  9628.       case VN_NDAY: {                   /* Numeric day of week */
  9629.           long k;
  9630.           z = mjd(zzndate());           /* Get modified Julian date */
  9631.           k = (((int)(z % 7L)) + 3) % 7; /* Get day number */
  9632.           sprintf(vvbuf,"%ld",k);
  9633.           return(vvbuf);
  9634.       }
  9635.  
  9636.       case VN_LCL:                      /* Local (vs remote) mode */
  9637.         strcpy(vvbuf, local ? "1" : "0");
  9638.         return(vvbuf);
  9639.  
  9640.       case VN_CMDS:                     /* Command source */
  9641.         if (cmdstk[cmdlvl].src == CMD_KB)
  9642.           strcpy(vvbuf,"prompt");
  9643.         else if (cmdstk[cmdlvl].src == CMD_MD)
  9644.           strcpy(vvbuf,"macro");
  9645.         else if (cmdstk[cmdlvl].src == CMD_TF)
  9646.           strcpy(vvbuf,"file");
  9647.         else strcpy(vvbuf,"unknown");
  9648.         return(vvbuf);
  9649.  
  9650.       case VN_CMDF:                     /* Current command file name */
  9651. #ifdef COMMENT                          /* (see comments above) */
  9652.         if (tfnam[tlevel]) {            /* (near dblbs declaration) */
  9653.             dblbs(tfnam[tlevel],vvbuf,VVBUFL);
  9654.             return(vvbuf);
  9655.         } else return("");
  9656. #else
  9657.         if (tlevel < 0)
  9658.           return("");
  9659.         else
  9660.           return(tfnam[tlevel] ? tfnam[tlevel] : "");
  9661. #endif /* COMMENT */
  9662.  
  9663.       case VN_MAC:                      /* Current macro name */
  9664.         return((maclvl > -1) ? m_arg[maclvl][0] : "");
  9665.  
  9666.       case VN_EXIT:
  9667.         sprintf(vvbuf,"%d",xitsta);
  9668.         return(vvbuf);
  9669.  
  9670.     } /* Break up long switch statements... */
  9671.  
  9672.     switch(y) {
  9673.       case VN_PRTY: {                   /* Parity */
  9674.           char *ss;
  9675.           switch (parity) {
  9676.             case 0:   ss = "none";  break;
  9677.             case 'e': ss = "even";  break;
  9678.             case 'm': ss = "mark";  break;
  9679.             case 'o': ss = "odd";   break;
  9680.             case 's': ss = "space"; break;
  9681.             default:  ss = "unknown"; break;
  9682.           }
  9683.           strcpy(vvbuf,ss);
  9684.           return(vvbuf);
  9685.       }
  9686.  
  9687.       case VN_DIAL:
  9688.         sprintf(vvbuf,"%d",
  9689. #ifndef NODIAL
  9690.                 dialsta
  9691. #else
  9692.                 -1
  9693. #endif /* NODIAL */
  9694.                 );
  9695.         return(vvbuf);
  9696.  
  9697. #ifdef OS2
  9698.       case VN_KEYB:
  9699.         ckstrncpy(vvbuf,conkbg(),VVBUFL);
  9700.         return(vvbuf);
  9701.  
  9702.       case VN_SELCT: {
  9703.           extern char * selection ;
  9704.           return( selection ? selection : "" ) ;
  9705.       }
  9706. #endif /* OS2 */
  9707.  
  9708. #ifndef NOXFER
  9709.       case VN_CPS:
  9710.         sprintf(vvbuf,"%ld",tfcps);
  9711.         return(vvbuf);
  9712. #endif /* NOXFER */
  9713.  
  9714.       case VN_MODE:                     /* File transfer mode */
  9715.         switch (binary) {
  9716.           case XYFT_T: strcpy(vvbuf,"text"); break;
  9717.           case XYFT_B:
  9718.           case XYFT_U: strcpy(vvbuf,"binary"); break;
  9719.           case XYFT_I: strcpy(vvbuf,"image"); break;
  9720.           case XYFT_L: strcpy(vvbuf,"labeled"); break;
  9721.           case XYFT_M: strcpy(vvbuf,"macbinary"); break;
  9722.           default:     strcpy(vvbuf,"unknown");
  9723.         }
  9724.         return(vvbuf);
  9725.  
  9726. #ifdef CK_REXX
  9727.       case VN_REXX:
  9728.         return(rexxbuf);
  9729. #endif /* CK_REXX */
  9730.  
  9731.       case VN_NEWL:                     /* System newline char or sequence */
  9732. #ifdef UNIX
  9733.         strcpy(vvbuf,"\n");
  9734. #else
  9735. #ifdef datageneral
  9736.         strcpy(vvbuf,"\n");
  9737. #else
  9738. #ifdef OSK
  9739.         strcpy(vvbuf,"\15");            /* Remember, these are octal... */
  9740. #else
  9741. #ifdef MAC
  9742.         strcpy(vvbuf,"\15");
  9743. #else
  9744. #ifdef OS2
  9745.         strcpy(vvbuf,"\15\12");
  9746. #else
  9747. #ifdef STRATUS
  9748.         strcpy(vvbuf,"\n");
  9749. #else
  9750. #ifdef VMS
  9751.         strcpy(vvbuf,"\15\12");
  9752. #else
  9753. #ifdef AMIGA
  9754.         strcpy(vvbuf,"\n");
  9755. #else
  9756. #ifdef GEMDOS
  9757.         strcpy(vvbuf,"\n");
  9758. #else
  9759.         strcpy(vvbuf,"\n");
  9760. #endif /* GEMDOS */
  9761. #endif /* AMIGA */
  9762. #endif /* VMS */
  9763. #endif /* STRATUS */
  9764. #endif /* OS2 */
  9765. #endif /* MAC */
  9766. #endif /* OSK */
  9767. #endif /* datageneral */
  9768. #endif /* UNIX */
  9769.         return(vvbuf);
  9770.  
  9771.       case VN_ROWS:                     /* ROWS */
  9772.       case VN_COLS:                     /* COLS */
  9773.         strcpy(vvbuf,(y == VN_ROWS) ? "24" : "80"); /* Default */
  9774. #ifdef CK_TTGWSIZ
  9775. #ifdef OS2
  9776.         if (tt_cols[VTERM] < 0 || tt_rows[VTERM] < 0)
  9777.           ttgwsiz();
  9778.         sprintf(vvbuf,"%d",(y == VN_ROWS) ? tt_rows[VTERM] : tt_cols[VTERM]);
  9779. #else /* OS2 */
  9780.         if (ttgwsiz() > 0)              /* Get window size */
  9781.           if (tt_cols > 0 && tt_rows > 0) /* sets tt_rows, tt_cols */
  9782.             sprintf(vvbuf,"%d",(y == VN_ROWS) ? tt_rows : tt_cols);
  9783. #endif /* OS2 */
  9784. #endif /* CK_TTGWSIZ */
  9785.         return(vvbuf);
  9786.  
  9787.       case VN_TTYP:
  9788. #ifdef OS2
  9789.         sprintf(vvbuf, "%s",
  9790.                 (tt_type >= 0 && tt_type <= max_tt) ?
  9791.                 tt_info[tt_type].x_name :
  9792.                 "unknown"
  9793.                 );
  9794. #else
  9795. #ifdef MAC
  9796.         strcpy(vvbuf,"vt320");
  9797. #else
  9798.         p = getenv("TERM");
  9799.         ckstrncpy(vvbuf,p ? p : "unknown",VVBUFL+1);
  9800. #endif /* MAC */
  9801. #endif /* OS2 */
  9802.         return(vvbuf);
  9803.  
  9804.       case VN_MINP:                     /* MINPUT */
  9805.         sprintf(vvbuf, "%d", m_found);
  9806.         return(vvbuf);
  9807.     } /* Break up long switch statements... */
  9808.  
  9809.     switch(y) {
  9810.       case VN_CONN:                     /* CONNECTION */
  9811.         if (!local) {
  9812.           strcpy(vvbuf,"remote");
  9813.         } else {
  9814.             if (!network)
  9815.               strcpy(vvbuf,"serial");
  9816. #ifdef TCPSOCKET
  9817.             else if (nettype == NET_TCPB || nettype == NET_TCPA) {
  9818.                 if (ttnproto == NP_TELNET)
  9819.                   strcpy(vvbuf,"tcp/ip_telnet");
  9820.                 else
  9821.                   strcpy(vvbuf,"tcp/ip");
  9822.             }
  9823. #endif /* TCPSOCKET */
  9824. #ifdef ANYX25
  9825.             else if (nettype == NET_SX25 ||
  9826.                      nettype == NET_VX25 ||
  9827.                      nettype == NET_IX25
  9828.                      )
  9829.               strcpy(vvbuf,"x.25");
  9830. #endif /* ANYX25 */
  9831. #ifdef DECNET
  9832.             else if (nettype == NET_DEC) {
  9833.                 if ( ttnproto == NP_LAT ) strcpy(vvbuf,"decnet_lat");
  9834.                 else if ( ttnproto == NP_CTERM ) sprintf(vvbuf,"decnet_cterm");
  9835.                 else strcpy(vvbuf,"decnet");
  9836.             }
  9837. #endif /* DECNET */
  9838. #ifdef SUPERLAT
  9839.         else if ( nettype == NET_SLAT )
  9840.            strcpy(vvbuf,"superlat");
  9841. #endif /* SUPERLAT */
  9842. #ifdef NETFILE
  9843.         else if ( nettype == NET_FILE )
  9844.            strcpy(vvbuf,"local file");
  9845. #endif /* NETFILE */
  9846. #ifdef NETCMD
  9847.         else if ( nettype == NET_CMD )
  9848.            strcpy(vvbuf,"pipe");
  9849. #endif /* NETCMD */
  9850. #ifdef NETPTY
  9851.         else if ( nettype == NET_PTY )
  9852.             strcpy(vvbuf,"psuedoterminal");
  9853. #endif /* NETPTY */
  9854. #ifdef NETDLL
  9855.         else if ( nettype == NET_DLL )
  9856.            strcpy(vvbuf,"dynamic link library");
  9857. #endif /* NETDLL */
  9858. #ifdef SSH
  9859.         else if ( nettype == NET_SSH )
  9860.            strcpy(vvbuf,"secure shell");
  9861. #endif /* SSH */
  9862.  
  9863. #ifdef NPIPE
  9864.             else if (nettype == NET_PIPE)
  9865.               strcpy(vvbuf,"named_pipe");
  9866. #endif /* NPIPE */
  9867. #ifdef CK_NETBIOS
  9868.             else if (nettype == NET_BIOS)
  9869.               strcpy(vvbuf,"netbios");
  9870. #endif /* CK_NETBIOS */
  9871.             else
  9872.               strcpy(vvbuf,"unknown");
  9873.         }
  9874.         return(vvbuf);
  9875.  
  9876. #ifndef NOXFER
  9877.       case VN_SYSI:                     /* System ID, Kermit code */
  9878.         return((char *)cksysid);
  9879. #endif /* NOXFER */
  9880.  
  9881. #ifdef OS2
  9882.       case VN_SPA:
  9883.         sprintf(vvbuf,"%ld",zdskspace(0));
  9884.         return(vvbuf);
  9885. #endif /* OS2 */
  9886.  
  9887. #ifndef NOXFER
  9888.       case VN_QUE: {
  9889.           extern char querybuf[];
  9890.           return(querybuf);
  9891.       }
  9892. #endif /* NOXFER */
  9893.  
  9894. #ifndef NOCSETS
  9895.       case VN_CSET:
  9896. #ifdef OS2
  9897.         sprintf(vvbuf,"cp%d",os2getcp());
  9898. #else
  9899.         ckstrncpy(vvbuf,fcsinfo[fcharset].keyword,VVBUFL+1);
  9900. #endif /* OS2 */
  9901.         return(vvbuf);
  9902. #endif /* NOCSETS */
  9903.  
  9904. #ifdef OS2
  9905.       case VN_STAR:
  9906.         return(startupdir);
  9907.  
  9908.       case VN_EXEDIR:
  9909.         return(exedir);
  9910. #else
  9911. #ifdef VMSORUNIX
  9912.       case VN_STAR:
  9913.         return(startupdir);
  9914. #endif /* VMSORUNIX */
  9915. #endif /* OS2 */
  9916.  
  9917.       case VN_INI:
  9918.         return(inidir);
  9919.  
  9920.       case VN_MDM:
  9921.         return(gmdmtyp());
  9922.  
  9923.       case VN_EVAL:
  9924.         return(evalbuf);
  9925.  
  9926. #ifndef NODIAL
  9927.       case VN_D_CC:                     /* DIAL COUNTRY-CODE */
  9928.         return(diallcc ? diallcc : "");
  9929.  
  9930.       case VN_D_AC:                     /* DIAL AREA-CODE */
  9931.         return(diallac ? diallac : "");
  9932.  
  9933.       case VN_D_IP:                     /* DIAL INTERNATIONAL-PREFIX */
  9934.         return(dialixp ? dialixp : "");
  9935.  
  9936.       case VN_D_LP:                     /* DIAL LD-PREFIX */
  9937.         return(dialldp ? dialldp : "");
  9938.  
  9939.       case VN_D_LCP:                    /* DIAL LOCAL-PREFIX */
  9940.         return(diallcp ? diallcp : "");
  9941.  
  9942.       case VN_D_PXX:                    /* DIAL PBX-EXCHANGE that matched */
  9943.         return(matchpxx ? matchpxx : "");
  9944. #else
  9945.       case VN_D_CC:                     /* DIAL COUNTRY-CODE */
  9946.       case VN_D_AC:                     /* DIAL AREA-CODE */
  9947.       case VN_D_IP:                     /* DIAL INTERNATIONAL-PREFIX */
  9948.       case VN_D_LP:                     /* DIAL LD-PREFIX */
  9949.       case VN_D_LCP:                    /* DIAL LOCAL-PREFIX */
  9950.       case VN_D_PXX:                    /* DIAL PBX-EXCHANGE */
  9951.         return("");
  9952. #endif /* NODIAL */
  9953.       case VN_UID:
  9954. #ifdef UNIX
  9955.         {
  9956.             extern char * whoami();     /* From ckufio.c... */
  9957. #ifdef IKSD
  9958.             if (inserver)
  9959.               return((char *)uidbuf);
  9960.             else
  9961. #endif /* IKSD */
  9962.           if (uidbuf[0])
  9963.                 return((char *)uidbuf);
  9964.           else
  9965.                 return(whoami());
  9966.         }
  9967. #else
  9968.         return((char *)uidbuf);
  9969. #endif /* UNIX */
  9970.     } /* Break up long switch statements... */
  9971.  
  9972.     switch(y) {
  9973.       case VN_PWD:
  9974. #ifdef OS2
  9975.         if (activecmd == XXOUT) {
  9976.             ckstrncpy(vvbuf,pwbuf,VVBUFL);
  9977.             ck_encrypt((char *)vvbuf);
  9978.             return((char *)vvbuf);
  9979.         } else
  9980. #endif /* OS2 */
  9981.           return((char *)pwbuf);
  9982.  
  9983.       case VN_PRM:
  9984.         return((char *)prmbuf);
  9985.  
  9986.       case VN_PROTO:
  9987. #ifdef NOXFER
  9988.         return("none");
  9989. #else
  9990. #ifdef CK_XYZ
  9991.         return(ptab[protocol].p_name);
  9992. #else
  9993.         return("kermit");
  9994. #endif /* CK_XYZ */
  9995. #endif /* NOXFER */
  9996.  
  9997. #ifndef NOXFER
  9998. #ifdef CK_TMPDIR
  9999.       case VN_DLDIR:
  10000.         return(dldir ? dldir : "");
  10001. #endif /* CK_TMPDIR */
  10002. #endif /* NOXFER */
  10003.  
  10004. #ifndef NODIAL
  10005.       case VN_M_INI:                    /* Modem init string */
  10006.         return(dialini ? dialini : (m ? m->wake_str : ""));
  10007.  
  10008.       case VN_M_DCM:                    /* Modem dial command */
  10009.         return(dialcmd ? dialcmd : (m ? m->dial_str : ""));
  10010.  
  10011.       case VN_M_DCO:                    /* Modem data compression on */
  10012.         return(dialdcon ? dialdcon : (m ? m->dc_on_str : ""));
  10013.  
  10014.       case VN_M_DCX:                    /* Modem data compression off */
  10015.         return(dialdcoff ? dialdcoff : (m ? m->dc_off_str : ""));
  10016.  
  10017.       case VN_M_ECO:                    /* Modem error correction on */
  10018.         return(dialecon ? dialecon : (m ? m->ec_on_str : ""));
  10019.  
  10020.       case VN_M_ECX:                    /* Modem error correction off */
  10021.         return(dialecoff ? dialecoff : (m ? m->ec_off_str : ""));
  10022.  
  10023.       case VN_M_AAO:                    /* Modem autoanswer on */
  10024.         return(dialaaon ? dialaaon : (m ? m->aa_on_str : ""));
  10025.  
  10026.       case VN_M_AAX:                    /* Modem autoanswer off */
  10027.         return(dialaaoff ? dialaaoff : (m ? m->aa_off_str : ""));
  10028.  
  10029.       case VN_M_HUP:                    /* Modem hangup command */
  10030.         return(dialhcmd ? dialhcmd : (m ? m->hup_str : ""));
  10031.  
  10032.       case VN_M_HWF:                    /* Modem hardware flow command */
  10033.         return(dialhwfc ? dialhwfc : (m ? m->hwfc_str : ""));
  10034.  
  10035.       case VN_M_SWF:                    /* Modem software flow command */
  10036.         return(dialswfc ? dialswfc : (m ? m->swfc_str : ""));
  10037.  
  10038.       case VN_M_NFC:                    /* Modem no flow-control command */
  10039.         return(dialnofc ? dialnofc : (m ? m->nofc_str : ""));
  10040.  
  10041.       case VN_M_PDM:                    /* Modem pulse dialing mode */
  10042.         return(dialpulse ? dialpulse : (m ? m->pulse : ""));
  10043.  
  10044.       case VN_M_TDM:                    /* Modem tone dialing mode */
  10045.         return(dialtone ? dialtone : (m ? m->tone : ""));
  10046.  
  10047.       case VN_M_NAM:                    /* Modem full name */
  10048.         return(dialname ? dialname : (m ? m->name : ""));
  10049. #else
  10050.       case VN_M_INI:                    /* Modem init string */
  10051.       case VN_M_DCM:                    /* Modem dial command */
  10052.       case VN_M_DCO:                    /* Modem data compression on */
  10053.       case VN_M_DCX:                    /* Modem data compression off */
  10054.       case VN_M_ECO:                    /* Modem error correction on */
  10055.       case VN_M_ECX:                    /* Modem error correction off */
  10056.       case VN_M_AAO:                    /* Modem autoanswer on */
  10057.       case VN_M_AAX:                    /* Modem autoanswer off */
  10058.       case VN_M_HUP:                    /* Modem hangup command */
  10059.       case VN_M_HWF:                    /* Modem hardware flow command */
  10060.       case VN_M_SWF:                    /* Modem software flow command */
  10061.       case VN_M_NFC:                    /* Modem no flow-control command */
  10062.       case VN_M_PDM:                    /* Modem pulse dialing mode */
  10063.       case VN_M_TDM:                    /* Modem tone dialing mode */
  10064.       case VN_M_NAM:
  10065.         return("");
  10066. #endif /* NODIAL */
  10067.  
  10068.       case VN_ISTAT:                    /* INPUT status */
  10069.         sprintf(vvbuf, "%d", instatus);
  10070.         return(vvbuf);
  10071.  
  10072.       case VN_TEMP:                     /* Temporary directory */
  10073.         if (tempdir) {
  10074.             p = tempdir;
  10075.         } else {
  10076. #ifdef OS2
  10077. #ifdef NT
  10078.             p = getenv("K95TMP");
  10079. #else
  10080.             p = getenv("K2TMP");
  10081. #endif /* NT */
  10082.             if ( !p )
  10083.                 p = getenv("CK_TMP");
  10084.             if (!p)
  10085. #endif /* OS2 */
  10086.             p = getenv("TMPDIR");
  10087.             if (!p) p = getenv("TEMP");
  10088.             if (!p) p = getenv("TMP");
  10089.             if (!p)
  10090. #ifdef UNIX                             /* Systems that have a standard */
  10091.               p = "/tmp/";              /* temporary directory... */
  10092. #else
  10093. #ifdef datageneral
  10094.               p = ":TMP:";
  10095. #else
  10096.               p = "";
  10097. #endif /* datageneral */
  10098. #endif /* UNIX */
  10099.         }
  10100.         ckstrncpy(vvbuf,p,VVBUFL);
  10101.         p = vvbuf;
  10102.  
  10103. /* This needs generalizing for VOS, AOS/VS, etc... */
  10104.  
  10105.         while (*p) {
  10106. #ifdef OS2
  10107.             if (*p == '\\') *p = '/';
  10108. #endif /* OS2 */
  10109.             p++;
  10110.         }
  10111. #ifndef VMS
  10112.         if (p > vvbuf) {
  10113.             char c =                    /* Directory termination character */
  10114. #ifdef MAC
  10115.               ':'
  10116. #else
  10117. #ifdef datageneral
  10118.               ':'
  10119. #else
  10120. #ifdef STRATUS
  10121.               '>'
  10122. #else
  10123.               '/'
  10124. #endif /* STRATUS */
  10125. #endif /* datageneral */
  10126. #endif /* MAC */
  10127.                 ;
  10128.  
  10129.             if (*(p-1) != c) {
  10130.                 *p++ = c;
  10131.                 *p = NUL;
  10132.             }
  10133.         }
  10134. #endif /* VMS */
  10135.         return(vvbuf);
  10136.     } /* Break up long switch statements... */
  10137.  
  10138.     switch(y) {
  10139.       case VN_ERRNO:                    /* Error number */
  10140. #ifdef VMS
  10141.         {
  10142.             extern int vms_lasterr;
  10143.             sprintf(vvbuf, "%d", vms_lasterr);
  10144.         }
  10145. #else
  10146.         sprintf(vvbuf, "%d", errno);
  10147. #endif /* VMS */
  10148.         return(vvbuf);
  10149.  
  10150.       case VN_ERSTR:                    /* Error string */
  10151.         ckstrncpy(vvbuf,ck_errstr(),VVBUFL);
  10152.         return(vvbuf);
  10153.  
  10154. #ifndef NOXFER
  10155.       case VN_RPSIZ:                    /* RECEIVE packet-length */
  10156.         sprintf(vvbuf,"%d",urpsiz);
  10157.         return(vvbuf);
  10158.  
  10159.       case VN_WINDO:                    /* WINDOW slots */
  10160.         sprintf(vvbuf,"%d",wslotr);
  10161.         return(vvbuf);
  10162. #endif /* NOXFER */
  10163.  
  10164.       case VN_TFLN:                     /* TAKE-file line number */
  10165.         if (tlevel > -1) {
  10166.             sprintf(vvbuf, "%d", tfline[tlevel]);
  10167.             return(vvbuf);
  10168.         } else
  10169.           return("0");
  10170.  
  10171.       case VN_MDMSG:                    /* DIALRESULT */
  10172. #ifndef NODIAL
  10173.         return((char *)modemmsg);
  10174. #else
  10175.         return("");
  10176. #endif /* NODIAL */
  10177.  
  10178.       case VN_DNUM:                     /* DIALNUMBER */
  10179. #ifndef NODIAL
  10180.         return(dialnum ? (char *) dialnum : "");
  10181. #else
  10182.         return("");
  10183. #endif /* NODIAL */
  10184.  
  10185.       case VN_APC:
  10186.         sprintf(vvbuf, "%d",
  10187. #ifdef CK_APC
  10188.                 apcactive
  10189. #else
  10190.                 0
  10191. #endif /* CK_APC */
  10192.                 );
  10193.         return((char *)vvbuf);
  10194.  
  10195.       case VN_TRMK:
  10196.           sprintf(vvbuf, "%d",
  10197. #ifdef OS2
  10198.                 keymac
  10199. #else
  10200.                 0
  10201. #endif /* OS2 */
  10202.                 );
  10203.         return((char *)vvbuf);
  10204.  
  10205.       case VN_IPADDR:
  10206. #ifdef TCPSOCKET
  10207.         if (!myipaddr[0])
  10208.           getlocalipaddr();
  10209. #endif /* TCPSOCKET */
  10210.         sprintf(vvbuf, "%s",
  10211. #ifdef TCPSOCKET
  10212.                 (char *) myipaddr
  10213. #else
  10214.                 ""
  10215. #endif /* TCPSOCKET */
  10216.                 );
  10217.         return((char *)vvbuf);
  10218.  
  10219. #ifndef NOXFER
  10220.       case VN_CRC16:                    /* CRC-16 of most recent transfer */
  10221.         sprintf(vvbuf,"%d",crc16);
  10222.         return(vvbuf);
  10223. #endif /* NOXFER */
  10224.  
  10225. #ifdef CK_PID
  10226.       case VN_PID:
  10227. #ifdef IKSD
  10228. #ifdef CK_LOGIN
  10229.         if (inserver && isguest)
  10230.           return("");
  10231. #endif /* CK_LOGIN */
  10232. #endif /* IKSD */
  10233.         return(ckgetpid());
  10234. #endif /* CK_PID */
  10235.  
  10236. #ifndef NOXFER
  10237.       case VN_FNAM: {                   /* \v(filename) */
  10238.           extern char filnam[], ofn1[], *sfspec, *rrfspec;
  10239.           extern int what, lastxfer;
  10240.           char * tmp;
  10241.           switch (what) {               /* File transfer is in progress */
  10242.             case W_RECV:
  10243.             case W_REMO:
  10244.               return((char *)ofn1);
  10245.             default:                    /* Most recent file transferred */
  10246.               if (filnam[0]) {          /* (if any) */
  10247.                   return((char *)filnam);
  10248.               } else if (lastxfer == W_SEND && sfspec) {
  10249.                   if (fnspath == PATH_OFF)
  10250.                     zstrip(sfspec,&tmp);
  10251.                   else
  10252.                     tmp = sfspec;
  10253.                   return(tmp);
  10254.               } else if (lastxfer == W_RECV && rrfspec) {
  10255.                   if (fnrpath == PATH_OFF)
  10256.                     zstrip(rrfspec,&tmp);
  10257.                   else
  10258.                     tmp = rrfspec;
  10259.                   return(tmp);
  10260.               } else
  10261.                 return("");
  10262.           }
  10263.       }
  10264.       case VN_FNUM:                     /* \v(filenum) */
  10265.         sprintf(vvbuf,"%ld",filcnt);
  10266.         return((char *)vvbuf);
  10267. #endif /* NOXFER */
  10268.  
  10269. #ifdef PEXITSTAT
  10270.       case VN_PEXIT: {
  10271.           extern int pexitstat;
  10272.           sprintf(vvbuf,"%d",pexitstat);
  10273.           return((char *)vvbuf);
  10274.       }
  10275. #endif /* PEXITSTAT */
  10276.  
  10277. #ifndef NOXFER
  10278.       case VN_P_8BIT:
  10279.         vvbuf[0] = parity ? ebq : NUL;
  10280.         vvbuf[1] = NUL;
  10281.         return((char *)vvbuf);
  10282.  
  10283.       case VN_P_CTL: {
  10284.           extern CHAR myctlq;
  10285.           vvbuf[0] = myctlq;
  10286.           vvbuf[1] = NUL;
  10287.           return((char *)vvbuf);
  10288.       }
  10289.       case VN_P_RPT: {
  10290.           extern int rptena;
  10291.           vvbuf[0] = rptena ? rptq : NUL;
  10292.           vvbuf[1] = NUL;
  10293.           return((char *)vvbuf);
  10294.       }
  10295. #endif /* NOXFER */
  10296.  
  10297. #ifdef OS2
  10298.       case VN_REGN:
  10299.         return(get_reg_name());
  10300.       case VN_REGO:
  10301.         return(get_reg_corp());
  10302.       case VN_REGS:
  10303.         return(get_reg_sn());
  10304. #endif /* OS2 */
  10305.     } /* Break up long switch statements... */
  10306.  
  10307.     switch(y) {
  10308.       case VN_XPROG:
  10309. #ifdef OS2
  10310. #ifdef NT
  10311.         return("K-95");
  10312. #else
  10313.         return("K/2");
  10314. #endif /* NT */
  10315. #else
  10316.         return("C-Kermit");
  10317. #endif /* OS2 */
  10318.  
  10319.       case VN_EDITOR:
  10320. #ifdef NOFRILLS
  10321.         return("");
  10322. #else
  10323. #ifdef NOPUSH
  10324.         return("");
  10325. #else
  10326.         {
  10327.             extern char editor[];
  10328.             char *ss;
  10329.             if (!editor[0]) {
  10330.                 ss = getenv("EDITOR");
  10331.                 if (ss) {
  10332.                     ckstrncpy(editor,ss,CKMAXPATH);
  10333.                 }
  10334.             }
  10335.             debug(F110,"\v(editor)",editor,0);
  10336.             return(editor[0] ? (char *)editor : "");
  10337.         }
  10338. #endif /* NOPUSH */
  10339. #endif /* NOFRILLS */
  10340.  
  10341.       case VN_EDOPT:
  10342. #ifdef NOFRILLS
  10343.         return("");
  10344. #else
  10345. #ifdef NOPUSH
  10346.         return("");
  10347. #else
  10348.         {
  10349.             extern char editopts[];
  10350.             return(editopts[0] ? (char *)editopts : "");
  10351.         }
  10352. #endif /* NOPUSH */
  10353. #endif /* NOFRILLS */
  10354.  
  10355.       case VN_EDFILE:
  10356. #ifdef NOFRILLS
  10357.         return("");
  10358. #else
  10359. #ifdef NOPUSH
  10360.         return("");
  10361. #else
  10362.         {
  10363.             extern char editfile[];
  10364.             return(editfile[0] ? (char *)editfile : "");
  10365.         }
  10366. #endif /* NOPUSH */
  10367. #endif /* NOFRILLS */
  10368.  
  10369. #ifdef BROWSER
  10370.       case VN_BROWSR: {
  10371.           extern char browser[];
  10372.           if (!browser[0]) {
  10373.               s = getenv("BROWSER");
  10374.               if (s) ckstrncpy(browser,s,CKMAXPATH);
  10375.           }
  10376.           return(browser[0] ? (char *)browser : "");
  10377.       }
  10378.       case VN_BROPT: {
  10379.           extern char browsopts[];
  10380.           return(browsopts[0] ? (char *)browsopts : "");
  10381.       }
  10382.       case VN_URL: {
  10383.           extern char browsurl[];
  10384.           return(browsurl[0] ? (char *)browsurl : "");
  10385.       }
  10386. #endif /* BROWSER */
  10387.       case VN_HERALD:
  10388.         return((char *)versio);
  10389.  
  10390.       case VN_TEST: {                   /* test */
  10391.           extern char * ck_s_test, * ck_s_tver;
  10392.           if (!ck_s_test) ck_s_test = "";
  10393.           if (!ck_s_tver) ck_s_tver = "";
  10394.           if (*ck_s_test) {
  10395.               strcpy(vvbuf,ck_s_test);
  10396.               if (*ck_s_tver) {
  10397.                   strcat(vvbuf,".");
  10398.                   strcat(vvbuf,ck_s_tver);
  10399.               }
  10400.           } else
  10401.             strcpy(vvbuf,"0");
  10402.           return((char *)vvbuf);
  10403.       }
  10404.  
  10405. #ifndef NOXFER
  10406.       case VN_XFSTAT:                   /* xferstatus */
  10407.         x = xferstat;                   /* Like success */
  10408.         if (x > -1) x = (x == 0) ? 1 : 0; /* External value is reversed */
  10409.         sprintf(vvbuf,"%d",x);
  10410.         return((char *)vvbuf);
  10411.  
  10412.       case VN_XFMSG:                    /* xfermsg */
  10413.         return((char *)epktmsg);
  10414.  
  10415. #ifndef NOMSEND
  10416.       case VN_SNDL: {                   /* sendlist */
  10417.           extern int filesinlist;
  10418.           sprintf(vvbuf,"%d",filesinlist);
  10419.           return((char *)vvbuf);
  10420.       }
  10421. #endif /* NOMSEND */
  10422. #endif /* NOXFER */
  10423.  
  10424. #ifdef CK_TRIGGER
  10425.       case VN_TRIG: {
  10426.           extern char * triggerval;
  10427.           return(triggerval ? triggerval : "");
  10428.       }
  10429. #endif /* CK_TRIGGER */
  10430.  
  10431. #ifdef OS2
  10432.       case VN_MOU_X: {
  10433.           extern int MouseCurX;
  10434.           sprintf(vvbuf,"%d",MouseCurX);
  10435.           return((char *)vvbuf);
  10436.       }
  10437.       case VN_MOU_Y: {
  10438.           extern int MouseCurY;
  10439.           sprintf(vvbuf,"%d",MouseCurY);
  10440.           return((char *)vvbuf);
  10441.       }
  10442. #endif /* OS2 */
  10443.       case VN_PRINT: {
  10444.           extern int printpipe;
  10445.           extern char * printername;
  10446. #ifdef PRINTSWI
  10447.           extern int noprinter;
  10448.           if (noprinter) return("");
  10449. #endif /* PRINTSWI */
  10450.           sprintf(vvbuf,"%s%s",
  10451.                   printpipe ? "|" : "",
  10452.                   printername ? printername :
  10453. #ifdef OS2
  10454.                   "PRN"
  10455. #else
  10456.                   "(default)"
  10457. #endif /* OS2 */
  10458.                   );
  10459.           return((char *)vvbuf);
  10460.       }
  10461.     } /* Break up long switch statements... */
  10462.  
  10463.     switch(y) {
  10464.       case VN_ESC:                      /* Escape character */
  10465.         sprintf(vvbuf,"%d",escape);
  10466.         return((char *)vvbuf);
  10467.  
  10468.       case VN_INTIME:
  10469.         sprintf(vvbuf,"%ld",inetime);
  10470.         return((char *)vvbuf);
  10471.  
  10472.       case VN_INTMO:
  10473.         sprintf(vvbuf,"%d",inwait);
  10474.         return((char *)vvbuf);
  10475.  
  10476.       case VN_AUTHN:
  10477. #ifdef CK_AUTHENTICATION
  10478.         {
  10479.             extern char szUserNameAuthenticated[];
  10480.             return((char *)szUserNameAuthenticated);
  10481.         }
  10482. #else /* CK_AUTHENTICATION */
  10483.         return((char *)"");
  10484. #endif /* CK_AUTHENTICATION */
  10485.  
  10486.       case VN_AUTHS:
  10487. #ifdef CK_AUTHENTICATION
  10488.         switch (ck_tn_auth_valid()) {
  10489.           case AUTH_UNKNOWN:
  10490.             return((char *)"unknown");
  10491.           case AUTH_OTHER:
  10492.             return((char *)"other");
  10493.           case AUTH_USER:
  10494.             return((char *)"user");
  10495.           case AUTH_VALID:
  10496.             return((char *)"valid");
  10497.           case AUTH_REJECT:
  10498.           default:
  10499.             return((char *)"rejected");
  10500.         }
  10501. #else /* CK_AUTHENTICATION */
  10502.         return((char *)"rejected");
  10503. #endif /* CK_AUTHENTICATION */
  10504.  
  10505.       case VN_AUTHT:
  10506. #ifdef CK_AUTHENTICATION
  10507. #ifdef CK_SSL
  10508.         if ((ssl_active_flag || tls_active_flag) &&
  10509.         ck_tn_auth_valid() == AUTH_VALID &&
  10510.         (!TELOPT_U(TELOPT_AUTHENTICATION) ||
  10511.          ck_tn_authenticated() == AUTHTYPE_NULL ||
  10512.          ck_tn_authenticated() == AUTHTYPE_AUTO))
  10513.       return("X_509_CERTIFICATE");
  10514.         else
  10515. #endif /* CK_SSL */
  10516.       return(AUTHTYPE_NAME(ck_tn_authenticated()));
  10517. #else /* CK_AUTHENTICATION */
  10518.         return((char *)"NULL");
  10519. #endif /* CK_AUTHENTICATION */
  10520.  
  10521. #ifdef CK_KERBEROS
  10522.       case VN_K4PRN: {
  10523.           extern char * krb4_d_principal;
  10524.           if (krb4_d_principal)
  10525.             ckstrncpy(vvbuf,krb4_d_principal,VVBUFL+1);
  10526.           else
  10527.             *vvbuf = NUL;
  10528.           return((char *)vvbuf);
  10529.       }
  10530.       case VN_K5PRN: {
  10531.           extern char * krb5_d_principal;
  10532.           if (krb5_d_principal)
  10533.             ckstrncpy(vvbuf,krb5_d_principal,VVBUFL+1);
  10534.           else
  10535.             *vvbuf = NUL;
  10536.           return((char *)vvbuf);
  10537.       }
  10538.       case VN_K4RLM: {
  10539.           extern char * krb4_d_realm;
  10540.           if (krb4_d_realm) {
  10541.               ckstrncpy(vvbuf,krb4_d_realm,VVBUFL+1);
  10542.           } else {
  10543.               char * s = ck_krb4_getrealm();
  10544.               ckstrncpy(vvbuf,s ? s : "",VVBUFL+1);
  10545.           }
  10546.           return((char *)vvbuf);
  10547.       }
  10548.       case VN_K4SRV: {
  10549.           extern char * krb4_d_srv;
  10550.           if (krb4_d_srv)
  10551.             ckstrncpy(vvbuf,krb4_d_srv,VVBUFL+1);
  10552.           else
  10553.             strcpy(vvbuf,"rcmd");
  10554.           return((char *)vvbuf);
  10555.       }
  10556.       case VN_K5RLM: {
  10557.           extern char * krb5_d_realm;
  10558.           extern char * krb5_d_cc;
  10559.           if (krb5_d_realm) {
  10560.               ckstrncpy(vvbuf,krb5_d_realm,VVBUFL+1);
  10561.           } else {
  10562.               char * s = ck_krb5_getrealm(krb5_d_cc);
  10563.               ckstrncpy(vvbuf,s,VVBUFL+1);
  10564.           }
  10565.           return((char *)vvbuf);
  10566.       }
  10567.       case VN_K5CC: {
  10568.           extern char * krb5_d_cc;
  10569.           if (krb5_d_cc)
  10570.             ckstrncpy(vvbuf,krb5_d_cc,VVBUFL+1);
  10571.           else
  10572.             ckstrncpy(vvbuf,ck_krb5_get_cc_name(),VVBUFL+1);
  10573.           return((char *)vvbuf);
  10574.       }
  10575.       case VN_K5SRV: {
  10576.           extern char * krb5_d_srv;
  10577.           if (krb5_d_srv)
  10578.             ckstrncpy(vvbuf,krb5_d_srv,VVBUFL+1);
  10579.           else
  10580.             strcpy(vvbuf,"host");
  10581.           return((char *)vvbuf);
  10582.       }
  10583.       case VN_K4ENO: {
  10584.         extern char * krb4_errno;
  10585.         sprintf(vvbuf,"%d",krb4_errno);
  10586.         return((char *)vvbuf);
  10587.       }
  10588.       case VN_K5ENO: {
  10589.         extern char * krb5_errno;
  10590.         sprintf(vvbuf,"%d",krb5_errno);
  10591.         return((char *)vvbuf);
  10592.       }
  10593.       case VN_K4EMSG: {
  10594.         extern char * krb4_errmsg;
  10595.         ckstrncpy(vvbuf,krb4_errmsg?krb4_errmsg:"",VVBUFL+1);
  10596.         return((char *)vvbuf);
  10597.       }
  10598.       case VN_K5EMSG: {
  10599.         extern char * krb5_errmsg;
  10600.         ckstrncpy(vvbuf,krb5_errmsg,VVBUFL+1);
  10601.         return((char *)vvbuf);
  10602.       }
  10603. #endif /* CK_KERBEROS */
  10604. #ifdef CK_SSL
  10605.       case VN_X509_S:
  10606.     if (ssl_active_flag)
  10607.       ckstrncpy(vvbuf,ssl_get_subject_name(ssl_con),VVBUFL+1);
  10608.     else if (tls_active_flag)
  10609.       ckstrncpy(vvbuf,ssl_get_subject_name(tls_con),VVBUFL+1);
  10610.     else
  10611.       ckstrncpy(vvbuf,"",VVBUFL+1);
  10612.     return((char *)vvbuf);
  10613.       case VN_X509_I:
  10614.     if (ssl_active_flag)
  10615.       ckstrncpy(vvbuf,ssl_get_issuer_name(ssl_con),VVBUFL+1);
  10616.     else if (tls_active_flag)
  10617.       ckstrncpy(vvbuf,ssl_get_issuer_name(tls_con),VVBUFL+1);
  10618.     else
  10619.       ckstrncpy(vvbuf,"",VVBUFL+1);
  10620.     return((char *)vvbuf);
  10621. #endif /* CK_SSL */
  10622.  
  10623.       case VN_OSNAM:
  10624. #ifdef IKSD
  10625. #ifdef CK_LOGIN
  10626.         if (inserver && isguest)
  10627.           return("");
  10628. #endif /* CK_LOGIN */
  10629. #endif /* IKSD */
  10630. #ifdef CK_UTSNAME
  10631.         {
  10632.             extern char unm_nam[];
  10633.             return((char *)unm_nam);
  10634.         }
  10635. #else
  10636.         for (x = y = 0; x < VVBUFL; x++) {
  10637.             if (ckxsys[x] == SP && y == 0) continue;
  10638.             vvbuf[y++] = (char) ((ckxsys[x] == SP) ? '_' : ckxsys[x]);
  10639.         }
  10640.         vvbuf[y] = NUL;
  10641.         return(vvbuf);
  10642. #endif /* CK_UTSNAME */
  10643.  
  10644.       case VN_OSVER: {
  10645. #ifdef CK_UTSNAME
  10646.           extern char unm_ver[];
  10647. #ifdef IKSD
  10648. #ifdef CK_LOGIN
  10649.           if (inserver && isguest)
  10650.             return("");
  10651. #endif /* CK_LOGIN */
  10652. #endif /* IKSD */
  10653.           return((char *)unm_ver);
  10654. #else
  10655.           return("");
  10656. #endif /* CK_UTSNAME */
  10657.       }
  10658.  
  10659.       case VN_OSREL: {
  10660. #ifdef CK_UTSNAME
  10661.           extern char unm_rel[];
  10662. #ifdef IKSD
  10663. #ifdef CK_LOGIN
  10664.           if (inserver && isguest)
  10665.             return("");
  10666. #endif /* CK_LOGIN */
  10667. #endif /* IKSD */
  10668.           return((char *)unm_rel);
  10669. #else
  10670.           return("");
  10671. #endif /* CK_UTSNAME */
  10672.       }
  10673.     } /* Break up long switch statements... */
  10674.  
  10675.     switch(y) {
  10676.       case VN_NAME: {
  10677.           extern char * myname;
  10678.           return(myname);
  10679.       }
  10680.  
  10681.       case VN_MODL: {
  10682. #ifdef CK_UTSNAME
  10683.           extern char unm_mod[], unm_mch[];
  10684.           int y = VVBUFL - 1;
  10685.           char * s = unm_mod;
  10686. #endif /* CK_UTSNAME */
  10687. #ifdef IKSD
  10688. #ifdef CK_LOGIN
  10689.           if (inserver && isguest)
  10690.             return("");
  10691. #endif /* CK_LOGIN */
  10692. #endif /* IKSD */
  10693.  
  10694. #ifdef COMMENT                          /* was HPUX */
  10695.           if (!unm_mod[0] && !nopush)
  10696.             zzstring("\\fcommand(model)",&s,&y);
  10697. /*
  10698.    Another possibility would be:
  10699.      "\\fcommand(ksh -c 'whence model 1>&- && model || uname -m')"
  10700.    But that would depend on having ksh.
  10701. */
  10702. #else
  10703. #ifdef OSF32                            /* Digital UNIX 3.2 and higher... */
  10704. /* Note: Ultrix has /etc/sizer, but it is not publicly executable. */
  10705. /* sizer -c outputs 'cpu:<tab><tab>"DECxxxx"' */
  10706.           if (!unm_mod[0]) {
  10707.               char * p;
  10708.               int flag = 0;
  10709.               zzstring("\\fcommand(/usr/sbin/sizer -c)",&s,&y);
  10710.               debug(F110,"DU model",unm_mod,0);
  10711.               s = unm_mod;
  10712.               p = unm_mod;
  10713.               while (*p) {              /* Extract the part in quotes */
  10714.                   if (*p == '"') {
  10715.                       if (flag)
  10716.                         break;
  10717.                       flag = 1;
  10718.                       p++;
  10719.                       continue;
  10720.                   }
  10721.                   if (flag)
  10722.                     *s++ = *p;
  10723.                   p++;
  10724.               }
  10725.               *s = NUL;
  10726.           }
  10727. #endif /* OSF32 */
  10728. #endif /* COMMENT */
  10729.  
  10730. #ifdef CK_UTSNAME
  10731.           if (unm_mod[0])
  10732.             return((char *)unm_mod);
  10733.           else
  10734.             return((char *)unm_mch);
  10735. #else
  10736.           return("");
  10737. #endif /* CK_UTSNAME */
  10738.       }
  10739.  
  10740. #ifdef IBMX25
  10741.       /* X.25 variables (local and remote address) */
  10742.       case VN_X25LA:
  10743.         if (!local_nua[0] && !x25local_nua(local_nua))
  10744.           *vvbuf = NULL;
  10745.         else
  10746.           ckstrncpy(vvbuf,local_nua,VVBUFL+1);
  10747.         return((char *)vvbuf);
  10748.  
  10749.       case VN_X25RA:
  10750.         if (!remote_nua[0])
  10751.           *vvbuf = NULL;
  10752.         else
  10753.           ckstrncpy(vvbuf,remote_nua,VVBUFL+1);
  10754.         return((char *)vvbuf);
  10755. #endif /* IBMX25 */
  10756.  
  10757. #ifndef NODIAL
  10758.       case VN_PDSFX: {
  10759.           extern char pdsfx[];
  10760.           return((char *)pdsfx);
  10761.       }
  10762.       case VN_DTYPE: {
  10763.           extern int dialtype;
  10764.           sprintf(vvbuf,"%d",dialtype);
  10765.           return((char *)vvbuf);
  10766.       }
  10767. #endif /* NODIAL */
  10768.  
  10769. #ifdef UNIX
  10770.       case VN_LCKPID: {
  10771.           extern char lockpid[];
  10772.           return((char *)lockpid);
  10773.       }
  10774. #endif /* UNIX */
  10775.  
  10776. #ifndef NOXFER
  10777.       case VN_BLK:
  10778.         sprintf(vvbuf,"%d",bctr);
  10779.         return((char *)vvbuf);
  10780.  
  10781.       case VN_TFTIM:
  10782.         sprintf(vvbuf,
  10783. #ifdef GFTIMER
  10784.                 "%ld", (long)(fptsecs + 0.5)
  10785. #else
  10786.                 "%d", tsecs
  10787. #endif /* GFTIMER */
  10788.                 );
  10789.         return((char *)vvbuf);
  10790. #endif /* NOXFER */
  10791.  
  10792.       case VN_HWPAR:
  10793.       case VN_SERIAL: {
  10794.           int sb;
  10795.           char c, * ss;
  10796.           extern int stopbits;
  10797.           vvbuf[0] = NUL;
  10798.           if (hwparity && local && !network)
  10799.             ss = parnam((char)hwparity);
  10800.           else
  10801.             ss = parnam((char)parity);
  10802.           if (y == VN_HWPAR) {
  10803.               strcpy(vvbuf,ss);
  10804.               return((char *)vvbuf);
  10805.           }
  10806.           c = ss[0];
  10807.           if (islower(c)) c = toupper(c);
  10808.           sb = stopbits;
  10809.           if (sb < 1)
  10810.             sb = (speed <= 110L) ? 2 : 1;
  10811.           if (hwparity)
  10812.             sprintf(vvbuf," 8%c%d",c,sb);
  10813.           else if (parity)
  10814.             sprintf(vvbuf," 7%c%d",c,sb);
  10815.           else
  10816.             sprintf(vvbuf," 8N%d",sb);
  10817.           return((char *)vvbuf);
  10818.       }
  10819.  
  10820. #ifdef UNIX
  10821.       case VN_LCKDIR: {
  10822. #ifndef NOUUCP
  10823.           extern char * uucplockdir;
  10824.           ckstrncpy(vvbuf,uucplockdir,VVBUFL);
  10825.           x = strlen(vvbuf);
  10826.           if (x > 0) {
  10827.               if (vvbuf[x-1] != '/') {
  10828.                   vvbuf[x] = '/';
  10829.                   vvbuf[x+1] = NUL;
  10830.               }
  10831.           }
  10832. #else
  10833.           vvbuf[0] = NUL;
  10834. #endif /* NOUUCP */
  10835.           return((char *)vvbuf);
  10836.       }
  10837. #endif /* UNIX */
  10838.     } /* Break up long switch statements... */
  10839.  
  10840.     switch(y) {
  10841. #ifndef NODIAL
  10842.       case VN_DM_LP:
  10843.       case VN_DM_SP:
  10844.       case VN_DM_PD:
  10845.       case VN_DM_TD:
  10846.       case VN_DM_WA:
  10847.       case VN_DM_WD:
  10848.       case VN_DM_RC: {
  10849.           extern char * getdm();
  10850.           ckstrncpy(vvbuf,getdm(y),VVBUFL);
  10851.           return((char *)vvbuf);
  10852.       }
  10853. #endif /* NODIAL */
  10854.  
  10855.       case VN_TY_LN:
  10856.       case VN_TY_LC: {
  10857.           extern int typ_lines;
  10858.           sprintf(vvbuf,"%d",typ_lines);
  10859.           return((char *)vvbuf);
  10860.       }
  10861.       case VN_TY_LM: {
  10862.           extern int typ_mtchs;
  10863.           sprintf(vvbuf,"%d",typ_mtchs);
  10864.           return((char *)vvbuf);
  10865.       }
  10866.       case VN_MACLVL:
  10867.         sprintf(vvbuf,"%d",maclvl);
  10868.         return((char *)vvbuf);
  10869.     } /* Break up long switch statements... */
  10870.  
  10871.     switch(y) {
  10872. #ifndef NOXFER
  10873.       case VN_XF_BC:
  10874.         sprintf(vvbuf,"%d",crunched);
  10875.         return((char *)vvbuf);
  10876.  
  10877.       case VN_XF_TM:
  10878.         sprintf(vvbuf,"%d",timeouts);
  10879.         return((char *)vvbuf);
  10880.  
  10881.       case VN_XF_RX:
  10882.         sprintf(vvbuf,"%d",retrans);
  10883.         return((char *)vvbuf);
  10884. #endif /* NOXFER */
  10885.  
  10886.       case VN_MS_CD:                    /* Modem signals */
  10887.       case VN_MS_CTS:
  10888.       case VN_MS_DSR:
  10889.       case VN_MS_DTR:
  10890.       case VN_MS_RI:
  10891.       case VN_MS_RTS: {
  10892.           int x, z = -1;
  10893.           x = ttgmdm();                 /* Try to get them */
  10894.           if (x > -1) {
  10895.               switch (y) {
  10896.                 case VN_MS_CD:  z = (x & BM_DCD) ? 1 : 0; break;
  10897.                 case VN_MS_DSR: z = (x & BM_DSR) ? 1 : 0; break;
  10898.                 case VN_MS_CTS: z = (x & BM_CTS) ? 1 : 0; break;
  10899. #ifdef MAC
  10900.                 case VN_MS_DTR: z = (x & BM_DTR) ? 1 : 0; break;
  10901. #else
  10902. #ifndef STRATUS
  10903.                 case VN_MS_RI:  z = (x & BM_RNG) ? 1 : 0; break;
  10904. #ifndef NT
  10905.                 case VN_MS_DTR: z = (x & BM_DTR) ? 1 : 0; break;
  10906.                 case VN_MS_RTS: z = (x & BM_RTS) ? 1 : 0; break;
  10907. #endif /* NT */
  10908. #endif /* STRATUS */
  10909. #endif /* MAC */
  10910.               }
  10911.           }
  10912.           sprintf(vvbuf,"%d",z);
  10913.           return((char *)vvbuf);
  10914.       }
  10915.       case VN_MATCH:                    /* INPUT MATCH */
  10916.         return(inpmatch ? inpmatch : "");
  10917.  
  10918.       case VN_SLMSG: {                  /* SET LINE / HOST message */
  10919.           extern char * slmsg;
  10920.           vvbuf[0] = NUL;
  10921.           if (slmsg)
  10922.             ckstrncpy(vvbuf,slmsg,VVBUFL);
  10923.          return(vvbuf);
  10924.       }
  10925.  
  10926.       case VN_TXTDIR:                   /* TEXTDIR */
  10927.         return(k_info_dir ? k_info_dir : "");
  10928.  
  10929. #ifdef FNFLOAT
  10930.       case VN_MA_PI:
  10931.         ckstrncpy(vvbuf,"3.1415926535897932384626433832795",fp_digits+2);
  10932.         return(vvbuf);
  10933.  
  10934.       case VN_MA_E:
  10935.         ckstrncpy(vvbuf,"2.7182818284590452353602874713527",fp_digits+2);
  10936.         return(vvbuf);
  10937.  
  10938.       case VN_MA_PR:
  10939.         sprintf(vvbuf,"%d",fp_digits);
  10940.         return(vvbuf);
  10941. #endif /* FNFLOAT */
  10942.  
  10943.       case VN_CMDBL:
  10944.         sprintf(vvbuf,"%d",CMDBL);
  10945.         return(vvbuf);
  10946.  
  10947. #ifdef CKCHANNELIO
  10948.       case VN_FERR: {
  10949.           extern int z_error;
  10950.           sprintf(vvbuf,"%d",z_error);
  10951.           return(vvbuf);
  10952.       }
  10953.       case VN_FMAX: {
  10954.           extern int z_maxchan;
  10955.           sprintf(vvbuf,"%d",z_maxchan);
  10956.           return(vvbuf);
  10957.       }
  10958.       case VN_FCOU: {
  10959.           extern int z_filcount;
  10960.           sprintf(vvbuf,"%d",z_filcount);
  10961.           return(vvbuf);
  10962.       }
  10963. #endif /* CKCHANNELIO */
  10964.  
  10965. #ifndef NODIAL
  10966.       case VN_DRTR: {
  10967.           extern int dialcount;
  10968.           sprintf(vvbuf,"%d",dialcount);
  10969.           return(vvbuf);
  10970.       }
  10971. #endif /* NODIAL */
  10972.  
  10973. #ifndef NOLOCAL
  10974.       case VN_CXTIME:
  10975.         sprintf(vvbuf,"%ld",dologshow(0));
  10976.         return(vvbuf);
  10977. #endif /* NOLOCAL */
  10978.  
  10979.       case VN_BYTE:
  10980.         sprintf(vvbuf,"%d",byteorder);
  10981.         return(vvbuf);
  10982.  
  10983.       case VN_KBCHAR:
  10984.         vvbuf[0] = NUL;
  10985.         vvbuf[1] = NUL;
  10986.         if (kbchar > 0)
  10987.           vvbuf[0] = (kbchar & 0xff);
  10988.         return(vvbuf);
  10989.  
  10990.       case VN_TTYNAM: {
  10991. #ifdef HAVECTTNAM
  10992.           extern char cttnam[];
  10993.           return((char *)cttnam);
  10994. #else
  10995.           return(CTTNAM);
  10996. #endif /* HAVECTTNAM */
  10997.       }
  10998.  
  10999.     } /* End of variable-name switches */
  11000.  
  11001.     fnsuccess = 0;
  11002.     if (fnerror) {
  11003.         fnsuccess = 0;
  11004.     }
  11005.     if (fndiags) {
  11006.         if (!embuf)
  11007.            strcpy(embuf,"<ERROR:NO_SUCH_VARIABLE>");
  11008.         printf("?%s\n",embuf);
  11009.         return((char *)embuf);
  11010.     } else
  11011.       return("");
  11012. }
  11013. #endif /* NOSPL */
  11014.  
  11015.  
  11016. /*
  11017.   X X S T R I N G  --  Expand variables and backslash codes.
  11018.  
  11019.     int xxtstring(s,&s2,&n);
  11020.  
  11021.   Expands \ escapes via recursive descent.
  11022.   Argument s is a pointer to string to expand (source).
  11023.   Argument s2 is the address of where to put result (destination).
  11024.   Argument n is the length of the destination string (to prevent overruns).
  11025.   Returns -1 on failure, 0 on success,
  11026.     with destination string null-terminated and s2 pointing to the
  11027.     terminating null, so that subsequent characters can be added.
  11028. */
  11029.  
  11030. #define XXDEPLIM 100                    /* Recursion depth limit */
  11031.  
  11032. int
  11033. zzstring(s,s2,n) char *s; char **s2; int *n; {
  11034.     int x,                              /* Current character */
  11035.         y,                              /* Worker */
  11036.         pp,                             /* Paren level */
  11037.         kp,                             /* Brace level */
  11038.         argn,                           /* Function argument counter */
  11039.         n2,                             /* Local copy of n */
  11040.         d,                              /* Array dimension */
  11041.         vbi,                            /* Variable id (integer form) */
  11042.         argl,                           /* String argument length */
  11043.         nx;                             /* Save original length */
  11044.  
  11045.     char vb,                            /* Variable id (char form) */
  11046.         *vp,                            /* Pointer to variable definition */
  11047.         *new,                           /* Local pointer to target string */
  11048.         *old,                           /* Save original target pointer */
  11049.         *p,                             /* Worker */
  11050.         *q;                             /* Worker */
  11051.     char *r  = (char *)0;               /* For holding function args */
  11052.     char *r2 = (char *)0;
  11053.     char *r3p;
  11054.  
  11055. #ifndef NOSPL
  11056.     char vnambuf[VNAML];                /* Buffer for variable/function name */
  11057.     char *argp[FNARGS];                 /* Pointers to function args */
  11058. #endif /* NOSPL */
  11059.  
  11060.     static int depth = 0;               /* Call depth, avoid overflow */
  11061.  
  11062.     n2 = *n;                            /* Make local copies of args */
  11063.     nx = n2;
  11064.  
  11065.     new = *s2;                          /* for one less level of indirection */
  11066.     old = new;
  11067.  
  11068. #ifndef NOSPL
  11069.     ispattern = 0;                      /* For \fpattern() */
  11070. #endif /* NOSPL */
  11071.     depth++;                            /* Sink to a new depth */
  11072.     if (depth > XXDEPLIM) {             /* Too deep? */
  11073.         printf("?definition is circular or too deep\n");
  11074.         debug(F101,"zzstring fail","",depth);
  11075.         depth = 0;
  11076.         *new = NUL;
  11077.         return(-1);
  11078.     }
  11079.     if (!s || !new) {                   /* Watch out for null pointers */
  11080.         debug(F101,"zzstring fail 2","",depth);
  11081.         *new = NUL;
  11082.         depth = 0;
  11083.         return(-1);
  11084.     }
  11085.     argl = (int)strlen(s);              /* Get length of source string */
  11086.     debug(F111,"zzstring entry",s,argl);
  11087.     if (argl == 0) {                    /* Empty string */
  11088.         debug(F111,"zzstring empty arg",s,argl);
  11089.         depth = 0;
  11090.         *new = NUL;
  11091.         return(0);
  11092.     }
  11093.     if (argl < 0) {                     /* Watch out for garbage */
  11094.         debug(F101,"zzstring fail 3","",depth);
  11095.         *new = NUL;
  11096.         depth = 0;
  11097.         return(-1);
  11098.     }
  11099.     while (x = *s) {                    /* Loop for all characters */
  11100.         if (x != CMDQ) {                /* Is it the command-quote char? */
  11101.             *new++ = *s++;              /* No, normal char, just copy */
  11102.             if (--n2 < 0) {             /* and count it, careful of overflow */
  11103.                 debug(F101,"zzstring overflow 1","",depth);
  11104.                 depth = 0;
  11105.                 return(-1);
  11106.             }
  11107.             continue;
  11108.         }
  11109.  
  11110. /* We have the command-quote character. */
  11111.  
  11112.         x = *(s+1);                     /* Get the following character. */
  11113.         if (isupper(x)) x = tolower(x);
  11114.         switch (x) {                    /* Act according to variable type */
  11115. #ifndef NOSPL
  11116.           case 0:                       /* It's a lone backslash */
  11117.             *new++ = *s++;
  11118.             if (--n2 < 0) {
  11119.                 debug(F101,"zzstring overflow 2","",0);
  11120.                 return(-1);
  11121.             }
  11122.             break;
  11123.           case '%':                     /* Variable */
  11124.             s += 2;                     /* Get the letter or digit */
  11125.             vb = *s++;                  /* and move source pointer past it */
  11126.             vp = NULL;                  /* Assume definition is empty */
  11127.             if (vb >= '0' && vb <= '9') { /* Digit for macro arg */
  11128.                 if (maclvl < 0)         /* Digit variables are global */
  11129.                   vp = g_var[vb];       /* if no macro is active */
  11130.                 else                    /* otherwise */
  11131.                   vp = m_arg[maclvl][vb - '0']; /* they're on the stack */
  11132.             } else if (vb == '*' && maclvl >= 0) {
  11133.                 vp = m_line[maclvl];
  11134.                 if (!vp) vp = "";
  11135.             } else {
  11136.                 if (isupper(vb)) vb += ('a'-'A');
  11137.                 vp = g_var[vb];         /* Letter for global variable */
  11138.             }
  11139.             if (!vp) vp = "";
  11140. #ifdef COMMENT
  11141.             if (vp) {                   /* If definition not empty */
  11142. #endif /* COMMENT */
  11143.                 debug(F110,"xxstring %n vp",vp,0);
  11144.                 if (zzstring(vp,&new,&n2) < 0) { /* call self to evaluate it */
  11145.                     debug(F101,"zzstring fail 6","",depth);
  11146.                     return(-1);         /* Pass along failure */
  11147.                 }
  11148. #ifdef COMMENT
  11149.             } else {
  11150.                 debug(F110,"xxstring %n vp","(NULL)",0);
  11151.                 n2 = nx;
  11152.                 new = old;
  11153.                 *new = NUL;
  11154.             }
  11155. #endif /* COMMENT */
  11156.             break;
  11157.           case '&':                     /* An array reference */
  11158.             x = arraynam(s,&vbi,&d);    /* Get name and subscript */
  11159.             debug(F111,"zzstring arraynam",s,x);
  11160.             if (x < 0) {
  11161.                 debug(F101,"zzstring fail 7","",depth);
  11162.                 return(-1);
  11163.             }
  11164.             pp = 0;                     /* Bracket counter */
  11165.             while (*s) {                /* Advance source pointer... */
  11166.                 if (*s == '[') pp++;
  11167.                 if (*s == ']' && --pp == 0) break;
  11168.                 s++;
  11169.             }
  11170.             if (*s == ']') s++;         /* ...past the closing bracket. */
  11171.  
  11172.             x = chkarray(vbi,d);        /* Array is declared? */
  11173.             debug(F101,"zzstring chkarray","",x);
  11174.             if (x > 0) {
  11175. #ifdef COMMENT
  11176.                 char * s1 = NULL;
  11177. #endif /* COMMENT */
  11178.                 vbi -= ARRAYBASE;       /* Convert name to index */
  11179.  
  11180. #ifdef COMMENT
  11181.                 if (vbi == 0) {         /* Argument vector array */
  11182.                     extern char ** toparg, ** m_xarg[];
  11183.                     extern int n_xarg[];
  11184.                     if (maclvl < 0) {
  11185.                         if (topargc >= d) {
  11186.                             s1 = toparg[d];
  11187.                         }
  11188.                     } else {
  11189.                         if (n_xarg[maclvl] >= d) {
  11190.                             s1 = m_xarg[maclvl][d];
  11191.                         }
  11192.                     }
  11193.                     if (s1) {
  11194.                         if (zzstring(s1,&new,&n2) < 0) { /* evaluate */
  11195.                             debug(F101,"zzstring fail 7.5","",depth);
  11196.                             return(-1); /* Pass along failure */
  11197.                         }
  11198.                     } else {
  11199.                         old = new;
  11200.                         n2 = nx;
  11201.                     }
  11202.                 } else
  11203. #endif /* COMMENT */
  11204.                   if (a_dim[vbi] >= d) {        /* If subscript in range */
  11205.                     char **ap;
  11206. #ifndef COMMENT
  11207.                     debug(F110,"zzstring a_ptr[vbi]",a_ptr[vbi],0);
  11208.                     debug(F110,"zzstring a_ptr[vbi][d]",a_ptr[vbi][d],0);
  11209. #endif /* COMMENT */
  11210.                     ap = a_ptr[vbi];    /* get data pointer */
  11211.                     if (ap) {           /* and if there is one */
  11212.                         if (ap[d]) {    /* If definition not empty */
  11213.                             debug(F111,"zzstring ap[d]",ap[d],d);
  11214.                             if (zzstring(ap[d],&new,&n2) < 0) { /* evaluate */
  11215.                                 debug(F101,"zzstring fail 8","",depth);
  11216.                                 return(-1); /* Pass along failure */
  11217.                             }
  11218.                         }
  11219.                     } else {
  11220.                         old = new;
  11221.                         n2 = nx;
  11222.                     }
  11223.                 }
  11224.             }
  11225.             break;
  11226.  
  11227.           case 'f':                     /* A builtin function */
  11228.             q = vnambuf;                /* Copy the name */
  11229.             y = 0;                      /* into a separate buffer */
  11230.             s += 2;                     /* point past 'F' */
  11231.             while (y++ < VNAML) {
  11232.                 if (*s == '(') { s++; break; } /* Look for open paren */
  11233.                 if ((*q = *s) == NUL) break;   /* or end of string */
  11234.                 s++; q++;
  11235.             }
  11236.             *q = NUL;                   /* Terminate function name */
  11237.             if (y >= VNAML) {           /* Handle pathological case */
  11238.                 while (*s && (*s != '(')) /* of very long string entered */
  11239.                   s++;                    /* as function name. */
  11240.                 if (*s == ')') s++;       /* Skip past it. */
  11241.             }
  11242.             r = r2 = malloc(argl+2);    /* And make a place to copy args */
  11243.             /* debug(F101,"zzstring r2","",r2); */
  11244.             if (!r2) {                  /* Watch out for malloc failure */
  11245.                 debug(F101,"zzstring fail 9","",depth);
  11246.                 *new = NUL;
  11247.                 depth = 0;
  11248.                 return(-1);
  11249.             }
  11250.             if (r3) free(r3); /* And another to copy literal arg string */
  11251.             r3 = malloc(argl+2);
  11252.             /* debug(F101,"zzstring r3","",r3); */
  11253.             if (!r3) {
  11254.                 debug(F101,"zzstring fail 10","",depth);
  11255.                 depth = 0;
  11256.                 *new = NUL;
  11257.                 if (r2) free(r2);
  11258.                 return(-1);
  11259.             } else
  11260.               r3p = r3;
  11261.             argn = 0;                   /* Argument counter */
  11262.             argp[argn++] = r;           /* Point to first argument */
  11263.             y = 0;                      /* Completion flag */
  11264.             pp = 1;                     /* Paren level (already have one). */
  11265.             kp = 0;
  11266.             while (1) {                 /* Copy each argument, char by char. */
  11267.                 *r3p++ = *s;            /* This is a literal copy for \flit */
  11268.                 if (!*s) break;
  11269.  
  11270.                 if (*s == '{') {        /* Left brace */
  11271.                     kp++;
  11272.                 }
  11273.                 if (*s == '}') {        /* Right brace */
  11274.                     kp--;
  11275.                 }
  11276.                 if (*s == '(' && kp <= 0) { /* Open paren not in brace */
  11277.                     pp++;               /* Count it */
  11278.                 }
  11279.                 *r = *s;                /* Now copy resulting byte */
  11280.                 if (!*r)                /* If NUL, done. */
  11281.                   break;
  11282.                 if (*r == ')' && kp <= 0) { /* Closing paren, count it. */
  11283.                     if (--pp == 0) {    /* Final one? */
  11284.                         *r = NUL;       /* Make it a terminating null */
  11285.                         *(r3p - 1) = NUL;
  11286.                         s++;            /* Point past it in source string */
  11287.                         y = 1;          /* Flag we've got all the args */
  11288.                         break;          /* Done with while loop */
  11289.                     }
  11290.                 }
  11291.                 if (*r == ',' && kp <= 0) { /* Comma */
  11292.                     if (pp == 1) {          /* If not within ()'s, */
  11293.                         if (argn >= FNARGS) { /* Too many args */
  11294.                             s++; r++;   /* Keep collecting flit() string */
  11295.                             continue;
  11296.                         }
  11297.                         *r = NUL;           /* New arg, skip past comma */
  11298.                         argp[argn++] = r+1; /* In range, point to new arg */
  11299.                     }                   /* Otherwise just skip past  */
  11300.                 }
  11301.                 s++; r++;               /* Advance pointers */
  11302.             }
  11303.             debug(F111,"zzstring function name",vnambuf,y);
  11304.             debug(F110,"zzstring function r3",r3,0);
  11305.             if (!y) {                   /* If we didn't find closing paren */
  11306.                 debug(F101,"zzstring fail 11","",depth);
  11307.                 if (r2) { free(r2); r2 = NULL; }
  11308.                 if (r3) { free(r3); r3 = NULL; } /* Remember this is global */
  11309.                 return(-1);             /* Return failure */
  11310.             }
  11311. #ifdef DEBUG
  11312.             if (deblog)
  11313.               for (y = 0; y < argn; y++)
  11314.                 debug(F111,"zzstring function arg",argp[y],y);
  11315. #endif /* DEBUG */
  11316.             vp = fneval(vnambuf,argp,argn,r3); /* Evaluate the function. */
  11317.             if (vp) {                   /* If definition not empty */
  11318.                 while (*new++ = *vp++)  /* copy it to output string */
  11319.                   if (--n2 < 0) {       /* watch out for overflow */
  11320.                       debug(F101,"zzstring fail 12","",depth);
  11321.                       if (r2) { free(r2); r2 = NULL; }
  11322.                       if (r3) { free(r3); r3 = NULL; }
  11323.                       return(-1);
  11324.                   }
  11325.                 new--;                  /* Back up over terminating null */
  11326.                 n2++;                   /* to allow for further deposits. */
  11327.             }
  11328.             if (r2) { free(r2); r2 = NULL; }
  11329.             if (r3) { free(r3); r3 = NULL; }
  11330.             break;
  11331.           case '$':                     /* An environment variable */
  11332.           case 'v':                     /* Or a named builtin variable. */
  11333.           case 'm':                     /* Or a macro /long variable */
  11334.           case 's':                     /* 196 Macro substring */
  11335.           case ':':                     /* 196 \-variable substring */
  11336.             pp = 0;
  11337.             p = s+2;                    /* $/V/M must be followed by (name) */
  11338.             if (*p != '(') {            /* as in \$(HOME) or \V(count) */
  11339.                 *new++ = *s++;          /* If not, just copy it */
  11340.                 if (--n2 < 0) {
  11341.                     debug(F101,"zzstring overflow 3","",depth);
  11342.                     return(-1);
  11343.                 }
  11344.                 break;
  11345.             }
  11346.             pp++;
  11347.             p++;                        /* Point to 1st char of name */
  11348.             q = vnambuf;                /* Copy the name */
  11349.             y = 0;                      /* into a separate buffer */
  11350.             while (y++ < VNAML) {       /* Watch out for name too long */
  11351.                 if (*p == '(') {        /* Parens can be nested... */
  11352.                     pp++;
  11353.                 } else if (*p == ')') { /* Name properly terminated with ')' */
  11354.                     pp--;
  11355.                     if (pp == 0) {
  11356.                         p++;            /* Move source pointer past ')' */
  11357.                         break;
  11358.                     }
  11359.                 }
  11360.                 if ((*q = *p) == NUL)   /* String ends before ')' */
  11361.                   break;
  11362.                 p++; q++;               /* Advance pointers */
  11363.             }
  11364.             *q = NUL;                   /* Terminate the variable name */
  11365.             if (y >= VNAML) {           /* Handle pathological case */
  11366.                 while (*p && (*p != ')')) /* of very long string entered */
  11367.                   p++;                    /* as variable name. */
  11368.                 if (*p == ')') p++;       /* Skip ahead to the end of it. */
  11369.             }
  11370.             s = p;                      /* Adjust global source pointer */
  11371.             p = malloc((int)strlen(vnambuf) + 1); /* Make temporary space */
  11372.             if (p) {                    /* If we got the space */
  11373.                 vp = vnambuf;           /* Point to original */
  11374.                 strcpy(p,vp);           /* Make a copy of it */
  11375.                 y = VNAML;              /* Length of name buffer */
  11376.                 zzstring(p,&vp,&y);     /* Evaluate the copy */
  11377.                 free(p);                /* Free the temporary space */
  11378.                 p = NULL;
  11379.             }
  11380.             debug(F110,"zzstring vname",vnambuf,0);
  11381.             q = NULL;
  11382.             if (x == '$') {             /* Look up its value */
  11383.                 vp = getenv(vnambuf);   /* This way for environment variable */
  11384.             } else if (x == 'm' || x == 's' || x == ':') { /* Macro / substr */
  11385.                 int k, x1 = -1, x2 = -1;
  11386.                 k = strlen(vnambuf);
  11387.                 /* \s(name[n:m]) -- Compact substring notation */
  11388.                 debug(F000,"XXX 0",vnambuf,x);
  11389.                 if ((x == 's' || x == ':') && (k > 1)) { /* Substring wanted */
  11390.                     if (vnambuf[k-1] == ']') {
  11391.                         int i;
  11392.                         for (i = k-1; i > 0; i--) {
  11393.                             if (vnambuf[i] == '[') {
  11394.                                 char * p = NULL;
  11395.                                 p = (char *)malloc(k - i + 8);
  11396.                                 if (p) {
  11397.                                     /* Now this is a dirty trick... */
  11398.                                     sprintf(p,"\\&a%s",&vnambuf[i]);
  11399.                                     debug(F110,"XXX",p,0);
  11400.                                     arraybounds(p,&x1,&x2);
  11401.                                     debug(F101,"XXX x1","",x1);
  11402.                                     debug(F101,"XXX x2","",x2);
  11403.                                     if (x1 < 1) x1 = 1;
  11404.                                     x1--; /* Adjust to 0-base */
  11405.                                     free(p);
  11406.                                     vnambuf[i] = NUL;
  11407.                                 }
  11408.                             }
  11409.                         }
  11410.                     }
  11411.                 }
  11412.                 if (x == ':') {
  11413.                     vp = vnambuf;
  11414.                 } else {
  11415.                     debug(F110,"XXX mlook",vnambuf,0);
  11416.                     y = mlook(mactab,vnambuf,nmac); /* get definition */
  11417.                     debug(F101,"XXX mlook","",y);
  11418.                     if (y > -1) {               /* Got definition */
  11419.                         vp = mactab[y].mval;
  11420.                     } else {
  11421.                         vp = NULL;
  11422.                     }
  11423.                 }
  11424.                 if (vp) {
  11425.                     if ((x == 's' || x == ':') && (k > 1)) {
  11426.                         /* Compact substring notation */
  11427.                         if (x2 == 0) {  /* Length */
  11428.                             vp = NULL;
  11429.                         } else if (x1 > -1) { /* Start */
  11430.                             k = strlen(vp);
  11431.                             debug(F111,"XXX vp",vp,k);
  11432.                             if (x1 > k) {  /* If it's off the end, */
  11433.                                 vp = NULL; /* result is empty */
  11434.                                 debug(F111,"XXX x1 > k",ckitoa(x1),k);
  11435.                             } else if (k > 0) {
  11436.                                 debug(F101,"XXX k > 0","",k);
  11437.                                 if (q = malloc(k+1)) {
  11438.                                     strcpy(q,vp);
  11439.                                     if ((x2 > -1) && ((x1 + x2) <= k)) {
  11440.                                         debug(F101,"XXX poke","",x1+x2);
  11441.                                         q[x1+x2] = NUL;
  11442.                                     }
  11443.                                     vp = q+x1;
  11444.                                     debug(F111,"XXX B",vp,k);
  11445.                                 }  else vp = NULL;
  11446.                             } else vp = NULL;
  11447.                         }
  11448. #ifdef DEBUG
  11449.                         if (deblog) {
  11450.                             if (!vp) {
  11451.                                 debug(F100,"XXX vp NULL","",0);
  11452.                             } else {
  11453.                                 k = strlen(vp);
  11454.                                 debug(F111,"XXX C",vp,k);
  11455.                             }
  11456.                         }
  11457. #endif /* DEBUG */
  11458.                     }
  11459.                 }
  11460.             } else {                    /* or */
  11461.                 vp = nvlook(vnambuf);   /* this way for builtin variable */
  11462.             }
  11463.             if (vp) {                   /* If definition not empty */
  11464.                 while (*new++ = *vp++)  /* copy it to output string. */
  11465.                   if (--n2 < 0) {
  11466.                       if (q) free(q);
  11467.                       debug(F101,"zzstring overflow 4","",depth);
  11468.                       return(-1);
  11469.                   }
  11470.                 new--;                  /* Back up over terminating null */
  11471.                 n2++;                   /* to allow for further deposits. */
  11472.             }
  11473.             if (q) {
  11474.                 free(q);
  11475.                 q = NULL;
  11476.             }
  11477.             break;
  11478. #endif /* NOSPL */                      /* Handle \nnn even if NOSPL. */
  11479.  
  11480. #ifndef NOKVERBS
  11481.         case 'K':
  11482.         case 'k': {
  11483.             extern struct keytab kverbs[];
  11484.             extern int nkverbs;
  11485. #define K_BUFLEN 30
  11486.             char kbuf[K_BUFLEN + 1];    /* Key verb name buffer */
  11487.             int x, y, z, brace = 0;
  11488.             s += 2;
  11489. /*
  11490.   We assume that the verb name is {braced}, or it extends to the end of the
  11491.   string, s, or it ends with a space, control character, or backslash.
  11492. */
  11493.             p = kbuf;                   /* Copy verb name into local buffer */
  11494.             x = 0;
  11495.             if (*s == '{')  {
  11496.                 s++;
  11497.                 brace++;
  11498.             }
  11499.             while ((x++ < K_BUFLEN) && (*s > SP) && (*s != CMDQ)) {
  11500.                 if (brace && *s == '}') {
  11501.                     s++;
  11502.                     break;
  11503.                 }
  11504.                 *p++ = *s++;
  11505.             }
  11506.             brace = 0;
  11507.             *p = NUL;                   /* Terminate. */
  11508.             p = kbuf;                   /* Point back to beginning */
  11509.             debug(F110,"zzstring kverb",p,0);
  11510.             y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */
  11511.             debug(F101,"zzstring lookup",0,y);
  11512.             if (y > -1) {
  11513.                 dokverb(VCMD,y);
  11514. #ifndef NOSPL
  11515.             } else {                    /* Is it a macro? */
  11516.                 y = mxlook(mactab,p,nmac);
  11517.                 if (y > -1) {
  11518.                     debug(F111,"zzstring mxlook",s,y);
  11519.                     if ((z = dodo(y,NULL,cmdstk[cmdlvl].ccflgs)) > 0) {
  11520.                         if (cmpush() > -1) {  /* Push command parser state */
  11521.                             extern int ifc;
  11522.                             int ifcsav = ifc; /* Push IF condition on stack */
  11523.                             y = parser(1);    /* New parser to execute macro */
  11524.                             cmpop();          /* Pop command parser */
  11525.                             ifc = ifcsav;     /* Restore IF condition */
  11526.                             if (y == 0) {     /* No errors, ignore actions */
  11527.                                 p = mrval[maclvl+1]; /* If OK set return val */
  11528.                                 if (p == NULL) p = "";
  11529.                             }
  11530.                         } else {                /* Can't push any more */
  11531.                             debug(F101,"zzstring pushed too deep","",depth);
  11532.                             printf(
  11533.                                "\n?Internal error: zzstring stack overflow\n"
  11534.                                    );
  11535.                             while (cmpop() > -1);
  11536.                             p = "";
  11537.                         }
  11538.                     }
  11539.                 }
  11540. #endif /* NOSPL */
  11541.             }
  11542.             break;
  11543.         }
  11544. #endif /* NOKVERBS */
  11545.  
  11546.         default:                        /* Maybe it's a backslash code */
  11547.           y = xxesc(&s);                /* Go interpret it */
  11548.           if (y < 0) {                  /* Upon failure */
  11549.               *new++ = (char) x;        /* Just quote the next character */
  11550.               s += 2;                   /* Move past the pair */
  11551.               n2 -= 2;
  11552.               if (n2 < 0) {
  11553.                   debug(F101,"zzstring overflow 5","",depth);
  11554.                   return(-1);
  11555.               }
  11556.               continue;                 /* and go back for more */
  11557.           } else {
  11558.               *new++ = (char) y;        /* else deposit interpreted value */
  11559.               if (--n2 < 0) {
  11560.                   debug(F101,"zzstring overflow 6","",depth);
  11561.                   return(-1);
  11562.               }
  11563.           }
  11564.         }
  11565.     }
  11566.     *new = NUL;                         /* Terminate the new string */
  11567.     depth--;                            /* Adjust stack depth gauge */
  11568.     *s2 = new;                          /* Copy results back into */
  11569.     *n = n2;                            /* the argument addresses */
  11570.     debug(F101,"zzstring ok","",depth);
  11571.     return(0);                          /* and return. */
  11572. }
  11573. #endif /* NOICP */
  11574.