1 #include "ckcsym.h"
2
3 /* C K U U S 4 -- "User Interface" for C-Kermit, part 4 */
4
5 /*
6 Authors:
7 Frank da Cruz <fdc@columbia.edu>,
8 The Kermit Project, New York City
9 Jeffrey E Altman <jaltman@secure-endpoints.com>
10 Secure Endpoints Inc., New York City
11
12 Copyright (C) 1985, 2021,
13 Trustees of Columbia University in the City of New York.
14 All rights reserved. See the C-Kermit COPYING.TXT file or the
15 copyright text in the ckcmai.c module for disclaimer and permissions.
16 Last update:
17 Tue Sep 14 15:09:25 2021
18 */
19
20 /*
21 File ckuus4.c -- Functions moved from other ckuus*.c modules to even
22 out their sizes.
23 */
24 #include "ckcdeb.h"
25 #include "ckcasc.h"
26 #include "ckcker.h"
27 #include "ckcnet.h" /* Network symbols */
28 #include "ckuusr.h"
29 #include "ckuver.h"
30 #include "ckcxla.h" /* Character sets */
31
32 #ifdef HAVE_LOCALE
33 #include <locale.h>
34 #endif /* HAVE_LOCALE */
35
36 #ifdef CK_AUTHENTICATION
37 #include "ckuath.h"
38 #endif /* CK_AUTHENTICATION */
39 #ifdef CK_SSL
40 #include "ck_ssl.h"
41 #endif /* CK_SSL */
42
43 #ifdef VMS
44 #include <errno.h> /* For \v(errno) */
45 extern char * ckvmserrstr(unsigned long);
46 #ifndef OLD_VMS
47 #include <lib$routines.h> /* Not for VAX C 2.4 */
48 #else
49 #include <libdef.h>
50 #endif /* OLD_VMS */
51 _PROTOTYP(int vmsttyfd, (void) );
52 #endif /* VMS */
53
54 #ifdef OS2
55 #ifndef NT
56 #define INCL_NOPM
57 #define INCL_VIO /* Needed for ckocon.h */
58 #include <os2.h>
59 #undef COMMENT
60 #else
61 #include <windows.h>
62 #include <tapi.h>
63 #include "ckntap.h"
64 #define APIRET ULONG
65 #endif /* NT */
66 #include "ckocon.h"
67 #include "ckodir.h" /* [jt] 2013/11/21 - for MAXPATHLEN */
68 #include "ckoetc.h"
69 int StartedFromDialer = 0;
70 HWND hwndDialer = 0;
71 LONG KermitDialerID = 0;
72 #ifdef putchar
73 #undef putchar
74 #endif /* putchar */
75 #define putchar(x) conoc(x)
76 #ifdef CK_PID
77 #include <process.h>
78 #endif /* CK_PID */
79 #endif /* OS2 */
80
81 #ifdef KUI
82 extern struct keytab * term_font;
83 extern int ntermfont, tt_font, tt_font_size;
84 #endif /* KUI */
85
86 extern xx_strp xxstring;
87
88 #ifdef DEC_TCPIP
89 #include <descrip>
90 #include <dvidef>
91 #include <dcdef>
92 #endif /* DEC_TCPIP */
93
94 #ifndef NOICP
95 extern char *tfnam[];
96 extern int tlevel;
97 #endif /* NOICP */
98
99 #ifdef FNFLOAT
100 #include <math.h> /* Floating-point functions */
101 #endif /* FNFLOAT */
102
103 int fp_rounding = 0; /* Nonzero if printf("%f") rounds */
104 int fp_digits = 0; /* Digits of floating point precision */
105
106 extern int quiet, network, xitsta, escape, nopush, xferstat,
107 exitonclose, tn_exit, ttnproto, autodl, flow, byteorder, what, lastxfer;
108
109 extern int filepeek, nscanfile, makestrlen;
110 extern char * k_info_dir;
111
112 #ifndef MAC
113 #ifndef AMIGA
114 extern int ttyfd;
115 #endif /* MAC */
116 #endif /* AMIGA */
117
118 #ifdef TNCODE
119 extern int tn_nlm, tn_b_nlm, tn_b_xfer, tn_sb_bug;
120 extern int tn_rem_echo;
121 extern int tn_b_meu, tn_b_ume, tn_auth_krb5_des_bug;
122 #endif /* TNCODE */
123
124 static char * lastkwval = NULL;
125
126 char * xferfile = NULL;
127 int xferlog = 0;
128
129 extern int local, xargc, stayflg, rcflag, bgset, backgrd, cfilef,
130 inserver, srvcdmsg, success;
131
132 #ifdef VMS
133 extern int batch;
134 #endif /* VMS */
135
136 extern char cmdfil[], *versio, *ckxsys, **xargv;
137 extern char lasttakeline[];
138 #ifdef DEBUG
139 extern char debfil[]; /* Debug log file name */
140 extern int debtim;
141 #endif /* DEBUG */
142
143 extern int noinit;
144
145 static char ndatbuf[10];
146
147 char *months[] = {
148 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
149 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
150 };
151
152 char *
zzndate()153 zzndate() { /* Returns today's date as yyyymmdd */
154 char * p = NULL;
155 int x;
156
157 /* WARNING - This will fail if asctime() returns non-English month names */
158
159 ztime(&p); /* Get "asctime" string */
160 if (p == NULL || *p == NUL) return("");
161 for (x = 20; x < 24; x++) /* yyyy */
162 ndatbuf[x - 20] = p[x];
163 ndatbuf[6] = (char) ((p[8] == ' ') ? '0' : p[8]);
164 ndatbuf[7] = p[9]; /* dd */
165 for (x = 0; x < 12; x++) /* mm */
166 if (!strncmp(p+4,months[x],3)) break;
167 if (x == 12) {
168 ndatbuf[4] = ndatbuf[5] = '?';
169 } else {
170 x++;
171 ndatbuf[4] = (char) ((x < 10) ? '0' : '1');
172 ndatbuf[5] = (char) ((x % 10) + 48);
173 }
174 ndatbuf[8] = NUL;
175 debug(F110,"zzndate return",ndatbuf,0);
176 return((char *)ndatbuf);
177 }
178
179 #ifdef DCMDBUF
180 extern struct cmdptr *cmdstk;
181 extern char *line, *tmpbuf;
182 #else
183 extern struct cmdptr cmdstk[];
184 extern char line[], tmpbuf[];
185 #endif /* DCMDBUF */
186
187 #ifdef OS2
188 extern char exedir[];
189 #else
190 extern char * exedir;
191 #endif /* OS2 */
192
193 extern int nettype;
194
195 #ifndef NOICP /* Most of this file... */
196 #ifdef CKLOGDIAL
197 extern char diafil[];
198 #endif /* CKLOGDIAL */
199
200 #ifndef AMIGA
201 #ifndef MAC
202 #include <signal.h>
203 #endif /* MAC */
204 #endif /* AMIGA */
205
206 #ifdef SV68 /* July 2006 believe it or not */
207 #ifndef SEEK_CUR
208 #include <unistd.h>
209 #endif /* SEEK_CUR */
210 #endif /* SV68 */
211
212 #ifdef SCO32 /* June 2011 believe it or not... */
213 #ifdef XENIX
214 #ifndef SEEK_CUR
215 #include <unistd.h>
216 #endif /* SEEK_CUR */
217 #endif /* XENIX */
218 #endif /* SCO32 */
219
220 #ifdef STRATUS /* Stratus Computer, Inc. VOS */
221 #ifdef putchar
222 #undef putchar
223 #endif /* putchar */
224 #define putchar(x) conoc(x)
225 #ifdef getchar
226 #undef getchar
227 #endif /* getchar */
228 #define getchar(x) coninc(0)
229 #endif /* STRATUS */
230
231
232 #ifdef ANYX25
233 extern int revcall, closgr, cudata;
234 int x25ver;
235 extern char udata[];
236 #ifndef IBMX25
237 extern int npadx3;
238 extern CHAR padparms[];
239 extern struct keytab padx3tab[];
240 #endif /* !IBMX25 */
241 #ifdef IBMX25
242 /* global variables only available for IBM X.25 - possibly interesting for
243 * other implementations
244 */
245 extern x25addr_t local_nua;
246 extern x25addr_t remote_nua;
247 #endif /* IBMX25 */
248 #endif /* ANYX25 */
249
250 #ifdef NETCONN
251 #ifndef NODIAL
252 extern int nnetdir;
253 extern char *netdir[];
254 #endif /* NODIAL */
255 extern char ipaddr[];
256
257 #ifdef CK_NETBIOS
258 extern unsigned short netbiosAvail;
259 extern unsigned long NetbeuiAPI;
260 extern unsigned char NetBiosName[];
261 extern unsigned char NetBiosAdapter;
262 extern unsigned char NetBiosLSN;
263 #endif /* CK_NETBIOS */
264
265 #ifdef TCPSOCKET
266 extern char myipaddr[];
267 extern int tcp_rdns;
268 #ifdef CK_DNS_SRV
269 extern int tcp_dns_srv;
270 #endif /* CK_DNS_SRV */
271 extern char * tcp_address;
272 #ifndef NOHTTP
273 extern char * tcp_http_proxy;
274 #endif /* NOHTTP */
275 #ifdef NT
276 #ifdef CK_SOCKS
277 extern char * tcp_socks_svr;
278 #ifdef CK_SOCKS_NS
279 extern char * tcp_socks_ns;
280 #endif /* CK_SOCKS_NS */
281 #endif /* CK_SOCKS */
282 #endif /* NT */
283
284 #ifndef NOTCPOPTS
285 #ifdef SOL_SOCKET
286 #ifdef SO_LINGER
287 extern int tcp_linger;
288 extern int tcp_linger_tmo;
289 #endif /* SO_LINGER */
290 #ifdef SO_DONTROUTE
291 extern int tcp_dontroute;
292 #endif /* SO_DONTROUTE */
293 #ifdef TCP_NODELAY
294 extern int tcp_nodelay;
295 #endif /* TCP_NODELAY */
296 #ifdef SO_SNDBUF
297 extern int tcp_sendbuf;
298 #endif /* SO_SNDBUF */
299 #ifdef SO_RCVBUF
300 extern int tcp_recvbuf;
301 #endif /* SO_RCVBUF */
302 #ifdef SO_KEEPALIVE
303 extern int tcp_keepalive;
304 #endif /* SO_KEEPALIVE */
305 #endif /* SOL_SOCKET */
306 #endif /* NOTCPOPTS */
307 #endif /* TCPSOCKET */
308 #endif /* NETCONN */
309
310 extern char * floname[];
311
312 #ifndef NOSPL
313 extern int vareval; /* Variable evaluation method */
314 extern int fndiags; /* Function diagnostics on/off */
315 extern int divbyzero;
316 int itsapattern = 0;
317 int isinbuflen = 0;
318 int isjoin = 0;
319 #ifdef CK_APC
320 extern int apcactive; /* Nonzero = APC command was rec'd */
321 extern int apcstatus; /* Are APC commands being processed? */
322 #ifdef DCMDBUF
323 extern char *apcbuf; /* APC command buffer */
324 #else
325 extern char apcbuf[];
326 #endif /* DCMDBUF */
327 #endif /* CK_APC */
328
329 extern char evalbuf[]; /* EVALUATE result */
330 extern char uidbuf[], pwbuf[], prmbuf[];
331 _PROTOTYP( static char * fneval, (char *, char * [], int, char * ) );
332 _PROTOTYP( static VOID myflsh, (void) );
333 _PROTOTYP( static char * getip, (char *) );
334 _PROTOTYP( int delta2sec, (char *, long *) );
335
336 #ifdef NEWFTP
337 _PROTOTYP( char * ftp_cpl_mode, (void) );
338 _PROTOTYP( char * ftp_dpl_mode, (void) );
339 _PROTOTYP( char * ftp_authtype, (void) );
340 #endif /* NEWFTP */
341
342 #ifndef NOHTTP
343 _PROTOTYP( char * http_host, (void) );
344 _PROTOTYP( int http_isconnected, (void) );
345 _PROTOTYP( char * http_security, (void) );
346 #endif /* NOHTTP */
347
348 #ifndef NOSEXP
349 _PROTOTYP( char * dosexp, (char *) );
350 int fsexpflag = 0;
351 #endif /* NOSEXP */
352
353 static char hexdigits[16] = {
354 '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
355 };
356 extern char * tempdir;
357
358 #ifdef CK_REXX
359 extern char rexxbuf[];
360 #endif /* CK_REXX */
361
362 extern int tfline[];
363
364 char *wkdays[] = {
365 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
366 };
367 #endif /* NOSPL */
368
369 #ifdef OS2
370 extern char startupdir[], inidir[];
371 #else
372 #ifdef VMSORUNIX
373 extern char startupdir[];
374 #endif /* VMSORUNIX */
375 #endif /* OS2 */
376
377 #ifdef OS2
378 _PROTOTYP (int os2getcp, (void) );
379 #ifdef TCPSOCKET
380 extern char tcpname[];
381 #endif /* TCPSOCKET */
382 extern int tcp_avail;
383 #ifdef DECNET
384 extern int dnet_avail;
385 #endif /* DECNET */
386 #ifdef SUPERLAT
387 extern int slat_avail;
388 #endif /* SUPERLAT */
389
390 #ifndef NOTERM
391 extern int tt_type, max_tt;
392 extern struct tt_info_rec tt_info[];
393 #endif /* NOTERM */
394 extern int tt_rows[], tt_cols[];
395 #else /* OS2 */
396 extern int tt_rows, tt_cols;
397 #endif /* OS2 */
398
399 #ifdef CK_TAPI
400 extern int tttapi;
401 extern int tapipass;
402 extern struct keytab * tapilinetab;
403 extern struct keytab * _tapilinetab;
404 extern int ntapiline;
405 #endif /* CK_TAPI */
406
407 extern struct keytab colxtab[];
408 extern int ncolx;
409
410 extern char ttname[], *zinptr, *kermrc;
411 extern char inidir[];
412
413 extern int activecmd, remonly, cmd_rows, cmd_cols, parity, seslog,
414 sessft, sosi, hwparity, tsecs, xargs, zincnt, tlevel, insilence, cmdmsk,
415 timint, timef, inbufsize, dialog, binary, carrier, cdtimo, cmask, duplex,
416 fmask, inecho, nmac, turnch, turn, kbchar;
417
418 #ifndef NOXFER
419 extern CHAR eol, mypadc, mystch, padch, seol, stchr, * epktmsg, feol;
420 extern char *cksysid;
421 extern struct ck_p ptab[];
422 extern int
423 protocol, prefixing, xfrbel, xfrcan, xfrint, xfrchr, xfrnum, pktpaus,
424 lscapr, lscapu, xfermode, dest, slostart, maxrps, maxsps, maxtry, mypadn,
425 npad, pkttim, bigrbsiz, bigsbsiz, keep, atcapr, autopar, bctr, bctu,
426 crunched, ckdelay, ebq, ebqflg, pktlog, retrans, rpackets, rptflg, rptq,
427 rtimo, spackets, spsiz, spsizf, spsizr, timeouts, fncact, fncnv, urpsiz,
428 wmax, wslotn, wslotr, fdispla, spmax, fnrpath, fnspath;
429 extern long crc16;
430 #endif /* NOXFER */
431
432 #ifdef OS2
433 extern int zxpn;
434 extern int viewonly;
435 #endif /* OS2 */
436
437 #ifndef NOXFER
438 #ifdef GFTIMER
439 extern CKFLOAT fptsecs, fpxfsecs;
440 #endif /* GFTIMER */
441 extern long xfsecs, tfcps;
442
443 #ifdef CK_TMPDIR
444 extern char *dldir;
445 #endif /* CK_TMPDIR */
446 #endif /* NOXFER */
447
448 #ifdef RECURSIVE
449 extern int recursive;
450 #endif /* RECURSIVE */
451
452 #ifdef VMS
453 extern int frecl;
454 #endif /* VMS */
455
456 extern CK_OFF_T ffc, tfc, tlci, tlco;
457 extern long filcnt, rptn, speed, ccu, ccp, vernum, xvernum;
458
459 #ifndef NOSPL
460 extern char fspec[], myhost[];
461 #endif /* NOSPL */
462
463 extern char *tfnam[]; /* Command file names */
464
465 extern char pktfil[], /* Packet log file name */
466 #ifdef TLOG
467 trafil[], /* Transaction log file name */
468 #endif /* TLOG */
469 sesfil[]; /* Session log file name */
470
471 #ifndef NOXMIT /* TRANSMIT command variables */
472 extern char xmitbuf[];
473 extern int xmitf, xmitl, xmitx, xmits, xmitw, xmitt;
474 #endif /* NOXMIT */
475
476 extern int cmdlvl;
477
478 #ifndef NOSPL
479 /* Script programming language items */
480 extern char **a_ptr[]; /* Arrays */
481 extern int a_dim[];
482 static char * inpmatch = NULL;
483 #ifdef CKFLOAT
484 char * inpscale = NULL;
485 #endif /* CKFLOAT */
486 extern char * inpbuf, inchar[]; /* Buffers for INPUT and REINPUT */
487 extern char *inpbp; /* And pointer to same */
488 static char *r3 = (char *)0;
489 extern int incount; /* INPUT character count */
490 extern int m_found; /* MINPUT result */
491 extern int maclvl; /* Macro invocation level */
492 extern struct mtab *mactab; /* Macro table */
493 extern char *mrval[];
494 extern int macargc[], topargc;
495
496 #ifdef COMMENT
497 extern char *m_line[];
498 extern char *topline;
499 #endif /* COMMENT */
500
501 extern char *m_arg[MACLEVEL][10]; /* You have to put in the dimensions */
502 extern char *g_var[GVARS]; /* for external 2-dimensional arrays. */
503 #ifdef DCMDBUF
504 extern int *count, *inpcas;
505 #else
506 extern int count[], inpcas[];
507 #endif /* DCMDBUF */
508 #endif /* NOSPL */
509
510 #ifdef UNIX
511 extern int haslock; /* For UUCP locks */
512 extern char flfnam[];
513 #ifndef USETTYLOCK
514 extern char lock2[];
515 #endif /* USETTYLOCK */
516 #endif /* UNIX */
517
518 #ifdef OS2ORUNIX
519 extern int maxnam, maxpath; /* Longest name, path length */
520 #endif /* OS2ORUNIX */
521
522 extern int mdmtyp, mdmsav;
523
524 #ifndef NODIAL
525 /* DIAL-related variables */
526 extern char modemmsg[];
527 extern MDMINF *modemp[]; /* Pointers to modem info structs */
528 extern int nmdm, dialhng, dialtmo, dialksp, dialdpy, dialsrt, dialsta;
529 extern int dialrtr, dialint, dialrstr, dialcon, dialcq, dialfld;
530 extern int mdmspd, dialec, dialdc, dialmth, dialmauto, dialesc;
531 extern char *dialnum, *dialini, *dialdir[], *dialcmd, *dialnpr,
532 *dialdcon, *dialdcoff, *dialecon, *dialecoff, *dialhcmd, *diallac,
533 *dialhwfc, *dialswfc, *dialnofc, *dialpulse, *dialtone, *dialname,
534 *dialaaon, *dialaaoff, *dialmac;
535 extern char *diallcc, *dialixp, *dialixs, *dialldp, *diallds,
536 *dialpxi, *dialpxo, *dialsfx, *dialtfp;
537 extern char *diallcp, *diallcs;
538 extern int ntollfree, ndialpxx, nlocalac;
539 extern char *dialtfc[], *diallcac[], *dialpxx[], *matchpxx;
540 extern int ndialpucc, ndialtocc;
541 extern char *dialtocc[], *dialpucc[];
542 extern int ndialdir, dialcnf, dialcvt, dialidt, dialpace;
543 extern long dialmax, dialcapas;
544
545 extern struct keytab mdmtab[];
546
547 #ifdef BIGBUFOK
548 #define ARGBUFSIZ 8191
549 #else
550 #define ARGBUFSIZ 1023
551 #endif /* BIGBUFOK */
552
553 #ifdef BIGBUFOK
554 extern char * dialmsg[];
555 #endif /* BIGBUFOK */
556
557 #endif /* NODIAL */
558
559 #ifndef NOCSETS
560 /* Translation stuff */
561 extern int nfilc;
562 extern struct keytab fcstab[];
563 extern int fcharset, tcharset, tslevel, language, nlng, tcsr, tcsl;
564 extern int dcset7, dcset8;
565 extern struct keytab lngtab[];
566 extern struct csinfo fcsinfo[], tcsinfo[];
567 extern struct langinfo langs[];
568 #ifdef CK_ANSIC
569 extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
570 extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
571 #else
572 extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */
573 extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */
574 #endif /* CK_ANSIC */
575 #ifdef UNICODE
576 extern int ucsbom, ucsorder;
577 #endif /* UNICODE */
578 #endif /* NOCSETS */
579
580 #ifndef NOSPL
581 /* Built-in variable names, maximum length VNAML (20 characters) */
582
583 struct keytab vartab[] = {
584 { "_line", VN_TFLN, CM_INV}, /* 192 */
585 { "apcactive", VN_APC, CM_INV}, /* 192 */
586 #ifdef NT
587 { "appdata", VN_APPDATA, 0}, /* 201 */
588 #endif /* NT */
589 { "argc", VN_ARGC, 0},
590 { "args", VN_ARGS, 0},
591 { "authname", VN_AUTHN, 0}, /* 196 */
592 { "authstate", VN_AUTHS, 0}, /* 195 */
593 { "authtype", VN_AUTHT, 0}, /* 195 */
594 { "bits", VN_BITS, 0}, /* 212 */
595 { "blockcheck",VN_BLK, 0}, /* 195 */
596 #ifdef BROWSER
597 { "browser", VN_BROWSR,0}, /* 193 */
598 { "browsopts", VN_BROPT, 0}, /* 193 */
599 { "browsurl", VN_URL, 0}, /* 193 */
600 { "buildid", VN_BUILD, 0}, /* 199 */
601 #endif /* BROWSER */
602 { "byteorder", VN_BYTE, 0}, /* 195 */
603 #ifndef NOCSETS
604 { "charset", VN_CSET, 0}, /* 192 */
605 #endif /* NOCSETS */
606 { "cmdbufsize",VN_CMDBL, 0}, /* 195 */
607 { "cmdfile", VN_CMDF, 0},
608 { "cmdlevel", VN_CMDL, 0},
609 { "cmdsource", VN_CMDS, 0},
610 { "cols", VN_COLS, 0}, /* 190 */
611 #ifdef NT
612 { "common", VN_COMMON, 0}, /* 201 */
613 #endif /* NT */
614 { "connection",VN_CONN, 0}, /* 190 */
615 { "count", VN_COUN, 0},
616 #ifndef NOXFER
617 { "cps", VN_CPS, 0}, /* 190 */
618 #endif /* NOXFER */
619 { "cpu", VN_CPU, 0},
620 #ifndef NOXFER
621 { "crc16", VN_CRC16, 0}, /* 192 */
622 { "ctty", VN_TTYNAM,0}, /* 196 */
623 #endif /* NOXFER */
624 #ifndef NOLOGDIAL
625 #ifndef NOLOCAL
626 { "cx_time", VN_CXTIME,0}, /* 195 */
627 { "cx_status", VN_CX_STA,0}, /* 199 */
628 #endif /* NOLOCAL */
629 #endif /* NOLOGDIAL */
630 #ifndef NODIAL
631 { "d$ac", VN_D_AC, 0}, /* 192 */
632 { "d$cc", VN_D_CC, 0}, /* 192 */
633 { "d$ip", VN_D_IP, 0}, /* 192 */
634 { "d$lc", VN_D_LCP, 0}, /* 193 */
635 { "d$lcp", VN_D_LCP, CM_INV}, /* 193 */
636 { "d$lp", VN_D_LP, 0}, /* 192 */
637 { "d$px", VN_D_PXX, 0}, /* 195 */
638 { "d$pxx", VN_D_PXX, CM_INV}, /* 195 */
639 #endif /* NODIAL */
640 { "date", VN_DATE, 0},
641 { "day", VN_DAY, 0},
642 #ifdef NT
643 { "desktop", VN_DESKTOP, 0}, /* 201 */
644 #endif /* NT */
645 #ifndef NODIAL
646 { "dialcount", VN_DRTR, 0}, /* 195 */
647 { "dialmessage",VN_DMSG, 0}, /* 212 */
648 { "dialnumber",VN_DNUM, 0}, /* 192 */
649 { "dialresult",VN_MDMSG, 0}, /* 192 */
650 { "dialstatus",VN_DIAL, 0}, /* 190 */
651 { "dialsuffix",VN_PDSFX, 0}, /* 193 */
652 { "dialtype", VN_DTYPE, 0}, /* 193 */
653 #endif /* NODIAL */
654 { "directory", VN_DIRE, 0},
655 #ifndef NODIAL
656 { "dm_hf", VN_DM_HF, 0}, /* 199 */
657 { "dm_lp", VN_DM_LP, 0}, /* 195 */
658 { "dm_sp", VN_DM_SP, 0}, /* 195 */
659 { "dm_pd", VN_DM_PD, 0}, /* 195 */
660 { "dm_td", VN_DM_TD, 0}, /* 195 */
661 { "dm_wa", VN_DM_WA, 0}, /* 195 */
662 { "dm_wb", VN_DM_WB, 0}, /* 199 */
663 { "dm_wd", VN_DM_WD, 0}, /* 195 */
664 { "dm_rc", VN_DM_RC, 0}, /* 195 */
665 #endif /* NODIAL */
666 #ifndef NOXFER
667 { "download", VN_DLDIR, 0}, /* 192 */
668 #endif /* NOXFER */
669 { "editor", VN_EDITOR,0},
670 { "editfile", VN_EDFILE,0},
671 { "editopts", VN_EDOPT, 0},
672 { "errno", VN_ERRNO, 0}, /* 192 */
673 { "errstring", VN_ERSTR, 0}, /* 192 */
674 { "escape", VN_ESC, 0}, /* 193 */
675 { "evaluate", VN_EVAL, 0}, /* 190 */
676 #ifdef OS2ORUNIX
677 { "exedir", VN_EXEDIR,0}, /* 192 */
678 #endif /* OS2ORUNIX */
679 { "exitstatus",VN_EXIT, 0},
680 #ifdef CKCHANNELIO
681 { "f_count", VN_FCOU, 0}, /* 195 */
682 { "f_error", VN_FERR, 0}, /* 195 */
683 { "f_max", VN_FMAX, 0}, /* 195 */
684 { "fileerror", VN_FERR, CM_INV}, /* 195 */
685 { "filemax", VN_FERR, CM_INV}, /* 195 */
686 #endif /* CKCHANNELIO */
687 { "filename", VN_FNAM, 0}, /* 193 */
688 { "filenumber",VN_FNUM, 0}, /* 193 */
689 { "filespec", VN_FILE, 0},
690 { "fsize", VN_FFC, 0}, /* 190 */
691 #ifdef GFTIMER
692 { "ftime", VN_FTIME, 0}, /* 199 */
693 #else
694 { "ftime", VN_NTIM, CM_INV},
695 #endif /* GFTIMER */
696 #ifndef NOFTP
697 #ifndef SYSFTP
698 { "ftp_code", VN_FTP_C, 0}, /* 199 */
699 { "ftp_cpl", VN_FTP_B, 0}, /* 199 */
700 { "ftp_connected", VN_FTP_X, 0}, /* 199 */
701 { "ftp_dpl", VN_FTP_D, 0}, /* 199 */
702 { "ftp_getputremote", VN_FTP_G, 0}, /* 199 */
703 { "ftp_host", VN_FTP_H, 0}, /* 199 */
704 { "ftp_loggedin", VN_FTP_L, 0}, /* 199 */
705 { "ftp_message", VN_FTP_M, 0}, /* 199 */
706 { "ftp_msg", VN_FTP_M, CM_INV}, /* 199 */
707 { "ftp_security", VN_FTP_Z, 0}, /* 199 */
708 { "ftp_server", VN_FTP_S, 0}, /* 199 */
709 #endif /* SYSFTP */
710 #endif /* NOFTP */
711 { "ftype", VN_MODE, 0}, /* 190 */
712 #ifdef KUI
713 { "gui_fontname", VN_GUI_FNM, 0}, /* 205 */
714 { "gui_fontsize", VN_GUI_FSZ, 0}, /* 205 */
715 { "gui_runmode", VN_GUI_RUN, 0}, /* 205 */
716 { "gui_xpos", VN_GUI_XP, 0}, /* 205 */
717 { "gui_xres", VN_GUI_XR, 0}, /* 205 */
718 { "gui_ypos", VN_GUI_YP, 0}, /* 205 */
719 { "gui_yres", VN_GUI_YR, 0}, /* 205 */
720 #endif /* KUI */
721 { "herald", VN_HERALD, 0},
722 { "home", VN_HOME, 0},
723 { "host", VN_HOST, 0},
724 { "hour", VN_HOUR, 0}, /* 200 */
725 #ifndef NOHTTP
726 { "http_code", VN_HTTP_C, 0}, /* 199 */
727 { "http_connected", VN_HTTP_N, 0}, /* 199 */
728 { "http_host", VN_HTTP_H, 0}, /* 199 */
729 { "http_message", VN_HTTP_M, 0}, /* 199 */
730 { "http_security", VN_HTTP_S, 0}, /* 199 */
731 #endif /* NOHTTP */
732 { "hwparity", VN_HWPAR, 0}, /* 195 */
733 { "input", VN_IBUF, 0},
734 { "inchar", VN_ICHR, 0},
735 { "incount", VN_ICNT, 0},
736 { "inidir", VN_INI, 0}, /* 192 */
737 { "inmatch", VN_MATCH, 0}, /* 196 */
738 { "inmessage", VN_INPMSG,0}, /* 212 */
739 { "inscale", VN_ISCALE,0}, /* 210 */
740 { "instatus", VN_ISTAT, 0}, /* 192 */
741 { "intime", VN_INTIME,0}, /* 193 */
742 { "inwait", VN_INTMO, 0}, /* 195 */
743 { "ip", VN_IPADDR, CM_ABR|CM_INV},
744 { "ipaddress", VN_IPADDR,0}, /* 192 */
745 { "iprompt", VN_PROMPT,0}, /* 199 */
746 { "kbchar", VN_KBCHAR,0}, /* 196 */
747 #ifndef NOLOCAL
748 #ifdef OS2
749 { "keyboard", VN_KEYB, 0},
750 #endif /* OS2 */
751 #endif /* NOLOCAL */
752 #ifdef CK_KERBEROS
753 { "krb4errmsg", VN_K4EMSG,0},
754 { "krb4errno", VN_K4ENO, 0},
755 { "krb4principal", VN_K4PRN, 0},
756 { "krb4realm", VN_K4RLM, 0},
757 { "krb4service", VN_K4SRV, 0},
758 { "krb5cc", VN_K5CC, 0},
759 { "krb5errmsg", VN_K5EMSG,0},
760 { "krb5errno", VN_K5ENO, 0},
761 { "krb5principal", VN_K5PRN, 0},
762 { "krb5realm", VN_K5RLM, 0},
763 { "krb5service", VN_K5SRV, 0},
764 #endif /* CK_KERBEROS */
765 { "lastcommand", VN_PREVCMD, 0}, /* 299 */
766 #ifndef NOLASTFILE
767 { "lastfilespec", VN_LASTFIL, 0}, /* 212 */
768 #endif /* NOLASTFILE */
769 { "lastkeywordvalue", VN_LASTKWV, 0}, /* 212 */
770 { "lastkwvalue", VN_LASTKWV, CM_ABR|CM_INV}, /* 212 */
771 { "line", VN_LINE, 0},
772 { "local", VN_LCL, 0},
773 #ifdef UNIX
774 { "lockdir", VN_LCKDIR,0}, /* 195 */
775 { "lockpid", VN_LCKPID,0}, /* 195 */
776 #endif /* UNIX */
777 { "log_connection", VN_LOG_CON, 0}, /* 206 */
778 { "log_debug", VN_LOG_DEB, 0}, /* 206 */
779 { "log_packet", VN_LOG_PKT, 0}, /* 206 */
780 { "log_session", VN_LOG_SES, 0}, /* 206 */
781 { "log_transaction", VN_LOG_TRA, 0},/* 206 */
782 { "maclevel", VN_MACLVL,0}, /* 195 */
783 { "macro", VN_MAC, 0},
784 #ifdef FNFLOAT
785 { "math_e", VN_MA_E, 0}, /* 195 */
786 { "math_pi", VN_MA_PI, 0}, /* 195 */
787 { "math_precision", VN_MA_PR, 0}, /* 195 */
788 #endif /* FNFLOAT */
789 { "minput", VN_MINP, 0}, /* 192 */
790 { "model", VN_MODL, 0}, /* 193 */
791 { "modem", VN_MDM, 0},
792 { "month", VN_MONTH, 0}, /* 304 */
793 #ifndef NOLOCAL
794 #ifdef OS2
795 { "mousecurx", VN_MOU_X, 0}, /* K95 1.1.14 */
796 { "mousecury", VN_MOU_Y, 0}, /* K95 1.1.14 */
797 #endif /* OS2 */
798 #endif /* NOLOCAL */
799 #ifndef NODIAL
800 { "m_aa_off", VN_M_AAX, 0}, /* all 192... */
801 { "m_aa_on", VN_M_AAO, 0},
802 { "m_dc_off", VN_M_DCX, 0},
803 { "m_dc_on", VN_M_DCO, 0},
804 { "m_dial", VN_M_DCM, 0},
805 { "m_ec_off", VN_M_ECX, 0},
806 { "m_ec_on", VN_M_ECO, 0},
807 { "m_fc_hw", VN_M_HWF, 0},
808 { "m_fc_no", VN_M_NFC, 0},
809 { "m_fc_sw", VN_M_SWF, 0},
810 { "m_hup", VN_M_HUP, 0},
811 { "m_init", VN_M_INI, 0},
812 { "m_name", VN_M_NAM, 0}, /* 195 */
813 { "m_pulse", VN_M_PDM, 0},
814 { "m_sig_cd", VN_MS_CD, 0}, /* 195 */
815 { "m_sig_cts", VN_MS_CTS,0}, /* 195 */
816 { "m_sig_dsr", VN_MS_DSR,0}, /* 195 */
817 { "m_sig_dtr", VN_MS_DTR,0}, /* 195 */
818 { "m_sig_ri", VN_MS_RI, 0}, /* 195 */
819 { "m_sig_rts", VN_MS_RTS,0}, /* 195 */
820 { "m_tone", VN_M_TDM, 0},
821 #endif /* NODIAL */
822 { "name", VN_NAME, 0},
823 { "ndate", VN_NDAT, 0},
824 { "nday", VN_NDAY, 0},
825 { "newline", VN_NEWL, 0},
826 { "nmonth", VN_NMONTH,0}, /* 304 */
827 { "ntime", VN_NTIM, 0},
828 { "osname", VN_OSNAM, 0}, /* 193 */
829 { "osrelease", VN_OSREL, 0}, /* 193 */
830 { "osversion", VN_OSVER, 0}, /* 193 */
831 #ifndef NOXFER
832 { "packetlen", VN_RPSIZ, 0}, /* 192 */
833 #endif /* NOXFER */
834 { "parity", VN_PRTY, 0}, /* 190 */
835 { "password", VN_PWD, CM_INV}, /* 192 */
836 #ifdef NT
837 { "personal", VN_PERSONAL, 0}, /* 201 */
838 #endif /* NT */
839 #ifdef PEXITSTAT
840 { "pexitstat", VN_PEXIT, 0}, /* 193 */
841 #endif /* PEXITSTAT */
842 #ifdef CK_PID
843 { "pid", VN_PID, 0}, /* 193 */
844 #endif /* CK_PID */
845 { "platform", VN_SYSV, 0},
846 { "printer", VN_PRINT, 0}, /* 193 */
847 { "program", VN_PROG, 0},
848 { "prompt", VN_PRM, CM_INV}, /* 192 */
849 #ifndef NOXFER
850 { "protocol", VN_PROTO, 0}, /* 192 */
851 { "p_8bit", VN_P_8BIT,0}, /* 193 */
852 { "p_ctl", VN_P_CTL, 0}, /* 193 */
853 { "p_rpt", VN_P_RPT, 0}, /* 193 */
854 { "query", VN_QUE, 0}, /* 190 */
855 #endif /* NOXFER */
856 { "remoteip", VN_HOSTIP,0}, /* 212 */
857 { "return", VN_RET, 0},
858 #ifdef CK_REXX
859 { "rexx", VN_REXX, 0}, /* 190 */
860 #endif /* CK_REXX */
861 #ifdef TN_COMPORT
862 { "rfc2217_signature", VN_TNC_SIG, 0}, /* 201 */
863 { "rfc2717_signature", VN_TNC_SIG, CM_INV}, /* 202 */
864 #endif /* TN_COMPORT */
865 { "rows", VN_ROWS, 0}, /* 190 */
866 #ifndef NOSEXP
867 { "sdepth", VN_LSEXP,0}, /* 199 */
868 #endif /* NOSEXP */
869 { "secure", VN_SECURE, 0}, /* 199 */
870 #ifndef NOLOCAL
871 #ifdef OS2
872 { "select", VN_SELCT, 0}, /* 192 */
873 #endif /* OS2 */
874 #endif /* NOLOCAL */
875 { "sendlist", VN_SNDL, 0},
876 { "serial", VN_SERIAL,0}, /* 195 */
877 { "setlinemsg",VN_SLMSG, 0}, /* 195 */
878 #ifndef NOSEXP
879 { "sexpression",VN_SEXP, 0}, /* 199 */
880 #endif /* NOSEXP */
881 { "speed", VN_SPEE, 0},
882 #ifdef OS2
883 { "space", VN_SPA, 0},
884 { "startup", VN_STAR, 0}, /* 190 */
885 #else
886 #ifdef UNIX
887 { "startup", VN_STAR, 0}, /* 193 */
888 #else
889 #ifdef VMS
890 { "startup", VN_STAR, 0}, /* 193 */
891 #endif /* VMS */
892 #endif /* UNIX */
893 #endif /* OS2 */
894 { "status", VN_SUCC, 0},
895 #ifndef NOSEXP
896 { "svalue", VN_VSEXP, 0}, /* 199 */
897 #endif /* NOSEXP */
898 #ifndef NOXFER
899 { "sysid", VN_SYSI, 0},
900 #endif /* NOXFER */
901 { "system", VN_SYST, 0},
902 { "terminal", VN_TTYP, 0},
903 #ifdef OS2
904 #ifndef NOKVERBS
905 { "termkey", VN_TRMK, CM_INV}, /* 192 */
906 #endif /* NOKVERBS */
907 #endif /* OS2 */
908 { "test", VN_TEST, 0}, /* 193 */
909 { "textdir", VN_TXTDIR,0}, /* 195 */
910 #ifndef NOXFER
911 { "tfsize", VN_TFC, 0},
912 { "tftime", VN_TFTIM, 0}, /* 195 */
913 #endif /* NOXFER */
914 { "time", VN_TIME, 0},
915 { "timestamp", VN_NOW, 0}, /* 200 */
916 { "tmpdir", VN_TEMP, 0}, /* 192 */
917 #ifdef CK_TRIGGER
918 { "trigger", VN_TRIG, 0}, /* 193 */
919 #endif /* CK_TRIGGER */
920 #ifdef CK_TTYFD
921 { "ttyfd", VN_TTYF, 0},
922 #endif /* CK_TTYFD */
923 { "ty_ln", VN_TY_LN, 0}, /* 195 */
924 { "ty_lc", VN_TY_LC, 0}, /* 195 */
925 { "ty_lm", VN_TY_LM, 0}, /* 195 */
926 #ifdef BROWSER
927 { "url", VN_URL, CM_INV}, /* 193 */
928 #endif /* BROWSER */
929 { "userid", VN_UID, 0}, /* 192 */
930 { "vareval", VN_VAREVAL, 0}, /* 212 */
931 { "version", VN_VERS, 0},
932 #ifndef NOXFER
933 { "window", VN_WINDO, 0}, /* 192 */
934 #endif /* NOXFER */
935 #ifdef IBMX25
936 { "x25local_nua", VN_X25LA, 0}, /* 193 */
937 { "x25remote_nua", VN_X25RA, 0}, /* 193 */
938 #endif /* IBMX25 */
939 #ifdef CK_SSL
940 { "x509_issuer", VN_X509_I, 0},
941 { "x509_subject", VN_X509_S, 0},
942 #endif /* CK_SSL */
943 #ifndef NOXFER
944 { "xferstatus",VN_XFSTAT,0}, /* 193 */
945 { "xfermsg", VN_XFMSG, 0}, /* 193 */
946 { "xfer_badpackets", VN_XF_BC, 0}, /* 195 */
947 { "xfer_timeouts", VN_XF_TM, 0}, /* 195 */
948 { "xfer_retransmits",VN_XF_RX, 0}, /* 195 */
949 #endif /* NOXFER */
950 { "xprogram", VN_XPROG, 0}, /* 193 */
951 { "xversion", VN_XVNUM, 0}, /* 192 */
952 { "year", VN_YEAR, 0} /* 304 */
953 };
954 int nvars = (sizeof(vartab) / sizeof(struct keytab));
955 #endif /* NOSPL */
956
957 #ifndef NOSPL
958 struct keytab fnctab[] = { /* Function names */
959 #ifdef OS2
960 { ".oox", FN_OOX, CM_INV}, /* ... */
961 #endif /* OS2 */
962
963 #ifdef CKCHANNELIO
964 { "_eof", FN_FEOF, 0},
965 { "_errmsg", FN_FERMSG, 0},
966 { "_getblock", FN_FGBLK, 0},
967 { "_getchar", FN_FGCHAR, 0},
968 { "_getline", FN_FGLINE, 0},
969 { "_handle", FN_FILNO, 0},
970 { "_line", FN_NLINE, 0},
971 { "_pos", FN_FPOS, 0},
972 { "_putblock", FN_FPBLK, 0},
973 { "_putchar", FN_FPCHAR, 0},
974 { "_putline", FN_FPLINE, 0},
975 { "_status", FN_FSTAT, 0},
976 #endif /* CKCHANNELIO */
977
978 { "aaconvert", FN_AADUMP, 0}, /* Associative Array conversion */
979 { "absolute", FN_ABS, 0}, /* Absolute value */
980 #ifdef TCPSOCKET
981 { "addr2name", FN_HSTADD,CM_INV}, /* IP Address to Hostname */
982 { "addrtoname", FN_HSTADD,CM_INV}, /* IP Address to Hostname */
983 #endif /* TCPSOCKET */
984 { "arraylook", FN_ALOOK,0}, /* Array lookup */
985 { "b64decode", FN_FMB64,0}, /* Base-64 conversion */
986 { "b64encode", FN_TOB64,0}, /* ... */
987 { "basename", FN_BSN, 0}, /* Basename */
988 { "break", FN_BRK, 0}, /* Break (as in Snobol) */
989 { "ca", FN_CAP, CM_INV|CM_ABR}, /* Abbreviation for capitablize */
990 { "cap", FN_CAP, CM_INV|CM_ABR}, /* Abbreviation for capitablize */
991 { "capitalize", FN_CAP, 0}, /* First Letter -> uppercase */
992 { "caps", FN_CAP, CM_INV}, /* ditto */
993 { "character", FN_CHR, 0}, /* Character from code */
994 { "checksum", FN_CHK, 0}, /* Checksum */
995 { "cmdstack", FN_CMDSTK,0}, /* Command stack */
996 { "cmpdates", FN_CMPDATE,0}, /* Compare dates */
997 { "code", FN_COD, 0}, /* Code from character */
998 #ifndef NOPUSH
999 { "command", FN_CMD, 0}, /* Output from a command */
1000 #endif /* NOPUSH */
1001 { "contents", FN_CON, 0}, /* Definition (contents) of variable */
1002 { "count", FN_COUNT, 0}, /* Occurrences of string in string */
1003 { "crc16", FN_CRC, 0}, /* CRC-16 */
1004 #ifdef OS2
1005 { "crypt", FN_CRY, CM_INV},
1006 #endif /* OS2 */
1007 { "cvtcset", FN_XLATE, 0}, /* Convert character set */
1008 { "cvtdate", FN_DTIM, 0}, /* Convert free date/time to std */
1009 #ifdef ZFCDAT
1010 { "date", FN_FD, 0}, /* File modification/creation date */
1011 #endif /* ZFCDAT */
1012 { "day", FN_DAY, 0}, /* Day of week */
1013 { "dayname", FN_DAYNAME,0}, /* Name of day of week */
1014 { "dayofyear", FN_JDATE, 0}, /* Date to Day of Year */
1015 { "decodehex", FN_UNPCT, 0}, /* Decode string with hex escapes */
1016 { "definition", FN_DEF, 0}, /* Return definition of given macro */
1017 { "delta2secs", FN_DELSEC, 0}, /* Delta time to seconds */
1018 { "deltatosecs", FN_DELSEC, CM_INV}, /* Delta time to seconds */
1019 #ifndef NODIAL
1020 { "dialconvert",FN_PNCVT,0}, /* Convert portable phone number */
1021 #endif /* NODIAL */
1022 { "diffdates", FN_DIFDATE,0}, /* Difference of two date-times */
1023 { "dimension", FN_DIM, 0}, /* Dimension of array */
1024 { "dir", FN_DIR, CM_INV|CM_ABR}, /* Abbreviation for direct.. */
1025 { "dire", FN_DIR, CM_INV|CM_ABR}, /* Abbreviation for direct.. */
1026 { "direc", FN_DIR, CM_INV|CM_ABR}, /* Abbreviation for direct.. */
1027 { "direct", FN_DIR, CM_INV|CM_ABR}, /* Abbreviation for direct.. */
1028 { "directo", FN_DIR, CM_INV|CM_ABR}, /* Abbreviation for direct.. */
1029 { "director", FN_DIR, CM_INV|CM_ABR}, /* Abbreviation for direct.. */
1030 { "directories",FN_DIR, 0}, /* List of directories */
1031 { "directory", FN_DIR, CM_INV}, /* List of directories */
1032 { "dirname", FN_DNAM, 0}, /* Directory part of filename */
1033 { "dos2unixpath",FN_PC_DU, CM_INV}, /* DOS to UNIX path */
1034 { "dostounixpath",FN_PC_DU, 0}, /* DOS to UNIX path */
1035 { "doy", FN_JDATE,CM_INV}, /* Date to Day of Year */
1036 { "doy2date", FN_DATEJ,0}, /* Day of Year to date */
1037 { "doytodate", FN_DATEJ,CM_INV}, /* Day of Year to date */
1038 { "emailaddress",FN_EMAIL, 0}, /* Email address */
1039 #ifdef FN_ERRMSG
1040 { "errstring", FN_ERRMSG,0}, /* Error code to message */
1041 #endif /* FN_ERRMSG */
1042 { "evaluate", FN_EVA, 0}, /* Evaluate given arith expression */
1043 { "execute", FN_EXE, 0}, /* Execute given macro */
1044 { "filecompare",FN_FILECMP, 0}, /* File compare */
1045 { "fileinfo", FN_FILEINF, 0}, /* File information */
1046 { "files", FN_FC, 0}, /* File count */
1047 #ifdef FNFLOAT
1048 { "fpabsolute", FN_FPABS, 0}, /* Floating-point absolute value */
1049 { "fpadd", FN_FPADD, 0}, /* FP add */
1050 { "fpcosine", FN_FPCOS, 0}, /* FP cosine */
1051 { "fpdivide", FN_FPDIV, 0}, /* FP divide */
1052 { "fpexp", FN_FPEXP, 0}, /* FP e to the x */
1053 { "fpint", FN_FPINT, 0}, /* FP to integer */
1054 { "fplog10", FN_FPLOG, 0}, /* FP base-10 logarithm */
1055 { "fplogn", FN_FPLN, 0}, /* FP natural logarithm */
1056 { "fpmaximum", FN_FPMAX, 0}, /* FP maxinum */
1057 { "fpminimum", FN_FPMIN, 0}, /* FP mininum */
1058 { "fpmodulus", FN_FPMOD, 0}, /* FP modulus */
1059 { "fpmultiply", FN_FPMUL, 0}, /* FP multiply */
1060 { "fpraise", FN_FPPOW, 0}, /* FP raise to a power */
1061 { "fpround", FN_FPROU, 0}, /* FP round */
1062 { "fpsine", FN_FPSIN, 0}, /* FP sine */
1063 { "fpsqrt", FN_FPSQR, 0}, /* FP square root */
1064 { "fpsubtract", FN_FPSUB, 0}, /* FP subtract */
1065 { "fptangent", FN_FPTAN, 0}, /* FP tangent */
1066 #endif /* FNFLOAT */
1067 { "function", FN_FUNC, 0 }, /* Test for existence of a function */
1068 { "getpidinfo", FN_PID, CM_INV }, /* Get PID info (synonym for pidnfo) */
1069 { "hex2ip", FN_HEX2IP,0}, /* Hex to IP address */
1070 { "hextoip", FN_HEX2IP,CM_INV}, /* Hex to IP address */
1071 { "hex2n", FN_HEX2N, CM_INV}, /* Hex to decimal number */
1072 { "hexify", FN_HEX, 0}, /* Hexify (string) */
1073 { "index", FN_IND, 0}, /* Index (string search) */
1074 { "ip2hex", FN_IP2HEX,0}, /* IP address to hex */
1075 { "iptohex", FN_IP2HEX,CM_INV}, /* IP address to hex */
1076 { "ipaddress", FN_IPA, 0}, /* Find and return IP address */
1077 { "jdate", FN_JDATE, CM_INV}, /* Date to Day of Year */
1078 { "join", FN_JOIN, 0}, /* Join array elements */
1079 { "keywordvalue", FN_KWVAL, 0}, /* Keyword=Value */
1080 #ifdef CK_KERBEROS
1081 { "krbflags", FN_KRB_FG, 0}, /* Kerberos functions */
1082 { "krbisvalid", FN_KRB_IV, 0},
1083 { "krbnextticket", FN_KRB_NX, 0},
1084 { "krbtickets", FN_KRB_TK, 0},
1085 { "krbtimeleft", FN_KRB_TT, 0},
1086 #endif /* CK_KERBEROS */
1087 { "kwvalue", FN_KWVAL, CM_INV}, /* Keyword=Value */
1088 { "left", FN_LEF, 0}, /* Leftmost n characters of string */
1089 { "length", FN_LEN, 0}, /* Return length of argument */
1090 { "literal", FN_LIT, 0}, /* Return argument literally */
1091 #ifdef NT
1092 { "longpathname",FN_LNAME,0}, /* GetLongPathName() */
1093 #else
1094 { "longpathname",FN_FFN,CM_INV},
1095 #endif /* NT */
1096 { "lop", FN_STL, 0}, /* Lop */
1097 { "lopx", FN_LOPX, 0}, /* Lopx */
1098 { "lower", FN_LOW, 0}, /* Return lowercased argument */
1099 { "lpad", FN_LPA, 0}, /* Return left-padded argument */
1100 { "ltrim", FN_LTR, 0}, /* Left-Trim */
1101 { "maximum", FN_MAX, 0}, /* Return maximum of two arguments */
1102 { "minimum", FN_MIN, 0}, /* Return minimum of two arguments */
1103 { "mjd", FN_MJD, 0}, /* Date to Modified Julian Date */
1104 { "mjd2date", FN_MJD2, CM_INV}, /* MJD to Date */
1105 { "mjdtodate", FN_MJD2, 0}, /* MJD to Date */
1106 { "modulus", FN_MOD, 0}, /* Return modulus of two arguments */
1107 { "monthname", FN_MONNAME,0}, /* Name of month of year */
1108 #ifdef COMMENT
1109 { "msleep", FN_MSLEEP,0}, /* Sleep for n milliseconds */
1110 #endif /* COMMENT */
1111 { "n2hex", FN_2HEX, CM_INV}, /* Number to hex */
1112 { "n2octal", FN_2OCT, CM_INV}, /* Number to octal */
1113 { "n2time", FN_N2TIM,0}, /* Number to hh:mm:ss */
1114 #ifdef TCPSOCKET
1115 { "name2addr", FN_HSTNAM,CM_INV}, /* Hostname to IP Address */
1116 #endif /* TCPSOCKET */
1117 { "nday", FN_NDAY, 0}, /* Numeric day of week */
1118 { "nextfile", FN_FIL, 0}, /* Next file in list */
1119 { "ntime", FN_NTIM, 0}, /* Time to seconds since midnight */
1120 { "ntohex", FN_2HEX, CM_INV}, /* Number to hex */
1121 { "ntooctal", FN_2OCT, CM_INV}, /* Number to octal */
1122 { "ntotime", FN_N2TIM,CM_INV}, /* Number to hh:mm:ss */
1123 { "oct2n", FN_OCT2N,CM_INV}, /* Octal to decimal number */
1124 { "octton", FN_OCT2N,CM_INV}, /* Octal to decimal number */
1125 { "pathname", FN_FFN, 0}, /* Full file name */
1126 { "pattern", FN_PATTERN, 0}, /* Pattern (for INPUT) */
1127 #ifdef CK_PERMS
1128 { "permissions",FN_PERM, 0}, /* Permissions of file */
1129 #else
1130 { "permissions",FN_PERM, CM_INV}, /* Permissions of file */
1131 #endif /* CK_PERMS */
1132 #ifdef SEEK_CUR
1133 { "pictureinfo",FN_PICTURE, 0 }, /* Picture orientation/dimensions */
1134 #endif /* SEEK_CUR */
1135 { "pidinfo", FN_PID, 0 }, /* Get PID info */
1136 { "radix", FN_RADIX, 0 }, /* Radix conversion */
1137 #ifndef NORANDOM
1138 { "random", FN_RAND, 0}, /* Random number */
1139 #endif /* NORANDOM */
1140 #ifndef NOPUSH
1141 { "rawcommand", FN_RAW, 0}, /* Output from a command (raw) */
1142 #endif /* NOPUSH */
1143 #ifdef RECURSIVE
1144 { "rdirectories", FN_RDIR, 0}, /* Recursive directory list */
1145 #endif /* RECURSIVE */
1146 { "recurse", FN_RECURSE, 0}, /* Recursive variable evaluation */
1147 #ifdef RECURSIVE
1148 { "rfiles", FN_RFIL, 0}, /* Recursive file list */
1149 #endif /* RECURSIVE */
1150 { "rep", FN_REP, CM_INV|CM_ABR},
1151 { "repeat", FN_REP, 0}, /* Repeat argument given # of times */
1152 { "replace", FN_RPL, 0}, /* Replace characters in string */
1153 { "reverse", FN_REV, 0}, /* Reverse the argument string */
1154 { "right", FN_RIG, 0}, /* Rightmost n characters of string */
1155 { "rindex", FN_RIX, 0}, /* Right index */
1156 { "rpad", FN_RPA, 0}, /* Right-pad the argument */
1157 { "rsearch", FN_RSEARCH, 0}, /* R-L Search for pattern in string */
1158 #ifdef OS2
1159 { "scrncurx", FN_SCRN_CX, 0}, /* Screen Cursor X Pos */
1160 { "scrncury", FN_SCRN_CY, 0}, /* Screen Cursor Y Pos */
1161 { "scrnstr", FN_SCRN_STR, 0}, /* Screen String */
1162 #endif /* OS2 */
1163 { "search", FN_SEARCH, 0}, /* L-R Search for pattern in string */
1164 #ifndef NOSEXP
1165 { "sexpression",FN_SEXP, 0}, /* S-Expression */
1166 #endif /* NOSEXP */
1167 #ifdef NT
1168 { "shortpathname",FN_SNAME,0}, /* GetShortPathName() */
1169 #else
1170 { "shortpathname",FN_FFN,CM_INV},
1171 #endif /* NT */
1172 { "size", FN_FS, 0}, /* File size */
1173 #ifdef COMMENT
1174 { "sleep", FN_SLEEP,0}, /* Sleep for n seconds */
1175 #endif /* COMMENT */
1176 { "span", FN_SPN, 0}, /* Span - like Snobol */
1177 { "split", FN_SPLIT,0}, /* Split string into words */
1178 { "squeeze", FN_SQUEEZE,0}, /* Squeeze whitespace in string */
1179 { "strcmp", FN_STRCMP,0}, /* String comparison */
1180 { "stringtype", FN_STRINGT,0}, /* String type (7-bit, 8-bit, UTF-8) */
1181 { "stripb", FN_STB, 0}, /* Strip enclosing braces/brackets */
1182 { "stripn", FN_STN, 0}, /* Strip n chars */
1183 { "stripx", FN_STX, 0}, /* Strip suffix */
1184 { "su", FN_SUB, CM_INV|CM_ABR},
1185 { "sub", FN_SUB, CM_INV|CM_ABR},
1186 { "subs", FN_SUB, CM_INV|CM_ABR},
1187 { "subst", FN_SUB, CM_INV|CM_ABR},
1188 { "substitute", FN_SUBST,0}, /* Substitute chars */
1189 { "substring", FN_SUB, 0}, /* Extract substring from argument */
1190 { "tablelook", FN_TLOOK,0}, /* Table lookup */
1191 { "time", FN_TIME, 0}, /* Free-format time to hh:mm:ss */
1192 { "tod2secs", FN_NTIM, CM_INV}, /* Time-of-day-to-secs-since-midnite */
1193 { "todtosecs", FN_NTIM, CM_INV}, /* Time-of-day-to-secs-since-midnite */
1194 { "trim", FN_TRM, 0}, /* Trim */
1195 { "unhexify", FN_UNH, 0}, /* Unhexify */
1196 { "unix2dospath",FN_PC_UD, CM_INV}, /* UNIX to DOS path */
1197 { "unixtodospath",FN_PC_UD, 0}, /* UNIX to DOS path */
1198 { "untabify", FN_UNTAB,0}, /* Untabify */
1199 { "upper", FN_UPP, 0}, /* Return uppercased argument */
1200 { "utcdate", FN_TOGMT,0}, /* Date-time to UTC (GMT) */
1201 { "verify", FN_VER, 0}, /* Verify */
1202 { "word", FN_WORD, 0}, /* Extract a word */
1203 { "", 0, 0}
1204 };
1205 int nfuncs = (sizeof(fnctab) / sizeof(struct keytab)) - 1;
1206 #endif /* NOSPL */
1207
1208 #ifndef NOSPL /* Buffer for expansion of */
1209 #ifdef BIGBUFOK /* built-in variables. */
1210 #define VVBUFL 1024
1211 #else
1212 #define VVBUFL 256
1213 #endif /* BIGBUFOK */
1214 char vvbuf[VVBUFL+1];
1215 #endif /* NOSPL */
1216
1217 struct keytab disptb[] = { /* Log file disposition */
1218 { "append", 1, 0},
1219 { "new", 0, 0}
1220 };
1221
1222 #ifdef CKFLOAT
1223
1224 /* I N I T F L O A T -- Deduce floating-point precision by inspection */
1225
1226 #ifdef COMMENT
1227 /* For looking at internal floating-point representations */
1228 static char fp_xbuf[128];
1229 static char *
tohex(s,n)1230 tohex(s, n) CHAR * s; int n; {
1231 int x;
1232 char * p = fp_xbuf;
1233 while (n-- > 0) {
1234 x = (*s >> 4) & 0x0f;
1235 *p++ = hexdigits[x];
1236 x = *s++ & 0x0f;
1237 *p++ = hexdigits[x];
1238 }
1239 *p = NUL;
1240 return((char *)fp_xbuf);
1241 }
1242 #endif /* COMMENT */
1243
1244 char math_pi[] = "3.1415926535897932384626433832795";
1245 char math_e[] = "2.7182818284590452353602874713527";
1246
1247 VOID
initfloat()1248 initfloat() {
1249 char * buf = NULL;
1250 int i, x, y;
1251 /*
1252 We malloc a big temporary buffer for sprintf() to minimize likelihood of
1253 (and damage from) sprintf buffer overflows. In any case, the only way this
1254 could happen would be if sprintf() itself had bugs, since the format
1255 descriptor says to cut it off at 250 decimal places.
1256 */
1257 if ((buf = (char *)malloc(4096))) {
1258 sprintf(buf,"%0.250f",(10.0 / 3.0));
1259 for (i = 2; i < 250 && buf[i] == '3'; i++) ;
1260 x = i - 1;
1261 debug(F111,"initfloat 10.0/3.0",buf,x);
1262 sprintf(buf,"%0.250f",(4.0 / 9.0));
1263 for (i = 2; i < 250 && buf[i] == '4'; i++) ;
1264 y = i - 1;
1265 debug(F111,"initfloat 4.0/9.0",buf,y);
1266 fp_digits = (x < y) ? x : y;
1267 if (fp_digits < sizeof(math_pi) - 1) {
1268 math_pi[fp_digits+1] = NUL;
1269 math_e[fp_digits+1] = NUL;
1270 }
1271 sprintf(buf,"%0.6f",(7.0 / 9.0));
1272 if (buf[7] == '8') fp_rounding = 1;
1273 debug(F111,"initfloat 7.0/9.0",buf,fp_rounding);
1274 debug(F101,"initfloat precision","",fp_digits);
1275 free(buf);
1276 }
1277 }
1278 #endif /* CKFLOAT */
1279
1280 /*
1281 P R E S C A N -- A quick look through the command-line options for
1282 items that must be handled before the initialization file is executed.
1283 */
1284 #ifdef NT
1285 extern int StartedFromDialer;
1286 #endif /* NT */
1287 #ifdef OS2
1288 extern int k95stdio;
1289 unsigned long startflags = 0L;
1290 #endif /* OS2 */
1291
1292 static char *
findinpath(arg)1293 findinpath(arg) char * arg; {
1294 #ifdef OS2
1295 char * scriptenv, * keymapenv;
1296 int len;
1297 #endif /* OS2 */
1298 #ifdef DCMDBUF
1299 extern char * cmdbuf;
1300 #else
1301 extern char cmdbuf[];
1302 #endif /* DCMDBUF */
1303 char takepath[4096];
1304 char * s;
1305 int x, z;
1306
1307 /* Set up search path... */
1308 #ifdef OS2
1309 char * appdata0 = NULL, *appdata1 = NULL;
1310 #ifdef NT
1311 scriptenv = getenv("K95SCRIPTS");
1312 keymapenv = getenv("K95KEYMAPS");
1313 makestr(&appdata0,(char *)GetAppData(0));
1314 makestr(&appdata1,(char *)GetAppData(1));
1315 #else /* NT */
1316 scriptenv = getenv("K2SCRIPTS");
1317 keymapenv = getenv("K2KEYMAPS");
1318 #endif /* NT */
1319 if (!scriptenv)
1320 scriptenv = getenv("CK_SCRIPTS");
1321 if (!scriptenv)
1322 scriptenv = "";
1323 if (!keymapenv)
1324 keymapenv = getenv("CK_KEYMAPS");
1325 if (!keymapenv)
1326 keymapenv = "";
1327
1328 debug(F110,"startupdir",startupdir,0);
1329 debug(F110,"common appdata directory",appdata1,0);
1330 debug(F110,"appdata directory",appdata0,0);
1331 debug(F110,"inidir",inidir,0);
1332 debug(F110,"home",zhome(),0);
1333 debug(F110,"exedir",exedir,0);
1334
1335 len = strlen(scriptenv) + strlen(keymapenv) + 3*strlen(startupdir)
1336 + 3*strlen(inidir) + 3*strlen(zhome()) + 3*strlen(exedir)
1337 + (appdata0 ? 3*strlen(appdata0) : 0)
1338 + (appdata1 ? 3*strlen(appdata1) : 0)
1339 + 6*strlen("SCRIPTS/") + 6*strlen("KEYMAPS/") + 16;
1340
1341 if (len >= 4096) { /* SAFE (length is checked) */
1342 takepath[0] = '\0';
1343 debug(F111,"findinpath error - path length too long","len",len);
1344 } else
1345 sprintf(takepath,
1346 /* semicolon-separated path list */
1347 "%s%s%s%s%s;%s%s;%s%s;%s%s%s%s%s%s%s%s%s%s%s%s%s;%s%s;%s%s;%s;%s%s;%s%s",
1348 scriptenv,
1349 (scriptenv[0] && scriptenv[strlen(scriptenv)-1]==';')?"":";",
1350 keymapenv,
1351 (keymapenv[0] && keymapenv[strlen(keymapenv)-1]==';')?"":";",
1352 startupdir,
1353 startupdir, "SCRIPTS/",
1354 startupdir, "KEYMAPS/",
1355 appdata1 ? appdata1 : "",
1356 appdata1 ? "Kermit 95;" : "",
1357 appdata1 ? appdata1 : "",
1358 appdata1 ? "Kermit 95/SCRIPTS/;" : "",
1359 appdata1 ? appdata1 : "",
1360 appdata1 ? "Kermit 95/KEYMAPS/;" : "",
1361 appdata0 ? appdata0 : "",
1362 appdata0 ? "Kermit 95;" : "",
1363 appdata0 ? appdata0 : "",
1364 appdata0 ? "Kermit 95/SCRIPTS/;" : "",
1365 appdata0 ? appdata0 : "",
1366 appdata0 ? "Kermit 95/KEYMAPS/;" : "",
1367 inidir,
1368 inidir, "SCRIPTS/",
1369 inidir, "KEYMAPS/",
1370 zhome(),
1371 zhome(), "SCRIPTS/",
1372 zhome(), "KEYMAPS/",
1373 exedir,
1374 exedir, "SCRIPTS/",
1375 exedir, "KEYMAPS/"
1376 );
1377 debug(F110,"findinpath takepath",takepath,0);
1378 #ifdef NT
1379 makestr(&appdata0,NULL);
1380 makestr(&appdata1,NULL);
1381 #endif /* NT */
1382 #else /* not OS2 */
1383 #ifndef NOSPL
1384 z = 1024; /* Look in home directory */
1385 s = takepath;
1386 zzstring("\\v(home)",&s,&z);
1387 #else
1388 takepath[0] = '\0';
1389 #endif /* NOSPL */
1390 #endif /* OS2 */
1391 /*
1392 All the logic for searching the take path is in the command parser.
1393 So even though we aren't parsing commands, we initialize and call the
1394 parser from here, with the purported filename stuffed into the command
1395 buffer, followed by some carriage returns to make the parser return.
1396 If the file is not found, or otherwise not accessible, the parser prints
1397 an appropriate message, and then we just exit.
1398 */
1399 cmdini(); /* Allocate command buffers etc */
1400 cmini(0); /* Initialize them */
1401 /* Stuff filename into command buf with braces in case of spaces */
1402 ckmakmsg(cmdbuf,CMDBL,"{",arg,"}",NULL);
1403 debug(F110,"findinpath cmdbuf",cmdbuf,0);
1404 ckstrncat(cmdbuf,"\r\r",CMDBL); /* And some carriage returns */
1405 if (cmifip("","",&s,&x,0,takepath,xxstring) < 0)
1406 return(NULL);
1407 cmres();
1408 return(s);
1409 }
1410
1411 static int tr_int; /* Flag if TRANSMIT interrupted */
1412
1413 #ifndef MAC
1414 SIGTYP
1415 #ifdef CK_ANSIC
trtrap(int foo)1416 trtrap(int foo) /* TRANSMIT interrupt trap */
1417 #else
1418 trtrap(foo) int foo; /* TRANSMIT interrupt trap */
1419 #endif /* CK_ANSIC */
1420 /* trtrap */ {
1421 #ifdef __EMX__
1422 signal(SIGINT, SIG_ACK);
1423 #endif
1424 tr_int = 1; /* (Need arg for ANSI C) */
1425 SIGRETURN;
1426 }
1427 #endif /* MAC */
1428 #endif /* NOICP */
1429
1430 #ifdef UNIX
1431 VOID
getexedir()1432 getexedir() {
1433 extern char * xarg0;
1434 long xx;
1435 /*
1436 Unix provides no standard service for this. We look in argv[0], and if
1437 we're lucky there's a full pathname. If not we do a PATH search.
1438 */
1439 if (ckstrchr(xarg0,'/')) { /* Global copy of argv[0] */
1440 int i, k;
1441 char * p = NULL;
1442 if ((k = ckstrncpy(tmpbuf,xarg0,TMPBUFSIZ-2)) > 0) {
1443 p = tmpbuf;
1444 /* Convert to fully qualified pathname */
1445 if (tmpbuf[0]) if (tmpbuf[0] != '/') {
1446 line[0] = NUL;
1447 zfnqfp(tmpbuf,LINBUFSIZ-2,(char *)line);
1448 if (line[0])
1449 p = line;
1450 }
1451 xx = zchki(p);
1452 if (xx > -1) { /* Is the result an existing file? */
1453 k = strlen(p);
1454 for (i = k-1; i > 0; i--) { /* Yes, strip name part */
1455 if (p[i] == '/') {
1456 if (i < k-1)
1457 p[i+1] = NUL;
1458 break;
1459 }
1460 }
1461 }
1462 makestr(&exedir,p); /* Save the result */
1463 }
1464 }
1465 if (!exedir && xarg0) { /* Not found? */
1466 char * p;
1467 p = getenv("PATH"); /* Search the PATH */
1468 if (p) { /* If there is one... */
1469 char * q, * PATH = NULL;
1470 int k;
1471 makestr(&PATH,p); /* Pokeable copy of PATH string */
1472 if (PATH) { /* If malloc succeeded... */
1473 p = PATH;
1474 while (p && *p) { /* Loop through segments */
1475 q = ckstrchr(p,':'); /* End of this segment */
1476 if (q == p) { /* Null PATH segment */
1477 p++; /* Skip over colon */
1478 continue;
1479 }
1480 if (q) /* If not at end of PATH string */
1481 *q++ = NUL; /* zero out the colon */
1482 if ((k = ckstrncpy(tmpbuf,p,TMPBUFSIZ)) > 0) {
1483 if (tmpbuf[k-1] != '/') { /* Copy this PATH segment */
1484 tmpbuf[k++] = '/'; /* Append '/' if needed */
1485 tmpbuf[k] = NUL;
1486 }
1487 /* Append the argv[0] value */
1488 if (ckstrncpy(&tmpbuf[k],xarg0,TMPBUFSIZ) > 0) {
1489 if (zchki(tmpbuf) > -1) { /* File exists? */
1490 tmpbuf[k] = NUL; /* Yes, we're done */
1491 zfnqfp(tmpbuf,LINBUFSIZ,(char *)line);
1492 makestr(&exedir,line);
1493 break;
1494 }
1495 } else break;
1496 } else break;
1497 p = q; /* Not found, go to next segment */
1498 } /* while */
1499 free(PATH); /* Free PATH copy */
1500 }
1501 }
1502 if (!exedir) { /* Still nothing? */
1503 if (zchki(xarg0) > -1) { /* Maybe it's in the current dir */
1504 zfnqfp(zgtdir(),LINBUFSIZ,(char *)line);
1505 makestr(&exedir,line);
1506 }
1507 }
1508 }
1509 if (!exedir) { /* Still nothing? */
1510 makestr(&exedir,"/"); /* Fake it with with root. */
1511 }
1512 }
1513 #endif /* UNIX */
1514
1515 int arg_x = 0;
1516 static int x_prescan = 0;
1517
1518 /*
1519 The argument y once meant something but I can't imagine what so now
1520 it's ignored. (Prior to 22 Aug 98, prescan() was called twice by main(),
1521 and the arg differentiated the two calls. But this caused all sorts of
1522 problems & confusion, so I commented out the second call. This issue might
1523 need to be revisited.)
1524 */
1525 VOID
prescan(dummy)1526 prescan(dummy) int dummy; { /* Arg is ignored. */
1527 extern int howcalled;
1528 int yargc; char **yargv;
1529 char x;
1530 char *yp, *yy;
1531 #ifdef DEBUG
1532 int debcount = 0;
1533 #endif /* DEBUG */
1534 int z;
1535
1536 if (x_prescan) /* Only run once */
1537 return;
1538 x_prescan = 1;
1539
1540 yargc = xargc; /* Make copy of arg vector */
1541 yargv = xargv;
1542
1543 #ifndef NOICP
1544 #ifdef DCMDBUF
1545 if (!kermrc)
1546 if (!(kermrc = (char *) malloc(KERMRCL+1)))
1547 fatal("prescan: no memory for kermrc");
1548 #endif /* DCMDBUF */
1549 ckstrncpy(kermrc,KERMRC,KERMRCL); /* Default init file name */
1550 #endif /* NOICP */
1551
1552 #ifdef OS2
1553 yp = getenv("K95STARTFLAGS");
1554 if (yp) {
1555 startflags = atoi(yp);
1556 }
1557 #endif /* OS2 */
1558
1559 #ifdef IKSD
1560 if (howcalled == I_AM_IKSD) /* Internet Kermit Service daemon */
1561 inserver = 1; /* (See inserver section of ckcmai) */
1562 #endif /* IKSD */
1563
1564 /* Command line options for Kermit */
1565
1566 #ifndef NOCMDL
1567 if (yargc > 1
1568 && *yargv[1] != '-'
1569 && (yargv[1][0] != '=')
1570 #ifdef KERBANG
1571 && (yargv[1][0] != '+')
1572 #endif /* KERBANG */
1573 #ifdef IKSD
1574 && (howcalled != I_AM_IKSD)
1575 #endif /* IKSD */
1576 ) { /* Filename as 1st argument */
1577 #ifndef NOICP
1578 char *s;
1579 #endif /* NOICP */
1580 #ifndef NOURL
1581 extern int haveurl;
1582 extern struct urldata g_url;
1583 if (urlparse(yargv[1],&g_url)) {
1584 if (!ckstrcmp(g_url.svc,"ftp",-1,0) ||
1585 !ckstrcmp(g_url.svc,"ftps",-1,0)) {
1586 haveurl = 1;
1587 howcalled = I_AM_FTP;
1588 } else if (!ckstrcmp(g_url.svc,"telnet",-1,0) ||
1589 !ckstrcmp(g_url.svc,"telnets",-1,0)) {
1590 haveurl = 1;
1591 howcalled = I_AM_TELNET;
1592 } else if (!ckstrcmp(g_url.svc,"ssh",-1,0)) {
1593 haveurl = 1;
1594 howcalled = I_AM_SSH;
1595 } else if (!ckstrcmp(g_url.svc,"iksd",-1,0) ||
1596 !ckstrcmp(g_url.svc,"kermit",-1,0)) {
1597 haveurl = 1;
1598 howcalled = I_AM_KERMIT;
1599 } else if (!ckstrcmp(g_url.svc,"http",-1,0) ||
1600 !ckstrcmp(g_url.svc,"https",-1,0)) {
1601 haveurl = 1;
1602 howcalled = I_AM_HTTP;
1603 }
1604 if (haveurl) {
1605 while (--yargc > 0) { /* Go through command-line args */
1606 yargv++; /* looking for -Y and -d */
1607 yp = *yargv+1;
1608 if (**yargv == '-') {
1609 x = *(*yargv+1);
1610 while (x) {
1611 switch (x) {
1612 #ifndef NOICP
1613 case '+':
1614 case '-':
1615 if (doxarg(yargv,1) < 0) {
1616 fatal("Extended argument error");
1617 }
1618 yp = "";
1619 break;
1620 #endif /* NOICP */
1621 case 'Y':
1622 noinit++;
1623 break;
1624
1625 case 'q':
1626 quiet = 1;
1627 break;
1628
1629 case 'h':
1630 noinit = 1;
1631 #ifdef OS2
1632 startflags |= 2; /* No network DLLs */
1633 startflags |= 4; /* No TAPI DLLs */
1634 startflags |= 8; /* No Security DLLs */
1635 startflags |= 16; /* No Zmodem DLLs */
1636 startflags |= 32; /* Stdin */
1637 startflags |= 64; /* Stdout */
1638 #endif /* OS2 */
1639 break;
1640 case 'd': /* = SET DEBUG ON */
1641 #ifdef DEBUG
1642 if (debcount++ > 0)
1643 debtim = 1;
1644 if (!deblog)
1645 deblog = debopn("debug.log",0);
1646 #endif /* DEBUG */
1647 break;
1648 #ifdef OS2
1649 case 'W':
1650 if (*(yp+1))
1651 fatal("invalid argument bundling after -W");
1652 yargv++, yargc--;
1653 if (yargc < 1)
1654 fatal("Window handle missing");
1655 hwndDialer = (HWND) atol(*yargv);
1656 StartedFromDialer = 1;
1657 yargv++, yargc--;
1658 KermitDialerID = atol(*yargv) ;
1659 break;
1660 case '#': /* K95 initialization options */
1661 if (*(yp+1)) {
1662 fatal("invalid argument bundling");
1663 }
1664 yargv++, yargc--;
1665 if (yargc < 1)
1666 fatal("-# argument missing");
1667 startflags |= atol(*yargv);
1668 break;
1669 #endif /* OS2 */
1670 }
1671 if (!yp)
1672 break;
1673 x = *++yp;
1674 }
1675 }
1676 }
1677 return;
1678 }
1679 }
1680 /* after this point non-Kermit personalities must return */
1681 switch (howcalled) {
1682 case I_AM_KERMIT:
1683 case I_AM_IKSD:
1684 case I_AM_SSHSUB:
1685 break;
1686 default:
1687 return;
1688 }
1689 #endif /* NOURL */
1690
1691 #ifndef NOICP
1692 /* If it is not a URL that we recognize, try to treat it as a file */
1693
1694 if (!isabsolute(yargv[1])) /* If not absolute */
1695 s = findinpath(yargv[1]); /* Look in PATH */
1696 else
1697 s = yargv[1];
1698 if (!s)
1699 doexit(BAD_EXIT,xitsta);
1700 zfnqfp(s,CKMAXPATH,cmdfil); /* In case of CD in file */
1701 yargc -= 1; /* Skip past the filename */
1702 yargv += 1; /* Otherwise we'll get an error */
1703 #endif /* NOICP */
1704 }
1705
1706 #ifndef NOCMDL
1707 #ifdef NEWFTP
1708 if (howcalled == I_AM_FTP) { /* Kermit's FTP client personality */
1709 while (--yargc > 0) { /* Go through command-line args */
1710 yargv++; /* looking for -Y and -d */
1711 yp = *yargv+1;
1712 if (**yargv == '-') {
1713 x = *(*yargv+1);
1714 while (x) {
1715 switch (x) {
1716 #ifndef NOICP
1717 case '+':
1718 case '-':
1719 if (doxarg(yargv,1) < 0) {
1720 fatal("Extended argument error");
1721 }
1722 yp = "";
1723 break;
1724 #endif /* NOICP */
1725 case 'Y':
1726 noinit++;
1727 break;
1728
1729 case 'q':
1730 quiet = 1;
1731 break;
1732
1733 case 'h':
1734 noinit = 1;
1735 #ifdef OS2
1736 startflags |= 2; /* No network DLLs */
1737 startflags |= 4; /* No TAPI DLLs */
1738 startflags |= 8; /* No Security DLLs */
1739 startflags |= 16; /* No Zmodem DLLs */
1740 startflags |= 32; /* Stdin */
1741 startflags |= 64; /* Stdout */
1742 #endif /* OS2 */
1743 break;
1744 case 'd': /* = SET DEBUG ON */
1745 #ifdef DEBUG
1746 if (debcount++ > 0)
1747 debtim = 1;
1748 if (!deblog)
1749 deblog = debopn("debug.log",0);
1750 #endif /* DEBUG */
1751 break;
1752 #ifdef OS2
1753 case 'W':
1754 if (*(yp+1))
1755 fatal("invalid argument bundling after -W");
1756 yargv++, yargc--;
1757 if (yargc < 1)
1758 fatal("Window handle missing");
1759 hwndDialer = (HWND) atol(*yargv);
1760 StartedFromDialer = 1;
1761 yargv++, yargc--;
1762 KermitDialerID = atol(*yargv) ;
1763 break;
1764 case '#': /* K95 initialization options */
1765 if (*(yp+1)) {
1766 fatal("invalid argument bundling");
1767 }
1768 yargv++, yargc--;
1769 if (yargc < 1)
1770 fatal("-# argument missing");
1771 startflags |= atol(*yargv);
1772 break;
1773 #endif /* OS2 */
1774 }
1775 if (!yp)
1776 break;
1777 x = *++yp;
1778 }
1779 }
1780 }
1781 return;
1782 }
1783 #endif /* NEWFTP */
1784 #endif /* NOCMDL */
1785
1786 while (--yargc > 0) { /* Go through command-line args */
1787 yargv++;
1788 yp = *yargv+1; /* Pointer for bundled args */
1789 if (**yargv == '=') /* Same rules as cmdlin()... */
1790 return;
1791 debug(F110,"prescan *yargv",*yargv,0);
1792
1793 #ifndef NOICP
1794 #ifdef KERBANG
1795 yy = *yargv;
1796 if (!strcmp(yy,"+") || (*yy == '+' && *(yy+1) < (char)33)) {
1797 char * s;
1798 yargv++;
1799 noinit = 1;
1800 if (!*yargv)
1801 return;
1802 cfilef = 1;
1803 s = findinpath(*yargv);
1804 if (s) {
1805 zfnqfp(s,CKMAXPATH,cmdfil);
1806 return;
1807 } else
1808 doexit(BAD_EXIT,xitsta);
1809 }
1810 #endif /* KERBANG */
1811 #endif /* NOICP */
1812 if (!strcmp(*yargv,"--")) /* getopt() conformance */
1813 return;
1814 #ifdef VMS
1815 else if (**yargv == '/')
1816 continue;
1817 #endif /* VMS */
1818 else if (**yargv == '-') { /* Got an option (begins with dash) */
1819 x = *(*yargv+1); /* Get option letter */
1820 while (x) { /* Allow for bundled options */
1821 debug(F000,"prescan arg","",x);
1822 switch (x) {
1823 #ifndef NOICP
1824 case '+':
1825 case '-':
1826 if (doxarg(yargv,1) < 0) {
1827 fatal("Extended argument error");
1828 }
1829 #ifndef COMMENT /* Jeff 28 Apr 2003 */
1830 yp = NULL; /* (not "") */
1831 #else
1832 yargv++, yargc--;
1833 yp = *yargv;
1834 #endif /* COMMENT */
1835 break;
1836 #endif /* NOICP */
1837
1838 case '7': /* Undocumented... */
1839 sstelnet = 1; /* (because it doesn't work) */
1840 break;
1841 #ifdef IKSD
1842 case 'A': {
1843 char * p;
1844 inserver = 1; /* Flag that we are doing this */
1845 srvcdmsg = 2; /* Preset this */
1846 /* See inserver section of ckcmai.c for more settings */
1847 #ifdef OS2
1848 if (*(yp+1)) {
1849 fatal("invalid argument bundling after -A");
1850 }
1851 #ifdef NT
1852 /* Support for Pragma Systems Telnet/Terminal Servers */
1853 p = getenv("PRAGMASYS_INETD_SOCK");
1854 if (p && atoi(p) != 0) {
1855 ttname[0] = '$';
1856 ckstrncpy(&ttname[1],p,TTNAMLEN-1);
1857 break;
1858 }
1859 #endif /* NT */
1860 yargv++, yargc--;
1861 if (yargc < 1 || **yargv == '-') {
1862 fatal("-A argument missing");
1863 } else {
1864 ttname[0] = '$';
1865 ckstrncpy(&ttname[1],*yargv,TTNAMLEN-1);
1866 }
1867 #endif /* OS2 */
1868 break;
1869 }
1870 #endif /* IKSD */
1871
1872 #ifdef OS2
1873 case 'W':
1874 if (*(yp+1))
1875 fatal("invalid argument bundling after -W");
1876 yargv++, yargc--;
1877 if (yargc < 1)
1878 fatal("Window handle missing");
1879 #ifdef COMMENT
1880 if (dummy) {
1881 yargv++, yargc--;
1882 break;
1883 } else {
1884 #endif /* COMMENT */
1885 hwndDialer = (HWND) atol(*yargv);
1886 StartedFromDialer = 1;
1887 yargv++, yargc--;
1888 KermitDialerID = atol(*yargv) ;
1889 #ifdef COMMENT
1890 }
1891 #endif /* COMMENT */
1892 break;
1893
1894 case '#': /* K95 initialization options */
1895 if (*(yp+1)) {
1896 fatal("invalid argument bundling");
1897 }
1898 yargv++, yargc--;
1899 if (yargc < 1)
1900 fatal("-# argument missing");
1901 startflags |= atol(*yargv);
1902 break;
1903 #endif /* OS2 */
1904
1905 #ifndef NOSPL
1906 case 'M': /* My User Name */
1907 if (*(yp+1)) {
1908 fatal("invalid argument bundling");
1909 }
1910 yargv++, yargc--;
1911 if ((yargc < 1) || (**yargv == '-')) {
1912 fatal("missing username");
1913 }
1914 if ((int)strlen(*yargv) > UIDBUFLEN) {
1915 fatal("username too long");
1916 }
1917 #ifdef COMMENT
1918 /*
1919 This can't work. uidbuf is overwritten in sysinit() which has yet to be
1920 called. This cannot be set in prescan().
1921 */
1922 #ifdef IKSD
1923 if (!inserver)
1924 #endif /* IKSD */
1925 ckstrncpy(uidbuf,*yargv,UIDBUFLEN);
1926 #endif /* COMMENT */
1927 break;
1928 #endif /* NOSPL */
1929 case 'R': /* Remote-only advisory */
1930 #ifdef CK_IFRO
1931 remonly = 1;
1932 #endif /* CK_IFRO */
1933 break;
1934 case 'S': /* STAY */
1935 stayflg = 1;
1936 break;
1937 case 'h':
1938 noinit = 1;
1939 #ifdef OS2
1940 startflags |= 2; /* No network DLLs */
1941 startflags |= 4; /* No TAPI DLLs */
1942 startflags |= 8; /* No Security DLLs */
1943 startflags |= 16; /* No Zmodem DLLs */
1944 startflags |= 32; /* Stdin */
1945 startflags |= 64; /* Stdout */
1946 #endif /* OS2 */
1947 break;
1948 #ifndef NOICP
1949 case 'Y': /* No init file */
1950 noinit = 1;
1951 break;
1952 #endif /* NOICP */
1953
1954 case 'q':
1955 quiet = 1;
1956 break;
1957
1958 case 'd': /* = SET DEBUG ON */
1959 #ifdef DEBUG
1960 if (debcount++ > 0)
1961 debtim = 1;
1962 if (!deblog)
1963 deblog = debopn("debug.log",0);
1964 #endif /* DEBUG */
1965 break;
1966
1967 case 'x': /* Server */
1968 arg_x = 1; /* Note in advance */
1969 break;
1970 #ifndef NOICP
1971 case 'y': /* Alternative init file */
1972 noinit = 0;
1973 yargv++, yargc--;
1974 if (yargc < 1) fatal("missing name in -y");
1975 /* Replace init file name */
1976 ckstrncpy(kermrc,*yargv,KERMRCL);
1977 rcflag = 1; /* Flag that this has been done */
1978 debug(F111,"prescan kermrc",kermrc,rcflag);
1979 break;
1980 #endif /* NOICP */
1981 case 'z': /* = SET BACKGROUND OFF */
1982 bgset = 0;
1983 backgrd = 0;
1984 #ifdef VMS
1985 batch = 0;
1986 #endif /* VMS */
1987 break;
1988
1989 case 'B': /* Force background (batch) */
1990 bgset = 1;
1991 backgrd = 1;
1992 #ifdef VMS
1993 batch = 1;
1994 #endif /* VMS */
1995 break;
1996
1997 #ifdef CK_NETBIOS
1998 case 'N':
1999 {
2000 int n ;
2001 yargv++, yargc--;
2002 #ifdef COMMENT
2003 if (y)
2004 break;
2005 #endif /* COMMENT */
2006 if (strlen(*yargv) != 1 || (*yargv)[0] == 'X') {
2007 NetBiosAdapter = -1;
2008 } else {
2009 n = atoi(*yargv);
2010 if (n >= 0 && n <= 9)
2011 NetBiosAdapter = n;
2012 else
2013 NetBiosAdapter = -1;
2014 }
2015 }
2016 break;
2017 #endif /* CK_NETBIOS */
2018 default:
2019 break;
2020 }
2021 if (!yp)
2022 break;
2023 x = *++yp; /* See if options are bundled */
2024 }
2025 }
2026 }
2027 #endif /* NOCMDL */
2028 }
2029
2030 /* G E T T C S -- Get Transfer (Intermediate) Character Set */
2031
2032 /*
2033 Given two file character sets, this routine picks out the appropriate
2034 "transfer" character set to use for translating between them.
2035 The transfer character set number is returned.
2036
2037 At present this routine is somewhat overloaded. It's fine for file
2038 transfer because it does not assume the Kermit partner understands UTF8.
2039 However, for terminal emulation it *should* use UTF8 as the intermediate
2040 character set whenever possible so as not to lose characters it might
2041 have been able to display; for example on a terminal connection from
2042 the Linux console (UTF8) to a BBS that uses CP437 box-drawing characters.
2043 This is handled in the CONNECT command code in ckucns.c, which avoids
2044 calling this routine if the character-set on either end is UTF8.
2045
2046 Translation between different Kanji character sets is not yet supported.
2047 */
2048 int
gettcs(cs1,cs2)2049 gettcs(cs1,cs2) int cs1, cs2; {
2050 #ifdef NOCSETS /* No character-set support */
2051 return(0); /* so no translation */
2052 #else
2053 int tcs = TC_TRANSP;
2054 #ifdef KANJI
2055 /* Kanji not supported yet */
2056 if (fcsinfo[cs1].alphabet == AL_JAPAN ||
2057 fcsinfo[cs2].alphabet == AL_JAPAN )
2058 tcs = TC_TRANSP;
2059 else
2060 #endif /* KANJI */
2061 #ifdef CYRILLIC
2062 /*
2063 I can't remember why we don't test both sets here, but I think there
2064 must have been a reason...
2065 */
2066 if (fcsinfo[cs2].alphabet == AL_CYRIL)
2067 tcs = TC_CYRILL;
2068 else
2069 #endif /* CYRILLIC */
2070 #ifdef HEBREW
2071 if (fcsinfo[cs1].alphabet == AL_HEBREW ||
2072 fcsinfo[cs2].alphabet == AL_HEBREW )
2073 tcs = TC_HEBREW;
2074 else
2075 #endif /* HEBREW */
2076 #ifdef GREEK
2077 if (fcsinfo[cs1].alphabet == AL_GREEK ||
2078 fcsinfo[cs2].alphabet == AL_GREEK )
2079 tcs = TC_GREEK;
2080 else
2081 #endif /* GREEK */
2082
2083 /* Roman sets ... */
2084
2085 #ifdef LATIN2 /* East European */
2086 if (cs1 == FC_2LATIN || cs2 == FC_2LATIN || /* Latin-2 */
2087 cs1 == FC_CP852 || cs2 == FC_CP852 || /* CP852 */
2088 cs1 == FC_CP1250 || cs2 == FC_CP1250 || /* Windows Latin-2 */
2089 cs1 == FC_MAZOVIA || cs2 == FC_MAZOVIA) /* Polish Mazovia */
2090 tcs = TC_2LATIN;
2091 else
2092 #endif /* LATIN2 */
2093 /* West European Euro-aware */
2094 if (cs1 == FC_CP858 || cs1 == FC_9LATIN ||
2095 cs2 == FC_CP858 || cs2 == FC_9LATIN)
2096 tcs = TC_9LATIN;
2097 else /* Traditional West European */
2098 tcs = TC_1LATIN;
2099 return(tcs);
2100 #endif /* NOCSETS */
2101 }
2102
2103 #ifndef NOLOCAL
2104 /* D O C O N E C T -- Do the connect command */
2105 /*
2106 q = 0 means issue normal informational message about how to get back, etc.
2107 q != 0 means to skip the message.
2108 */
2109
2110 int
doconect(q,async)2111 doconect(q,async) int q, async; {
2112 int x; /* Return code */
2113 #ifdef CK_AUTODL
2114 extern CHAR ksbuf[];
2115 #endif /* CK_AUTODL */
2116 #ifndef NOKVERBS /* Keyboard macro material */
2117 extern int keymac, keymacx;
2118 #endif /* NOKVERBS */
2119 extern int justone, adl_err;
2120 int qsave; /* For remembering "quiet" value */
2121 #ifdef OS2
2122 extern int term_io;
2123 int term_io_save;
2124 #ifdef KUI
2125 extern int kui_async;
2126 #endif /* KUI */
2127 #endif /* OS2 */
2128 int is_tn = 0;
2129
2130 #ifdef IKSD
2131 if (inserver) {
2132 if (!quiet)
2133 printf("?Sorry, IKSD cannot CONNECT.\r\n");
2134 return(success = 0);
2135 }
2136 #endif /* IKSD */
2137
2138 is_tn =
2139 #ifdef TNCODE
2140 (local && network && IS_TELNET()) || (!local && sstelnet)
2141 #else
2142 0
2143 #endif /* TNCODE */
2144 ;
2145 /*
2146 Saving, changing, and restoring the global "quiet" variable around calls
2147 to conect() to control whether the verbose CONNECT message is printed is
2148 obviously less elegant than passing a parameter to conect(), but we do it
2149 this way to avoid the need to change all of the ck?con.c modules. NOTE:
2150 it is important to restore the value immediately upon return in case there
2151 is an autodownload or APC.
2152 */
2153 qsave = quiet; /* Save it */
2154 if (!quiet && q > -1)
2155 quiet = q; /* Use argument temporarily */
2156 conres(); /* Put console back to normal */
2157 debug(F101,"doconect justone 1","",justone);
2158 #ifdef CK_AUTODL
2159 ksbuf[0] = NUL; /* Autodownload packet buffer */
2160 #endif /* CK_AUTODL */
2161 #ifdef OS2
2162 display_demo = 1; /* Remember to display demo */
2163 #endif /* OS2 */
2164
2165 #ifdef IKS_OPTION
2166 if (is_tn && TELOPT_U(TELOPT_KERMIT) && ttchk() >= 0
2167 #ifdef OS2
2168 && !viewonly
2169 #endif /* OS2 */
2170 ) {
2171 /* If the remote side is in a state of IKS START-SERVER */
2172 /* we request that the state be changed. We will detect */
2173 /* a failure to adhere to the request when we call ttinc() */
2174 if (!iks_wait(KERMIT_REQ_STOP,0) && !tcp_incoming) {
2175 if (!quiet) {
2176 printf("\r\nEnter Client/Server Mode... Use:\r\n\r\n");
2177 printf(
2178 " REMOTE LOGIN <user> <password> to log in to the server if necessary.\r\n");
2179 printf(" SEND and GET for file transfer.\r\n");
2180 printf(" REMOTE commands for file management.\r\n");
2181 printf(" FINISH to terminate Client/Server mode.\r\n");
2182 printf(" BYE to terminate and close connection.\r\n");
2183 printf(" REMOTE HELP for additional information.\r\n\r\n");
2184 }
2185 quiet = qsave;
2186 return(0); /* Failure */
2187 }
2188 }
2189
2190 /* Let our peer know our state. */
2191 #ifdef CK_AUTODL
2192 if (is_tn && TELOPT_ME(TELOPT_KERMIT)
2193 #ifdef OS2
2194 && !viewonly
2195 #endif /* OS2 */
2196 ) {
2197 if (autodl && !TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
2198 tn_siks(KERMIT_START); /* Send Kermit-Server Start */
2199 } else if (!autodl && TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
2200 tn_siks(KERMIT_STOP);
2201 }
2202 }
2203 #else /* CK_AUTODL */
2204 if (is_tn && TELOPT_ME(TELOPT_KERMIT) &&
2205 TELOPT_SB(TELOPT_KERMIT).kermit.me_start)
2206 tn_siks(KERMIT_STOP);
2207 #endif /* CK_AUTODL */
2208 #endif /* IKS_OPTION */
2209
2210 debug(F101,"doconect flow","",flow);
2211 #ifdef OS2
2212 debug(F101,"doconect async","",async);
2213 #ifdef KUI
2214 if (kui_async)
2215 async = 1;;
2216 #endif /* KUI */
2217 x = conect(async); /* Connect the first time */
2218 #else /* OS2 */
2219 x = conect();
2220 #endif /* OS2 */
2221 debok = 1;
2222
2223 #ifdef IKS_OPTION
2224 if (TELOPT_U(TELOPT_KERMIT) &&
2225 TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
2226 !tcp_incoming && !quiet && ttchk() >= 0
2227 ) {
2228 printf("\r\nEnter Client/Server Mode... Use:\r\n\r\n");
2229 printf(
2230 " REMOTE LOGIN <user> <password> to log in to the server if necessary.\r\n");
2231 printf(" SEND and GET for file transfer.\r\n");
2232 printf(" REMOTE commands for file management.\r\n");
2233 printf(" FINISH to terminate Client/Server mode.\r\n");
2234 printf(" BYE to terminate and close connection.\r\n");
2235 printf(" REMOTE HELP for additional information.\r\n\r\n");
2236 }
2237 #endif /* IKS_OPTION */
2238
2239 quiet = qsave; /* Restore "quiet" value */
2240 debug(F101,"doconect justone 2","",justone);
2241
2242 #ifdef NETCONN
2243 if (network && tn_exit && ttchk() < 0)
2244 doexit(GOOD_EXIT,xitsta); /* Exit with good status */
2245 #endif /* NETCONN */
2246
2247 #ifdef OS2ORUNIX
2248 /* Exit on disconnect if the port is not open or carrier detect */
2249 if (exitonclose && (ttchk() < 0))
2250 doexit(GOOD_EXIT,xitsta);
2251 #endif /* OS2ORUNIX */
2252
2253 #ifdef CKCONINTB4CB
2254 /* The order makes a difference in HP-UX 8.00. */
2255 /* The other order makes it think it's in the background when it */
2256 /* returns from CONNECT (Apr 1999). */
2257 setint();
2258 concb((char)escape); /* Restore console for commands */
2259 #else
2260 /* This is how it has always been so better leave it */
2261 /* this way for all non-HP-UX-8.00 builds. */
2262 concb((char)escape); /* Restore console for commands */
2263 setint();
2264 #endif /* CKCONINTB4CB */
2265
2266 #ifdef OS2
2267 if (!async) {
2268 term_io_save = term_io; /* Disable I/O by emulator */
2269 term_io = 0;
2270 #endif /* OS2 */
2271
2272 #ifdef CK_APC
2273 /*
2274 If an APC command was received during CONNECT mode, we define it now
2275 as a macro, execute the macro, and then return to CONNECT mode.
2276 We do this in a WHILE loop in case additional APCs come during subsequent
2277 CONNECT sessions.
2278 */
2279 debug(F101,"doconect apcactive","",apcactive);
2280 debug(F101,"doconect success","",success);
2281
2282 while (x > 0 && (apcactive == APC_LOCAL ||
2283 (apcactive == APC_REMOTE && apcstatus != APC_OFF))) {
2284 debug(F101,"doconect justone 3","",justone);
2285 if (mlook(mactab,"_apc_commands",nmac) == -1) {
2286 debug(F110,"doconect about to execute APC",apcbuf,0);
2287 domac("_apc_commands",apcbuf,cmdstk[cmdlvl].ccflgs|CF_APC);
2288 delmac("_apc_commands",1);
2289 #ifdef DEBUG
2290 } else {
2291 debug(F100,"doconect APC in progress","",0);
2292 #endif /* DEBUG */
2293 }
2294 debug(F101,"doconect apcactive after domac","",apcactive);
2295 if (!apcactive) { /* In case CLEAR APC was in APC */
2296 debug(F101,"doconect quit APC loop: apcactive","",apcactive);
2297 break;
2298 }
2299 /* Also don't reconnect if autodownload failed - very confusing! */
2300 /* Let them view the local screen to see what happened. - fdc */
2301
2302 /* This should be conditional. If someone is relying on the */
2303 /* connect mode autodownload for the kermit server to use with */
2304 /* a remotely executed script we should be able to return to */
2305 /* connect mode on the failure. What we really need to do is */
2306 /* report the status of the transfer and then return to CONNECT. */
2307 /* In unix this would simply be a printf(), but in K95 it could */
2308 /* use a popup dialog to report the status. - Jeff */
2309
2310 #ifndef NOXFER
2311 debug(F101,"doconect xferstat","",xferstat);
2312 if (apcactive == APC_LOCAL && !xferstat && adl_err != 0) {
2313 debug(F101,"doconect quit APC loop: xferstat","",xferstat);
2314 apcactive = APC_INACTIVE;
2315 break;
2316 }
2317 #endif /* NOXFER */
2318 #ifdef OS2
2319 msleep(250);
2320 #endif /* OS2 */
2321 debug(F101,"doconect justone 4","",justone);
2322 qsave = quiet; /* Do this again... */
2323 if (!quiet && q > -1)
2324 quiet = q;
2325 #ifdef CK_AUTODL
2326 ksbuf[0] = NUL;
2327 #endif /* CK_AUTODL */
2328 #ifdef IKS_OPTION
2329 #ifdef CK_AUTODL
2330 if (is_tn &&
2331 TELOPT_ME(TELOPT_KERMIT) &&
2332 !TELOPT_SB(TELOPT_KERMIT).kermit.me_start &&
2333 autodl
2334 #ifdef CK_APC
2335 && !apcactive
2336 #endif /* CK_APC */
2337 #ifdef OS2
2338 && !viewonly
2339 #endif /* OS2 */
2340 ) {
2341 tn_siks(KERMIT_START); /* Send Kermit-Server Start */
2342 }
2343 #endif /* CK_AUTODL */
2344 #endif /* IKS_OPTION */
2345 #ifndef OS2
2346 x = conect(); /* Re-CONNECT. */
2347 #else /* OS2 */
2348 x = conect(0);
2349 term_io = term_io_save;
2350 #endif /* OS2 */
2351 debok = 1;
2352 quiet = qsave;
2353 debug(F101,"doconect justone 5","",justone);
2354 #ifdef NETCONN
2355 if (network && ttchk() < 0) {
2356 if (tn_exit || exitonclose)
2357 doexit(GOOD_EXIT,xitsta);
2358 else
2359 break;
2360 }
2361 #endif /* NETCONN */
2362
2363 #ifdef OS2ORUNIX
2364 /* If connection dropped */
2365 if (ttchk() < 0) {
2366 concb((char)escape); /* Restore console. */
2367 if (exitonclose)
2368 doexit(GOOD_EXIT,xitsta);
2369 else
2370 break;
2371 }
2372 #endif /* OS2ORUNIX */
2373 } /* Loop back for more. */
2374 #endif /* CK_APC */
2375
2376 #ifndef NOKVERBS
2377 if ((keymac > 0) && (keymacx > -1)) { /* Executing a keyboard macro? */
2378 /* Set up the macro and return */
2379 /* Do not clear the keymac flag */
2380 #ifdef OS2
2381 term_io = term_io_save;
2382 #endif /* OS2 */
2383 return(dodo(keymacx,NULL,CF_KMAC|cmdstk[cmdlvl].ccflgs));
2384 }
2385 #endif /* NOKVERBS */
2386 #ifdef OS2
2387 term_io = term_io_save;
2388 } /* if (!async) */
2389 #endif /* OS2 */
2390
2391 #ifdef CKCONINTB4CB
2392 /* The order makes a difference in HP-UX 8.00. */
2393 /* The other order makes it think it's in the background when it */
2394 /* returns from CONNECT (Apr 1999). */
2395 setint();
2396 concb((char)escape); /* Restore console for commands */
2397 #else
2398 /* This is how it has always been so better leave it */
2399 /* this way for all non-HP-UX-8.00 builds. */
2400 concb((char)escape); /* Restore console for commands */
2401 setint();
2402 #endif /* CKCONINTB4CB */
2403 #ifdef OS2
2404 if (!async)
2405 #endif /* OS2 */
2406 what = W_COMMAND; /* Back in command mode. */
2407 return(x); /* Done. */
2408 }
2409 #endif /* NOLOCAL */
2410
2411 #ifndef NOICP
2412 #ifdef COMMENT
2413 /*
2414 It seemed that this was needed for OS/2, in which \v(cmdfile) and other
2415 file-oriented variables or functions can return filenames containing
2416 backslashes, which are subsequently interpreted as quotes rather than
2417 directory separators (e.g. see commented section for VN_CMDF below).
2418 But the problem can't be cured at this level. Example:
2419
2420 type \v(cmdfile)
2421
2422 Without doubling, the filename is parsed correctly, but then when passed
2423 to UNIX 'cat' through the shell, the backslash is removed, and then cat
2424 can't open the file. With doubling, the filename is not parsed correctly
2425 and the TYPE command fails immediately with a "file not found" error.
2426 */
2427 /*
2428 Utility routine to double all backslashes in a string.
2429 s1 is pointer to source string, s2 is pointer to destination string,
2430 n is length of destination string, both NUL-terminated.
2431 Returns 0 if OK, -1 if not OK (destination string too short).
2432 */
2433 int
dblbs(s1,s2,n)2434 dblbs(s1,s2,n) char *s1, *s2; int n; {
2435 int i = 0;
2436 while (*s1) {
2437 if (*s1 == '\\') {
2438 if (++i > n) return(-1);
2439 *s2++ = '\\';
2440 }
2441 if (++i > n) return(-1);
2442 *s2++ = *s1++;
2443 }
2444 *s2 = NUL;
2445 return(0);
2446 }
2447 #endif /* COMMENT */
2448
2449 char *
gmdmtyp()2450 gmdmtyp() { /* Get modem type */
2451 #ifndef NODIAL
2452 int i, x;
2453
2454 debug(F111,"gmdmtyp","mdmtyp",mdmtyp);
2455 debug(F111,"gmdmtyp","mdmsav",mdmsav);
2456
2457 x = mdmtyp;
2458 if (x < 0) /* In case of network dialing */
2459 x = mdmsav;
2460 if (x < 1)
2461 return("none");
2462 else
2463 for (i = 0; i < nmdm; i++)
2464 if ((mdmtab[i].kwval == x) && (mdmtab[i].flgs == 0))
2465 return(mdmtab[i].kwd);
2466 #endif /* NODIAL */
2467 return("none");
2468 }
2469
2470 #ifndef NOXMIT
2471 #ifndef NOLOCAL
2472 /* T R A N S M I T -- Raw upload */
2473
2474 /* Obey current line, duplex, parity, flow, text/binary settings. */
2475 /* Returns 0 upon apparent success, 1 on obvious failure. */
2476
2477 /***
2478 Things to add:
2479 . Make both text and binary mode obey set file bytesize.
2480 . Maybe allow user to specify terminators other than CR?
2481 . Maybe allow user to specify prompts other than single characters?
2482 . Make STATISTICS also work for TRANSMIT.
2483 . If TRANSMIT is done without echo, make some kind of (optional) display.
2484 . Make the same optimization for binary-mode transmit that was done for
2485 text-mode (in the no-echo / no-prompt / no-pause case).
2486 ***/
2487
2488 /* T R A N S M I T -- Raw upload */
2489
2490 /* s is the filename, t is the turnaround (prompt) character */
2491
2492 /*
2493 Maximum number of characters to buffer.
2494 Must be less than LINBUFSIZ
2495 */
2496 #ifdef OS2
2497 #define XMBUFS 4096 /* For compatibility with XYZmodem */
2498 #else /* OS2 */
2499 #define XMBUFS 1024
2500 #endif /* OS2 */
2501
2502 #ifdef TNCODE
2503 #ifndef IAC
2504 #define IAC 255
2505 #endif /* IAC */
2506 #endif /* TNCODE */
2507
2508 #define OUTXBUFSIZ 15
2509 static CHAR inxbuf[OUTXBUFSIZ+1]; /* Host-to-screen expansion buffer */
2510 static int inxcount = 0; /* and count */
2511 static CHAR outxbuf[OUTXBUFSIZ+1]; /* Keyboard-to-host expansion buf */
2512 static int outxcount = 0; /* and count */
2513
2514 /* T R A N S M I T -- Unguarded non-protocol file transmission */
2515 /*
2516 Call with:
2517 char * s: Name of file to transmit.
2518 char t: Turnaround char for text-mode transmission (normally LF).
2519 int xlate: nonzero = charset translation for text-mode xfer, 0 = skip.
2520 int binary: nonzero = transmit in binary mode, 0 = in text mode.
2521 */
2522 #define XBBUFSIZ 508 /* For binary blasting */
2523 static CHAR xbbuf[XBBUFSIZ+4];
2524
2525 int
2526 #ifdef CK_ANSIC
transmit(char * s,char t,int xlate,int binary,int xxecho)2527 transmit(char * s, char t, int xlate, int binary, int xxecho)
2528 #else
2529 transmit(s,t,xlate,binary,xxecho) char *s; char t; int xlate, binary, xxecho;
2530 #endif /* CK_ANSIC */
2531 /* transmit */ {
2532 #ifdef MAC
2533 extern char sstate;
2534 int count = 100;
2535 #else
2536 int count = 0;
2537 #ifdef OS2
2538 #ifdef NT
2539 SIGTYP (* oldsig)(int); /* For saving old interrupt trap. */
2540 #else /* NT */
2541 SIGTYP (* volatile oldsig)(int);
2542 #endif /* NT */
2543
2544 #else /* OS2 */
2545 SIGTYP (* oldsig)();
2546 #endif /* OS2 */
2547 #endif /* MAC */
2548 int eof = 0; /* End of File flag */
2549 int eol = 0; /* End of Line flag */
2550 int rc = 1; /* Return code. 0=fail, 1=succeed. */
2551 int myflow; /* Local copy of global flow... */
2552 int is_tn = 0; /* Do Telnet negotiations */
2553 int xbufsiz = XMBUFS; /* Size of TRANSMIT buffer */
2554 int x, y, c, i; /* Int workers... */
2555 int control = 0; /* Echo loop control */
2556 long nbytes = 0; /* File byte count */
2557 long zz; /* Long worker */
2558 char *p; /* Char * worker */
2559
2560 #ifdef PIPESEND
2561 extern int pipesend;
2562 #endif /* PIPESEND */
2563
2564 #ifndef NOCSETS
2565 int tcs = TC_TRANSP; /* Intermediate (xfer) char set */
2566 int langsv = L_USASCII; /* Save current language */
2567 int unicode = 0;
2568 int tcssize = 0;
2569
2570 #ifdef CK_ANSIC /* ANSI C prototypes... */
2571 CHAR (*sxo)(CHAR);
2572 CHAR (*rxo)(CHAR);
2573 CHAR (*sxi)(CHAR);
2574 CHAR (*rxi)(CHAR);
2575 #else /* Not ANSI C... */
2576 CHAR (*sxo)();
2577 CHAR (*rxo)();
2578 CHAR (*sxi)();
2579 CHAR (*rxi)();
2580 #endif /* CK_ANSIC */
2581 #ifdef UNICODE
2582 union ck_short uc;
2583 int bomorder = 0;
2584 #ifdef CK_ANSIC
2585 extern int (*xl_ufc[MAXFCSETS+1])(USHORT); /* Unicode to FCS */
2586 extern USHORT (*xl_fcu[MAXFCSETS+1])(CHAR); /* FCS to Unicode */
2587 extern int (*xuf)(USHORT);
2588 extern USHORT (*xfu)(CHAR);
2589 #else
2590 extern int (*xl_ufc[MAXFCSETS+1])();
2591 extern USHORT (*xl_fcu[MAXFCSETS+1])();
2592 extern int (*xuf)();
2593 extern USHORT (*xfu)();
2594 #endif /* CK_ANSIC */
2595 #endif /* UNICODE */
2596 #endif /* NOCSETS */
2597
2598 debug(F101,"xmit t","",t);
2599 debug(F101,"xmit xlate","",xlate);
2600 debug(F101,"xmit binary","",binary);
2601
2602 #ifdef PIPESEND
2603 if (pipesend) {
2604 if (nopush) return(-2);
2605 if (zxcmd(ZIFILE,s) < 1) {
2606 printf("?Can't start command: %s\n",s);
2607 return(0);
2608 }
2609 } else
2610 #endif /* PIPESEND */
2611 if (zopeni(ZIFILE,s) == 0) { /* Open the file to be transmitted */
2612 printf("?Can't open file %s\n",s);
2613 return(0);
2614 }
2615 x = -1; /* Open the communication channel */
2616 if (ttopen(ttname,&x,mdmtyp,cdtimo) < 0) { /* (no harm if already open) */
2617 printf("Can't open device %s\n",ttname);
2618 return(0);
2619 }
2620 zz = x ? speed : -1L;
2621 if (binary) { /* Binary file transmission */
2622 myflow = (flow == FLO_XONX) ? FLO_NONE : flow;
2623
2624 if (ttvt(zz,myflow) < 0) { /* So no Xon/Xoff! */
2625 printf("Can't condition line\n");
2626 return(0);
2627 }
2628 } else {
2629 if (ttpkt(zz,flow,parity) < 0) { /* Put the line in "packet mode" */
2630 printf("Can't condition line\n"); /* so Xon/Xoff will work, etc. */
2631 return(0);
2632 }
2633 }
2634 is_tn =
2635 #ifdef TNCODE
2636 (local && network && IS_TELNET()) || (!local && sstelnet)
2637 #else
2638 0
2639 #endif /* TNCODE */
2640 ;
2641
2642 #ifndef NOCSETS
2643 /* Set up character set translations */
2644
2645 tcs = 0; /* "Transfer" or "Other" charset */
2646 sxo = rxo = NULL; /* Initialize byte-to-byte functions */
2647 sxi = rxi = NULL;
2648 unicode = 0; /* Assume Unicode won't be involved */
2649 if (!binary && xlate) { /* Set up charset translations */
2650 /*
2651 In the SENDING direction, we are converting from the local file's
2652 character-set (fcharset) to the remote terminal charset (tcsr). In the
2653 RECEIVING direction (echoing) we are converting from the remote end of the
2654 terminal charset (tcsr) to its local end (tcsl), which is not necessarily
2655 the same as the file character-set. Especially when the file character
2656 set is UCS-2, which is not a valid terminal character set. The various
2657 combinations are represented in this table:
2658
2659 FCS = File Character Set
2660 RCS = Remote Terminal Character Set
2661 CCS = Console (Local Terminal) Character Set
2662
2663 8 4 2 1
2664 FCS FCS RCS CCS
2665 UCS UTF UTF UTF
2666 0 0 0 0 = 0 = No translation
2667 0 0 0 1 = 1 = FCS -> RCS, Echo RCS -> UTF
2668 0 0 1 0 = 2 = FCS -> UTF, Echo UTF -> CCS
2669 0 0 1 1 = 3 = FCS -> UTF, Echo no translation
2670
2671 0 1 0 0 = 4 = UTF -> RCS, Echo RCS -> CCS
2672 0 1 0 1 = 5 = UTF -> RCS, Echo RCS -> UTF
2673 0 1 1 0 = 6 = UTF -> UTF, Echo UTF -> CCS
2674 0 1 1 1 = 7 = No translation
2675
2676 1 0 0 0 = 8 = UCS -> RCS, Echo RCS -> CCS
2677 1 0 0 1 = 9 = UCS -> RCS, Echo RCS -> UTF
2678 1 0 1 0 = 10 = UCS -> UTF, Echo UTF -> CCS
2679 1 0 1 1 = 11 = UCS -> UTF, Echo no translation
2680 */
2681 #ifdef UNICODE
2682 xfu = NULL; /* Unicode translation functions */
2683 xuf = NULL;
2684 bomorder = ucsorder; /* UCS-2 byte order */
2685
2686 if (fcharset == FC_UCS2) /* File charset is UCS-2 */
2687 unicode |= 8;
2688 else if (fcharset == FC_UTF8) /* File charset is UTF-8 */
2689 unicode |= 4;
2690 if (tcsr == FC_UTF8) /* Remote term charset is UTF-8 */
2691 unicode |= 2;
2692 if (tcsl == FC_UTF8) /* Local term charset is UTF-8 */
2693 unicode |= 1;
2694 #endif /* UNICODE */
2695 /*
2696 When Unicode not involved -- TCS is the intermediate (xfer) set, and:
2697 sxo = File-to-Intermediate charset function
2698 rxo = Intermediate-to-Remote-Terminal charset function
2699 sxi = Remote-Terminal-to-Intermediate
2700 rxi = Intermediate-to-Local-Terminal
2701 */
2702 tcs = gettcs(tcsr,fcharset); /* Get intermediate set. */
2703 sxo = xls[tcs][fcharset]; /* translation function */
2704 rxo = xlr[tcs][tcsr]; /* pointers for output functions */
2705 sxi = xls[tcs][tcsr]; /* and for input functions. */
2706 rxi = xlr[tcs][tcsl];
2707 /*
2708 At this point we have unicode nonzero if Unicode is involved in the
2709 conversion, and to 0 if it is not.
2710 The following is to prevent use of zmstuff() and zdstuff() by translation
2711 functions (stuffing works with file i/o, not with communication i/o).
2712 */
2713 langsv = language; /* Save current SET LANGUAGE */
2714 language = L_USASCII; /* No language-specific translations */
2715 }
2716 #endif /* NOCSETS */
2717
2718 i = 0; /* Beginning of buffer. */
2719 #ifndef MAC
2720 #ifndef AMIGA
2721 oldsig = signal(SIGINT, trtrap); /* Save current interrupt trap. */
2722 #endif /* AMIGA */
2723 #endif /* MAC */
2724 tr_int = 0; /* Have not been interrupted (yet). */
2725 rc = 1; /* Return code presumed good. */
2726 #ifdef VMS
2727 conres();
2728 #endif /* VMS */
2729
2730 #ifndef NOCSETS
2731 debug(F101,"XMIT unicode","",unicode);
2732 #ifdef UNICODE
2733 debug(F101,"XMIT bomorder","",bomorder);
2734 #endif /* UNICODE */
2735 #endif /* NOCSETS */
2736
2737 c = 0; /* Initial condition */
2738 while (c > -1 && !eof) { /* Loop for all characters in file */
2739 eol = 0;
2740 #ifdef MAC
2741 /*
2742 * It is expensive to run the miniparser so don't do it for
2743 * every character.
2744 */
2745 if (--count < 0) {
2746 count = 100;
2747 miniparser(1);
2748 if (sstate == 'a') {
2749 sstate = '\0';
2750 goto xmitfail;
2751 }
2752 }
2753 #else /* Not MAC */
2754 if (tr_int) { /* Interrupted? */
2755 printf("^C...\n"); /* Print message */
2756 goto xmitfail;
2757 }
2758 #endif /* MAC */
2759 c = zminchar(); /* Get a file character */
2760 #ifdef COMMENT
2761 /* too much */
2762 #ifdef DEBUG
2763 if (deblog) {
2764 if (c < 0)
2765 debug(F101,"XMIT zminchar","",c);
2766 else
2767 debug(F000,"XMIT zminchar","",c);
2768 }
2769 #endif /* DEBUG */
2770 #endif /* COMMENT */
2771 if (c < -1) { /* Other error */
2772 printf("?TRANSMIT file read error: %s\n",ck_errstr());
2773 goto xmitfail;
2774 } else if (c > -1) {
2775 nbytes++;
2776 c &= fmask; /* Apply SET FILE BYTESIZE mask */
2777 } else if (c == -1) {
2778 eof = 1;
2779 debug(F101,"XMIT eof","",eof);
2780 }
2781 if (binary) { /* Binary... */
2782 if (c == -1) { /* If EOF */
2783 rc = 1; /* Success */
2784 eof = 1;
2785 goto xmitexit; /* Done */
2786 }
2787 if (!xmitw && !xxecho) { /* Special "blast" mode */
2788 if (count == XBBUFSIZ) { /* File input buffer full... */
2789 while (count > 0) {
2790 errno = 0;
2791 y = ttol(xbbuf,count);
2792 if (y < 0) { /* try to send it. */
2793 printf("?TRANSMIT output error: %s\n",
2794 ck_errstr());
2795 debug(F111,"XMIT binary ttol error",
2796 ck_errstr(),errno);
2797 rc = 0;
2798 break;
2799 }
2800 if (y < 0) break;
2801 count -= y;
2802 }
2803 count = 0;
2804 }
2805 xbbuf[count++] = c;
2806 #ifdef TNCODE
2807 if (c == IAC && is_tn) /* Telnet IAC */
2808 xbbuf[count++] = IAC; /* must be doubled */
2809 #endif /* TNCODE */
2810 continue;
2811 }
2812 if (ttoc(dopar((char) c)) < 0) { /* else just send the char */
2813 printf("?Can't transmit character\n");
2814 goto xmitfail;
2815 }
2816 #ifdef TNCODE
2817 if (c == IAC && is_tn) /* Quote Telnet IAC */
2818 ttoc((char)IAC);
2819 #endif /* TNCODE */
2820
2821 if (xmitw) /* Pause if requested */
2822 msleep(xmitw);
2823
2824 if (xxecho) { /* SET TRANSMIT ECHO ON? */
2825 if (duplex) { /* Yes, for half duplex */
2826 #ifndef NOLOCAL
2827 #ifdef OS2
2828 /* Echo to emulator */
2829 scriptwrtbuf((USHORT)(c & cmdmsk));
2830 #endif /* OS2 */
2831 #endif /* NOLOCAL */
2832 if (conoc((char)(c & cmdmsk)) < 0) /* echo locally. */
2833 goto xmitfail;
2834 } else { /* For full duplex, */
2835 int i, n; /* display whatever is there. */
2836 n = ttchk(); /* See how many chars are waiting */
2837 if (n < 0) { /* Connection dropped? */
2838 printf("?Connection lost\n");
2839 goto xmitfail;
2840 }
2841 for (i = 0; i < n; i++) { /* Read and echo that many. */
2842 x = ttinc(xmitt); /* Timed read just in case. */
2843 if (x > -1) { /* If no timeout */
2844 if (parity) x &= 0x7f; /* display the char, */
2845 #ifndef NOLOCAL
2846 #ifdef OS2
2847 /* Echo to emulator */
2848 scriptwrtbuf((USHORT)x);
2849 #endif /* OS2 */
2850 #endif /* NOLOCAL */
2851 if (conoc((char)(x & cmdmsk)) < 0) {
2852 printf("?Output error\n");
2853 goto xmitfail;
2854 }
2855 } else if (x == -2) {
2856 printf("Connection closed.\n");
2857 ttclos(1);
2858 goto xmitfail;
2859 } else if (x == -3) {
2860 printf(
2861 "Session Limit exceeded - closing connection.\n"
2862 );
2863 ttclos(1);
2864 goto xmitfail;
2865 } else {
2866 printf("?Communications error\n");
2867 goto xmitfail;
2868 }
2869 }
2870 }
2871 } else ttflui(); /* Not echoing, just flush input. */
2872
2873 } else { /* Text mode, line at a time. */
2874 #ifdef UNICODE
2875 if (fcharset == FC_UCS2 && xlate) { /* Special for UCS-2 */
2876 char xbuf[8];
2877 x = 1 - (nbytes & 1); /* Odd or even byte */
2878 if (x == 0) /* Note: 1 = the 1st, 0 = 2nd, etc */
2879 uc.x_short = 0;
2880 if (bomorder) /* Little Endian */
2881 x = 1 - x; /* Save byte in appropriate half */
2882 debug(F101,"XMIT UCS2 x","",x);
2883 uc.x_char[x] = (CHAR) (c & 0xff);
2884 if (nbytes & 1) /* First byte, go back for next */
2885 continue;
2886 if (nbytes == 2) { /* UCS-2 Byte Order Mark */
2887 if (uc.x_short == (USHORT) 0xfeff) {
2888 debug(F100,"XMIT UCS2 BOM FEFF","",bomorder);
2889 continue;
2890 } else if (uc.x_short == (USHORT) 0xfffe) {
2891 bomorder = 1 - bomorder;
2892 debug(F100,"XMIT UCS2 BOM FFFE (swap)","",bomorder);
2893 continue;
2894 }
2895 }
2896 sprintf(xbuf,"%04X",uc.x_short); /* SAFE */
2897 debug(F111,"XMIT UCS2",xbuf,uc.x_short);
2898 if (nbytes & 1) /* Special eol test for UCS-2 */
2899 if (uc.x_short == '\n')
2900 eol = 1;
2901 #ifdef COMMENT
2902 if (uc.x_short == 0x2028 || uc.x_short == 0x2029)
2903 eol = 1;
2904 #endif /* COMMENT */
2905 } else
2906 #endif /* UNICODE */
2907 if (c == '\n') { /* Normal eol test otherwise */
2908 eol = 1;
2909 }
2910 if (eol) { /* End of line? */
2911 int stuff = -1;
2912 debug(F101,"XMIT eol length","",i);
2913 if (i == 0) { /* Blank line? */
2914 if (xmitf) /* Yes, insert fill if asked. */
2915 line[i++] = dopar((char) xmitf);
2916 }
2917 if (i == 0 || ((char) line[i-1]) != ((char) dopar(CR)))
2918 line[i++] = dopar(CR); /* Terminate it with CR */
2919 if (xmitl) {
2920 stuff = LF;
2921 #ifdef TNCODE
2922 } else if (is_tn && (tn_nlm != TNL_CR)) {
2923 /* TELNET NEWLINE ON/OFF/RAW */
2924 stuff = (tn_nlm == TNL_CRLF) ? LF : NUL;
2925 #endif /* TNCODE */
2926 }
2927 if (stuff > -1)
2928 line[i++] = dopar((char)stuff);
2929 line[i] = NUL;
2930 debug(F111,"XMIT eol line",line,i);
2931
2932 } else if (c != -1) { /* Not a newline, regular character */
2933 int k, x;
2934 outxbuf[0] = c; /* In case of no translation */
2935 outxcount = 1; /* Assume result is one byte */
2936 #ifndef NOCSETS
2937 switch (unicode) {
2938 case 0: /* No Unicode involved */
2939 case 1:
2940 if (xlate) { /* If not /TRANSPARENT */
2941 /* Local-to-intermediate */
2942 if (sxo) c = (*sxo)((char)c);
2943 /* Intermediate-to-remote */
2944 if (rxo) c = (*rxo)((char)c);
2945 outxbuf[0] = c;
2946 }
2947 break;
2948 #ifdef UNICODE
2949 case 2: /* Local byte to UTF-8 */
2950 case 3:
2951 xfu = xl_fcu[fcharset];
2952 tcssize = fcsinfo[fcharset].size;
2953 outxcount =
2954 b_to_u((CHAR)c,outxbuf,OUTXBUFSIZ,tcssize);
2955 break;
2956 case 4: /* Local UTF-8 to remote byte */
2957 case 5:
2958 xuf = xl_ufc[tcsr];
2959 x = u_to_b((CHAR)c); /* Convert to byte */
2960 if (x == -1) { /* If more input bytes needed */
2961 continue; /* go back and get them */
2962 } else if (x == -2) { /* LS or PS (shouldn't happen) */
2963 outxbuf[0] = CR;
2964 } else if (x == -9) { /* UTF-8 error */
2965 outxbuf[0] = '?'; /* Insert error char */
2966 outxbuf[1] = u_to_b2(); /* Insert next char */
2967 outxcount = 2;
2968 } else {
2969 outxbuf[0] = /* Otherwise store result */
2970 (unsigned)(x & 0xff);
2971 }
2972 break;
2973 case 6: /* UTF-8 to UTF-8 */
2974 case 7:
2975 break;
2976 case 8: /* UCS-2 to byte */
2977 case 9:
2978 xuf = xl_ufc[tcsr];
2979 outxbuf[0] = (*xuf)(uc.x_short);
2980 break;
2981 case 10:
2982 case 11: { /* UCS-2 to UTF-8 */
2983 int j;
2984 CHAR * buf = NULL;
2985 x = ucs2_to_utf8(uc.x_short,&buf);
2986 if (x < 0) {
2987 outxbuf[0] = 0xff; /* (= U+FFFD) */
2988 outxbuf[1] = 0xbd;
2989 x = 2;
2990 }
2991 for (j = 0; j < x; j++)
2992 outxbuf[j] = buf[j];
2993 outxcount = x;
2994 break;
2995 }
2996 #endif /* UNICODE */
2997 }
2998 #endif /* NOCSETS */
2999 outxbuf[outxcount] = NUL;
3000 debug(F111,"XMIT outxbuf",outxbuf,outxcount);
3001 /*
3002 Now the input character (1 or more bytes) is translated into the output
3003 expansion buffer (1 or more bytes); outxcount = number of bytes to add to
3004 the TRANSMIT line buffer, which we do here, taking care of parity, SI/SO
3005 processing, and quoting Telnet IACs.
3006 */
3007 for (k = 0; k < outxcount; k++) {
3008 c = outxbuf[k];
3009 if (xmits && parity && (c & 0200)) { /* If shifting */
3010 line[i++] = dopar(SO); /* needs to be done, */
3011 line[i++] = dopar((char)c); /* do it here, */
3012 line[i++] = dopar(SI); /* crudely. */
3013 } else {
3014 line[i++] = dopar((char)c);
3015 #ifdef TNCODE
3016 if (c == (CHAR)IAC && is_tn)
3017 line[i++] = (CHAR)IAC;
3018 #endif /* TNCODE */
3019 }
3020 }
3021 }
3022 /*
3023 Send characters if buffer full, or at end of line, or at end of file.
3024 (End of line only if echoing, waiting for a prompt, or pausing.)
3025 */
3026 debug(F000,"XMIT c",ckitoa(i),c);
3027 if (i >= xbufsiz || eof || (eol && (xxecho || xmitw || t))) {
3028 p = line;
3029 line[i] = '\0';
3030 debug(F111,"transmit buf",p,i);
3031 if (ttol((CHAR *)p,i) < 0) { /* try to send it. */
3032 printf("?TRANSMIT output error: %s\n",ck_errstr());
3033 rc = 0;
3034 break;
3035 }
3036 i = 0; /* Reset buffer pointer. */
3037 /*
3038 Now we handle the echo. If the user wants to see it, or if we have to
3039 wait for the turnaround character, t. If the echo is being displayed,
3040 and terminal character-set translation is required, we do it here.
3041 */
3042 if (duplex && xxecho) { /* If local echo, echo it */
3043 if (parity || cmdmsk == 0x7f) { /* Strip hi bits */
3044 char *ss = line; /* if necessary */
3045 while (*ss) {
3046 *ss &= 0x7f;
3047 ss++;
3048 }
3049 }
3050 #ifndef NOLOCAL
3051 #ifdef OS2
3052 { /* Echo to emulator */
3053 char *ss = p;
3054 while (*ss) {
3055 scriptwrtbuf((USHORT)*ss);
3056 ss++;
3057 }
3058 }
3059 #endif /* OS2 */
3060 #endif /* NOLOCAL */
3061 if (conoll(p) < 0)
3062 goto xmitfail;
3063 }
3064 if (xmitw) /* Sleep TRANSMIT PAUSE interval */
3065 msleep(xmitw);
3066
3067 control = 0; /* Readback loop control */
3068 if (t != 0 && eol) /* TRANSMIT PROMPT given and at EOL */
3069 control |= 1;
3070 if (xxecho && !duplex) /* Echo desired and is remote */
3071 control |= 2;
3072
3073 if (control) { /* Do this if reading back the echo */
3074 int n;
3075 x = 0;
3076 while (1) {
3077 if (control & 1) { /* Termination criterion */
3078 if (x == t) /* for turnaround */
3079 break;
3080 } else if (control & 2) { /* And for echoing */
3081 if ((n = ttchk()) < 1)
3082 break;
3083 }
3084 if ((x = ttinc(xmitt)) < 0) { /* Read with timeout */
3085 switch (x) {
3086 case -2:
3087 printf("Connection closed.\n");
3088 ttclos(1);
3089 goto xmitfail;
3090 case -3:
3091 printf(
3092 "Session Limit exceeded - closing connection.\n"
3093 );
3094 ttclos(1); /* full thru... */
3095 goto xmitfail;
3096 default:
3097 printf("?Timeout\n");
3098 goto xmitfail;
3099 }
3100 }
3101 if (x > -1 && (control & 2)) { /* Echo any echoes */
3102 if (parity)
3103 x &= 0x7f;
3104 c = x;
3105 #ifndef NOLOCAL
3106 #ifdef OS2
3107 scriptwrtbuf((USHORT)x);
3108 #endif /* OS2 */
3109 #endif /* NOLOCAL */
3110 inxbuf[0] = c;
3111 inxcount = 1;
3112 #ifndef NOCSETS
3113 switch (unicode & 3) { /* Remote bits */
3114 case 0:
3115 if (xlate) {
3116 if (sxi) c = (*sxi)((CHAR)c);
3117 if (rxi) c = (*rxi)((CHAR)c);
3118 inxbuf[0] = c;
3119 }
3120 break;
3121 #ifdef UNICODE
3122 case 1: /* Remote Byte to local UTF-8 */
3123 xfu = xl_fcu[tcsr];
3124 tcssize = fcsinfo[tcsr].size;
3125 inxcount =
3126 b_to_u((CHAR)c,
3127 inxbuf,
3128 OUTXBUFSIZ,
3129 tcssize
3130 );
3131 break;
3132 case 2: /* Remote UTF-8 to local Byte */
3133 xuf = xl_ufc[tcsl];
3134 x = u_to_b((CHAR)c);
3135 if (x < 0)
3136 continue;
3137 inxbuf[0] = (unsigned)(x & 0xff);
3138 break;
3139 case 3: /* UTF-8 to UTF-8 */
3140 break;
3141 #endif /* UNICODE */
3142 }
3143 #endif /* NOCSETS */
3144 inxbuf[inxcount] = NUL;
3145 if (conxo(inxcount,(char *)inxbuf) < 0)
3146 goto xmitfail;
3147 }
3148 }
3149 } else /* Not echoing */
3150 ttflui(); /* Just flush input buffer */
3151 } /* End of buffer-dumping block */
3152 } /* End of text mode */
3153 if (eof) {
3154 rc = 1;
3155 goto xmitexit;
3156 }
3157 } /* End of character-reading loop */
3158
3159 xmitfail: /* Failure exit point */
3160 rc = 0;
3161
3162 xmitexit: /* General exit point */
3163 if (rc > 0) {
3164 if (binary && !xmitw && !xxecho) { /* "blasting"? */
3165 while (count > 0) { /* Partial buffer still to go? */
3166 errno = 0;
3167 y = ttol(xbbuf,count);
3168 if (y < 0) {
3169 printf("?TRANSMIT output error: %s\n",
3170 ck_errstr());
3171 debug(F111,"XMIT binary eof ttol error",
3172 ck_errstr(),errno);
3173 rc = 0;
3174 break;
3175 }
3176 count -= y;
3177 }
3178 } else if (!binary && *xmitbuf) { /* Anything to send at EOF? */
3179 p = xmitbuf; /* Yes, point to string. */
3180 while (*p) /* Send it. */
3181 ttoc(dopar(*p++)); /* Don't worry about echo here. */
3182 }
3183 }
3184
3185 #ifndef AMIGA
3186 #ifndef MAC
3187 signal(SIGINT,oldsig); /* Put old signal action back. */
3188 #endif /* MAC */
3189 #endif /* AMIGA */
3190 #ifdef VMS
3191 concb(escape); /* Put terminal back, */
3192 #endif /* VMS */
3193 zclose(ZIFILE); /* Close file, */
3194 #ifndef NOCSETS
3195 language = langsv; /* restore language, */
3196 #endif /* NOCSETS */
3197 ttres(); /* and terminal modes, */
3198 return(rc); /* and return successfully. */
3199 }
3200 #endif /* NOLOCAL */
3201 #endif /* NOXMIT */
3202
3203 #ifndef NOCSETS
3204
3205 _PROTOTYP( CHAR (*sxx), (CHAR) ); /* Local translation function */
3206 _PROTOTYP( CHAR (*rxx), (CHAR) ); /* Local translation function */
3207 _PROTOTYP( CHAR zl1as, (CHAR) ); /* Latin-1 to ascii */
3208 _PROTOTYP( CHAR xl1as, (CHAR) ); /* ditto */
3209
3210 /* X L A T E -- Translate a local file from one character set to another */
3211
3212 /*
3213 Translates input file (fin) from character set csin to character set csout
3214 and puts the result in the output file (fout). The two character sets are
3215 file character sets from fcstab.
3216 */
3217
3218 int
xlate(fin,fout,csin,csout)3219 xlate(fin, fout, csin, csout) char *fin, *fout; int csin, csout; {
3220
3221 #ifndef MAC
3222 #ifdef OS2
3223 extern int k95stdout;
3224 extern int wherex[], wherey[];
3225 extern unsigned char colorcmd;
3226 #ifdef NT
3227 SIGTYP (* oldsig)(int); /* For saving old interrupt trap. */
3228 #else /* NT */
3229 SIGTYP (* volatile oldsig)(int); /* For saving old interrupt trap. */
3230 #endif /* NT */
3231 #else /* OS2 */
3232 SIGTYP (* oldsig)();
3233 #endif /* OS2 */
3234 #endif /* MAC */
3235 #ifdef CK_ANSIC
3236 int (*fn)(char); /* Output function pointer */
3237 #else
3238 int (*fn)();
3239 #endif /* CK_ANSIC */
3240 extern int xlatype;
3241 int filecode; /* Code for output file */
3242 int scrnflg = 0;
3243
3244 int z = 1; /* Return code. */
3245 int x, c, c2; /* Workers */
3246 #ifndef UNICODE
3247 int tcs;
3248 #endif /* UNICODE */
3249
3250 ffc = 0L;
3251
3252 if (zopeni(ZIFILE,fin) == 0) { /* Open the file to be translated */
3253 #ifdef COMMENT
3254 /* An error message was already printed by zopeni() */
3255 printf("?Can't open input file %s\n",fin);
3256 #endif /* COMMENT */
3257 return(0);
3258 }
3259 #ifdef MAC
3260 /*
3261 If user specified no output file, it goes to the screen. For the Mac,
3262 this must be done a special way (result goes to a new window); the Mac
3263 doesn't have a "controlling terminal" device name.
3264 */
3265 filecode = !strcmp(fout,CTTNAM) ? ZCTERM : ZOFILE;
3266 #else
3267 #ifdef VMS
3268 filecode = !strcmp(fout,CTTNAM) ? ZCTERM : ZMFILE;
3269 #else
3270 #ifdef OS2
3271 filecode = (!stricmp(fout,"con") || !stricmp(fout,"con:")) ?
3272 ZCTERM : ZMFILE;
3273 if ((filecode == ZCTERM) && !k95stdout && !inserver)
3274 csout = FC_UCS2;
3275 #else /* OS2 */
3276 filecode = ZOFILE;
3277 #endif /* OS2 */
3278 #endif /* VMS */
3279 #endif /* MAC */
3280 if (zopeno(filecode,fout,NULL,NULL) == 0) { /* And the output file */
3281 printf("?Can't open output file %s\n",fout);
3282 return(0);
3283 }
3284 #ifndef AMIGA
3285 #ifndef MAC
3286 oldsig = signal(SIGINT, trtrap); /* Save current interrupt trap. */
3287 #endif /* MAC */
3288 #endif /* AMIGA */
3289
3290 scrnflg = (filecode == ZCTERM); /* Set output function */
3291 if (scrnflg)
3292 fn = NULL;
3293 else if (filecode == ZMFILE)
3294 fn = putmfil;
3295 else
3296 fn = putfil;
3297
3298 tr_int = 0; /* Have not been interrupted (yet). */
3299 z = 1; /* Return code presumed good. */
3300
3301 if (!scrnflg && !quiet)
3302 printf(" %s (%s) => %s (%s)\n", /* Say what we're doing. */
3303 fin, fcsinfo[csin].keyword,
3304 fout,fcsinfo[csout].keyword
3305 );
3306
3307 #ifndef UNICODE
3308 /*
3309 Non-Unicode picks the "most appropriate" transfer character set as the
3310 intermediate set, which results in loss of any characters that the source
3311 and target sets have in common, but are lacking from the intermediate set.
3312 */
3313 #ifdef KANJI
3314 /* Special handling for Japanese... */
3315
3316 if (fcsinfo[csin].alphabet == AL_JAPAN ||
3317 fcsinfo[csout].alphabet == AL_JAPAN) {
3318 USHORT eu;
3319 int c, x, y;
3320
3321 xpnbyte(-1,0,0,NULL); /* Reset output machine */
3322 xlatype = XLA_JAPAN;
3323
3324 while ((c = xgnbyte(FC_JEUC,csin,NULL)) > -1) { /* Get an EUC byte */
3325 if (tr_int) { /* Interrupted? */
3326 printf("^C...\n"); /* Print message */
3327 z = 0;
3328 break;
3329 }
3330 /* Send EUC byte to output machine */
3331 if ((x = xpnbyte(c,TC_JEUC,csout,fn)) < 0) {
3332 z = -1;
3333 break;
3334 }
3335 }
3336 goto xxlate;
3337 }
3338 #endif /* KANJI */
3339
3340 /* Regular bytewise conversion... */
3341
3342 tcs = gettcs(csin,csout); /* Get intermediate set. */
3343 if (csin == csout) { /* Input and output sets the same? */
3344 sxx = rxx = NULL; /* If so, no translation. */
3345 } else { /* Otherwise, set up */
3346 if (tcs < 0 || tcs > MAXTCSETS ||
3347 csin < 0 || csin > MAXFCSETS ||
3348 csout < 0 || csout > MAXFCSETS) {
3349 debug(F100,"XLATE csets out of range","",0);
3350 sxx = rxx = NULL;
3351 } else {
3352 sxx = xls[tcs][csin]; /* translation function */
3353 rxx = xlr[tcs][csout]; /* pointers. */
3354 if (rxx == zl1as) rxx = xl1as;
3355 }
3356 }
3357 while ((c = zminchar()) != -1) { /* Loop for all characters in file */
3358 if (tr_int) { /* Interrupted? */
3359 printf("^C...\n"); /* Print message */
3360 z = 0;
3361 break;
3362 }
3363 if (sxx) c = (*sxx)((CHAR)c); /* From fcs1 to tcs */
3364 if (rxx) c = (*rxx)((CHAR)c); /* from tcs to fcs2 */
3365 if (zchout(filecode,(char)c) < 0) { /* Output xlated character */
3366 z = -1;
3367 break;
3368 }
3369 }
3370 goto xxlate; /* Done. */
3371
3372 #else /* UNICODE */
3373 /*
3374 Use Unicode as the intermediate character set. It's simple and gives
3375 little or no loss, but the overhead is a bit higher.
3376 */
3377 initxlate(csin,csout); /* Set up translation functions */
3378
3379 if (xlatype == XLA_NONE) {
3380 while ((c = zminchar()) != -1) { /* Loop for all characters in file */
3381 if (tr_int) { /* Interrupted? */
3382 printf("^C...\n"); /* Print message */
3383 z = 0;
3384 break;
3385 }
3386 if (zchout(filecode,(char)c) < 0) { /* Output xlated character */
3387 z = -1;
3388 break;
3389 }
3390 }
3391 goto xxlate; /* Done. */
3392 }
3393
3394
3395 #ifndef NOLOCAL
3396 #ifdef OS2
3397 if (csout == FC_UCS2 && /* we're translating to UCS-2 */
3398 filecode == ZCTERM && /* for the real screen... */
3399 !k95stdout && !inserver
3400 ) {
3401 union {
3402 USHORT ucs2;
3403 UCHAR bytes[2];
3404 } output;
3405
3406 while (1) { /* In this case we go two-by-two. */
3407 if ((c = xgnbyte(FC_UCS2,csin,NULL)) < 0)
3408 break;
3409 output.bytes[0] = c;
3410 if ((c = xgnbyte(FC_UCS2,csin,NULL)) < 0)
3411 break;
3412 output.bytes[1] = c;
3413
3414 if (tr_int) { /* Interrupted? */
3415 printf("^C...\n"); /* Print message */
3416 z = 0;
3417 break;
3418 }
3419
3420 VscrnWrtUCS2StrAtt(VCMD,
3421 &output.ucs2,
3422 1,
3423 wherey[VCMD],
3424 wherex[VCMD],
3425 &colorcmd
3426 );
3427 }
3428 } else
3429 #endif /* OS2 */
3430 #endif /* NOLOCAL */
3431
3432 /* General case: Get next byte translated from fcs to UCS-2 */
3433
3434 #ifdef COMMENT
3435 while ((c = xgnbyte(FC_UCS2,csin,NULL)) > -1 &&
3436 (c2 = xgnbyte(FC_UCS2,csin,NULL)) > -1) {
3437 extern int fileorder;
3438
3439 if (tr_int) { /* Interrupted? */
3440 printf("^C...\n"); /* Print message */
3441 z = 0;
3442 break;
3443 }
3444 debug(F001,"XLATE c","",c);
3445 debug(F001,"XLATE c2","",c2);
3446
3447 /* And then send UCS-2 byte to translate-and-output machine */
3448
3449 if ((x = xpnbyte(fileorder?c2:c,TC_UCS2,csout,fn)) < 0) {
3450 z = -1;
3451 break;
3452 }
3453 if ((x = xpnbyte(fileorder?c:c2,TC_UCS2,csout,fn)) < 0) {
3454 z = -1;
3455 break;
3456 }
3457 }
3458 #else
3459 while ((c = xgnbyte(FC_UCS2,csin,NULL)) > -1) {
3460 if (tr_int) { /* Interrupted? */
3461 printf("^C...\n"); /* Print message */
3462 z = 0;
3463 break;
3464 }
3465 if ((x = xpnbyte(c,TC_UCS2,csout,fn)) < 0) {
3466 z = -1;
3467 break;
3468 }
3469 }
3470 #endif /* COMMENT */
3471
3472 #endif /* UNICODE */
3473
3474 xxlate: /* Common exit point */
3475
3476 #ifndef AMIGA
3477 #ifndef MAC
3478 signal(SIGINT,oldsig); /* Put old signal action back. */
3479 #endif /* MAC */
3480 #endif /* AMIGA */
3481 tr_int = 0;
3482 if (z < 0) {
3483 if (z == -1)
3484 printf("?File output error: %s\n",ck_errstr());
3485 z = 0;
3486 }
3487 zclose(ZIFILE); /* Close files */
3488 zclose(filecode); /* ... */
3489 return(success = z); /* and return status. */
3490 }
3491
3492 int
doxlate()3493 doxlate() {
3494 #ifdef OS2ONLY
3495 extern int tt_font;
3496 #endif /* OS2ONLY */
3497 #ifdef UNIX
3498 extern char ** mtchs; /* zxpand() file list */
3499 #endif /* UNIX */
3500 int x, y, incs, outcs, multiple = 0, wild = 0, fc = 0, len = 0;
3501 int ofisdir = 0;
3502 char * s, * tocs = "";
3503
3504 if ((x = cmifi("File(s) to translate","",&s,&wild,xxstring)) < 0) {
3505 if (x == -3) {
3506 printf("?Name of an existing file\n");
3507 return(-9);
3508 } else
3509 return(x);
3510 }
3511 ckstrncpy(line,s,LINBUFSIZ); /* Save copy of string just parsed. */
3512
3513 if ((incs = cmkey(fcstab,nfilc,"from character-set","",xxstring)) < 0)
3514 return(incs);
3515
3516 #ifdef OS2
3517 if (isunicode())
3518 tocs = "ucs2";
3519 else
3520 #endif /* OS2 */
3521 tocs = getdcset();
3522
3523 if ((outcs = cmkey(fcstab,nfilc,"to character-set",tocs,xxstring)) < 0)
3524 return(outcs);
3525 if ((x = cmofi("output file",CTTNAM,&s,xxstring)) < 0) return(x);
3526 if (x > 1)
3527 ofisdir = 1;
3528
3529 len = ckstrncpy(tmpbuf,s,TMPBUFSIZ);
3530 if ((y = cmcfm()) < 0) return(y); /* Confirm the command */
3531
3532 if (len < 1)
3533 return(-2);
3534
3535 if (ofisdir)
3536 multiple = 2;
3537 else if (wild) {
3538 if (isdir(tmpbuf))
3539 multiple = 2;
3540 else if (!strcmp(tmpbuf,CTTNAM))
3541 multiple = 1;
3542 #ifdef OS2
3543 else if (!stricmp(tmpbuf,"con") || !stricmp(tmpbuf,"con:"))
3544 multiple = 1;
3545 #else
3546 #ifdef UNIXOROSK
3547 else if (!strncmp(tmpbuf,"/dev/",4))
3548 multiple = 1;
3549 #endif /* UNIXOROSK */
3550 #endif /* OS2 */
3551 if (!multiple) {
3552 printf("?A single file please\n");
3553 return(-9);
3554 }
3555 }
3556 if (!multiple) { /* Just one file */
3557 return(success = xlate(line,tmpbuf,incs,outcs));
3558 } else { /* Translate multiple files */
3559 char dirbuf[CKMAXPATH+4];
3560 int k;
3561 #ifndef ZXREWIND
3562 int flags = ZX_FILONLY;
3563 #endif /* ZXREWIND */
3564
3565 if (multiple == 2) { /* Target is a directory */
3566 k = ckstrncpy(dirbuf,tmpbuf,CKMAXPATH+1) - 1;
3567 if (k < 0)
3568 return(-2);
3569 #ifdef OS2ORUNIX
3570 if (dirbuf[k] != '/') {
3571 dirbuf[k+1] = '/';
3572 dirbuf[k+2] = NUL;
3573 }
3574 #else
3575 #ifdef OSK
3576 if (dirbuf[k] != '/') {
3577 dirbuf[k+1] = '/';
3578 dirbuf[k+2] = NUL;
3579 }
3580 #else
3581 #ifdef VMS
3582 if (ckmatch("*.DIR;1",s,0,0))
3583 k = cvtdir(tmpbuf,dirbuf,TMPBUFSIZ);
3584 if (dirbuf[k] != ']' &&
3585 dirbuf[k] != '>' &&
3586 dirbuf[k] != ':')
3587 return(-2);
3588 #else
3589 #ifdef datageneral
3590 if (dirbuf[k] != ':') {
3591 dirbuf[k+1] = ':';
3592 dirbuf[k+2] = NUL;
3593 }
3594 #else
3595 #ifdef STRATUS
3596 if (dirbuf[k] != '>') {
3597 dirbuf[k+1] = '>';
3598 dirbuf[k+2] = NUL;
3599 }
3600 #endif /* STRATUS */
3601 #endif /* datageneral */
3602 #endif /* VMS */
3603 #endif /* OSK */
3604 #endif /* OS2ORUNIX */
3605 }
3606
3607 #ifdef ZXREWIND
3608 fc = zxrewind(); /* Rewind the file list */
3609 #else
3610 if (matchdot) flags |= ZX_MATCHDOT;
3611 fc = nzxpand(line,flags);
3612 #endif /* ZXREWIND */
3613
3614 if (fc < 1) {
3615 printf("?Wildcard expansion error\n");
3616 return(-9);
3617 }
3618 #ifdef UNIX
3619 sh_sort(mtchs,NULL,fc,0,0,filecase); /* Sort the file list */
3620 #endif /* UNIX */
3621
3622 while (1) { /* Loop through the files */
3623 znext(line);
3624 if (!line[0])
3625 break;
3626 if (multiple == 2)
3627 ckmakmsg(tmpbuf,TMPBUFSIZ,dirbuf,line,NULL,NULL);
3628 if (xlate(line,tmpbuf,incs,outcs) < 1)
3629 return(success = 0);
3630 }
3631 }
3632 return(success = 1);
3633 }
3634 #endif /* NOCSETS */
3635
3636 /*
3637 Returns path of user's actual home directory (or, if specified, SET CD HOME
3638 directory), properly terminated to allow filenames or sub-paths to be
3639 appended.
3640 */
3641 static char hompthbuf[CKMAXPATH+1] = { NUL, NUL }; /* Home directory path */
3642
3643 char *
homepath()3644 homepath() {
3645 int x;
3646 extern char hompthbuf[];
3647 extern char * myhome;
3648 char * h;
3649
3650 /* myhome = SET CD HOME; zhome() uses API to get home directory */
3651 h = myhome ? myhome : zhome();
3652 hompthbuf[0] = NUL;
3653
3654 /* Ensure it is terminated with appropriate directory or device separator. */
3655
3656 #ifdef UNIXOROSK
3657 x = ckstrncpy(hompthbuf,h,CKMAXPATH+1);
3658 if (x <= 0) {
3659 hompthbuf[0] = '/';
3660 hompthbuf[1] = NUL;
3661 } else if (x < CKMAXPATH - 2 && hompthbuf[x-1] != '/') {
3662 hompthbuf[x] = '/';
3663 hompthbuf[x+1] = NUL;
3664 }
3665 return(hompthbuf);
3666 #else
3667 #ifdef STRATUS
3668 if (strlen(h) < CKMAXPATH)
3669 sprintf(hompthbuf,"%s>",h); /* SAFE */
3670 return(hompthbuf);
3671 #else
3672 return(h);
3673 #endif /* STRATUS */
3674 #endif /* UNIXOROSK */
3675 }
3676
3677 /* D O L O G -- Do the log command */
3678
3679 int
dolog(x)3680 dolog(x) int x; {
3681 int y, disp; char *s = NULL, * p = NULL, * q = NULL;
3682 extern int isguest;
3683 #ifdef ZFNQFP
3684 struct zfnfp * fnp;
3685 #endif /* ZFNQFP */
3686
3687 if (isguest) {
3688 printf("?Anonymous log creation not allowed\n");
3689 return(-9);
3690 }
3691 switch (x) { /* Which log... */
3692
3693 #ifdef DEBUG
3694 case LOGD:
3695 q = "debug.log";
3696 y = cmofi("Name of debugging log file",q,&s,xxstring);
3697 break;
3698 #endif /* DEBUG */
3699
3700 case LOGP:
3701 q = "packet.log";
3702 y = cmofi("Name of packet log file",q,&s,xxstring);
3703 break;
3704
3705 #ifndef NOLOCAL
3706 case LOGS:
3707 q = "session.log";
3708 y = cmofi("Name of session log file",q,&s,xxstring);
3709 break;
3710 #endif /* NOLOCAL */
3711
3712 #ifdef TLOG
3713 case LOGT:
3714 q = "transact.log";
3715 y = cmofi("Name of transaction log file",q,&s,xxstring);
3716 break;
3717 #endif /* TLOG */
3718
3719 #ifdef CKLOGDIAL
3720 case LOGM: {
3721 int m, n;
3722 char mypath[CKMAXPATH+1];
3723 q = CXLOGFILE;
3724 m = ckstrncpy(mypath,homepath(),CKMAXPATH);
3725 n = strlen(CXLOGFILE);
3726 if (m + n < CKMAXPATH)
3727 ckstrncat(mypath,CXLOGFILE,CKMAXPATH);
3728 else
3729 ckstrncpy(mypath,CXLOGFILE,CKMAXPATH);
3730 y = cmofi("Name of connection log file",mypath,&s,xxstring);
3731 break;
3732 }
3733 #endif /* CKLOGDIAL */
3734
3735 default:
3736 printf("\n?Unknown log designator - %d\n",x);
3737 return(-2);
3738 }
3739 if (y < 0) return(y);
3740 if (y == 2) { /* If they gave a directory name */
3741 int k;
3742 char * ds = "/";
3743 k = strlen(s);
3744 if (k > 0 && s[k-1] == '/') ds = "";
3745 ckmakmsg(tmpbuf,TMPBUFSIZ,s,ds,q,NULL);
3746 s = tmpbuf;
3747 }
3748 #ifdef ZFNQFP
3749 #ifdef OS2ORUNIX
3750 if (*s != '|') /* Allow for pipes */
3751 #else
3752 #ifdef OSK
3753 if (*s != '|')
3754 #endif /* OSK */
3755 #endif /* OS2ORUNIX */
3756 if ((fnp = zfnqfp(s,TMPBUFSIZ - 1,tmpbuf))) {
3757 if (fnp->fpath)
3758 if ((int) strlen(fnp->fpath) > 0)
3759 s = fnp->fpath;
3760 } /* else if error keep original string */
3761 #endif /* ZFNQFP */
3762
3763 ckstrncpy(line,s,LINBUFSIZ);
3764 s = line;
3765 #ifdef MAC
3766 y = 0;
3767 #else
3768
3769 p = "new";
3770 #ifdef TLOG
3771 if ((x == LOGT && tlogfmt == 2) || x == LOGM)
3772 p = "append";
3773 #endif /* TLOG */
3774
3775 if ((y = cmkey(disptb,2,"Disposition",p,xxstring)) < 0)
3776 return(y);
3777 #endif /* MAC */
3778 disp = y;
3779 if ((y = cmcfm()) < 0) return(y);
3780
3781 switch (x) {
3782
3783 #ifdef DEBUG
3784 case LOGD:
3785 return(deblog = debopn(s,disp));
3786 #endif /* DEBUG */
3787
3788 #ifndef NOXFER
3789 case LOGP:
3790 return(pktlog = pktopn(s,disp));
3791 #endif /* NOXFER */
3792
3793 #ifndef NOLOCAL
3794 case LOGS:
3795 setseslog(sesopn(s,disp));
3796 return(seslog);
3797 #endif /* NOLOCAL */
3798
3799 #ifdef TLOG
3800 case LOGT:
3801 return(tralog = traopn(s,disp));
3802 #endif /* TLOG */
3803
3804 #ifdef CKLOGDIAL
3805 case LOGM:
3806 return(dialog = diaopn(s,disp,0));
3807 #endif /* CKLOGDIAL */
3808
3809 default:
3810 return(-2);
3811 }
3812 }
3813
3814 #ifndef NOXFER
3815 int
pktopn(s,disp)3816 pktopn(s,disp) char *s; int disp; {
3817 static struct filinfo xx;
3818
3819 if (!s)
3820 s = "";
3821 if (!*s)
3822 return(0);
3823
3824 debug(F111,"pktopn",s,disp);
3825
3826 zclose(ZPFILE);
3827
3828 #ifdef OS2ORUNIX
3829 if (s[0] == '|') { /* Pipe */
3830 char * p = s + 1;
3831 debug(F110,"pktopn p",p,0);
3832 while (*p) {
3833 if (*p != ' ')
3834 break;
3835 else
3836 p++;
3837 }
3838 debug(F110,"pktopn pipe",p,0);
3839 pktlog = zxcmd(ZPFILE,p);
3840 debug(F101,"pktopn seslog","",seslog);
3841 } else { /* File */
3842 #endif /* OS2ORUNIX */
3843 if (disp) {
3844 xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
3845 xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
3846 xx.lblopts = 0;
3847 pktlog = zopeno(ZPFILE,s,NULL,&xx);
3848 } else pktlog = zopeno(ZPFILE,s,NULL,NULL);
3849 if (!pktlog && !quiet)
3850 printf("?%s - %s\n",s,ck_errstr());
3851 #ifdef OS2ORUNIX
3852 }
3853 #endif /* OS2ORUNIX */
3854 if (pktlog > 0)
3855 ckstrncpy(pktfil,s,CKMAXPATH+1);
3856 else
3857 *pktfil = '\0';
3858 return(pktlog);
3859 }
3860 #endif /* NOXFER */
3861
3862 int
traopn(s,disp)3863 traopn(s,disp) char *s; int disp; {
3864 #ifdef TLOG
3865 static struct filinfo xx;
3866
3867 if (!s)
3868 s = "";
3869 if (!*s)
3870 return(0);
3871
3872 debug(F111,"traopn",s,disp);
3873 debug(F101,"traopn tlogfmt","",tlogfmt);
3874
3875 zclose(ZTFILE);
3876
3877 #ifdef OS2ORUNIX
3878 if (tlogfmt == 2) { /* FTP format is special... */
3879 VOID doiklog();
3880 if (!disp) /* Append? */
3881 if (zchki(s) > -1) /* No - does file exist? */
3882 (VOID) zdelet(s); /* Yes - delete it. */
3883 xferlog = 1;
3884 ckstrncpy(trafil,s,CKMAXPATH);
3885 makestr(&xferfile,s);
3886 doiklog();
3887 return(1);
3888 }
3889 if (s[0] == '|') { /* Pipe */
3890 char * p = s + 1;
3891 debug(F110,"traopn p",p,0);
3892 while (*p) {
3893 if (*p != ' ')
3894 break;
3895 else
3896 p++;
3897 }
3898 debug(F110,"traopn pipe",p,0);
3899 tralog = zxcmd(ZTFILE,p);
3900 debug(F101,"traopn tralog","",tralog);
3901 }
3902 #endif /* OS2ORUNIX */
3903
3904 if (s[0] != '|') { /* File */
3905 if (disp) {
3906 xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
3907 xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
3908 xx.lblopts = 0;
3909 tralog = zopeno(ZTFILE,s,NULL,&xx);
3910 } else tralog = zopeno(ZTFILE,s,NULL,NULL);
3911 }
3912 if (!tralog && !quiet)
3913 printf("?%s - %s\n",s,ck_errstr());
3914 if (tralog > 0 && tlogfmt > 0) {
3915 ckstrncpy(trafil,s,CKMAXPATH);
3916 tlog(F110,"Transaction Log:",versio,0L);
3917 #ifndef MAC
3918 tlog(F100,ckxsys,"",0L);
3919 #endif /* MAC */
3920 ztime(&s);
3921 tlog(F100,s,"",0L);
3922 } else
3923 *trafil = '\0';
3924 return(tralog);
3925 #else
3926 return(0);
3927 #endif /* TLOG */
3928 }
3929
3930 #ifndef NOLOCAL
3931 int
sesopn(s,disp)3932 sesopn(s,disp) char * s; int disp; {
3933 static struct filinfo xx;
3934 extern int tsstate;
3935
3936 tsstate = 0; /* Session log timestamp state */
3937
3938 if (!s)
3939 s = "";
3940 if (!*s)
3941 return(0);
3942
3943 debug(F111,"sesopn",s,disp);
3944
3945 zclose(ZSFILE);
3946
3947 #ifdef OS2ORUNIX
3948 if (s[0] == '|') { /* Pipe */
3949 char * p = s + 1;
3950 debug(F110,"sesopn p",p,0);
3951 while (*p) {
3952 if (*p != ' ')
3953 break;
3954 else
3955 p++;
3956 }
3957 debug(F110,"sesopn pipe",p,0);
3958 setseslog(zxcmd(ZSFILE,p));
3959 debug(F101,"sesopn seslog","",seslog);
3960 } else { /* File */
3961 #endif /* OS2ORUNIX */
3962 if (disp) {
3963 xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
3964 xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
3965 xx.lblopts = 0;
3966 setseslog(zopeno(ZSFILE,s,NULL,&xx));
3967 } else
3968 setseslog(zopeno(ZSFILE,s,NULL,NULL));
3969 if (!seslog && !quiet)
3970 printf("?%s - %s\n",s,ck_errstr());
3971 #ifdef OS2ORUNIX
3972 }
3973 #endif /* OS2ORUNIX */
3974 if (seslog > 0)
3975 ckstrncpy(sesfil,s,CKMAXPATH+1);
3976 else
3977 *sesfil = '\0';
3978 return(seslog);
3979 }
3980 #endif /* NOLOCAL */
3981 #endif /* NOICP */
3982
3983 int
debopn(s,disp)3984 debopn(s,disp) char *s; int disp; {
3985 #ifdef DEBUG
3986 #ifdef CK_UTSNAME
3987 extern char unm_mch[], unm_nam[], unm_rel[], unm_ver[], unm_mod[];
3988 #endif /* CK_UTSNAME */
3989 #ifdef OS2
3990 extern char ckxsystem[];
3991 #endif /* OS2 */
3992 char *tp;
3993 static struct filinfo xx;
3994
3995 if (!s)
3996 s = "";
3997 if (!*s)
3998 return(0);
3999
4000 zclose(ZDFILE);
4001
4002 #ifdef OS2ORUNIX
4003 if (s[0] == '|') { /* Pipe */
4004 char * p = s + 1;
4005 debug(F110,"debopn p",p,0);
4006 while (*p) {
4007 if (*p != ' ')
4008 break;
4009 else
4010 p++;
4011 }
4012 debug(F110,"debopn pipe",p,0);
4013 deblog = zxcmd(ZDFILE,p);
4014 debug(F101,"debopn deblog","",deblog);
4015 } else { /* File */
4016 #endif /* OS2ORUNIX */
4017 if (disp) {
4018 xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
4019 xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
4020 xx.lblopts = 0;
4021 deblog = zopeno(ZDFILE,s,NULL,&xx);
4022 } else
4023 deblog = zopeno(ZDFILE,s,NULL,NULL);
4024 if (!deblog && !quiet)
4025 printf("?%s - %s\n",s,ck_errstr());
4026 #ifdef OS2ORUNIX
4027 }
4028 #endif /* OS2ORUNIX */
4029 if (deblog > 0) {
4030 ckstrncpy(debfil,s,CKMAXPATH+1);
4031 debug(F110,"Debug Log ",versio,0);
4032 #ifndef MAC
4033 #ifdef OS2
4034 debug(F110,ckxsys,ckxsystem,0);
4035 #else /* OS2 */
4036 debug(F100,ckxsys,"",0);
4037 #endif /* OS2 */
4038 #endif /* MAC */
4039 #ifdef CK_UTSNAME
4040 if (unm_mch[0]) {
4041 debug(F110,"uname machine",unm_mch,0);
4042 if (unm_mod[0])
4043 debug(F110,"uname model ",unm_mod,0);
4044 debug(F110,"uname sysname",unm_nam,0);
4045 debug(F110,"uname release",unm_rel,0);
4046 debug(F110,"uname version",unm_ver,0);
4047 }
4048 #ifdef KTARGET
4049 {
4050 char * s; /* Makefile target */
4051 s = KTARGET;
4052 if (!s) s = "";
4053 if (!*s) s = "(unknown)";
4054 debug(F110,"build target",s,0);
4055 }
4056 #endif /* KTARGET */
4057 deblog = 0;
4058 ztime(&tp);
4059 deblog = 1;
4060 debug(F100,tp,"",0);
4061 #endif /* UTSNAME */
4062 debug(F101,"byteorder","",byteorder);
4063 #ifndef NOICP
4064 #ifndef NOLOCAL
4065 if (local) {
4066 debug(F110,"Active connection: ",ttname,0);
4067 if (!network) {
4068 debug(F101,"Speed","",speed);
4069 if (hwparity)
4070 debug(F110,"Parity[hardware]",parnam((char)hwparity),0);
4071 else
4072 debug(F110,"Parity",parnam((char)parity),0);
4073 deblog = 0;
4074 debug(F110,"Modem",gmdmtyp(),0);
4075 deblog = 1;
4076 }
4077 } else {
4078 debug(F110,"Active connection: ","none",0);
4079 }
4080 #endif /* NOLOCAL */
4081 #endif /* NOICP */
4082 } else *debfil = '\0';
4083 return(deblog);
4084 #else
4085 return(0);
4086 #endif /* MAC */
4087 }
4088
4089
4090 /* C K D A T E -- Returns current date/time in standard format */
4091
4092 static char nowbuf[18];
4093
4094 char *
ckdate()4095 ckdate() {
4096 extern struct keytab cmonths[];
4097 int x;
4098 char * t; /* Substitute today's date */
4099 char dbuf[32];
4100 ztime(&t);
4101
4102 /* 012345678901234567890123 */
4103 /* Sat Jul 4 12:16:43 1998 */
4104
4105 ckstrncpy(dbuf,t,32);
4106 t = dbuf;
4107 debug(F110,"ckdate dbuf",dbuf,0);
4108 nowbuf[0] = t[20];
4109 nowbuf[1] = t[21];
4110 nowbuf[2] = t[22];
4111 nowbuf[3] = t[23];
4112
4113 nowbuf[4] = NUL;
4114 debug(F110,"ckdate nowbuf",nowbuf,0);
4115
4116 t[7] = NUL;
4117 if ((x = lookup(cmonths,t+4,12,NULL)) < 0) {
4118 debug(F110,"ckdate bad month",t,0);
4119 return("<BAD_MONTH>");
4120 }
4121 sprintf(nowbuf+4,"%02d",x); /* SAFE */
4122 nowbuf[6] = (t[8] == SP) ? '0' : t[8];
4123 nowbuf[7] = t[9];
4124 nowbuf[8] = ' ';
4125
4126 nowbuf[9] = NUL;
4127 debug(F110,"ckdate nowbuf",nowbuf,0);
4128
4129 for (x = 11; x < 19; x++) nowbuf[x-2] = t[x];
4130 nowbuf[17] = NUL;
4131 debug(F110,"ckdate nowbuf",nowbuf,0);
4132
4133 return((char *)nowbuf);
4134 }
4135
4136 #ifndef NOICP
4137 #ifdef CKLOGDIAL
4138
4139 /*
4140 fc = 0 for initial open, meaning open, then close immediately.
4141 fc > 0 for subsequent opens, meaning open for use, leave open.
4142 */
4143 int
diaopn(s,disp,fc)4144 diaopn(s,disp,fc) char *s; int disp, fc; {
4145 static struct filinfo xx;
4146
4147 if (!s)
4148 s = "";
4149 if (!*s)
4150 return(0);
4151
4152 debug(F110,"diaopn log",s,0);
4153 debug(F101,"diaopn fc",s,fc);
4154 debug(F101,"diaopn disp 1",s,disp);
4155 if (fc) disp = 1; /* Force append if open for use */
4156 debug(F101,"diaopn disp 2",s,disp);
4157
4158 zclose(ZDIFIL); /* In case a log was already open */
4159
4160 #ifdef OS2ORUNIX
4161 if (s[0] == '|') { /* Pipe */
4162 char * p = s + 1;
4163 debug(F110,"diaopn p",p,0);
4164 while (*p) {
4165 if (*p != ' ')
4166 break;
4167 else
4168 p++;
4169 }
4170 debug(F110,"diaopn pipe",p,0);
4171 dialog = zxcmd(ZDIFIL,p);
4172 debug(F101,"diaopn dialog","",dialog);
4173 } else { /* File */
4174 #endif /* OS2ORUNIX */
4175 if (disp) {
4176 xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
4177 xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
4178 xx.lblopts = 0;
4179 dialog = zopeno(ZDIFIL,s,NULL,&xx);
4180 } else dialog = zopeno(ZDIFIL,s,NULL,NULL);
4181 if (!dialog)
4182 printf("?%s - %s\n",s,ck_errstr());
4183 #ifdef OS2ORUNIX
4184 }
4185 #endif /* OS2ORUNIX */
4186 if (dialog > 0)
4187 ckstrncpy(diafil,s,CKMAXPATH+1);
4188 else
4189 *diafil = '\0';
4190 if (fc == 0) /* Initial open */
4191 zclose(ZDIFIL); /* close it */
4192 return(dialog);
4193 }
4194 #endif /* CKLOGDIAL */
4195
4196 #ifndef NOSHOW
4197
4198 /* SHOW command routines */
4199
4200 char *
shoxm()4201 shoxm() {
4202 char * s;
4203 switch (binary) {
4204 case XYFT_T: s = "text"; break;
4205 #ifdef VMS
4206 case XYFT_B: s = "binary fixed"; break;
4207 case XYFT_I: s = "image"; break;
4208 case XYFT_L: s = "labeled"; break;
4209 case XYFT_U: s = "binary undef"; break;
4210 #else
4211 #ifdef MAC
4212 case XYFT_B: s = "binary"; break;
4213 case XYFT_M: s = "macbinary"; break;
4214 #else
4215 case XYFT_B: s = "binary"; break;
4216 #ifdef CK_LABELED
4217 case XYFT_L: s = "labeled"; break;
4218 #endif /* CK_LABELED */
4219 #endif /* MAC */
4220 #endif /* VMS */
4221 default: s = "unknown"; break;
4222 }
4223 return(s);
4224 }
4225
4226 #ifndef NOXFER
4227 VOID /* SHOW TRANSFER */
shoxfer()4228 shoxfer() {
4229 extern int docrc, usepipes, xfrxla, whereflg;
4230 extern char * xfrmsg;
4231 printf("\n");
4232 printf(" Transfer Bell: %s\n",showoff(xfrbel));
4233 printf(" Transfer Interruption: %s\n",showoff(xfrint));
4234 printf(" Transfer Cancellation: %s\n",showoff(xfrcan));
4235 #ifndef NOCSETS
4236 printf(" Transfer Translation: %s\n",showoff(xfrxla));
4237 printf(" Transfer Character-set: ");
4238 if (tcharset == TC_TRANSP)
4239 printf("Transparent\n");
4240 else
4241 printf("%s\n",tcsinfo[tcharset].keyword);
4242 #endif /* NOCSETS */
4243 printf(" Transfer CRC-calculation: %s\n",showoff(docrc));
4244 printf(" Transfer Display: ");
4245 switch (fdispla) {
4246 case XYFD_N: printf("%s\n","none"); break;
4247 case XYFD_R: printf("%s\n","serial"); break;
4248 case XYFD_C: printf("%s\n","fullscreen"); break;
4249 case XYFD_S: printf("%s\n","crt"); break;
4250 case XYFD_B: printf("%s\n","brief"); break;
4251 case XYFD_G: printf("%s\n","gui"); break;
4252 }
4253 printf(" Transfer Message: %s\n", xfrmsg ? xfrmsg : "(none)");
4254 printf(" Transfer Locking-shift: ");
4255 if (lscapu == 2) {
4256 printf("forced");
4257 } else {
4258 printf("%s", (lscapr ? "enabled" : "disabled"));
4259 if (lscapr) printf(",%s%s", (lscapu ? " " : " not "), "used");
4260 }
4261 printf("\n Transfer Mode: %s\n",
4262 xfermode == XMODE_A ?
4263 "automatic" :
4264 "manual"
4265 );
4266 printf(" Transfer Pipes: %s\n", showoff(usepipes));
4267 printf(" Transfer Protocol: %s\n",ptab[protocol].p_name);
4268 printf(" Transfer Report: %s\n",showoff(whereflg));
4269 printf(" Transfer Slow-start: %s\n",showoff(slostart));
4270 printf("\n");
4271 }
4272 #endif /* NOXFER */
4273
4274 VOID
shoflow()4275 shoflow() {
4276 int i, x;
4277 extern int cxflow[], cxtype, ncxname, nfloname, autoflow;
4278 extern char * cxname[];
4279 printf("\nConnection type: %s\n",cxname[cxtype]);
4280 if (autoflow) {
4281 printf("Current flow-control: %s\n", floname[cxflow[cxtype]]);
4282 printf("Switches automatically: yes\n");
4283 } else {
4284 printf("Current flow-control: %s\n", floname[flow]);
4285 printf("Switches automatically: no\n");
4286 }
4287 printf("\nDefaults by connection type:\n");
4288 debug(F111,"shoflow cxtype",cxname[cxtype],cxtype);
4289 debug(F101,"shoflow flow","",flow);
4290 for (i = 0; i < ncxname; i++) {
4291 #ifdef NOLOCAL
4292 if (i > 0) break;
4293 #endif /* NOLOCAL */
4294 #ifndef NETCONN
4295 if (i > 2) break;
4296 #endif /* NETCONN */
4297 #ifndef DECNET
4298 if (i == CXT_DECNET) continue;
4299 #endif /* DECNET */
4300 #ifndef DECNET
4301 #ifndef SUPERLAT
4302 if (i == CXT_LAT) continue;
4303 #endif /* SUPERLAT */
4304 #endif /* DECNET */
4305 #ifndef CK_NETBIOS
4306 if (i == CXT_NETBIOS) continue;
4307 #endif /* CK_NETBIOS */
4308 #ifndef NPIPE
4309 if (i == CXT_NPIPE) continue;
4310 #endif /* NPIPE */
4311 #ifndef NETCMD
4312 if (i == CXT_PIPE) continue;
4313 #endif /* NETCMD */
4314 #ifndef ANYX25
4315 if (i == CXT_X25) continue;
4316 #endif /* ANYX25 */
4317 x = cxflow[i];
4318 debug(F101,"shoflow x","",x);
4319 if (x < nfloname)
4320 printf(" %-14s: %s\n",cxname[i],floname[x]);
4321 else
4322 printf(" %-14s: (%d)\n",cxname[i],x);
4323 }
4324 printf("\n");
4325 }
4326
4327 #ifndef NOLOCAL
4328 #ifdef ANYX25
4329 int
shox25(n)4330 shox25(n) int n; {
4331 if (nettype == NET_SX25) {
4332 printf("SunLink X.25 V%d.%d",x25ver / 10,x25ver % 10);
4333 if (ttnproto == NP_X3) printf(", PAD X.3, X.28, X.29 protocol,");
4334 printf("\n");
4335 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4336 printf(" Reverse charge call %s",
4337 revcall ? "selected" : "not selected");
4338 printf (", Closed user group ");
4339 if (closgr > -1)
4340 printf ("%d",closgr);
4341 else
4342 printf ("not selected");
4343 printf("\n");
4344 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4345 printf(" Call user data %s.\n", cudata ? udata : "not selected");
4346 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4347 } else if (nettype == NET_VX25) {
4348 if (ttnproto == NP_X3) printf(", PAD X.3, X.28, X.29 protocol,");
4349 printf("\n");
4350 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4351 printf(" Reverse charge call %s",
4352 revcall ? "selected" : "not selected");
4353 printf (", Closed user group [unsupported]");
4354 if (closgr > -1)
4355 printf ("%d",closgr);
4356 else
4357 printf ("not selected");
4358 printf (",");
4359 printf("\n");
4360 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4361 printf(" Call user data %s.\n", cudata ? udata : "not selected");
4362 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4363 } else if (nettype == NET_IX25) {
4364 printf("AIX NPI X.25\n");
4365 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4366 printf("\n Reverse charge call %s",
4367 revcall ? "selected" : "not selected");
4368 printf (", Closed user group [unsupported]");
4369 if (closgr > -1)
4370 printf ("%d",closgr);
4371 else
4372 printf ("not selected");
4373 printf (",");
4374 printf("\n Call user data %s.\n", cudata ? udata : "not selected");
4375 }
4376 return(n);
4377 }
4378
4379 #ifndef IBMX25
4380 int
shopad(n)4381 shopad(n) int n; {
4382 int i;
4383 printf("\nX.3 PAD Parameters:\n");
4384 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4385 for (i = 0; i < npadx3; i++) {
4386 printf(" [%d] %s %d\n",padx3tab[i].kwval,padx3tab[i].kwd,
4387 padparms[padx3tab[i].kwval]);
4388 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4389 }
4390 return(n);
4391 }
4392 #endif /* IBMX25 */
4393 #endif /* ANYX25 */
4394
4395 VOID
shoparc()4396 shoparc() {
4397 extern int reliable, stopbits, clsondisc;
4398 int i; char *s;
4399 long zz;
4400
4401 #ifdef NEWFTP
4402 if (ftpisconnected()) {
4403 shoftp(1);
4404 printf("\n");
4405 }
4406 #endif /* NEWFTP */
4407
4408 printf("Communications Parameters:\n");
4409
4410 if (network
4411 #ifdef IKSD
4412 || inserver
4413 #endif /* IKSD */
4414 ) {
4415 printf(" Network Host: %s%s",ttname,
4416 (reliable == SET_ON || (reliable == SET_AUTO && !local)
4417 #ifdef TN_COMPORT
4418 && !istncomport()
4419 #endif /* TN_COMPORT */
4420 #ifdef IKSD
4421 || inserver
4422 #endif /* IKSD */
4423 ) ? " (reliable)" : "");
4424 #ifdef TN_COMPORT
4425 if (istncomport()) {
4426 int modemstate;
4427 char * oflow, * iflow = "", * parity, * stopsize, * signature;
4428 int baud = tnc_get_baud();
4429
4430 switch (tnc_get_oflow()) {
4431 case TNC_CTL_OFLOW_NONE:
4432 oflow = "none";
4433 break;
4434 case TNC_CTL_OFLOW_XON_XOFF:
4435 oflow = "xon/xoff";
4436 break;
4437 case TNC_CTL_OFLOW_RTS_CTS:
4438 oflow = "rts/cts";
4439 break;
4440 case TNC_CTL_OFLOW_DCD:
4441 oflow = "dcd";
4442 break;
4443 case TNC_CTL_OFLOW_DSR:
4444 oflow = "dsr";
4445 break;
4446 default:
4447 oflow = "(unknown)";
4448 }
4449 switch (tnc_get_iflow()) {
4450 case TNC_CTL_IFLOW_NONE:
4451 iflow = "none";
4452 break;
4453 case TNC_CTL_IFLOW_XON_XOFF:
4454 iflow = "xon/xoff";
4455 break;
4456 case TNC_CTL_IFLOW_RTS_CTS:
4457 iflow = "rts/cts";
4458 break;
4459 case TNC_CTL_IFLOW_DTR:
4460 break;
4461 default:
4462 iflow = oflow;
4463 }
4464 switch (tnc_get_parity()) {
4465 case TNC_PAR_NONE:
4466 parity = "none";
4467 break;
4468 case TNC_PAR_ODD:
4469 parity = "odd";
4470 break;
4471 case TNC_PAR_EVEN:
4472 parity = "even";
4473 break;
4474 case TNC_PAR_MARK:
4475 parity = "mark";
4476 break;
4477 case TNC_PAR_SPACE:
4478 parity = "space";
4479 break;
4480 default:
4481 parity = "(unknown)";
4482 }
4483 switch (tnc_get_stopsize()) {
4484 case TNC_SB_1:
4485 stopsize = "1";
4486 break;
4487 case TNC_SB_1_5:
4488 stopsize = "1.5";
4489 break;
4490 case TNC_SB_2:
4491 stopsize = "2";
4492 break;
4493 default:
4494 stopsize = "(unknown)";
4495 }
4496 signature = (char *)tnc_get_signature();
4497 printf("\n Signature : %s\n",signature?signature:"");
4498 if (baud <= 0)
4499 printf(" Speed : (unknown)\n");
4500 else
4501 printf(" Speed : %d\n", baud);
4502 printf(" Outbound Flow Control: %s\n", oflow);
4503 printf(" Inbound Flow Control : %s\n", iflow);
4504 printf(" Parity : %s\n", parity);
4505 printf(" Data Size : %d\n", tnc_get_datasize());
4506 printf(" Stop Bits : %s\n", stopsize);
4507 printf(" DTR Signal : %d\n", tnc_get_dtr_state());
4508 printf(" RTS Signal : %d\n", tnc_get_rts_state());
4509 printf(" Modem State:\n");
4510 modemstate = tnc_get_ms();
4511 if (modemstate & TNC_MS_EDGE_RING)
4512 printf(" Trailing Edge Ring Detector On\n");
4513 else
4514 printf(" Trailing Edge Ring Detector Off\n");
4515 if (modemstate & TNC_MS_CTS_SIG)
4516 printf(" CTS Signal On\n");
4517 else
4518 printf(" CTS Signal Off\n");
4519 if (modemstate & TNC_MS_DSR_SIG)
4520 printf(" DSR Signal On\n");
4521 else
4522 printf(" DSR Signal Off\n");
4523 if (modemstate & TNC_MS_RI_SIG)
4524 printf(" Ring Indicator On\n");
4525 else
4526 printf(" Ring Indicator Off\n");
4527 if (modemstate & TNC_MS_RLSD_SIG)
4528 printf(" RLSD (CD) Signal On\n");
4529 else
4530 printf(" RLSD (CD) Signal Off\n");
4531 printf("\n");
4532 }
4533 #endif /* TN_COMPORT */
4534 } else {
4535
4536 printf(" %s: %s%s, speed: ",
4537 #ifdef OS2
4538 "Port",
4539 #else
4540 "Line",
4541 #endif /* OS2 */
4542 ttname,
4543 #ifdef CK_TTYFD
4544 (local &&
4545 #ifdef VMS
4546 vmsttyfd() < 0
4547 #else
4548 ttyfd == -1
4549 #endif /* VMS */
4550 ) ?
4551 " (closed)" :
4552 (reliable == SET_ON ? " (reliable)" : "")
4553 #else
4554 ""
4555 #endif /* CK_TTYFD */
4556 );
4557 if (
4558 #ifdef CK_TTYFD
4559 #ifdef VMS
4560 vmsttyfd() < 0
4561 #else
4562 ttyfd == -1
4563 #endif /* VMS */
4564 ||
4565 #endif /* CK_TTYFD */
4566 (zz = ttgspd()) < 0) {
4567 printf("unknown");
4568 } else {
4569 if (speed == 8880) printf("75/1200");
4570 else if (speed == 134) printf("134.5");
4571 else printf("%ld",zz);
4572 }
4573 }
4574 if (network
4575 #ifdef IKSD
4576 || inserver
4577 #endif /* IKSD */
4578 )
4579 printf("\n Mode: ");
4580 else
4581 printf(", mode: ");
4582 if (local) printf("local"); else printf("remote");
4583 if (network == 0
4584 #ifdef IKSD
4585 && !inserver
4586 #endif/* IKSD */
4587 ) {
4588 #ifdef CK_TAPI
4589 if (tttapi && !tapipass )
4590 printf(", modem: %s","TAPI");
4591 else
4592 #endif /* CK_TAPI */
4593 printf(", modem: %s",gmdmtyp());
4594 } else {
4595 #ifdef NETCONN
4596 if (nettype == NET_TCPA) printf(", TCP/IP");
4597 if (nettype == NET_TCPB) printf(", TCP/IP");
4598 if (nettype == NET_DEC) {
4599 if (ttnproto == NP_LAT) printf(", DECnet LAT");
4600 else if ( ttnproto == NP_CTERM ) printf(", DECnet CTERM");
4601 else printf(", DECnet");
4602 }
4603 if (nettype == NET_SLAT) printf(", Meridian Technologies' SuperLAT");
4604 #ifdef NETFILE
4605 if (nettype == NET_FILE) printf(", local file");
4606 #endif /* NETFILE */
4607 #ifdef NETCMD
4608 if (nettype == NET_CMD) printf(", pipe");
4609 #endif /* NETCMD */
4610 #ifdef NETPTY
4611 if (nettype == NET_PTY) printf(", pseudoterminal");
4612 #endif /* NETPTY */
4613 #ifdef NETDLL
4614 if (nettype == NET_DLL) printf(", dynamic load library");
4615 #endif /* NETDLL */
4616 if (nettype == NET_PIPE) printf(", Named Pipes");
4617 #ifdef SSHBUILTIN
4618 if (nettype == NET_SSH)
4619 printf(", Secure Shell protocol (SECURE)");
4620 #endif /* SSHBUILTIN */
4621 #ifdef ANYX25
4622 if (shox25(0) < 0) return;
4623 #endif /* ANYX25 */
4624 if (IS_TELNET()) {
4625 printf(", telnet protocol");
4626 if (0
4627 #ifdef CK_ENCRYPTION
4628 || ck_tn_encrypting() && ck_tn_decrypting()
4629 #endif /* CK_ENCRYPTION */
4630 #ifdef CK_SSL
4631 || tls_active_flag || ssl_active_flag
4632 #endif /* CK_SSL */
4633 )
4634 printf(" (SECURE)");
4635 }
4636 #ifdef RLOGCODE
4637 else if (ttnproto == NP_RLOGIN || ttnproto == NP_K4LOGIN ||
4638 ttnproto == NP_K5LOGIN)
4639 printf(", rlogin protocol");
4640 else if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN)
4641 printf(", rlogin protocol (SECURE)");
4642 #endif /* RLOGCODE */
4643 #ifdef CK_KERBEROS
4644 #ifdef KRB5
4645 else if (ttnproto == NP_K5U2U)
4646 printf(", Kerberos 5 User to User protocol (SECURE)");
4647 #endif /* KRB5 */
4648 #endif /* CK_KERBEROS */
4649 #endif /* NETCONN */
4650 }
4651 printf("\n");
4652 if (hwparity && local && !network)
4653 s = parnam((char)hwparity);
4654 else
4655 s = parnam((char)parity);
4656 printf(" Parity: %s%s",hwparity ? "hardware " : "", s);
4657 #ifndef NOLOCAL
4658 if (local && !network) {
4659 int sb;
4660 char c;
4661 c = s[0];
4662 if (islower(c)) c = toupper(c);
4663 sb = stopbits;
4664 if (sb < 1) {
4665 sb = (speed > 0 && speed <= 110L) ? 2 : 1;
4666 printf(", stop-bits: (default)");
4667 } else {
4668 printf(", stop-bits: %d",sb);
4669 }
4670 if (hwparity)
4671 printf(" (8%c%d)",c,sb);
4672 else if (parity)
4673 printf(" (7%c%d)",c,sb);
4674 else
4675 printf(" (8N%d)",sb);
4676 printf("\n D");
4677 } else
4678 printf(", d");
4679 #endif /* NOLOCAL */
4680
4681 printf("uplex: %s, ", duplex ? "half" : "full");
4682 debug(F101,"shoparp flow","",flow);
4683 printf("flow: %s", floname[flow]);
4684 printf(", handshake: ");
4685 if (turn) printf("%d\n",turnch); else printf("none\n");
4686 #ifdef COMMENT
4687 if (local && !network) { /* SET CARRIER-WATCH */
4688 #endif /* COMMENT */
4689 if (carrier == CAR_OFF) s = "off";
4690 else if (carrier == CAR_ON) s = "on";
4691 else if (carrier == CAR_AUT) s = "auto";
4692 else s = "unknown";
4693 printf(" Carrier-watch: %s", s);
4694 if (carrier == CAR_ON) {
4695 if (cdtimo) printf(", timeout: %d sec", cdtimo);
4696 else printf(", timeout: none");
4697 }
4698 #ifdef COMMENT
4699 }
4700 #endif /* COMMENT */
4701 printf(", close-on-disconnect: %s\n",showoff(clsondisc));
4702
4703 #ifdef UNIX /* UUCP lockfile, UNIX only */
4704 if (local) {
4705 #ifndef NOUUCP
4706 if (!network && haslock && *flfnam)
4707 printf(" Lockfile: %s",flfnam);
4708 #ifndef USETTYLOCK
4709 if (!network && haslock && lock2[0])
4710 printf("\n Secondary lockfile: %s",lock2);
4711 #endif /* USETTYLOCK */
4712 #else
4713 #ifdef QNX
4714 {
4715 extern int qnxportlock, qnxopencount();
4716 if (local)
4717 printf(" Qnx-port-lock: %s, Open count: %d",
4718 showoff(qnxportlock),
4719 qnxopencount()
4720 );
4721 else
4722 printf(" Qnx-port-lock: %s", showoff(qnxportlock));
4723 }
4724 #endif /* QNX */
4725 #endif /* NOUUCP */
4726 printf("\n");
4727 } else {
4728 char * s;
4729 s = ttglckdir();
4730 if (!s) s = "";
4731 printf(" Lockfile directory: %s\n", *s ? s : "(none)");
4732 }
4733 #endif /* UNIX */
4734 #ifndef MACOSX
4735 if (!local) {
4736 printf(" Typical port device name: %s\n",ttgtpn());
4737 }
4738 #endif /* MACOSX */
4739 if (local) {
4740 int i;
4741 i = parity ? 7 : 8;
4742 if (i == 8) i = (cmask == 0177) ? 7 : 8;
4743 printf(" Terminal bytesize: %d,",i);
4744 printf(" escape character: %d (^%c)\n",escape,ctl(escape));
4745 }
4746 }
4747
4748 int
shotcp(n)4749 shotcp(n) int n; {
4750 #ifdef TCPSOCKET
4751 if (nettype == NET_TCPA || nettype == NET_TCPB) {
4752 printf("SET TCP parameters:\n");
4753 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4754 printf(" Reverse DNS lookup: %s\n", showooa(tcp_rdns));
4755 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
4756
4757 #ifdef CK_DNS_SRV
4758 printf(" DNS Service Records lookup: %s\n", showooa(tcp_dns_srv));
4759 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
4760 #endif /* CK_DNS_SRV */
4761
4762 #ifndef NOTCPOPTS
4763 #ifdef SOL_SOCKET
4764 #ifdef SO_KEEPALIVE
4765 printf(" Keepalive: %s\n", showoff(tcp_keepalive));
4766 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
4767 #endif /* SO_KEEPALIVE */
4768
4769 #ifdef SO_LINGER
4770 printf(" Linger: %s", tcp_linger ? "on, " : "off\n" );
4771 if (tcp_linger) {
4772 if (tcp_linger_tmo)
4773 printf("%d x 10 milliseconds\n",tcp_linger_tmo);
4774 else
4775 printf("no timeout\n");
4776 }
4777 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
4778 #endif /* SO_LINGER */
4779
4780 #ifdef SO_DONTROUTE
4781 printf(" DontRoute: %s\n", tcp_dontroute ? "on" : "off" );
4782 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
4783 #endif /* SO_DONTROUTE */
4784
4785 #ifdef TCP_NODELAY
4786 printf(" Nodelay: %s\n", showoff(tcp_nodelay));
4787 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
4788 #endif /* TCP_NODELAY */
4789
4790 #ifdef SO_SNDBUF
4791 if (tcp_sendbuf <= 0)
4792 printf(" Send buffer: (default size)\n");
4793 else
4794 printf(" Send buffer: %d bytes\n", tcp_sendbuf);
4795 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
4796 #endif /* SO_SNDBUF */
4797 #ifdef SO_RCVBUF
4798 if (tcp_recvbuf <= 0)
4799 printf(" Receive buffer: (default size)\n");
4800 else
4801 printf(" Receive buffer: %d bytes\n", tcp_recvbuf);
4802 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
4803 #endif /* SO_RCVBUF */
4804 #endif /* SOL_SOCKET */
4805 #endif /* NOTCPOPTS */
4806 printf(" address: %s\n",tcp_address ? tcp_address : "(none)");
4807 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4808 #ifndef NOHTTP
4809 printf(" http-proxy: %s\n",tcp_http_proxy ? tcp_http_proxy : "(none)");
4810 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4811 #endif /* NOHTTP */
4812 #ifdef NT
4813 #ifdef CK_SOCKS
4814 printf(" socks-server: %s\n",tcp_socks_svr ? tcp_socks_svr : "(none)");
4815 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4816 #ifdef CK_SOCKS_NS
4817 printf(" socks-name-server: %s\n",
4818 tcp_socks_ns ? tcp_socks_ns : "(none)");
4819 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4820 #endif /* CK_SOCKS_NS */
4821 #endif /* CK_SOCKS */
4822 #endif /* NT */
4823 }
4824 #endif /* TCPSOCKET */
4825 return(n);
4826 }
4827
4828 #ifdef TNCODE
4829 int
shotopt(n)4830 shotopt(n) int n; {
4831 int opt;
4832
4833 printf("%-21s %12s %12s %12s %12s\n\n",
4834 "Telnet Option","Me (client)","U (client)",
4835 "Me (server)","U (server)");
4836 n += 2;
4837 if (n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4838
4839 for ( opt = TELOPT_FIRST; opt <= TELOPT_LAST; opt++) {
4840 switch (opt) {
4841 case TELOPT_AUTHENTICATION:
4842 case TELOPT_ENCRYPTION:
4843 case TELOPT_TTYPE:
4844 case TELOPT_NAWS:
4845 case TELOPT_BINARY:
4846 case TELOPT_NEWENVIRON:
4847 case TELOPT_SNDLOC:
4848 case TELOPT_XDISPLOC:
4849 case TELOPT_SGA:
4850 case TELOPT_ECHO:
4851 case TELOPT_KERMIT:
4852 case TELOPT_START_TLS:
4853 case TELOPT_FORWARD_X:
4854 case TELOPT_COMPORT:
4855 break;
4856 default:
4857 continue;
4858 }
4859 printf("%03d %-17s ",
4860 opt, TELOPT(opt)
4861 );
4862 printf("%12s %12s ",
4863 TELOPT_MODE(TELOPT_DEF_C_ME_MODE(opt)),
4864 TELOPT_MODE(TELOPT_DEF_C_U_MODE(opt))
4865 );
4866 printf("%12s %12s\n",
4867 TELOPT_MODE(TELOPT_DEF_S_ME_MODE(opt)),
4868 TELOPT_MODE(TELOPT_DEF_S_U_MODE(opt))
4869 );
4870
4871 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4872 if (sstelnet)
4873 printf("%21s %12s %12s %12s %12s\n",
4874 "",
4875 "",
4876 "",
4877 (TELOPT_ME(opt)?"WILL":"WONT"),
4878 (TELOPT_U(opt)?"DO":"DONT")
4879 );
4880 else
4881 printf("%21s %12s %12s %12s %12s\n",
4882 "",
4883 (TELOPT_ME(opt)?"WILL":"WONT"),
4884 (TELOPT_U(opt)?"DO":"DONT"),
4885 "",
4886 ""
4887 );
4888 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4889 }
4890 return(n);
4891 }
4892
4893 int
shotel(n)4894 shotel(n) int n; {
4895 extern int tn_duplex;
4896 #ifdef CK_ENVIRONMENT
4897 extern int tn_env_flg;
4898 extern char tn_env_acct[];
4899 extern char tn_env_job[];
4900 extern char tn_env_prnt[];
4901 extern char tn_env_sys[];
4902 extern char * tn_env_uservar[8][2];
4903 int x;
4904 #endif /* CK_ENVIRONMENT */
4905 #ifdef CK_SNDLOC
4906 extern char * tn_loc;
4907 #endif /* CK_SNDLOC */
4908 printf("SET TELNET parameters:\n echo: %s\n NVT newline-mode: ",
4909 tn_duplex ? "local" : "remote");
4910 switch (tn_nlm) {
4911 case TNL_CRNUL: printf("%s\n","off (cr-nul)"); break;
4912 case TNL_CRLF: printf("%s\n","on (cr-lf)"); break;
4913 case TNL_CR: printf("%s\n","raw (cr)"); break;
4914 case TNL_LF: printf("%s\n","(lf)"); break;
4915 }
4916 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4917 #ifdef CK_AUTHENTICATION
4918 {
4919 int type = ck_tn_authenticated();
4920 printf(" authentication: ");
4921 switch (sstelnet ?
4922 TELOPT_U_MODE(TELOPT_AUTHENTICATION) :
4923 TELOPT_ME_MODE(TELOPT_AUTHENTICATION)
4924 ) {
4925 case TN_NG_AC: printf( "accepted " ); break;
4926 case TN_NG_RF: printf( "refused " ); break;
4927 case TN_NG_RQ: printf( "requested"); break;
4928 case TN_NG_MU: printf( "required "); break;
4929 }
4930
4931 #ifdef CK_SSL
4932 if ((ssl_active_flag || tls_active_flag) &&
4933 ck_tn_auth_valid() == AUTH_VALID &&
4934 (!TELOPT_U(TELOPT_AUTHENTICATION) ||
4935 type == AUTHTYPE_NULL ||
4936 type == AUTHTYPE_AUTO))
4937 printf(" in use: X.509 certificate\n");
4938 else
4939 #endif /* CK_SSL */
4940 printf(" in use: %s\n",AUTHTYPE_NAME(type));
4941 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4942 if (forward_flag)
4943 printf(" credentials forwarding requested %s\n",
4944 forwarded_tickets ? "and completed" :
4945 "but not completed");
4946 else
4947 printf(" credentials forwarding disabled\n");
4948 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4949 }
4950 #endif /* CK_AUTHENTICATION */
4951 #ifdef CK_ENCRYPTION
4952 {
4953 int i,x;
4954 int e_type = ck_tn_encrypting();
4955 int d_type = ck_tn_decrypting();
4956 char * e_str = NULL, * d_str = NULL;
4957 static struct keytab * tnetbl = NULL;
4958 static int ntnetbl = 0;
4959
4960 x = ck_get_crypt_table(&tnetbl,&ntnetbl);
4961
4962 for (i = 0; i < ntnetbl; i++) {
4963 if (e_type == tnetbl[i].kwval)
4964 e_str = tnetbl[i].kwd;
4965 if (d_type == tnetbl[i].kwval)
4966 d_str = tnetbl[i].kwd;
4967 }
4968 printf(" encryption: ");
4969 switch (TELOPT_ME_MODE(TELOPT_ENCRYPTION)) {
4970 /* This should be changed to report both ME and U modes */
4971 case TN_NG_AC: printf( "accepted " ); break;
4972 case TN_NG_RF: printf( "refused " ); break;
4973 case TN_NG_RQ: printf( "requested"); break;
4974 case TN_NG_MU: printf( "required "); break;
4975 }
4976 printf(" in use: ");
4977 switch ((e_type ? 1 : 0) | (d_type ? 2 : 0)) {
4978 case 0:
4979 printf("plain text in both directions");
4980 break;
4981 case 1:
4982 printf("%s output, plain text input",e_str);
4983 break;
4984 case 2:
4985 printf("plain text output, %s input",d_str);
4986 break;
4987 case 3:
4988 printf("%s output, %s input",e_str,d_str);
4989 break;
4990 }
4991 printf("\n");
4992 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4993 }
4994 #endif /* CK_ENCRYPTION */
4995 #ifdef IKS_OPTION
4996 printf(" kermit: ");
4997 switch (TELOPT_U_MODE(TELOPT_KERMIT)) {
4998 case TN_NG_AC: printf( "u, accepted; " ); break;
4999 case TN_NG_RF: printf( "u, refused; " ); break;
5000 case TN_NG_RQ: printf( "u, requested; "); break;
5001 case TN_NG_MU: printf( "u, required; "); break;
5002 }
5003 switch (TELOPT_ME_MODE(TELOPT_KERMIT)) {
5004 case TN_NG_AC: printf( "me, accepted; " ); break;
5005 case TN_NG_RF: printf( "me, refused; " ); break;
5006 case TN_NG_RQ: printf( "me, requested; "); break;
5007 case TN_NG_MU: printf( "me, required; "); break;
5008 }
5009 if (TELOPT_U(TELOPT_KERMIT))
5010 printf(" u, %s",
5011 TELOPT_SB(TELOPT_KERMIT).kermit.u_start ?
5012 "started" :
5013 "stopped"
5014 );
5015 else
5016 printf(" u, n/a");
5017 if (TELOPT_ME(TELOPT_KERMIT))
5018 printf(" me, %s;",
5019 TELOPT_SB(TELOPT_KERMIT).kermit.me_start ?
5020 "started" :
5021 "stopped"
5022 );
5023 else
5024 printf(" me, n/a;");
5025 printf("\n");
5026 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5027 #endif /* IKS_OPTION */
5028 printf(" BINARY newline-mode: ");
5029 switch (tn_b_nlm) {
5030 case TNL_CRNUL: printf("%s\n","off (cr-nul)"); break;
5031 case TNL_CRLF: printf("%s\n","on (cr-lf)"); break;
5032 case TNL_CR: printf("%s\n","raw (cr)"); break;
5033 case TNL_LF: printf("%s\n","(lf)"); break;
5034 }
5035 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5036 printf(" binary-mode: ");
5037 switch (TELOPT_U_MODE(TELOPT_BINARY)) {
5038 case TN_NG_AC: printf( "u, accepted; " ); break;
5039 case TN_NG_RF: printf( "u, refused; " ); break;
5040 case TN_NG_RQ: printf( "u, requested; "); break;
5041 case TN_NG_MU: printf( "u, required; "); break;
5042 }
5043 switch (TELOPT_ME_MODE(TELOPT_BINARY)) {
5044 case TN_NG_AC: printf( "me, accepted; " ); break ;
5045 case TN_NG_RF: printf( "me, refused; " ); break;
5046 case TN_NG_RQ: printf( "me, requested; "); break;
5047 case TN_NG_MU: printf( "me, required; "); break;
5048 }
5049 printf("u, %s; me, %s\n",
5050 TELOPT_U(TELOPT_BINARY) ? "BINARY" : "NVT",
5051 TELOPT_ME(TELOPT_BINARY) ? "BINARY" : "NVT"
5052 );
5053 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5054 printf(" binary-transfer-mode: %s\n",showoff(tn_b_xfer));
5055 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5056 printf(" bug binary-me-means-u-too: %s\n",showoff(tn_b_meu));
5057 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5058 printf(" bug binary-u-means-me-too: %s\n",showoff(tn_b_ume));
5059 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5060 printf(" bug sb-implies-will-do: %s\n",showoff(tn_sb_bug));
5061 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5062 printf(" bug auth-krb5-des: %s\n",showoff(tn_auth_krb5_des_bug));
5063 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5064 printf(" terminal-type: ");
5065 if (tn_term) {
5066 printf("%s\n",tn_term);
5067 } else {
5068 char *p;
5069 #ifdef OS2
5070 p = (tt_type >= 0 && tt_type <= max_tt) ?
5071 tt_info[tt_type].x_name :
5072 "UNKNOWN";
5073 #else
5074 p = getenv("TERM");
5075 #endif /* OS2 */
5076 if (p)
5077 printf("none (%s will be used)\n",p);
5078 else printf("none\n");
5079 }
5080 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5081 #ifdef CK_ENVIRONMENT
5082 printf(" environment: %s\n", showoff(tn_env_flg));
5083 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5084 printf(" ACCOUNT: %s\n",tn_env_acct);
5085 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5086 printf(" DISPLAY: %s\n",(char *)tn_get_display() ?
5087 (char *)tn_get_display() : "");
5088 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5089 printf(" JOB : %s\n",tn_env_job);
5090 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5091 printf(" PRINTER: %s\n",tn_env_prnt);
5092 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5093 #ifndef NOSPL
5094 printf(" USER : %s\n",uidbuf);
5095 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5096 #endif /* NOSPL */
5097 printf(" SYSTEM : %s\n",tn_env_sys);
5098 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5099 for (x = 0; x < 8; x++) {
5100 if (tn_env_uservar[x][0] && tn_env_uservar[x][1]) {
5101 printf(" %-7s: %s\n",tn_env_uservar[x][0],
5102 tn_env_uservar[x][1]);
5103 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5104 }
5105 }
5106 #endif /* CK_ENVIRONMENT */
5107 #ifdef CK_SNDLOC
5108 printf(" LOCATION: %s\n", tn_loc ? tn_loc : "");
5109 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5110 #endif /* CK_SNDLOC */
5111 #ifdef CK_FORWARD_X
5112 printf(" .Xauthority-file: %s\n", (char *)XauFileName() ?
5113 (char *)XauFileName() : "(none)");
5114 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5115 #endif /* CK_FORWARD_X */
5116 return(n);
5117 }
5118 #endif /* TNCODE */
5119
5120 #ifdef CK_NETBIOS
5121 static int
shonb(n)5122 shonb(n) int n; {
5123 printf("NETBIOS parameters:\n");
5124 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5125 printf(" API : %s\n",
5126 NetbeuiAPI ?
5127 "NETAPI.DLL - IBM Extended Services or Novell Netware Requester"
5128 : "ACSNETB.DLL - IBM Network Transport Services/2" ) ;
5129 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5130 printf(" Local Name: [%s]\n", NetBiosName);
5131 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5132 printf(" Adapter : %d\n", NetBiosAdapter);
5133 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5134 if (NetBiosLSN > 0xFF) {
5135 printf(" Session : %d\n", NetBiosLSN);
5136 } else {
5137 printf(" Session : none active\n");
5138 }
5139 if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5140 return(n);
5141 }
5142 #endif /* CK_NETBIOS */
5143
5144 #ifndef NONET
5145 int
shonet()5146 shonet() {
5147
5148 #ifndef NETCONN
5149 printf("\nNo networks are supported in this version of C-Kermit\n");
5150
5151 #else
5152 #ifdef NOLOCAL
5153 printf("\nNo networks are supported in this version of C-Kermit\n");
5154
5155 #else /* rest of this routine */
5156
5157 int i, n = 4;
5158
5159 #ifndef NODIAL
5160 if (nnetdir <= 1) {
5161 printf("\nNetwork directory: %s\n",netdir[0] ? netdir[0] : "(none)");
5162 n++;
5163 } else {
5164 int i;
5165 printf("\nNetwork directories:\n");
5166 for (i = 0; i < nnetdir; i++) {
5167 printf("%2d. %s\n",i,netdir[i]);
5168 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5169 }
5170 }
5171 #endif /* NODIAL */
5172
5173 #ifdef SSHCMD
5174 {
5175 extern char * sshcmd;
5176 printf("SSH COMMAND: %s\n",sshcmd ? sshcmd : "ssh -e none");
5177 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5178 }
5179 #endif /* SSHCMD */
5180
5181 #ifdef OS2
5182 printf("\nNetwork availability:\n");
5183 #else
5184 printf("\nSupported networks:\n");
5185 #endif /* OS2 */
5186 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5187
5188 #ifdef VMS
5189
5190 #ifdef TCPWARE
5191 printf(" Process Software Corporation TCPware for OpenVMS");
5192 #else
5193 #ifdef MULTINET
5194 printf(" TGV MultiNet TCP/IP");
5195 #else
5196 #ifdef WINTCP
5197 printf(" WOLLONGONG WIN/TCP");
5198 #else
5199 #ifdef DEC_TCPIP
5200 {
5201 static $DESCRIPTOR(tcp_desc,"_TCP0:");
5202 int status;
5203 long devclass;
5204 static int itmcod = DVI$_DEVCLASS;
5205
5206 #ifdef COMMENT
5207 status = LIB$GETDVI(&itmcod, 0, &tcp_desc, &devclass);
5208 #else
5209 /* Martin Zinser 9/96 */
5210 status = lib$getdvi(&itmcod, 0, &tcp_desc, &devclass);
5211 #endif /* COMMENT */
5212 if ((status & 1) && (devclass == DC$_SCOM))
5213 printf(" Process Software Corporation TCPware for OpenVMS");
5214 else
5215 #ifdef UCX50
5216 printf(" DEC TCP/IP Services for (Open)VMS 5.0");
5217 #else
5218 printf(" DEC TCP/IP Services for (Open)VMS");
5219 #endif /* UCX50 */
5220 }
5221 #else
5222 #ifdef CMU_TCPIP
5223 printf(" CMU-OpenVMS/IP");
5224 #else
5225 printf(" None");
5226 #endif /* CMU_TCPIP */
5227 #endif /* DEC_TCPIP */
5228 #endif /* WINTCP */
5229 #endif /* MULTINET */
5230 #endif /* TCPWARE */
5231 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5232 #ifdef TNCODE
5233 printf(", TELNET protocol\n\n");
5234 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5235 n = shotel(n);
5236 if (n < 0) return(0);
5237 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5238 #endif /* TNCODE */
5239 printf("\n");
5240 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5241 printf("\n");
5242 n = shotcp(++n);
5243 if (n < 0) return(0);
5244 #else /* Not VMS */
5245
5246 #ifdef SUNX25
5247 printf(" SunLink X.25\n");
5248 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5249 #endif /* SUNX25 */
5250
5251 #ifdef STRATUSX25
5252 printf(" Stratus VOS X.25\n");
5253 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5254 #endif /* STRATUSX25 */
5255
5256 #ifdef IBMX25
5257 printf(" IBM AIX X.25\n");
5258 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5259 #endif /* IBMX25 */
5260
5261 #ifdef HPX25
5262 printf(" HP-UX X.25\n");
5263 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5264 #endif /* HPX25 */
5265
5266 #ifdef SSHBUILTIN
5267 if (ck_ssleay_is_installed())
5268 printf(" SSH V1 and V2 protocols\n");
5269 else
5270 printf(" SSH V1 and V2 protocols - not available\n");
5271 #endif /* SSHBUILTIN */
5272
5273 #ifdef DECNET
5274 #ifdef OS2
5275 #ifdef NT
5276 if (dnet_avail)
5277 printf(" DECnet, LAT and CTERM protocols\n");
5278 else
5279 printf(" DECnet, LAT and CTERM protocols - not available\n");
5280 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5281 #else /* NT */
5282 if (dnet_avail)
5283 printf(" DECnet, LAT protocol\n");
5284 else
5285 printf(" DECnet, LAT protocol - not available\n");
5286 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5287 #endif /* NT */
5288 #else
5289 printf(" DECnet\n");
5290 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5291 #endif /* OS2 */
5292 #endif /* DECNET */
5293
5294 #ifdef NPIPE
5295 printf(" Named Pipes\n");
5296 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5297 #endif /* NPIPE */
5298
5299 #ifdef CK_NETBIOS
5300 if (netbiosAvail)
5301 printf(" NETBIOS\n");
5302 else
5303 printf(" NETBIOS - not available\n");
5304 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5305 #endif /* CK_NETBIOS */
5306
5307 #ifdef SUPERLAT
5308 if (slat_avail)
5309 printf(" SuperLAT\n");
5310 else
5311 printf(" SuperLAT - not available\n") ;
5312 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5313 #endif /* SUPERLAT */
5314
5315 #ifdef TCPSOCKET
5316 if (
5317 #ifdef OS2
5318 tcp_avail
5319 #else
5320 1
5321 #endif /* OS2 */
5322 ) {
5323 char ipaddr[16];
5324
5325 if (getlocalipaddrs(ipaddr,16,0) < 0) {
5326 #ifdef OS2ONLY
5327 printf(" TCP/IP via %s\n", tcpname);
5328 #else
5329 printf(" TCP/IP\n");
5330 #endif /* OS2ONLY */
5331 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5332 } else {
5333 int i = 1;
5334 #ifdef OS2ONLY
5335 printf(" TCP/IP [%16s] via %s\n", ipaddr, tcpname);
5336 #else
5337 printf(" TCP/IP [%16s]\n",ipaddr);
5338 #endif /* OS2ONLY */
5339 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5340
5341 while (getlocalipaddrs(ipaddr,16,i++) >= 0) {
5342 printf(" [%16s]\n",ipaddr);
5343 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5344 }
5345 }
5346 if (nettype == NET_TCPB) {
5347 printf("\n");
5348 n = shotcp(++n);
5349 if (n < 0) return(0);
5350 #ifdef TNCODE
5351 printf("\n");
5352 n = shotel(++n);
5353 if (n < 0) return(0);
5354 #endif /* TNCODE */
5355 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5356 }
5357 #ifdef OS2
5358 } else {
5359 printf(" TCP/IP - not available%s\n",tcpname[0] ? tcpname : "" );
5360 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5361 #endif /* OS2 */
5362 }
5363 #endif /* TCPSOCKET */
5364
5365 #ifdef CK_NETBIOS
5366 if (netbiosAvail && nettype == NET_BIOS) {
5367 printf("\n") ;
5368 if ((n = shonb(++n)) < 0) return(0);
5369 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5370 }
5371 #endif /* CK_NETBIOS */
5372
5373 #endif /* VMS */
5374
5375 printf("\nActive network connection:\n");
5376 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5377
5378 if (network) {
5379 printf(" Host: %s",ttname);
5380 if ((nettype == NET_TCPA || nettype == NET_TCPB) && *ipaddr)
5381 printf(" [%s]",ipaddr);
5382 } else
5383 printf(" Host: none");
5384 printf(", via: ");
5385 if (nettype == NET_TCPA || nettype == NET_TCPB)
5386 printf("tcp/ip\n");
5387 else if (nettype == NET_SX25)
5388 printf("SunLink X.25\n");
5389 else if (nettype == NET_VX25)
5390 printf("Stratus VOS X.25\n");
5391 else if (nettype == NET_IX25)
5392 printf("IBM AIX X.25\n");
5393 else if (nettype == NET_HX25)
5394 printf("HP-UX X.25\n");
5395 else if (nettype == NET_DEC) {
5396 if ( ttnproto == NP_LAT )
5397 printf("DECnet LAT\n");
5398 else if ( ttnproto == NP_CTERM )
5399 printf("DECnet CTERM\n");
5400 else
5401 printf("DECnet\n");
5402 } else if (nettype == NET_PIPE)
5403 printf("Named Pipes\n");
5404 else if (nettype == NET_BIOS)
5405 printf("NetBIOS\n");
5406 else if (nettype == NET_SLAT)
5407 printf("SuperLAT\n");
5408
5409 #ifdef NETFILE
5410 else if ( nettype == NET_FILE )
5411 printf("local file\n");
5412 #endif /* NETFILE */
5413 #ifdef NETCMD
5414 else if ( nettype == NET_CMD )
5415 printf("pipe\n");
5416 #endif /* NETCMD */
5417 #ifdef NETPTY
5418 else if ( nettype == NET_PTY )
5419 printf("pseudoterminal\n");
5420 #endif /* NETPTY */
5421 #ifdef NETDLL
5422 else if ( nettype == NET_DLL )
5423 printf("dynamic link library\n");
5424 #endif /* NETDLL */
5425 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5426
5427 #ifdef ANYX25
5428 if ((nettype == NET_SX25) ||
5429 (nettype == NET_VX25) ||
5430 (nettype == NET_IX25))
5431 if ((n = shox25(n)) < 0) return(0);
5432 #endif /* ANYX25 */
5433
5434 #ifdef SSHBUILTIN
5435 if (nettype == NET_SSH) {
5436 printf("Secure Shell protocol\n");
5437 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5438 }
5439 #endif /* SSHBUILTIN */
5440
5441 if (nettype == NET_TCPA || nettype == NET_TCPB) {
5442 #ifdef RLOGCODE
5443 if (ttnproto == NP_RLOGIN) {
5444 printf(" LOGIN (rlogin) protocol\n");
5445 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5446 }
5447 #ifdef CK_KERBEROS
5448 else if (ttnproto == NP_K4LOGIN) {
5449 printf(" Kerberos 4 LOGIN (klogin) protocol\n");
5450 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5451 }
5452 else if (ttnproto == NP_EK4LOGIN) {
5453 printf(" Encrypted Kerberos 4 LOGIN (eklogin) protocol\n");
5454 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5455 }
5456 else if (ttnproto == NP_K5LOGIN) {
5457 printf(" Kerberos 5 LOGIN (klogin) protocol\n");
5458 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5459 }
5460 else if (ttnproto == NP_EK5LOGIN) {
5461 printf(" Encrypted Kerberos 5 LOGIN (eklogin) protocol\n");
5462 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5463 }
5464 #endif /* CK_KERBEROS */
5465 #endif /* RLOGCODE */
5466 #ifdef CK_KERBEROS
5467 if (ttnproto == NP_K5U2U) {
5468 printf(" Kerberos 5 User to User protocol\n");
5469 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5470 }
5471 #endif /* CK_KERBEROS */
5472
5473 #ifdef TNCODE
5474 if (IS_TELNET()) {
5475 printf(" TELNET protocol\n");
5476 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5477 printf(" Echoing is currently %s\n",duplex ? "local" : "remote");
5478 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5479 }
5480 #endif /* TNCODE */
5481 if (ttnproto == NP_TCPRAW) {
5482 printf(" Raw TCP socket\n");
5483 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5484 }
5485 }
5486 printf("\n");
5487 #endif /* NOLOCAL */
5488 #endif /* NETCONN */
5489 return(0);
5490 }
5491 #endif /* NONET */
5492
5493 #ifndef NODIAL
5494 VOID
shodial()5495 shodial() {
5496 if (mdmtyp >= 0 || local != 0) doshodial();
5497 }
5498
5499 VOID
shods(s)5500 shods(s) char *s; { /* Show a dial-related string */
5501 char c;
5502 if (s == NULL || !(*s)) { /* Empty? */
5503 printf("(none)\n");
5504 } else { /* Not empty. */
5505 while ((c = *s++)) /* Can contain controls */
5506 if (c == '\\') /* a backslash */
5507 printf("\\\\");
5508 else if (c > 31 && c < 127) {
5509 putchar(c);
5510 } else
5511 printf("\\{%d}",c);
5512 printf("\n");
5513 }
5514 }
5515
5516 int
doshodial()5517 doshodial() {
5518
5519 int i, n = 2;
5520
5521 printf(" Dial status: %d", dialsta);
5522
5523 #ifdef BIGBUFOK
5524 if (dialsta > 90)
5525 printf(" = Unknown error");
5526 else if (dialsta < 0)
5527 printf(" = (none)");
5528 else if (dialsta < 35 && dialmsg[dialsta])
5529 printf(" = %s", dialmsg[dialsta]);
5530 #endif /* BIGBUFOK */
5531 n++;
5532 if (ndialdir <= 1) {
5533 printf("\n Dial directory: %s\n",dialdir[0] ? dialdir[0] : "(none)");
5534 } else {
5535 int i;
5536 printf("\n Dial directories:\n");
5537 for (i = 0; i < ndialdir; i++)
5538 printf("%2d. %s\n",i+1,dialdir[i]);
5539 n += ndialdir;
5540 }
5541 printf(" Dial method: ");
5542 if (dialmauto) printf("auto ");
5543 else if (dialmth == XYDM_D) printf("default");
5544 else if (dialmth == XYDM_P) printf("pulse ");
5545 else if (dialmth == XYDM_T) printf("tone ");
5546 printf(" Dial sort: %s\n",dialsrt ? "on" : "off");
5547 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5548 printf(" Dial hangup: %s Dial display: %s\n",
5549 dialhng ? "on " : "off", dialdpy ? "on" : "off");
5550 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5551 if (dialrtr > 0) {
5552 printf(" Dial retries: %-12d Dial interval: %d\n",
5553 dialrtr, dialint);
5554 } else {
5555 printf(" Dial retries: (auto) Dial interval: %d\n", dialint);
5556 }
5557 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5558 printf(" Dial timeout: ");
5559 #ifdef CK_TAPI
5560 if (tttapi && !tapipass)
5561 printf("(tapi)");
5562 else
5563 #endif /* CK_TAPI */
5564 if (dialtmo > 0)
5565 printf("%4d sec", dialtmo);
5566 else
5567 printf("0 (auto)");
5568 printf(" Redial number: %s\n",dialnum ? dialnum : "(none)");
5569 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5570 printf(" Dial confirmation: %s Dial convert-directory: %s\n",
5571 dialcnf ? "on " : "off",
5572 dialcvt ? ((dialcvt == 1) ? "on" : "ask") : "off");
5573 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5574 printf(" Dial ignore-dialtone: %s", dialidt ? "on " : "off");
5575 printf(" Dial pacing: %d\n",dialpace);
5576 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5577 printf(
5578 " Dial prefix: %s\n", dialnpr ? dialnpr : "(none)");
5579 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5580 printf(
5581 " Dial suffix: %s\n", dialsfx ? dialsfx : "(none)");
5582 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5583 printf(
5584 " Dial country-code: %-12s", diallcc ? diallcc : "(none)");
5585 printf("Dial connect: %s", dialcon ? ((dialcon == 1) ? "on" : "auto")
5586 : "off");
5587 if (dialcon != CAR_OFF)
5588 printf(" %s", dialcq ? "quiet" : "verbose");
5589 printf(
5590 "\n Dial area-code: %-12s", diallac ? diallac : "(none)");
5591 n++;
5592 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5593 printf("Dial restrict: ");
5594 if (dialrstr == 5) printf("international\n");
5595 else if (dialrstr == 4) printf("long-distance\n");
5596 else if (dialrstr == 2) printf("local\n");
5597 else if (dialrstr == 6) printf("none\n");
5598 else printf("?\n");
5599 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5600 printf(" Dial lc-area-codes: ");
5601 if (nlocalac == 0)
5602 printf("(none)");
5603 else
5604 for (i = 0; i < nlocalac; i++)
5605 printf("%s ", diallcac[i]);
5606 printf(
5607 "\n Dial lc-prefix: %s\n", diallcp ? diallcp : "(none)");
5608 n++;
5609 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5610 printf(
5611 " Dial lc-suffix: %s\n", diallcs ? diallcs : "(none)");
5612 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5613 printf(
5614 " Dial ld-prefix: %s\n", dialldp ? dialldp : "(none)");
5615 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5616 printf(
5617 " Dial ld-suffix: %s\n", diallds ? diallds : "(none)");
5618 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5619 printf(
5620 " Dial force-long-distance %s\n", showoff(dialfld));
5621 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5622 printf(
5623 " Dial intl-prefix: %s\n", dialixp ? dialixp : "(none)");
5624 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5625 printf(
5626 " Dial intl-suffix: %s\n", dialixs ? dialixs : "(none)");
5627 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5628 printf(
5629 " Dial toll-free-area-code: ");
5630 if (ntollfree == 0)
5631 printf("(none)");
5632 else
5633 for (i = 0; i < ntollfree; i++)
5634 printf("%s ", dialtfc[i]);
5635 printf("\n");
5636 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5637
5638 printf(
5639 " Dial pulse-countries: ");
5640 if (ndialpucc == 0)
5641 printf("(none)");
5642 else
5643 for (i = 0; i < ndialpucc; i++)
5644 printf("%s ", dialpucc[i]);
5645 printf("\n");
5646 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5647
5648 printf(
5649 " Dial tone-countries: ");
5650 if (ndialtocc == 0)
5651 printf("(none)");
5652 else
5653 for (i = 0; i < ndialtocc; i++)
5654 printf("%s ", dialtocc[i]);
5655 printf("\n");
5656 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5657
5658 printf(
5659 " Dial toll-free-prefix: %s\n",
5660 dialtfp ? dialtfp :
5661 (dialldp ? dialldp : "(none)")
5662 );
5663 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5664 printf(" Dial pbx-exchange: ");
5665 if (ndialpxx == 0)
5666 printf("(none)");
5667 else
5668 for (i = 0; i < ndialpxx; i++)
5669 printf("%s ", dialpxx[i]);
5670 printf("\n");
5671
5672 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5673 printf(
5674 " Dial pbx-inside-prefix: %s\n", dialpxi ? dialpxi : "(none)");
5675 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5676 printf(
5677 " Dial pbx-outside-prefix: %s\n", dialpxo ? dialpxo : "(none)");
5678 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5679 printf(
5680 " Dial macro: %s\n", dialmac ? dialmac : "(none)");
5681 return(0);
5682 }
5683 #endif /* NODIAL */
5684 #endif /* NOLOCAL */
5685
5686 /* Show File Parameters */
5687
5688 static char *
pathval(x)5689 pathval(x) int x; {
5690 switch (x) {
5691 case PATH_OFF: return("off");
5692 case PATH_ABS: return("absolute");
5693 case PATH_REL: return("relative");
5694 case PATH_AUTO: return("auto");
5695 default: return("unknown");
5696 }
5697 }
5698
5699 VOID
shofil()5700 shofil() {
5701 char *s; int i = 0, n = 1;
5702 extern char * ifdnam[];
5703 extern int wildena;
5704 #ifdef UNIX
5705 extern int wildxpand;
5706 #endif /* UNIX */
5707 extern char * snd_move, * snd_rename, * rcv_move, * rcv_rename;
5708 #ifdef PATTERNS
5709 extern int patterns;
5710 #endif /* PATTERNS */
5711 extern char * rfspec, * sfspec;
5712 #ifdef UNIX
5713 extern int zobufsize, zofbuffer, zofblock;
5714 #endif /* UNIX */
5715 #ifdef CK_CTRLZ
5716 extern int eofmethod;
5717 #endif /* CK_CTRLZ */
5718
5719 printf("\n");
5720
5721 #ifdef VMS
5722 printf(" File record-Length: %5d\n",frecl);
5723 n++;
5724 #endif /* VMS */
5725
5726 #ifndef NOXFER
5727 printf(" Transfer mode: %s\n",
5728 xfermode == XMODE_A ?
5729 "automatic" :
5730 "manual"
5731 );
5732 n++;
5733 #ifdef PATTERNS
5734 printf(" File patterns: %s", showooa(patterns));
5735 if (xfermode == XMODE_M && patterns)
5736 printf(" (but disabled by TRANSFER-MODE MANUAL)");
5737 else if (patterns)
5738 printf(" (SHOW PATTERNS for list)");
5739 printf("\n");
5740 n++;
5741 #endif /* PATTERNS */
5742 if (filepeek)
5743 printf(" File scan: on %d\n", nscanfile);
5744 else
5745 printf(" File scan: off\n");
5746 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5747 if (xfermode == XMODE_A)
5748 printf(" Default file type: %s\n",shoxm());
5749 else
5750 printf(" File type: %s\n",shoxm());
5751 n++;
5752 if (fncnv == XYFN_L)
5753 s = "literal";
5754 else if (fncnv == XYFN_C)
5755 s = "converted";
5756 else
5757 s = "(unknown)";
5758 printf(" File names: %s\n",s);
5759 n++;
5760 printf(" Send pathnames: %s\n", pathval(fnspath));
5761 n++;
5762 printf(" Receive pathnames: %s\n", pathval(fnrpath));
5763 n++;
5764 #ifdef UNIXOROSK
5765 printf(" Match dot files: %s\n", matchdot ? "yes" : "no");
5766 n++;
5767 #ifdef UNIX
5768 printf(" Wildcard-expansion: %s (%s)\n", showoff(wildena),
5769 wildxpand ? "shell" : "kermit");
5770 n++;
5771 #endif /* UNIX */
5772 #endif /* UNIXOROSK */
5773 printf(" File collision: ");
5774 for (i = 0; i < ncolx; i++)
5775 if (colxtab[i].kwval == fncact) break;
5776 printf("%s\n", (i == ncolx) ? "unknown" : colxtab[i].kwd);
5777 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5778 printf(" File destination: %s\n",
5779 (dest == DEST_D) ? "disk" :
5780 ((dest == DEST_S) ? "screen" :
5781 ((dest == DEST_N) ? "nowhere" :
5782 "printer"))
5783 );
5784 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5785 s = (keep >= 0 && keep <= 2) ? ifdnam[keep] : "keep";
5786 printf(" File incomplete: %s\n",s);
5787 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5788 printf(" File bytesize: %d\n",(fmask == 0177) ? 7 : 8);
5789 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5790 #ifndef NOCSETS
5791 printf(" File character-set: %s\n",fcsinfo[fcharset].keyword);
5792 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5793 printf(" File default 7-bit: %s\n",fcsinfo[dcset7].keyword);
5794 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5795 printf(" File default 8-bit: %s\n",fcsinfo[dcset8].keyword);
5796 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5797 #ifdef UNICODE
5798 printf(" File UCS bom: %s\n",showoff(ucsbom));
5799 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5800 printf(" File UCS byte-order: %s-endian\n",
5801 ucsorder ? "little" : "big");
5802 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5803 printf(" Computer byteorder: %s-endian\n",
5804 byteorder ? "little" : "big");
5805 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5806 #endif /* UNICODE */
5807 #endif /* NOCSETS */
5808
5809 printf(" File end-of-line: ");
5810 i = feol;
5811 switch (feol) {
5812 case XYFA_C: printf("%s\n","cr"); break;
5813 case XYFA_L: printf("%s\n","lf"); break;
5814 case XYFA_2: printf("%s\n","crlf"); break;
5815 default: printf("%d\n",i);
5816 }
5817 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5818 #endif /* NOXFER */
5819
5820 #ifdef CK_CTRLZ
5821 printf(" File eof: %s\n", eofmethod ? "ctrl-z" : "length");
5822 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5823 #endif /* CK_CTRLZ */
5824 #ifndef NOXFER
5825 #ifdef CK_TMPDIR
5826 printf(" File download-directory: %s\n", dldir ? dldir : "(none)");
5827 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5828 #ifdef COMMENT
5829 i = 256;
5830 s = line;
5831 zzstring("\\v(tmpdir)",&s,&i);
5832 printf(" Temporary directory: %s\n", line);
5833 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5834 #endif /* COMMENT */
5835 #endif /* CK_TMPDIR */
5836 #ifdef VMS
5837 {
5838 extern int vmssversions, vmsrversions;
5839 printf(" Send version-numbers: %s\n",showoff(vmssversions));
5840 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5841 printf(" Receive version-numbers: %s\n",showoff(vmsrversions));
5842 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5843 }
5844 #endif /* VMS */
5845 printf(" Send move-to: %s\n",
5846 snd_move ? snd_move : "(none)");
5847 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5848 printf(" Send rename-to: %s\n",
5849 snd_rename ? snd_rename : "(none)");
5850 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5851 printf(" Receive move-to: %s\n",
5852 rcv_move ? rcv_move : "(none)");
5853 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5854 printf(" Receive rename-to: %s\n",
5855 rcv_rename ? rcv_rename : "(none)");
5856 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5857 #endif /* NOXFER */
5858 #ifdef KERMRC
5859 printf(" Initialization file: %s\n", noinit ? "(none)" :
5860 #ifdef CK_SYSINI
5861 CK_SYSINI
5862 #else
5863 kermrc
5864 #endif /* CK_SYSINI */
5865 );
5866 #endif /* KERMRC */
5867 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5868
5869 if (k_info_dir) {
5870 printf(" Kermit doc files: %s\n", k_info_dir);
5871 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5872 }
5873
5874 #ifdef CKROOT
5875 s = zgetroot();
5876 printf(" Root set: %s\n", s ? s : "(none)");
5877 #endif /* CKROOT */
5878
5879 #ifdef UNIX
5880 printf(" Disk output buffer: %d (writes are %s, %s)\n",
5881 zobufsize,
5882 zofbuffer ? "buffered" : "unbuffered",
5883 zofblock ? "blocking" : "nonblocking"
5884 );
5885 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5886 #ifdef DYNAMIC
5887 printf(" Stringspace: %d\n", zsetfil(0,2));
5888 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5889 printf(" Listsize: %d\n", zsetfil(0,4));
5890 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5891 #endif /* DYNAMIC */
5892 #endif /* UNIX */
5893 #ifdef OS2ORUNIX
5894 printf(" Longest filename: %d\n", maxnam);
5895 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5896 printf(" Longest pathname: %d\n", maxpath);
5897 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5898 #endif /* OS2ORUNIX */
5899
5900 printf(" Last file sent: %s\n", sfspec ? sfspec : "(none)");
5901 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5902 printf(" Last file received: %s\n", rfspec ? rfspec : "(none)");
5903 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5904 printf("\n Also see:\n");
5905 n++;
5906 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5907 printf(" SHOW PROTOCOL, SHOW XFER");
5908 #ifdef CK_LABELED
5909 printf(", SHOW LABELED");
5910 #endif /* CK_LABELED */
5911 #ifdef PATTERNS
5912 printf(", SHOW PATTERNS");
5913 #endif /* PATTERNS */
5914 #ifdef STREAMING
5915 printf(", SHOW STREAMING");
5916 #endif /* STREAMING */
5917 #ifndef NOCSETS
5918 printf(", SHOW CHARACTER-SETS");
5919 #endif /* NOCSETS */
5920 printf("\n\n");
5921 }
5922
5923 #ifndef NOXFER
5924 VOID
shoparp()5925 shoparp() { /* Protocol */
5926 extern int docrc, skipbup;
5927 char *s;
5928
5929 #ifdef CK_TIMERS
5930 extern int rttflg;
5931 #endif /* CK_TIMERS */
5932
5933 printf("Protocol: %s\n",ptab[protocol].p_name);
5934
5935 if (protocol == PROTO_K) {
5936 printf("\nProtocol Parameters: Send Receive");
5937 if (timef)
5938 printf("\n Timeout (used=%2d):%7d*%8d ", timint, rtimo, pkttim);
5939 else
5940 printf("\n Timeout (used=%2d):%7d%9d ", timint, rtimo, pkttim);
5941 #ifdef XFRCAN
5942 printf(" Cancellation: %s",showoff(xfrcan));
5943 if (xfrcan)
5944 printf(" %d %d", xfrchr, xfrnum);
5945 #endif /* XFRCAN */
5946 printf("\n Padding: %11d%9d", npad, mypadn);
5947 if (bctr == 4)
5948 printf(" Block Check: blank-free-2\n");
5949 else
5950 printf(" Block Check: %6d\n",bctr);
5951 printf( " Pad Character:%11d%9d", padch, mypadc);
5952 printf(" Delay: %6d\n",ckdelay);
5953 printf( " Pause: %11d%9d", pktpaus, pktpaus);
5954 printf(" Attributes: %s\n",showoff(atcapr));
5955 printf( " Packet Start: %11d%9d", mystch, stchr);
5956 printf(" Max Retries: %6d%s\n",
5957 maxtry,
5958 (maxtry == 0) ? " (unlimited)" : ""
5959 );
5960 printf( " Packet End: %11d%9d", seol, eol);
5961 if (ebqflg)
5962 printf(" 8th-Bit Prefix: '%c'",ebq);
5963 else
5964 printf(" 8th-Bit Prefix: ('%c' but not used)",ebq);
5965 printf( "\n Packet Length:%11d ", spmax);
5966 printf("%8d ", urpsiz);
5967 if (rptflg)
5968 printf(" Repeat Prefix: '%c'",rptq);
5969 else
5970 printf(" Repeat Prefix: ('%c' but not used)",rptq);
5971 printf( "\n Maximum Length: %9d%9d", maxsps, maxrps);
5972 printf(" Window Size:%7d set, %d used\n",wslotr,wmax);
5973 printf( " Buffer Size: %11d%9d", bigsbsiz, bigrbsiz);
5974 printf(" Locking-Shift: ");
5975 if (lscapu == 2) {
5976 printf("forced");
5977 } else {
5978 printf("%s", (lscapr ? "enabled" : "disabled"));
5979 if (lscapr) printf(",%s%s", (lscapu ? " " : " not "), "used");
5980 }
5981 printf("\n\n");
5982
5983 if (!(s = ptab[protocol].h_b_init)) s = "";
5984 printf(" Auto-upload command (binary): ");
5985 if (*s) {
5986 shostrdef((CHAR *)s);
5987 printf("\n");
5988 } else {
5989 printf("(none)\n");
5990 }
5991 if (!(s = ptab[protocol].h_t_init)) s = "";
5992 printf(" Auto-upload command (text): ");
5993 if (*s) {
5994 shostrdef((CHAR *)s);
5995 printf("\n");
5996 } else {
5997 printf("(none)\n");
5998 }
5999 if (!(s = ptab[protocol].h_x_init)) s = "";
6000 printf(" Auto-server command: ");
6001 if (*s) {
6002 shostrdef((CHAR *)s);
6003 printf("\n");
6004 } else {
6005 printf("(none)\n");
6006 }
6007 tmpbuf[0] = NUL;
6008 #ifdef CK_TIMERS
6009 if (rttflg) {
6010 extern int mintime, maxtime;
6011 sprintf(tmpbuf," Packet timeouts: dynamic %d:%d", /* SAFE */
6012 mintime,
6013 maxtime);
6014 } else {
6015 sprintf(tmpbuf," Packet timeouts: fixed"); /* SAFE */
6016 }
6017 #endif /* CK_TIMERS */
6018 if (tmpbuf[0])
6019 printf("%-31s",tmpbuf);
6020 printf("Send backup: %s\n",showoff(!skipbup));
6021
6022 printf(" Transfer mode: %s", xfermode == XMODE_A ?
6023 "automatic " :
6024 "manual "
6025 );
6026 printf(" Transfer slow-start: %s, crc: %s\n",
6027 showoff(slostart),
6028 showoff(docrc)
6029 );
6030 #ifdef PIPESEND
6031 {
6032 extern int usepipes;
6033 printf(" Transfer pipes: %s ",usepipes ? "on " : "off");
6034 }
6035 #endif /* PIPESEND */
6036 #ifndef NOCSETS
6037 printf(" Transfer character-set: ");
6038 if (tcharset == TC_TRANSP)
6039 printf("transparent\n");
6040 else
6041 printf("%s\n", tcsinfo[tcharset].keyword );
6042 #endif /* NOCSETS */
6043 #ifdef PIPESEND
6044 {
6045 extern char * sndfilter, * rcvfilter;
6046 printf(" Send filter: %s\n", sndfilter ? sndfilter : "(none)");
6047 printf(" Receive filter: %s\n", rcvfilter ? rcvfilter : "(none)");
6048 }
6049 #endif /* PIPESEND */
6050 printf("\nAlso see:\n");
6051 printf(" SHOW FILE, SHOW XFER");
6052
6053 #ifdef CK_LABELED
6054 printf(", SHOW LABELED");
6055 #endif /* CK_LABELED */
6056 #ifdef PATTERNS
6057 printf(", SHOW PATTERNS");
6058 #endif /* PATTERNS */
6059 #ifdef STREAMING
6060 printf(", SHOW STREAMING");
6061 #endif /* STREAMING */
6062 #ifndef NOCSETS
6063 printf(", SHOW CHARACTER-SETS");
6064 #endif /* NOCSETS */
6065 }
6066
6067 #ifdef CK_XYZ
6068 #ifdef XYZ_INTERNAL
6069 if (protocol != PROTO_K) {
6070 int i;
6071 int x;
6072 printf(" File type: %s\n", binary ? "binary" : "text");
6073 if (protocol == PROTO_Z) { /* Zmodem */
6074 printf(" Window size: ");
6075 if (ptab[protocol].winsize < 1)
6076 printf("none\n");
6077 else
6078 printf("%d\n",wslotr);
6079 #ifdef COMMENT
6080 printf(" Packet (frame) length: ");
6081 if (ptab[protocol].spktlen < 0)
6082 printf("none\n");
6083 else
6084 printf("%d\n",spmax);
6085 #endif /* COMMENT */
6086 } else {
6087 if (ptab[protocol].spktlen >= 1000)
6088 printf(" 1K packets\n");
6089 else
6090 printf(" 128-byte packets\n");
6091 }
6092 printf(" Pathname stripping when sending: %s\n",
6093 showoff(ptab[protocol].fnsp)
6094 );
6095 printf(" Pathname stripping when receiving: %s\n",
6096 showoff(ptab[protocol].fnrp)
6097 );
6098 printf(" Filename collision action: ");
6099 for (i = 0; i < ncolx; i++)
6100 if (colxtab[i].kwval == fncact) break;
6101 printf("%-12s", (i == ncolx) ? "unknown" : colxtab[i].kwd);
6102
6103 printf("\n Escape control characters: ");
6104 x = ptab[protocol].prefix;
6105 if (x == PX_ALL)
6106 printf("all\n");
6107 else if (x == PX_CAU || x==PX_WIL)
6108 printf("minimal\n");
6109 else
6110 printf("none\n");
6111 if (!(s = ptab[protocol].h_b_init))
6112 s = "";
6113 printf(" Autoreceive command (binary): %s\n", *s ? s : "(none)");
6114 if (!(s = ptab[protocol].h_t_init))
6115 s = "";
6116 printf(" Autoreceive command (text): %s\n", *s ? s : "(none)");
6117 }
6118 #else
6119 #ifndef NOPUSH
6120 if (protocol != PROTO_K) {
6121 _PROTOTYP( VOID shoextern, (void) );
6122 printf("\nExecuted by external commands:\n\n");
6123 s = ptab[protocol].p_b_scmd;
6124 if (!s) s = "";
6125 printf(" SEND command (binary): %s\n", *s ? s : "(none)");
6126 s = ptab[protocol].p_t_scmd;
6127 if (!s) s = "";
6128 printf(" SEND command (text): %s\n", *s ? s : "(none)");
6129 s = ptab[protocol].p_b_rcmd;
6130 if (!s) s = "";
6131 printf(" RECEIVE command (binary): %s\n", *s ? s : "(none)");
6132 s = ptab[protocol].p_t_rcmd;
6133 if (!s) s = "";
6134 printf(" RECEIVE command (text): %s\n", *s ? s : "(none)");
6135 s = ptab[protocol].h_b_init;
6136 if (!s) s = "";
6137 printf(" Autoreceive command (binary): %s\n", *s ? s : "(none)");
6138 s = ptab[protocol].h_t_init;
6139 if (!s) s = "";
6140 printf(" Autoreceive command (text): %s\n", *s ? s : "(none)");
6141 (VOID) shoextern();
6142 }
6143 #endif /* NOPUSH */
6144 #endif /* XYZ_INTERNAL */
6145 #endif /* CK_XYZ */
6146 }
6147 #endif /* NOXFER */
6148
6149 #ifndef NOCSETS
6150 /* Character-set items */
6151
6152 extern int s_cset, r_cset, axcset[], afcset[];
6153 extern struct keytab xfrmtab[];
6154
6155 VOID
shoparl()6156 shoparl() {
6157 #ifdef COMMENT
6158 int i;
6159 /* Misleading... */
6160 printf("\nAvailable Languages:\n");
6161 for (i = 0; i < MAXLANG; i++) {
6162 printf(" %s\n",langs[i].description);
6163 }
6164 #else
6165 printf("\nLanguage-specific translation rules: %s\n",
6166 language == L_USASCII ? "none" : langs[language].description);
6167 shocharset();
6168 printf("\n\n");
6169 #endif /* COMMENT */
6170 }
6171
6172 VOID
shocharset()6173 shocharset() {
6174 int x;
6175 #ifdef COMMENT
6176 char * s = "Unknown";
6177 extern int xlatype;
6178 #endif /* COMMENT */
6179
6180 #ifndef NOXFER
6181 extern int xfrxla;
6182 #endif /* NOXFER */
6183
6184 debug(F101,"SHOW FILE CHAR","",fcharset);
6185 printf("\n");
6186 #ifndef NOXFER
6187 printf(" Transfer Translation: %s\n", showoff(xfrxla));
6188 if (!xfrxla) {
6189 printf(
6190 " Because transfer translation is off, the following are ignored:\n\n");
6191 }
6192 #endif /* NOXFER */
6193 printf(" File Character-Set: %s (%s), ",
6194 fcsinfo[fcharset].keyword,
6195 fcsinfo[fcharset].name
6196 );
6197 if ((x = fcsinfo[fcharset].size) == 128)
6198 printf("7-bit");
6199 else if (x == 256)
6200 printf("8-bit");
6201 else
6202 printf("multibyte");
6203 printf("\n");
6204 printf(" File Scan: %s\n",showoff(filepeek));
6205 printf(" Default 7bit-Character-Set: %s\n",fcsinfo[dcset7].keyword);
6206 printf(" Default 8bit-Character-Set: %s\n",fcsinfo[dcset8].keyword);
6207 printf(" Transfer Character-Set");
6208 #ifdef COMMENT
6209 if (tslevel == TS_L2)
6210 printf(": (international)");
6211 else
6212 #endif /* COMMENT */
6213 if (tcharset == TC_TRANSP)
6214 printf(": Transparent");
6215 else
6216 printf(": %s (%s)",tcsinfo[tcharset].keyword, tcsinfo[tcharset].name);
6217 printf("\n");
6218 #ifdef COMMENT
6219 switch (xlatype) {
6220 case XLA_NONE: s = "None"; break;
6221 case XLA_BYTE: s = "Byte"; break;
6222 case XLA_JAPAN: s = "Japanese"; break;
6223 case XLA_UNICODE: s = "Unicode"; break;
6224 }
6225 printf("\n Translation type: %s\n",s);
6226 #endif /* COMMENT */
6227 printf(" SEND character-set-selection: %s\n",xfrmtab[s_cset].kwd);
6228 printf(" RECEIVE character-set-selection: %s\n",xfrmtab[r_cset].kwd);
6229 if (s_cset == XMODE_A || r_cset == XMODE_A)
6230 printf(
6231 " (Use SHOW ASSOCIATIONS to list automatic character-set selections.)\n"
6232 );
6233 }
6234
6235 VOID
showassoc()6236 showassoc() {
6237 int i, k, n = 4;
6238 char * s;
6239 printf("\nFor incoming files:\n\n");
6240 printf("Transfer Character-Set File Character-Set\n");
6241 for (i = 1; i <= MAXTCSETS; i++) {
6242 k = axcset[i];
6243 if (k < 0 || k > MAXFCSETS)
6244 s = "(none)";
6245 else
6246 s = fcsinfo[k].keyword;
6247 if (!s) s = "";
6248 if (!*s) s = "(none)";
6249 printf(" %-25s%s\n",tcsinfo[i].keyword,s);
6250 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
6251 }
6252 printf("\nFor outbound files:\n\n");
6253 n += 2;
6254 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
6255 printf("File Character-Set Transfer Character-Set\n");
6256 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
6257 for (i = 0; i <= MAXFCSETS; i++) {
6258 k = afcset[i];
6259 if (k < 0 || k > MAXTCSETS)
6260 s = "(none)";
6261 else
6262 s = tcsinfo[k].keyword;
6263 if (!s) s = "";
6264 if (!*s) s = "(none)";
6265 printf(" %-25s%s\n",fcsinfo[i].keyword,s);
6266 if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
6267 }
6268 }
6269 #endif /* NOCSETS */
6270
6271 VOID
shopar()6272 shopar() {
6273 printf("Show what? (Type \"show ?\" for a list of possibilities.)\n");
6274 }
6275 #endif /* NOSHOW */
6276
6277 #ifndef NOXFER
6278 /* D O S T A T -- Display file transfer statistics. */
6279
6280 int
dostat(brief)6281 dostat(brief) int brief; {
6282 extern long filrej, peakcps;
6283 extern int lastspmax, streamed, cleared, streamok;
6284 extern char whoareu[];
6285 int n = 0, ftp = 0;
6286 extern int docrc, interrupted, fatalio;
6287
6288 ftp = lastxfer & W_FTP;
6289
6290 #ifdef CK_TTGWSIZ
6291 #ifdef OS2
6292 if (tt_cols[VTERM] < 0 || tt_rows[VTERM] < 0)
6293 ttgwsiz();
6294 #else /* OS2 */
6295 if (ttgwsiz() > 0) {
6296 if (tt_rows > 0 && tt_cols > 0) {
6297 cmd_rows = tt_rows;
6298 cmd_cols = tt_cols;
6299 }
6300 }
6301 #endif /* OS2 */
6302 #endif /* CK_TTGWSIZ */
6303
6304 debug(F101,"dostat xferstat","",xferstat);
6305 if (xferstat < 0) {
6306 printf(" No file transfers yet.\n");
6307 return(1);
6308 }
6309 n = 0;
6310 if (brief) { printf("\n"); n++; };
6311 printf(" protocol : %s\n",
6312 ftp ? "ftp" : ptab[protocol].p_name);
6313 n++;
6314 printf(" status : ");
6315 if (xferstat) printf("SUCCESS\n");
6316 else if (interrupted) printf("FAILURE (interrupted)\n");
6317 else if (fatalio) printf("FAILURE (i/o error)\n");
6318 else printf("FAILURE\n");
6319 #ifndef XYZ_INTERNAL
6320 if (!ftp && protocol != PROTO_K) {
6321 printf("\n external protocol statistics not available\n");
6322 return(1);
6323 }
6324 #endif /* XYZ_INTERNAL */
6325 n++;
6326 if (!ftp) {
6327 if (!xferstat > 0) {
6328 if (docrc)
6329 printf(" crc-16 of file(s) : %ld\n", crc16);
6330 else
6331 printf(" crc-16 of file(s) : (disabled)\n");
6332 n++;
6333 }
6334 if (!xferstat && *epktmsg) {
6335 printf(" reason : %s\n", epktmsg);
6336 n++;
6337 }
6338 }
6339 if (!brief) {
6340 #ifdef NEWFTP
6341 if (ftp) {
6342 extern char ftp_srvtyp[];
6343 printf(" remote system type : %s\n",ftp_srvtyp);
6344 } else
6345 #endif /* NEWFTP */
6346 if (whoareu[0]) {
6347 printf(" remote system type : %s\n",
6348 getsysid((char *)whoareu));
6349 n++;
6350 }
6351 printf(" files transferred : %ld\n",filcnt - filrej);
6352 if (!ftp)
6353 printf(" files not transferred : %ld\n",filrej);
6354 printf(" characters last file : %s\n",ckfstoa(ffc));
6355 printf(" total file characters : %s\n",ckfstoa(tfc));
6356 n += ftp ? 3 : 4;
6357 if (!ftp) {
6358 printf(" communication line in : %s\n",ckfstoa(tlci));
6359 printf(" communication line out : %s\n",ckfstoa(tlco));
6360 printf(" packets sent : %d\n", spackets);
6361 printf(" packets received : %d\n", rpackets);
6362 n += 4;
6363 }
6364 }
6365 if (ftp) goto dotimes;
6366
6367 printf(" damaged packets rec'd : %d\n", crunched);
6368 printf(" timeouts : %d\n", timeouts);
6369 printf(" retransmissions : %d\n", retrans);
6370 n += 3;
6371
6372 if (!brief) {
6373 if (filcnt > 0) {
6374 printf(" parity : %s",parnam((char)parity));
6375 n++;
6376 if (autopar) { printf(" (detected automatically)"); n++; }
6377 printf(
6378 "\n control characters : %ld prefixed, %ld unprefixed\n",
6379 ccp, ccu);
6380 n++;
6381 printf(" 8th bit prefixing : ");
6382 n++;
6383 if (ebqflg) printf("yes [%c]\n",ebq); else printf("no\n");
6384 n++;
6385 printf(" locking shifts : %s\n", lscapu ? "yes" : "no");
6386 n++;
6387 }
6388 }
6389 if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
6390 if (streamed > 0)
6391 printf(" window slots used : (streaming)\n");
6392 else
6393 printf(" window slots used : %d of %d\n", wmax, wslotr);
6394 if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
6395 printf(" reliable: : %s%s\n",
6396 streamok ? "" : "not ", "negotiated");
6397 if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
6398 printf(" clearchannel: : %s%s\n",
6399 cleared ? "" : "not ", "negotiated");
6400 if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
6401
6402 if (!brief) {
6403 printf(" packet length : %d (send), %d (receive)\n",
6404 lastspmax, urpsiz);
6405 if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
6406 printf(" compression : ");
6407 if (rptflg)
6408 printf("yes [%c] (%ld)\n",(char) rptq,rptn);
6409 else
6410 printf("no\n");
6411 if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
6412 if (bctu == 4)
6413 printf(" block check type used : blank-free-2\n");
6414 else
6415 printf(" block check type used : %d\n",bctu);
6416 if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
6417 }
6418
6419 dotimes:
6420
6421 #ifdef GFTIMER
6422 #ifdef COMMENT
6423 printf(" elapsed time : %0.3f sec, %s\n", fptsecs,hhmmss(tsecs));
6424 #endif /* COMMENT */
6425 printf(" elapsed time : %s (%0.3f sec)\n",
6426 hhmmss((long)(fptsecs + 0.5)),fptsecs);
6427 #else
6428 #ifdef COMMENT
6429 printf(" elapsed time : %s (%d sec)\n",hhmmss(tsecs),tsecs);
6430 #endif /* COMMENT */
6431 printf(" elapsed time : %d sec, %s\n",tsecs,hhmmss(tsecs));
6432 #endif /* GFTIMER */
6433 if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
6434 if (!ftp && local && !network && !brief) {
6435 if (speed <= 0L) speed = ttgspd();
6436 if (speed > 0L) {
6437 if (speed == 8880)
6438 printf(" transmission rate : 75/1200 bps\n");
6439 else
6440 printf(" transmission rate : %ld bps\n",speed);
6441 if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
6442 }
6443 }
6444 if (!ftp && local && !network && /* Only makes sense for */
6445 mdmtyp == 0 && /* direct serial connections */
6446 speed > 99L && /* when we really know the speed */
6447 speed != 8880L
6448 ) {
6449 int eff;
6450 eff = (((tfcps * 100L) / (speed / 100L)) + 5L) / 10L;
6451 printf(" effective data rate : %ld cps (%d%%)\n",tfcps,eff);
6452 } else
6453 printf(" effective data rate : %ld cps\n", tfcps);
6454 if (!ftp && peakcps > 0L && peakcps > tfcps)
6455 printf(" peak data rate : %ld cps\n", peakcps);
6456 if (brief)
6457 printf("\nUse STATISTICS /VERBOSE for greater detail.\n\n");
6458 return(1);
6459 }
6460 #endif /* NOXFER */
6461
6462 #ifndef NOSPL
6463
6464 /* The INPUT command */
6465
6466 /*
6467 NOTE: An INPUT timeout of 0 means to perform a nonblocking read of the
6468 material that has already arrived and is waiting to be read, and perform
6469 matches against it, without doing any further reads. It should succeed
6470 or fail instantaneously.
6471 */
6472
6473 /* Output buffering for "doinput" */
6474
6475 #ifdef pdp11
6476 #define MAXBURST 16 /* Maximum size of input burst */
6477 #else
6478 #define MAXBURST 1024
6479 #endif /* pdp11 */
6480 #ifdef OSK
6481 static CHAR *conbuf; /* Buffer to hold output for console */
6482 #else
6483 static CHAR conbuf[MAXBURST]; /* Buffer to hold output for console */
6484 #endif /* OSK */
6485 static int concnt = 0; /* Number of characters buffered */
6486 #ifdef OSK
6487 static CHAR *sesbuf; /* Buffer to hold output for session log */
6488 #else
6489 static CHAR sesbuf[MAXBURST]; /* Buffer to hold output for session log */
6490 #endif /* OSK */
6491 static int sescnt = 0; /* Number of characters buffered */
6492
6493 extern int debses; /* TERMINAL DEBUG ON/OFF */
6494
6495 static VOID /* Flush INPUT echoing */
myflsh()6496 myflsh() { /* and session log output. */
6497 if (concnt > 0) {
6498 if (debses) { /* Terminal debugging? */
6499 int i;
6500 for (i = 0; i < concnt; i++)
6501 conol(dbchr(conbuf[i]));
6502 } else
6503 conxo(concnt, (char *) conbuf);
6504 concnt = 0;
6505 }
6506 if (sescnt > 0) {
6507 logstr((char *) sesbuf, sescnt);
6508 sescnt = 0;
6509 }
6510 }
6511
6512 /* Execute the INPUT and MINPUT commands */
6513
6514 int instatus = -1;
6515 long inetime = -1L;
6516 int inwait = 0;
6517 int nowrap = 0;
6518
6519 /* For returning the input sequence that matched */
6520
6521 #ifdef BIGBUFOK
6522 #define MATCHBUFSIZ 8191
6523 #else
6524 #define MATCHBUFSIZ 1023
6525 #endif /* BIGBUFOK */
6526 static char * matchbuf = NULL;
6527 static int matchindex = 0;
6528 static int burst = 0; /* Chars remaining in input burst */
6529 /*
6530 timo = How long to wait:
6531 < 0 = Wait forever
6532 0 = Don't wait at all - material must already have arrived
6533 > 0 = Wait this many seconds
6534 ms = Array of strings to wait for.
6535 mp = Array of flags.
6536 If mp[i] == 0, ms[i] is literal, else it's a pattern.
6537 flags = bit mask
6538 INPSW_NOM = /NOMATCH = 1
6539 INPSW_CLR = /CLEAR = 2
6540 INPSW_NOW = /NOWRAP = 4
6541 INPSW_COU = /COUNT = 8
6542 count = /COUNT: value if a /COUNT switch was given.
6543
6544 Returns:
6545 0 on failure, 1 on success.
6546 */
6547 #ifndef ES_NORMAL
6548 #define ES_NORMAL 0
6549 #endif /* ES_NORMAL */
6550 extern int inesc[], oldesc[];
6551
6552 int
doinput(timo,ms,mp,flags,count)6553 doinput(timo,ms,mp,flags,count)
6554 int timo; char *ms[]; int mp[]; int flags; int count; {
6555 extern int inintr;
6556 #ifdef CK_AUTODL
6557 extern int inautodl;
6558 #endif /* CK_AUTODL */
6559 int x, y, i, t, rt, icn, anychar = 0, mi[MINPMAX];
6560 #ifdef GFTIMER
6561 CKFLOAT fpt = 0.0;
6562 #endif /* GFTIMER */
6563 int savecount = 0;
6564 int nomatch = 0;
6565 int clearfirst = 0;
6566 int lastchar = 0;
6567 int waiting = 0;
6568 int imask = 0;
6569 char ch, *xp, *s;
6570 CHAR c;
6571 #ifndef NOLOCAL
6572 #ifdef OS2
6573 extern int term_io;
6574 int term_io_save;
6575 #endif /* OS2 */
6576 #endif /* NOLOCAL */
6577 #ifdef TNCODE
6578 static int cr = 0;
6579 #endif /* TNCODE */
6580 int is_tn = 0;
6581 #ifdef SSHBUILTIN
6582 extern int ssh_cas;
6583 extern char * ssh_cmd;
6584 #endif /* SSHBUILTIN */
6585 int noescseq = 0; /* Filter escape sequences */
6586
6587 debug(F101,"input count","",count);
6588 debug(F101,"input flags","",flags);
6589
6590 /*
6591 CK_BURST enables the INPUT speedup code, which depends on ttchk() returning
6592 accurate information. If INPUT fails with this code enabled, change the
6593 above "#define" to "#undef".
6594 */
6595 #define CK_BURST
6596
6597 /***** CHANGE THIS TO A SET INPUT PARAMETER *****/
6598
6599 noescseq = (sessft == XYFT_T); /* Filter escape sequences */
6600
6601 imask = cmask;
6602 if (parity) imask = 0x7f;
6603 inwait = timo; /* For \v(inwait) */
6604
6605 /* Options from command switches */
6606
6607 nowrap = flags & INPSW_NOW; /* 4 = /NOWRAP */
6608 nomatch = flags & INPSW_NOM; /* 1 = /NOMATCH */
6609 clearfirst = flags & INPSW_CLR; /* 2 = /CLEAR */
6610 savecount = count;
6611
6612 makestr(&inpmatch,NULL);
6613 if (!matchbuf) {
6614 matchbuf = malloc(MATCHBUFSIZ+1);
6615 matchbuf[0] = NUL;
6616 }
6617 matchindex = 0;
6618
6619 /* If last time through we returned because of /NOWRAP and buffer full */
6620 /* now we have to clear the buffer to make room for another load. */
6621
6622 if (nowrap && instatus == INP_BF)
6623 clearfirst = 1;
6624
6625 if (clearfirst) { /* INPUT /CLEAR */
6626 int i;
6627 myflsh(); /* Flush screen and log buffers */
6628 for (i = 0; i < inbufsize; i++)
6629 inpbuf[i] = NUL;
6630 inpbp = inpbuf;
6631 }
6632 is_tn =
6633 #ifdef TNCODE
6634 (local && network && IS_TELNET()) || (!local && sstelnet)
6635 #else
6636 0
6637 #endif /* TNCODE */
6638 ;
6639
6640 #ifdef CK_SSL
6641 if (is_tn) if (ssl_raw_flag || tls_raw_flag) is_tn = 0;
6642 #endif /* CK_SSL */
6643
6644 instatus = INP_IE; /* 3 = internal error */
6645 kbchar = 0;
6646
6647 #ifdef OSK
6648 if (conbuf == NULL) {
6649 if ((conbuf = (CHAR *)malloc(MAXBURST*2)) == NULL) {
6650 return(0);
6651 }
6652 sesbuf = conbuf + MAXBURST;
6653 }
6654 #endif /* OSK */
6655
6656 #ifndef NOLOCAL
6657 if (local) { /* In local mode... */
6658 if ((waiting = ttchk()) < 0) { /* check that connection is open */
6659 if (!quiet) {
6660 if ((!network
6661 #ifdef TN_COMPORT
6662 || istncomport()
6663 #endif /* TN_COMPORT */
6664 ) && carrier != CAR_OFF)
6665 printf("?Carrier detect failure on %s.\n", ttname);
6666 else
6667 printf("?Connection %s %s is not open.\n",
6668 network ? "to" : "on",
6669 ttname
6670 );
6671 }
6672 instatus = INP_IO;
6673 return(0);
6674 }
6675 debug(F101,"doinput waiting","",waiting);
6676 y = ttvt(speed,flow); /* Put line in "ttvt" mode */
6677 if (y < 0) {
6678 printf("?INPUT initialization error\n");
6679 instatus = INP_IO;
6680 return(0); /* Watch out for failure. */
6681 }
6682 }
6683 #endif /* NOLOCAL */
6684
6685 #ifdef SSHBUILTIN
6686 if ( network && nettype == NET_SSH && ssh_cas && ssh_cmd &&
6687 !(strcmp(ssh_cmd,"kermit") && strcmp(ssh_cmd,"sftp"))) {
6688 if (!quiet)
6689 printf("?SSH Subsystem active: %s\n", ssh_cmd);
6690 instatus = INP_IKS;
6691 return(0);
6692 }
6693 #endif /* SSHBUILTIN */
6694
6695 debug(F111,"doinput ms[0]",ms[0],waiting);
6696
6697 if (!ms[0] || isemptystring(ms[0])) { /* No search string was given nor */
6698 if (count < 2) /* a /COUNT: switch so we just */
6699 anychar = 1; /* wait for the first character */
6700 }
6701 if (nomatch) anychar = 0; /* Don't match anything */
6702
6703 if (!anychar && waiting == 0 && timo == 0)
6704 return(0);
6705
6706 #ifndef NODEBUG
6707 if (deblog) {
6708 char xbuf[100];
6709 debug(F101,"doinput anychar","",anychar);
6710 debug(F101,"doinput timo","",timo);
6711 debug(F101,"doinput echo","",inecho);
6712 #ifdef CK_BURST
6713 debug(F101,"doinput burst","",burst);
6714 #endif /* CK_BURST */
6715 y = -1;
6716 while (ms[++y]) {
6717 sprintf(xbuf,"doinput string %2d",y); /* SAFE (24) */
6718 debug(F111,xbuf,ms[y],mp[y]);
6719 }
6720 }
6721 #endif /* NODEBUG */
6722
6723 #ifdef IKS_OPTION
6724 if (is_tn) {
6725 /* If the remote side is in a state of IKS START-SERVER */
6726 /* we request that the state be changed. We will detect */
6727 /* a failure to adhere to the request when we call ttinc() */
6728 if (TELOPT_U(TELOPT_KERMIT) &&
6729 TELOPT_SB(TELOPT_KERMIT).kermit.u_start)
6730 iks_wait(KERMIT_REQ_STOP,0); /* Send Request-Stop */
6731 #ifdef CK_AUTODL
6732 /* If we are processing packets during INPUT and we have not */
6733 /* sent a START message, do so now. */
6734 if (inautodl && TELOPT_ME(TELOPT_KERMIT) &&
6735 !TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
6736 tn_siks(KERMIT_START); /* Send Kermit-Server Start */
6737 }
6738 #endif /* CK_AUTODL */
6739 }
6740 #endif /* IKS_OPTION */
6741 x = 0; /* Return code, assume failure */
6742 instatus = INP_TO; /* Status, assume timeout */
6743
6744 for (y = 0; y < MINPMAX; y++) /* Initialize... */
6745 mi[y] = 0; /* ..string pattern match position */
6746
6747 if (!inpcas[cmdlvl]) { /* INPUT CASE = IGNORE? */
6748 y = -1;
6749 while ((xp = ms[++y])) { /* Convert each target to lowercase */
6750 while (*xp) {
6751 if (isupper(*xp)) *xp = (char) tolower(*xp);
6752 xp++;
6753 }
6754 }
6755 }
6756 rtimer(); /* Reset timer. */
6757 #ifdef GFTIMER
6758 rftimer(); /* Floating-point timer too. */
6759 #endif /* GFTIMER */
6760 inetime = -1L; /* Initialize elapsed time. */
6761 t = 0; /* Time now is 0. */
6762 m_found = 0; /* Default to timed-out */
6763 incount = 0; /* Character counter */
6764 rt = (timo == 0) ? 0 : 1; /* Character-read timeout interval */
6765
6766 #ifndef NOLOCAL
6767 #ifdef OS2
6768 term_io_save = term_io; /* Disable I/O by emulator */
6769 term_io = 0;
6770 #endif /* OS2 */
6771 #endif /* NOLOCAL */
6772
6773 while (1) { /* Character-getting loop */
6774 #ifdef CK_APC
6775 /* Check to see if there is an Autodown or other APC command */
6776 if (apcactive == APC_LOCAL ||
6777 (apcactive == APC_REMOTE && apcstatus != APC_OFF)) {
6778 if (mlook(mactab,"_apc_commands",nmac) == -1) {
6779 debug(F110,"doinput about to execute APC",apcbuf,0);
6780 domac("_apc_commands",apcbuf,cmdstk[cmdlvl].ccflgs|CF_APC);
6781 delmac("_apc_commands",1);
6782 apcactive = APC_INACTIVE;
6783 #ifdef DEBUG
6784 } else {
6785 debug(F100,"doinput APC in progress","",0);
6786 #endif /* DEBUG */
6787 }
6788 }
6789 #endif /* CK_APC */
6790
6791 if (timo == 0 && waiting < 1) { /* Special exit criterion */
6792 instatus = INP_TO; /* for timeout == 0 */
6793 break;
6794 }
6795 if (local) { /* One case for local */
6796 y = ttinc(rt); /* Get character from comm device */
6797 debug(F101,"doinput ttinc(rt) returns","",y);
6798 if (y < -1) { /* Connection failed. */
6799 instatus = INP_IO; /* Status = i/o error */
6800 #ifndef NOLOCAL
6801 #ifdef OS2
6802 term_io = term_io_save;
6803 #endif /* OS2 */
6804 #endif /* NOLOCAL */
6805 switch (y) {
6806 case -2: /* Connection lost */
6807 if (local && !network && carrier != CAR_OFF) {
6808 dologend();
6809 printf("Connection closed.\n");
6810 ttclos(1);
6811 }
6812 break;
6813 case -3:
6814 dologend();
6815 printf("Session Limit exceeded - closing connection.\n");
6816 ttclos(1);
6817 default:
6818 break;
6819 }
6820 debug(F111,"doinput Connection failed","returning 0",y);
6821 return(0);
6822 }
6823 if (inintr) {
6824 debug(F111,"doinput","inintr",inintr);
6825 if ((icn = conchk()) > 0) { /* Interrupted from keyboard? */
6826 debug(F101,"input interrupted from keyboard","",icn);
6827 kbchar = coninc(0);
6828 if (kbchar >= 0) {
6829 while (--icn > 0) {
6830 debug(F110,"doinput","absorbing",0);
6831 coninc(0); /* Yes, absorb what was typed. */
6832 }
6833 instatus = INP_UI; /* Fail and remember why. */
6834 break;
6835 }
6836 }
6837 }
6838 } else { /* Another for remote */
6839 y = coninc(rt);
6840 debug(F101,"doinput coninc(rt) returns","",y);
6841 }
6842 if (y > -1) { /* A character arrived */
6843 debug(F111,"doinput","a character arrived",y);
6844 if (timo == 0)
6845 waiting--;
6846 #ifndef OS2
6847 #define TN_NOLO
6848 #endif /* OS2 */
6849 #ifdef NOLOCAL
6850 #define TN_NOLO
6851 #endif /* NOLOCAL */
6852
6853 #ifdef TN_NOLO
6854 debug(F100,"doinput TN_NOLO","",0);
6855 #ifdef TNCODE
6856 /* Check for telnet protocol negotiation */
6857 if (is_tn) {
6858 switch (y & 0xff) {
6859 case IAC:
6860 cr = 0;
6861 myflsh(); /* Break from input burst for tn_doop() */
6862 #ifdef CK_BURST
6863 burst = 0;
6864 #endif /* CK_BURST */
6865 waiting -= 2; /* (not necessarily...) */
6866 switch (tn_doop((CHAR)(y & 0xff),duplex,ttinc)) {
6867 case 2: duplex = 0; continue;
6868 case 1: duplex = 1; continue;
6869 #ifdef IKS_OPTION
6870 case 4:
6871 if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
6872 !tcp_incoming) {
6873 instatus = INP_IKS;
6874 printf(
6875 " Internet Kermit Service in SERVER mode.\n Please use REMOTE commands.\n"
6876 );
6877 break;
6878 }
6879 continue;
6880 #endif /* IKS_OPTION */
6881 case 6: /* TELNET DO LOGOUT received */
6882 continue;
6883 case 7:
6884 case 3: /* A quoted IAC */
6885 break;
6886 default:
6887 continue;
6888 }
6889 case CR:
6890 cr = 1;
6891 break;
6892 case NUL:
6893 if (!TELOPT_U(TELOPT_BINARY) && cr) {
6894 cr = 0;
6895 continue;
6896 }
6897 cr = 0;
6898 break;
6899 default:
6900 cr = 0;
6901 }
6902 /* I'm echoing remote chars */
6903 if (TELOPT_ME(TELOPT_ECHO) && tn_rem_echo)
6904 ttoc((char)y);
6905 }
6906 #endif /* TNCODE */
6907 #ifdef CK_AUTODL
6908 /* Check for file transfer packets */
6909 if (inautodl) autodown(y);
6910 #endif /* CK_AUTODL */
6911 #else /* TN_NOLO */
6912 debug(F100,"doinput !TN_NOLO","",0);
6913 #ifdef TNCODE
6914 /* Check for telnet protocol negotiation */
6915 if (is_tn) {
6916 int tx;
6917 switch (y & 0xff) {
6918 case IAC:
6919 myflsh(); /* Break from input burst for tn_doop() */
6920 #ifdef CK_BURST
6921 burst = 0;
6922 #endif /* CK_BURST */
6923 #ifdef IKS_OPTION
6924 tx = scriptwrtbuf((USHORT)y);
6925 if (tx == 4) {
6926 if (TELOPT_U(TELOPT_KERMIT) &&
6927 TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
6928 !tcp_incoming
6929 ) {
6930 instatus = INP_IKS;
6931 printf(
6932 " Internet Kermit Service in SERVER mode.\n Please use REMOTE commands.\n"
6933 );
6934 break;
6935 }
6936 } else if (tx == 6) {
6937 /* TELNET DO LOGOUT received */
6938
6939 }
6940 #else /* IKS_OPTION */
6941 /* Handles Telnet negotiations */
6942 tx = scriptwrtbuf((USHORT)y);
6943 if (tx == 6) {
6944 /* TELNET DO LOGOUT received */
6945 }
6946 #endif /* IKS_OPTION */
6947 waiting -= 2; /* (not necessarily...) */
6948 cr = 0;
6949 continue; /* and autodownload check */
6950 case CR:
6951 cr = 1;
6952 tx = scriptwrtbuf((USHORT)y);
6953 if (tx == 6) {
6954 /* TELNET DO LOGOUT received */
6955 }
6956 break;
6957 case NUL:
6958 cr = 0;
6959 if (!TELOPT_U(TELOPT_BINARY) && cr)
6960 continue;
6961 tx = scriptwrtbuf((USHORT)y);
6962 if (tx == 6) {
6963 /* TELNET DO LOGOUT received */
6964 }
6965 break;
6966 default:
6967 cr = 0;
6968 tx = scriptwrtbuf((USHORT)y);
6969 if (tx == 6) {
6970 /* TELNET DO LOGOUT received */
6971 }
6972 }
6973 /* I'm echoing remote chars */
6974 if (TELOPT_ME(TELOPT_ECHO) && tn_rem_echo)
6975 ttoc((CHAR)y);
6976 } else
6977 #endif /* TNCODE */
6978 /* Handles terminal emulation responses */
6979 scriptwrtbuf((USHORT)y);
6980 #endif /* TN_NOLO */
6981
6982 /* Real input character to be checked */
6983
6984 #ifdef CK_BURST
6985 burst--; /* One less character waiting */
6986 debug(F101,"doinput burst","",burst);
6987 #endif /* CK_BURST */
6988 c = (CHAR) (imask & (CHAR) y); /* Mask off any parity */
6989 inchar[0] = c; /* Remember character for \v(inchar) */
6990 #ifdef COMMENT
6991 #ifdef CK_BURST
6992 /* Update "lastchar" time only once during input burst */
6993 if (burst <= 0)
6994 #endif /* CK_BURST */
6995 #endif /* COMMENT */
6996 lastchar = gtimer(); /* Remember when it came */
6997
6998 if (c == '\0') { /* NUL, we can't use it */
6999 if (anychar) { /* Except if any character will do? */
7000 x = 1; /* Yes, done. */
7001 instatus = INP_OK;
7002 incount = 1; /* This must be the first and only. */
7003 break;
7004 } else goto refill; /* Otherwise continue INPUTting */
7005 }
7006 *inpbp++ = c; /* Store char in circular buffer */
7007 incount++; /* Count it for \v(incount) */
7008
7009 if (flags & INPSW_COU) { /* INPUT /COUNT */
7010 if (--count < 1) {
7011 x = 1;
7012 instatus = INP_OK;
7013 incount = savecount;
7014 break;
7015 }
7016 }
7017 if (matchbuf) {
7018 if (matchindex < MATCHBUFSIZ) {
7019 matchbuf[matchindex++] = c;
7020 matchbuf[matchindex] = NUL;
7021 }
7022 }
7023 #ifdef MAC
7024 {
7025 extern char *ttermw; /* fake pointer cast */
7026 if (inecho) {
7027 outchar(ttermw, c); /* echo to terminal window */
7028 /* this might be too much overhead to do here ? */
7029 updatecommand(ttermw);
7030 }
7031 }
7032 #else /* Not MAC */
7033 if (inecho) { /* Buffer console output */
7034 conbuf[concnt++] = c;
7035 }
7036 #endif /* MAC */
7037 #ifndef OS2
7038 if (seslog) {
7039 int dummy = 0, skip = 0;
7040 #ifndef NOLOCAL
7041 if (noescseq) {
7042 dummy = chkaes(c,0);
7043 if (inesc[0] != ES_NORMAL || oldesc[0] != ES_NORMAL)
7044 skip = 1;
7045 }
7046 #endif /* NOLOCAL */
7047 #ifdef UNIXOROSK
7048 if (sessft == XYFT_T) {
7049 #ifdef UNIX
7050 if (c == '\r')
7051 #else
7052 #ifdef OSK
7053 if (c == '\012')
7054 #endif /* OSK */
7055 #endif /* UNIX */
7056 skip = 1;
7057 }
7058 #endif /* UNIXOROSK */
7059 if (!skip)
7060 sesbuf[sescnt++] = c; /* Buffer session log output */
7061 }
7062 #endif /* OS2 */
7063 if (anychar) { /* Any character will do? */
7064 x = 1;
7065 instatus = INP_OK;
7066 break;
7067 }
7068 if (!inpcas[cmdlvl]) { /* Ignore alphabetic case? */
7069 if (isupper(c)) /* Yes, convert input char to lower */
7070 c = (CHAR) tolower(c);
7071 }
7072 debug(F000,"doinput char","",c);
7073
7074 /* Here is the matching section */
7075
7076 y = -1; /* Loop thru search strings */
7077 while (!nomatch && (s = ms[++y])) { /* ...as many as we have. */
7078 if (mp[y]) { /* Pattern match? */
7079 #ifdef COMMENT
7080 int j;
7081 /* This is gross but it works... */
7082 /* We could just as easily have prepended '*' to the */
7083 /* pattern and skipped the loop, except then we would */
7084 /* not have any way to identify the matching string. */
7085 for (j = 0; j < matchindex; j++) {
7086 if (ckmatch(s,&matchbuf[j],1,1)) {
7087 matchindex = j;
7088 instatus = INP_OK;
7089 x = 1;
7090 break;
7091 }
7092 }
7093 if (x > 0)
7094 break;
7095 #else
7096 /* July 2001 - ckmatch() returns match position. */
7097 /* It works and it's not gross. */
7098 /* (4 = floating pattern) */
7099 x = ckmatch(s,matchbuf,inpcas[cmdlvl],1+4);
7100 if (x > 0) {
7101 matchindex = x - 1;
7102 instatus = INP_OK;
7103 x = 1;
7104 break;
7105 }
7106 #endif /* COMMENT */
7107 continue;
7108 } /* Literal match. */
7109 i = mi[y]; /* Match-position in search string. */
7110 debug(F000,"compare char","",(CHAR)s[i]);
7111 if (c == (CHAR) s[i]) { /* Check for match */
7112 i++; /* Got one, go to next character */
7113 } else { /* Don't have a match */
7114 int j;
7115 for (j = i; i > 0; ) { /* Back up in search string */
7116 i--; /* (Do this here to prevent compiler foulup) */
7117 /* j is the length of the substring that matched */
7118 if (c == (CHAR) s[i]) {
7119 if (!strncmp(s,&s[j-i],i)) {
7120 i++; /* c actually matches -- cfk */
7121 break;
7122 }
7123 }
7124 }
7125 }
7126 if ((CHAR) s[i] == (CHAR) '\0') { /* Matched to end? */
7127 ckstrncpy(matchbuf,ms[y],MATCHBUFSIZ);
7128 matchindex = 0;
7129 instatus = INP_OK; /* Yes, */
7130 x = 1;
7131 break; /* done. */
7132 }
7133 mi[y] = i; /* No, remember match-position */
7134 }
7135 if (x == 1) { /* Set \v(minput) result */
7136 instatus = INP_OK;
7137 m_found = y + 1;
7138 break;
7139 }
7140 if (inpbp >= inpbuf + inbufsize) { /* Reached end of buffer? */
7141 if (nowrap) { /* If /NOWRAP...*/
7142 instatus = INP_BF; /* ...return indicating buffer full. */
7143 *inpbp = NUL;
7144 goto xinput;
7145 }
7146 *inpbp = NUL; /* Make it null-terminated */
7147 inpbp = inpbuf; /* Yes. */
7148 }
7149 }
7150 #ifdef CK_BURST
7151 else if (y <= -1 && burst > 0) {
7152 debug(F111,"doinput (y<=-1&&burst>0)","burst",burst);
7153 /* A timeout occurred so there can't */
7154 burst = 0; /* be data waiting; must check timo */
7155 }
7156 refill:
7157 if (burst <= 0) { /* No buffered chars remaining... */
7158 myflsh(); /* Flush buffered output */
7159 if (local) { /* Get size of next input burst */
7160 burst = ttchk();
7161 if (burst < 0) { /* ttchk() says connection is closed */
7162 instatus = INP_IO; /* Status = i/o error */
7163 #ifndef NOLOCAL
7164 #ifdef OS2
7165 term_io = term_io_save;
7166 #endif /* OS2 */
7167 #endif /* NOLOCAL */
7168
7169 if ((!network
7170 #ifdef TN_COMPORT
7171 || istncomport()
7172 #endif /* TN_COMPORT */
7173 ) && carrier != CAR_OFF) {
7174 /* The test is written this way because the Microsoft compiler
7175 * is producing bad code if written:
7176 *
7177 * if (network && (!istncomport() || carrier == CAR_OFF) )
7178 */
7179 break;
7180 } else {
7181 printf("Fatal error - disconnected.\n");
7182 ttclos(1);
7183 break;
7184 }
7185 }
7186 if (inintr) {
7187 if ((icn = conchk()) > 0) { /* Interrupt from keyboard? */
7188 kbchar = coninc(0);
7189 debug(F101,"input interrupted from keyboard","",icn);
7190 while (--icn > 0) coninc(0); /* Yes, absorb chars. */
7191 break; /* And fail. */
7192 }
7193 }
7194 } else {
7195 burst = conchk();
7196 }
7197 debug(F101,"doinput burst","",burst);
7198 /* Prevent overflow of "conbuf" and "sesbuf" */
7199 if (burst > MAXBURST)
7200 burst = MAXBURST;
7201
7202 /* Did not match, timer exceeded? */
7203 t = gtimer();
7204 debug(F111,"doinput gtimer","burst",t);
7205 debug(F101,"doinput timo","",timo);
7206 if ((t >= timo) && (timo > 0))
7207 break;
7208 else if (insilence > 0 && (t - lastchar) > insilence)
7209 break;
7210 } else {
7211 debug(F111,"doinput (burst > 0)","burst",burst);
7212 }
7213 #else /* CK_BURST */
7214 refill:
7215 myflsh(); /* Flush buffered output */
7216 /* Did not match, timer exceeded? */
7217 t = gtimer();
7218 debug(F111,"doinput gtimer","no burst",t);
7219 debug(F101,"doinput timo","",timo);
7220 if ((t >= timo) && (timo > -1))
7221 break;
7222 else if (insilence > 0 && (t - lastchar) > insilence)
7223 break;
7224 #endif /* CK_BURST */
7225 } /* Still have time left, continue. */
7226 xinput:
7227 myflsh(); /* Flush buffered output */
7228 if (instatus == INP_BF) { /* Buffer full and /NOWAIT */
7229 x = 0; /* Must not succeed */
7230 } else { /* Buffer full and /NOWAIT */
7231 if (nomatch) x = 1; /* Succeed if nomatch and timed out */
7232 if (x > 0 && !nomatch)
7233 instatus = 0;
7234 }
7235 #ifndef NOLOCAL
7236 #ifdef OS2
7237 term_io = term_io_save;
7238 #endif /* OS2 */
7239 #endif /* NOLOCAL */
7240 #ifdef COMMENT
7241 #ifdef IKS_OPTION
7242 #ifdef CK_AUTODL
7243 if (is_tn && TELOPT_ME(TELOPT_KERMIT) && inautodl) {
7244 tn_siks(KERMIT_STOP); /* Send Kermit-Server Stop */
7245 }
7246 #endif /* CK_AUTODL */
7247 #endif /* IKS_OPTION */
7248 #endif /* COMMENT */
7249
7250 #ifdef GFTIMER
7251 fpt = gftimer(); /* Get elapsed time */
7252
7253 /* If a long is 32 bits, it would take about 50 days for this to overflow. */
7254
7255 inetime = (int)(fpt * (CKFLOAT)1000.0);
7256 #else
7257 inetime = (int)(gtimer() * 1000);
7258 #endif /* GFTIMER */
7259
7260 if (x > 0)
7261 makestr(&inpmatch,&matchbuf[matchindex]); /* \v(inmatch) */
7262 return(x); /* Return the return code. */
7263 }
7264 #endif /* NOSPL */
7265
7266 #ifndef NOSPL
7267 /* REINPUT Command */
7268
7269 /*
7270 Note, the timeout parameter is required, but ignored. Syntax is compatible
7271 with MS-DOS Kermit except timeout can't be omitted. This function only
7272 looks at the characters already received and does not read any new
7273 characters from the connection.
7274 */
7275 int
doreinp(timo,s,pat)7276 doreinp(timo,s,pat) int timo; char *s; int pat; {
7277 int x, y, i;
7278 char *xx, *xp, *xq = (char *)0;
7279 CHAR c;
7280
7281 if (!s) s = "";
7282 debug(F101,"doreinput pat","",pat);
7283
7284 y = (int)strlen(s);
7285 debug(F111,"doreinput search",s,y);
7286
7287 if (y > inbufsize) { /* If search string longer than */
7288 debug(F101,"doreinput inbufsize","",inbufsize);
7289 return(0); /* input buffer, fail. */
7290 }
7291 makestr(&inpmatch,NULL);
7292 if (!matchbuf)
7293 matchbuf = malloc(MATCHBUFSIZ+1);
7294 matchindex = 0;
7295
7296 x = 0; /* Return code, assume failure */
7297 i = 0; /* String pattern match position */
7298
7299 if (!inpcas[cmdlvl]) { /* INPUT CASE = IGNORE? */
7300 xp = malloc(y+2); /* Make a separate copy of the */
7301 if (!xp) { /* search string. */
7302 printf("?malloc error 6\n");
7303 return(x);
7304 } else xq = xp; /* Keep pointer to beginning. */
7305 while (*s) { /* Yes, convert to lowercase */
7306 *xp = *s;
7307 if (isupper(*xp)) *xp = (char) tolower(*xp);
7308 xp++; s++;
7309 }
7310 *xp = NUL; /* Terminate it! */
7311 s = xq; /* Move search pointer to it. */
7312 }
7313 xx = *inpbp ? inpbp : inpbuf; /* Current INPUT buffer pointer */
7314 do {
7315 c = *xx++; /* Get next character */
7316 if (!c) break;
7317 if (xx >= inpbuf + inbufsize) /* Wrap around if necessary */
7318 xx = inpbuf;
7319 if (!inpcas[cmdlvl]) { /* Ignore alphabetic case? */
7320 if (isupper(c)) c = (CHAR) tolower(c); /* Yes */
7321 }
7322 if (pat) {
7323 int j;
7324 if (matchbuf) {
7325 if (matchindex < MATCHBUFSIZ) {
7326 matchbuf[matchindex++] = c;
7327 matchbuf[matchindex] = NUL;
7328 }
7329 for (j = 0; j < matchindex; j++) { /* Gross but effective */
7330 if (ckmatch(s,&matchbuf[j],1,1)) {
7331 debug(F101,"GOT IT","",j);
7332 matchindex = j;
7333 x = 1;
7334 break;
7335 }
7336 }
7337 }
7338 if (x > 0)
7339 break;
7340 continue;
7341 }
7342 debug(F000,"doreinp char","",c);
7343 debug(F000,"compare char","",(CHAR) s[i]);
7344 if (((char) c) == ((char) s[i])) { /* Check for match */
7345 i++; /* Got one, go to next character */
7346 } else { /* Don't have a match */
7347 int j;
7348 for (j = i; i > 0; ) { /* [jrs] search backwards for it */
7349 i--;
7350 if (((char) c) == ((char) s[i])) {
7351 if (!strncmp(s,&s[j-i],i)) {
7352 i++;
7353 break;
7354 }
7355 }
7356 }
7357 } /* [jrs] or return to zero from -1 */
7358 if (s[i] == '\0') { /* Matched all the way to end? */
7359 ckstrncpy(matchbuf,s,MATCHBUFSIZ);
7360 matchindex = 0;
7361 x = 1; /* Yes, */
7362 break; /* done. */
7363 }
7364 } while (xx != inpbp && x < 1); /* Until back where we started. */
7365
7366 if (!inpcas[cmdlvl]) if (xq) free(xq); /* Free this if it was malloc'd. */
7367 makestr(&inpmatch,&matchbuf[matchindex]); /* \v(inmatch) */
7368 return(x); /* Return search result. */
7369 }
7370
7371 /* X X S T R I N G -- Interpret strings containing backslash escapes */
7372 /* Z Z S T R I N G -- (new name...) */
7373 /*
7374 Copies result to new string.
7375 strips enclosing braces or doublequotes.
7376 interprets backslash escapes.
7377 returns 0 on success, nonzero on failure.
7378 tries to be compatible with MS-DOS Kermit.
7379
7380 Syntax of input string:
7381 string = chars | "chars" | {chars}
7382 chars = (c*e*)*
7383 where c = any printable character, ascii 32-126
7384 and e = a backslash escape
7385 and * means 0 or more repetitions of preceding quantity
7386 backslash escape = \operand
7387 operand = {number} | number | fname(operand) | v(name) | $(name) | m(name)
7388 number = [r]n[n[n]]], i.e. an optional radix code followed by 1-3 digits
7389 radix code is oO (octal), xX (hex), dD or none (decimal) (see xxesc()).
7390 */
7391
7392 #ifndef NOFRILLS
7393 int
yystring(s,s2)7394 yystring(s,s2) char *s; char **s2; { /* Reverse a string */
7395 int x;
7396 static char *new;
7397 new = *s2;
7398 if (!s || !new) return(-1); /* Watch out for null pointers. */
7399 if ((x = (int)strlen(s)) == 0) { /* Recursion done. */
7400 *new = '\0';
7401 return(0);
7402 }
7403 x--; /* Otherwise, call self */
7404 *new++ = s[x]; /* to reverse rest of string. */
7405 s[x] = 0;
7406 return(yystring(s,&new));
7407 }
7408 #endif /* NOFRILLS */
7409
7410 static char ipabuf[16] = { NUL }; /* IP address buffer */
7411
7412 static char *
getip(s)7413 getip(s) char *s; {
7414 char c=NUL; /* Workers... */
7415 int i=0, p=0, d=0;
7416 int state = 0; /* State of 2-state FSA */
7417
7418 while ((c = *s++)) {
7419 switch(state) {
7420 case 0: /* Find first digit */
7421 i = 0; /* Output buffer index */
7422 ipabuf[i] = NUL; /* Initialize output buffer */
7423 p = 0; /* Period counter */
7424 d = 0; /* Digit counter */
7425 if (isdigit(c)) { /* Have first digit */
7426 d = 1; /* Count it */
7427 ipabuf[i++] = c; /* Copy it */
7428 state = 1; /* Change state */
7429 }
7430 break;
7431
7432 case 1: /* In numeric field */
7433 if (isdigit(c)) { /* Have digit */
7434 if (++d > 3) /* Too many */
7435 state = 0; /* Start over */
7436 else /* Not too many */
7437 ipabuf[i++] = c; /* Keep it */
7438 } else if (c == '.' && p < 3) { /* Have a period */
7439 p++; /* Count it */
7440 if (d == 0) /* Not preceded by a digit */
7441 state = 0; /* Start over */
7442 else /* OK */
7443 ipabuf[i++] = c; /* Keep it */
7444 d = 0; /* Reset digit counter */
7445 } else if (p == 3 && d > 0) { /* Not part of address */
7446 ipabuf[i] = NUL; /* If we have full IP address */
7447 return((char *)ipabuf); /* Return it */
7448 } else { /* Otherwise */
7449 state = 0; /* Start over */
7450 ipabuf[0] = NUL; /* (in case no more chars left) */
7451 }
7452 }
7453 } /* Fall thru at end of string */
7454 ipabuf[i] = NUL; /* Maybe we have one */
7455 return((p == 3 && d > 0) ? (char *)ipabuf : "");
7456 }
7457 #endif /* NOSPL */
7458
7459 /* Date Routines */
7460
7461 /* Z J D A T E -- Convert yyyymmdd date to Day of Year */
7462
7463 static int jdays[12] = { 0,31,59,90,120,151,181,212,243,273,304,334 };
7464 static int ldays[12] = { 0,31,60,91,121,152,182,213,244,274,305,335 };
7465 static char zjdbuf[12] = { NUL, NUL };
7466 /*
7467 Deinde, ne in posterum a XII kalendas aprilis aequinoctium recedat,
7468 statuimus bissextum quarto quoque anno (uti mos est) continuari debere,
7469 praeterquam in centesimis annis; qui, quamvis bissextiles antea semper
7470 fuerint, qualem etiam esse volumus annum MDC, post eum tamen qui deinceps
7471 consequentur centesimi non omnes bissextiles sint, sed in quadringentis
7472 quibusque annis primi quique tres centesimi sine bissexto transigantur,
7473 quartus vero quisque centesimus bissextilis sit, ita ut annus MDCC, MDCCC,
7474 MDCCCC bissextiles non sint. Anno vero MM, more consueto dies bissextus
7475 intercaletur, februario dies XXIX continente, idemque ordo intermittendi
7476 intercalandique bissextum diem in quadringentis quibusque annis perpetuo
7477 conservetur. - Gregorius XIII, Anno Domini MDLXXXII.
7478 */
7479 char *
zjdate(date)7480 zjdate(date) char * date; { /* date = yyyymmdd */
7481 char year[5];
7482 char month[3];
7483 char day[3];
7484 int d, m, x, y;
7485 int leapday, j;
7486 char * time = NULL;
7487
7488 if (!date) date = ""; /* Validate arg */
7489 x = strlen(date);
7490 if (x < 1) return("0");
7491 if (x < 8) return("-1");
7492 for (x = 0; x < 8; x++)
7493 if (!isdigit(date[x]))
7494 return("-1");
7495
7496 if (date[8]) if (date[9])
7497 time = date + 9;
7498
7499 year[0] = date[0]; /* Isolate year */
7500 year[1] = date[1];
7501 year[2] = date[2];
7502 year[3] = date[3];
7503 year[4] = '\0';
7504
7505 month[0] = date[4]; /* Month */
7506 month[1] = date[5];
7507 month[2] = '\0';;
7508
7509 day[0] = date[6]; /* And day */
7510 day[1] = date[7];
7511 day[2] = '\0';
7512
7513 leapday = 0; /* Assume no leap day */
7514 y = atoi(year);
7515 m = atoi(month);
7516 d = atoi(day);
7517 if (m > 2) { /* No Leap day before March */
7518 if (y % 4 == 0) { /* If year is divisible by 4 */
7519 leapday = 1; /* It's a Leap year */
7520 if (y % 100 == 0) { /* Except if divisible by 100 */
7521 if (y % 400 != 0) /* but not by 400 */
7522 leapday = 0;
7523 }
7524 }
7525 }
7526 j = jdays[m - 1] + d + leapday; /* Day of year */
7527 if (time)
7528 sprintf(zjdbuf,"%04d%03d %s",y,j,time); /* SAFE */
7529 else
7530 sprintf(zjdbuf,"%04d%03d",y,j); /* SAFE */
7531 return((char *)zjdbuf);
7532 }
7533
7534 static char jzdbuf[32];
7535
7536 /* J Z D A T E -- Convert Day of Year to yyyyddmm date */
7537
7538 char *
jzdate(date)7539 jzdate(date) char * date; { /* date = yyyyddd */
7540 char year[5]; /* with optional time */
7541 char day[4];
7542 char * time = NULL, * p;
7543 int d, m, x, y;
7544 int leapday, j;
7545 int * zz;
7546
7547 if (!date) date = ""; /* Validate arg */
7548 x = strlen(date);
7549
7550 debug(F111,"jzdate len",date,x);
7551
7552 if (x < 1) return("0");
7553 if (x < 7) return("-1");
7554 if (x > 8) time = date + 8;
7555
7556 for (x = 0; x < 7; x++)
7557 if (!isdigit(date[x]))
7558 return("-1");
7559
7560 year[0] = date[0]; /* Isolate year */
7561 year[1] = date[1];
7562 year[2] = date[2];
7563 year[3] = date[3];
7564 year[4] = '\0';
7565
7566 debug(F110,"jzdate year",year,0);
7567
7568 day[0] = date[4]; /* And day */
7569 day[1] = date[5];
7570 day[2] = date[6];
7571 day[3] = '\0';
7572
7573 debug(F110,"jzdate day",day,0);
7574
7575 j = atoi(day);
7576 if (j > 366)
7577 return("-1");
7578
7579 leapday = 0; /* Assume no leap day */
7580 y = atoi(year);
7581 if (y % 4 == 0) { /* If year is divisible by 4 */
7582 leapday = 1; /* It's a Leap year */
7583 if (y % 100 == 0) { /* Except if divisible by 100 */
7584 if (y % 400 != 0) /* but not by 400 */
7585 leapday = 0;
7586 }
7587 }
7588 debug(F101,"jzdate leapday","",leapday);
7589 zz = leapday ? ldays : jdays;
7590
7591 for (x = 0; x < 11; x++)
7592 if (j > zz[x] && j <= zz[x+1])
7593 break;
7594 m = x + 1;
7595
7596 debug(F101,"jzdate m","",m);
7597
7598 d = j - zz[x];
7599
7600 debug(F101,"jzdate d","",d);
7601
7602 if (time)
7603 sprintf(jzdbuf,"%04d%02d%02d %s",y,m,d,time); /* SAFE */
7604 else
7605 sprintf(jzdbuf,"%04d%02d%02d",y,m,d); /* SAFE */
7606
7607 debug(F101,"jzdate jzdbuf",jzdbuf,0);
7608
7609 p = ckcvtdate((char *)jzdbuf, 0); /* Convert to standard form */
7610 ckstrncpy(jzdbuf,p,32);
7611 if (!time) jzdbuf[8] = NUL; /* Remove time if not wanted */
7612 return((char *)jzdbuf);
7613 }
7614
7615 /* M J D -- Modified Julian Date */
7616 /*
7617 Call with:
7618 Standard-format date-time string: yyyymmdd[ hh:mm:ss].
7619 The time, if any, is ignored.
7620
7621 Returns:
7622 -1L on error, otherwise:
7623 The number of days since 17 Nov 1858 as a whole number:
7624 16 Nov 1858 = -1, 17 Nov 1858 = 0, 18 Nov 1858 = 1, 19 Nov 1858 = 2, ...
7625
7626 The Modified Julian Date is defined by the International Astronomical
7627 Union as the true Julian date minus 2400000.5 days. The true Julian
7628 date is the number days since since noon of 1 January 4713 BCE of the
7629 Julian proleptic calendar. Conversions between calendar dates and
7630 Julian dates, however, assume Gregorian dating. The day of the week
7631 is MJD mod 7: 0=We, 1=Th, 2=Fr, 3=Sa, 4=Su, 5=Mo, 6=Tu.
7632 */
7633 long
mjd(date)7634 mjd(date) char * date; {
7635 char year[5];
7636 char month[3];
7637 char day[3];
7638 int x, a, d, m, y;
7639 long z;
7640
7641 if (!date) date = ""; /* Validate arg */
7642 x = strlen(date);
7643 if (x < 1) return(0L);
7644 if (x < 8) return(-1L);
7645 for (x = 0; x < 8; x++)
7646 if (!isdigit(date[x]))
7647 return(-1L);
7648
7649 year[0] = date[0]; /* Isolate year */
7650 year[1] = date[1];
7651 year[2] = date[2];
7652 year[3] = date[3];
7653 year[4] = '\0';
7654
7655 month[0] = date[4]; /* Month */
7656 month[1] = date[5];
7657 month[2] = '\0';;
7658 m = atoi(month);
7659
7660 day[0] = date[6]; /* And day */
7661 day[1] = date[7];
7662 day[2] = '\0';
7663 d = atoi(day);
7664
7665 a = (14-m)/12; /* Calculate true Julian date */
7666 y = atoi(year) + 4800 - a;
7667 m = m + 12 * a - 3;
7668 z = d + (long)(306*m+5)/10 + (long)(y*365) + y/4 - y/100 + y/400 - 32045L;
7669
7670 z -= 2400001L; /* Convert JD to MJD */
7671
7672 return(z);
7673 }
7674
7675 static char mjd2dbuf[32];
7676
7677 /* M J D 2 D A T E -- Converts MJD to yyyymmdd */
7678
7679 char *
7680 #ifdef CK_ANSIC
mjd2date(long mjd)7681 mjd2date(long mjd)
7682 #else
7683 mjd2date(mjd) long mjd;
7684 #endif /* CK_ANSIC */
7685 /* mjd2date */ {
7686 long jd, l, n;
7687 int d, m, y;
7688 jd = (long)(mjd + 2400001L);
7689 l = jd + 68569;
7690 n = 4 * l / 146097L;
7691 l = l - (146097 * n + 3) / 4;
7692 y = 4000 * (l + 1) / 1461001L;
7693 l = l - 1461 * y / 4 + 31;
7694 m = 80 * l / 2447;
7695 d = l - 2447 * m / 80;
7696 l = m / 11;
7697 m = m + 2 - 12 * l;
7698 y = 100 * (n - 49) + y + l;
7699 sprintf(mjd2dbuf,"%04d%02d%02d",y,m,d); /* SAFE */
7700 return((char *)mjd2dbuf);
7701 }
7702
7703 #ifndef NOSPL
7704 static char ** flist = (char **) NULL; /* File list for \fnextfile() */
7705 static int flistn = 0; /* Number of items in file list */
7706
7707 /*
7708 The function return-value buffer must be global, since fneval() returns a
7709 pointer to it. fneval() is called only by zzstring(), which always copies
7710 the result out of this buffer to somewhere else, so it's OK to have only
7711 one buffer for this in most cases. However, since function calls can be
7712 nested -- e.g. functions whose arguments are functions, or recursive
7713 functions, at some point we should convert this to an array of buffers,
7714 indexed by function depth (which might or might not be the same as the
7715 "depth" variable). Also, since function results are potentially quite big,
7716 we'd need to allocate and deallocate dynamically as we descend and ascend
7717 function depth. Left for a future release...
7718 */
7719 char fnval[FNVALL+2]; /* Function return value */
7720 static int fndepth = 0; /* (we don't actually use this yet) */
7721 int fnsuccess = 1;
7722 extern int fnerror;
7723
7724 /* f p f o r m a t -- Floating-point number nicely formatted. */
7725 /*
7726 Returns results from a circular 1K buffer.
7727 Don't count on too many results remaining available at once; it could
7728 be anywhere from 5 to maybe 100, depending on the sizes of the results.
7729 */
7730 #ifdef CKFLOAT
7731 #define FPFMTSIZ 1024
7732 static char fpfmtbuf[FPFMTSIZ] = { NUL, NUL };
7733 static int fpfbufpos = 0; /* (why was this char before?) */
7734
7735 char *
fpformat(fpresult,places,round)7736 fpformat(fpresult,places,round) CKFLOAT fpresult; int places, round; {
7737 char fbuf[16]; /* For creating printf format */
7738 int nines = 0, sign = 0, x, y, i, j, size = 0;
7739 char * buf;
7740 CKFLOAT ftmp;
7741
7742 x = places ? places : (fp_digits ? fp_digits : 6);
7743
7744 debug(F101,"fpformat fpresult","",fpresult);
7745 debug(F101,"fpformat places","",places);
7746 debug(F101,"fpformat fpfbufpos 1","",fpfbufpos);
7747
7748 ftmp = fpresult;
7749 if (ftmp < 0.0) ftmp = 0.0 - fpresult;
7750
7751 #ifdef FNFLOAT
7752 if (!fp_rounding && /* If printf doesn't round, */
7753 (places > 0 || /* round result to decimal places. */
7754 (places == 0 && round)))
7755 fpresult += (0.5 / pow(10.0,(CKFLOAT)places));
7756 y = (ftmp == 0.0) ? 1 : (int)log10(ftmp);
7757 size = y + x + 3; /* Estimated length of result */
7758 if (fpresult < 0.0) size++;
7759 #else
7760 size = 200; /* No way to estimate, be generous */
7761 #endif /* FNFLOAT */
7762
7763 debug(F101,"fpformat size","",size);
7764
7765 if (fpfbufpos > (FPFMTSIZ - size)) /* Wrap around if necessary */
7766 fpfbufpos = 0;
7767 debug(F101,"fpformat fpfbufpos 1","",fpfbufpos);
7768
7769 buf = &fpfmtbuf[fpfbufpos];
7770
7771 if (places > 0) { /* If places specified */
7772 /* use specified places to write given number of digits */
7773 sprintf(fbuf,"%%0.%df",places); /* SAFE */
7774 sprintf(buf,fbuf,fpresult); /* SAFE */
7775 } else { /* Otherwise... */
7776 /* Go for max precision */
7777 sprintf(fbuf,"%%0.%df",fp_digits); /* SAFE */
7778 sprintf(buf,fbuf,fpresult); /* SAFE */
7779 }
7780 if (buf[0] == '-') sign = 1;
7781 debug(F111,"fpresult 1 errno",buf,errno); /* Check for over/underflow */
7782 debug(F111,"fpresult 1 fpfbufpos",buf,fpfbufpos);
7783 /* Give requested decimal places */
7784 for (i = sign; i < FPFMTSIZ && buf[i]; i++) {
7785 if (buf[i] == '.') /* First find the decimal point */
7786 break;
7787 else if (i > fp_digits + sign - 1) /* replacing garbage */
7788 buf[i] = '0'; /* digits with 0... */
7789 }
7790 if (buf[i] == '.') { /* Have decimal point */
7791 int gotend = 0;
7792 /* places < 0 so truncate fraction */
7793 if (places < 0 || (places == 0 && round)) {
7794 buf[i] = NUL;
7795 } else if (places > 0) { /* d > 0 so this many decimal places */
7796 i++; /* First digit after decimal */
7797 for (j = 0; j < places; j++) { /* Truncate after d decimal */
7798 if (!buf[j+i]) /* places or extend to d */
7799 gotend = 1; /* decimal places. */
7800 if (gotend || j+i+sign > fp_digits)
7801 buf[j+i] = '0';
7802 }
7803 buf[j+i] = NUL;
7804 } else { /* places == 0 so Do The Right Thing */
7805 for (j = (int)strlen(buf) - 1; j > i+1; j--) {
7806 if ((j - sign) > fp_digits)
7807 buf[j] = '0';
7808 if (buf[j] == '0')
7809 buf[j] = NUL; /* Strip useless trailing 0's. */
7810 else
7811 break;
7812 }
7813 }
7814 }
7815 fpfmtbuf[FPFMTSIZ-1] = NUL;
7816 j = strlen(buf);
7817 sign = 0;
7818 for (i = j-1; i >= 0; i--) {
7819 if (buf[i] == '9')
7820 nines++;
7821 else
7822 break;
7823 }
7824 /* Do something about xx.xx99999999... */
7825 if (nines > 5) {
7826 if (isdigit(buf[i]) && i < FPFMTSIZ - 2) {
7827 buf[i] = buf[i] + 1;
7828 buf[i+1] = '0';
7829 buf[i+2] = '\0';
7830 }
7831 }
7832 if (!strncmp(buf,"-0.0",FPFMTSIZ))
7833 ckstrncpy(buf,"0.0",FPFMTSIZ);
7834 fpfbufpos += (int)strlen(buf) + 1;
7835 return((char *)buf);
7836 }
7837 #endif /* CKFLOAT */
7838
7839 static VOID
evalerr(fn)7840 evalerr(fn) char * fn; {
7841 if (fndiags) {
7842 if (divbyzero)
7843 ckmakmsg(fnval,FNVALL,"<ERROR:DIVIDE_BY_ZERO:\\f",fn,"()>",NULL);
7844 else
7845 ckmakmsg(fnval,FNVALL,"<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
7846 }
7847 }
7848
7849
7850 static int
ckcindex(c,s)7851 ckcindex(c,s) char c, *s; {
7852 int rc;
7853 if (!c || !s) return(0);
7854 for (rc = 0; s[rc]; rc++) {
7855 if (c == s[rc]) return(rc+1);
7856 }
7857 return(0);
7858 }
7859
7860 static char *
dokwval(s,sep)7861 dokwval(s,sep) char * s, * sep; {
7862 char c = '\0', * p, * kw = NULL, * vp = NULL;
7863 char * rc = "0"; /* Return code */
7864 int x = 0;
7865 if (!s) return(rc);
7866 if (!*s) return(rc);
7867 debug(F110,"kwval arg",s,0);
7868 debug(F110,"kwval sep",sep,0);
7869 p = (char *)malloc((int)strlen(s)+1);
7870 if (!p) goto xdokwval;
7871 strcpy(p,s); /* SAFE */
7872 s = p;
7873 while (*s < '!' && *s > '\0') /* Get first nonblank */
7874 s++;
7875 if (!*s) goto xdokwval;
7876 if (ckcindex(*s,sep)) /* Separator but no keyword */
7877 goto xdokwval;
7878 kw = s; /* Keyword */
7879 while (*s > ' ') {
7880 if (ckcindex(*s,sep)) { /* keyword=... */
7881 c = *s;
7882 break;
7883 }
7884 s++;
7885 }
7886 if (*kw) rc = "1"; /* Have keyword, promote return code */
7887 *s++ = NUL; /* Terminate keyword */
7888 while (*s < '!' && *s > '\0') /* Skip blanks */
7889 s++;
7890 if (!c && ckcindex(*s,sep)) {
7891 c = *s++; /* Have separator */
7892 while (*s < '!' && *s > '\0') /* Skip blanks */
7893 s++;
7894 }
7895 if (c) {
7896 vp = s;
7897 if (*vp) rc = "2"; /* Have value, another promotion */
7898 #ifdef COMMENT
7899 while (*s > ' ') /* Skip to end */
7900 s++;
7901 *s = NUL; /* Terminate value */
7902 #endif /* COMMENT */
7903 }
7904 debug(F110,"kwval c",ckctoa(c),0);
7905 debug(F110,"kwval keyword",kw,0);
7906 debug(F110,"kwval value",vp,0);
7907 makestr(&lastkwval,kw);
7908 vp = brstrip(vp);
7909 debug(F110,"kwval value",vp,0);
7910 x = addmac(kw,vp);
7911 debug(F111,"kwval addmac",kw,x);
7912 xdokwval:
7913 if (p) free(p);
7914 return((x < 0) ? "-1" : rc);
7915 }
7916
7917 static int
isaarray(s)7918 isaarray(s) char * s; { /* Is s an associative array element */
7919 int state = 0;
7920 CHAR c;
7921 if (!s) return(0);
7922 while ((c = *s++)) {
7923 if (!isprint(c)) {
7924 return(0);
7925 } else if (c == '<') {
7926 if (state != 0)
7927 return(0);
7928 state = 1;
7929 } else if (c == '>') {
7930 return((state != 1 || *s) ? 0 : 1);
7931 }
7932 }
7933 return(0);
7934 }
7935
7936 /* J P G D A T E -- Get "date taken" from JPG file Exif data */
7937
7938 /*
7939 This routine doesn't follow the Exif spec, it just hunts for
7940 date-time strings in the first 8K of the JPG and keeps the earliest one.
7941 Call with file pointer, returns Exif date-time string "yyyy:mm:dd hh:mm:ss"
7942 or an empty string if none found.
7943 */
7944 #define JPGYEAR 1
7945 #define JPGMONTH 2
7946 #define JPGDAY 3
7947 #define JPGHOUR 4
7948 #define JPGMIN 5
7949 #define JPGSEC 6
7950
7951 #define JPGDATEBUF 8192 /* Should be more than enough bytes to find date */
7952
7953 static char *
jpgdate(fp)7954 jpgdate(fp) FILE * fp; {
7955 static char datebuf[20];
7956 char tmpbuf[20];
7957 CHAR buf[JPGDATEBUF+1];
7958 CHAR * p;
7959 CHAR * z;
7960 CHAR c;
7961 int i;
7962 int k = 0;
7963 int n = 0;
7964 int count = 0;
7965 int state = 0;
7966
7967 if (fp == NULL)
7968 return("");
7969 rewind(fp);
7970
7971 for (i = 0; i < 20; i++) { datebuf[i] = NUL; tmpbuf[i] = NUL; }
7972
7973 datebuf[0] = NUL;
7974 tmpbuf[0] = NUL;
7975
7976 count = fread(buf,1,JPGDATEBUF,fp); /* Read a buffer */
7977 if (count == EOF || count == 0) {
7978 return("");
7979 }
7980 p = (CHAR *) buf;
7981 z = p + JPGDATEBUF;
7982
7983 while (p < z) {
7984 c = *p++;
7985 n++;
7986 if (c != ' ' && c != ':' && !isdigit(c)) {
7987 state = 0;
7988 k = 0;
7989 continue;
7990 }
7991 switch (state) {
7992 case 0:
7993 if (c == '1' && *p == '9') state = JPGYEAR;
7994 else if (c == '2' && *p == '0') state = JPGYEAR;
7995 if (state == JPGYEAR) {
7996 k = 0;
7997 tmpbuf[k++] = c;
7998 }
7999 continue;
8000
8001 case JPGYEAR:
8002 if (c == ':' && k == 4) {
8003 tmpbuf[k++] = c;
8004 state = JPGMONTH;
8005 continue;
8006 }
8007 if (k > 3 || !isdigit(c))
8008 state = k = 0;
8009 else
8010 tmpbuf[k++] = c;
8011 continue;
8012
8013 case JPGMONTH:
8014 if (c == ':' && k == 7) {
8015 tmpbuf[k++] = c;
8016 state = JPGDAY;
8017 continue;
8018 }
8019 if (k > 6 || !isdigit(c))
8020 state = k = 0;
8021 else
8022 tmpbuf[k++] = c;
8023 continue;
8024
8025 case JPGDAY:
8026 if (c == ' ' && k == 10) {
8027 tmpbuf[k++] = c;
8028 state = JPGHOUR;
8029 continue;
8030 }
8031 if (k > 9 || !isdigit(c))
8032 state = k = 0;
8033 else
8034 tmpbuf[k++] = c;
8035 continue;
8036
8037 case JPGHOUR:
8038 if (c == ':' && k == 13) {
8039 tmpbuf[k++] = c;
8040 state = JPGMIN;
8041 continue;
8042 }
8043 if (k > 12 || !isdigit(c))
8044 state = k = 0;
8045 else
8046 tmpbuf[k++] = c;
8047 continue;
8048
8049 case JPGMIN:
8050 if (c == ':' && k == 16) {
8051 tmpbuf[k++] = c;
8052 state = JPGSEC;
8053 continue;
8054 }
8055 if (k > 15 || !isdigit(c))
8056 state = k = 0;
8057 else
8058 tmpbuf[k++] = c;
8059 continue;
8060
8061 case JPGSEC:
8062 if (!isdigit(c) || !isdigit(*p)) {
8063 state = k = 0;
8064 continue;
8065 }
8066 tmpbuf[k++] = c;
8067 tmpbuf[k++] = *p;
8068 tmpbuf[k] = NUL;
8069 }
8070 if (!datebuf[0]) { /* First date */
8071 strncpy(datebuf,tmpbuf,19);
8072 } else if (strncmp(tmpbuf,datebuf,19) < 0) { /* Earlier date */
8073 strncpy(datebuf,tmpbuf,19);
8074 }
8075 }
8076 return((char *) datebuf);
8077 }
8078
8079 int /* Is character alphnumeric? */
cisalphanum(ch)8080 cisalphanum(ch) CHAR ch; { /* i.e. a letter, digit, @, $, or _ */
8081 /* All 8-bit characters are counted as alphanumeric */
8082 int c;
8083 c = (int)ch; /* Avoid C-language character syntax */
8084 if (c == 36) return(1); /* '$' is alphanumeric */
8085 if (c == 95) return(1); /* '_' is alphanumeric */
8086 if (c < 48) return(0); /* Space, punctuation, math */
8087 if (c > 57 && c < 64) return(0); /* Between '9' and '@' */
8088 if (c > 90 && c < 97) return(0); /* Between 'Z' and 'a' */
8089 if (c > 122 && c < 127) return(0); /* Between 'z' and DEL */
8090 return(1);
8091 }
8092
8093 int /* Is character non-alphanumeric */
cnonalphanum(ch)8094 cnonalphanum(ch) CHAR ch; { /* i.e. not letter, digit, [$@_] */
8095 int c;
8096 c = (int)ch; /* Avoid C-language character syntax */
8097 if (c == 36) return(0); /* '$' is alphanumeric */
8098 if (c == 95) return(0); /* '_' is alphanumeric */
8099 if (c < 48) return(1); /* Space, punctuation, math */
8100 if (c > 57 && c < 64) return(1); /* Between '9' and '@' */
8101 if (c > 90 && c < 97) return(1); /* Between 'Z' and 'a' */
8102 if (c > 122 && c < 127) return(1); /* Between 'z' and DEL */
8103 return(0);
8104 }
8105
8106 /* Tell if a string contains only alphanumeric characters */
8107 int
isalphanum(s)8108 isalphanum(s) char *s; {
8109 CHAR c;
8110 while ((c = (int)(*s++))) {
8111 if (!cisalphanum(c)) return(0);
8112 }
8113 return(1);
8114 }
8115 /* Tell if a string contains only non-alphanumeric characters */
8116 int
nonalphanum(s)8117 nonalphanum(s) char *s; {
8118 CHAR c;
8119 while ((c = (int)(*s++))) {
8120 if (!cnonalphanum(c)) return(0);
8121 }
8122 return(1);
8123 }
8124
8125 static char * /* Evaluate builtin functions */
fneval(fn,argp,argn,xp)8126 fneval(fn,argp,argn,xp) char *fn, *argp[]; int argn; char * xp; {
8127 int i=0, j=0, k=0, len1=0, len2=0, len3=0, n=0, t=0, x=0, y=0;
8128 int cx, failed = 0; /* Return code, 0 = ok */
8129 long z = 0L;
8130 char *bp[FNARGS + 1]; /* Pointers to malloc'd strings */
8131 char c = NUL;
8132 char *p = NULL, *s = NULL;
8133 char *val1 = NULL, *val2 = NULL; /* Pointers to numeric string values */
8134
8135 #ifdef RECURSIVE
8136 int rsave = recursive;
8137 #endif /* RECURSIVE */
8138 #ifdef OS2
8139 int zsave = zxpn;
8140 #endif /* OS2 */
8141
8142 if (!fn) fn = ""; /* Protect against null pointers */
8143 if (!*fn) return("");
8144
8145 for (i = 0; i < FNARGS; i++) /* Initialize argument pointers */
8146 bp[i] = NULL;
8147 /*
8148 IMPORTANT: Note that argn is not an accurate count of the number of
8149 arguments. We can't really tell if an argument is null until after we
8150 execute the code below. So argn is really the maximum number of arguments
8151 we might have. Argn should always be at least 1, even if the function is
8152 called with empty parentheses (but don't count on it).
8153 */
8154 debug(F111,"fneval",fn,argn);
8155 debug(F110,"fneval",argp[0],0);
8156 if (argn > FNARGS) /* Discard excess arguments */
8157 argn = FNARGS;
8158
8159 fndepth++;
8160 debug(F101,"fneval fndepth","",fndepth);
8161 p = fnval;
8162 fnval[0] = NUL;
8163 y = lookup(fnctab,fn,nfuncs,&x); /* Look up the function name */
8164 cx = y; /* Because y is too generic... */
8165 if (cx < 0) { /* Not found */
8166 failed = 1;
8167 if (fndiags) { /* FUNCTION DIAGNOSTIC ON */
8168 int x;
8169 x = strlen(fn);
8170 /* The following sprintf's are safe */
8171 switch (cx) {
8172 case -1:
8173 if (x + 32 < FNVALL)
8174 sprintf(fnval,"<ERROR:NO_SUCH_FUNCTION:\\f%s()>",fn);
8175 else
8176 sprintf(fnval,"<ERROR:NO_SUCH_FUNCTION>");
8177 break;
8178 case -2:
8179 if (x + 26 < FNVALL)
8180 sprintf(fnval,"<ERROR:NAME_AMBIGUOUS:\\f%s()>",fn);
8181 else
8182 sprintf(fnval,"<ERROR:NAME_AMBIGUOUS>");
8183 break;
8184 case -3:
8185 sprintf(fnval,"<ERROR:FUNCTION_NAME_MISSING:\\f()>");
8186 break;
8187 default:
8188 if (x + 26 < FNVALL)
8189 sprintf(fnval,"<ERROR:LOOKUP_FAILURE:\\f%s()>",fn);
8190 else
8191 sprintf(fnval,"<ERROR:LOOKUP_FAILURE>");
8192 break;
8193 }
8194 }
8195 goto fnend; /* Always leave via common exit */
8196 }
8197 fn = fnctab[x].kwd; /* Full name of function */
8198
8199 if (argn < 0) {
8200 failed = 1;
8201 p = fnval;
8202 if (fndiags)
8203 sprintf(fnval,"<ERROR:MISSING_ARG:\\f%s()>",fn);
8204 goto fnend;
8205 }
8206 if (cx == FN_LIT) { /* literal(arg1) */
8207 debug(F010,"flit",xp,0);
8208 p = xp ? xp : ""; /* Return a pointer to arg itself */
8209 goto fnend;
8210 }
8211
8212 #ifdef DEBUG
8213 if (deblog) {
8214 int j;
8215 for (j = 0; j < argn; j++)
8216 debug(F111,"fneval arg",argp[j],j);
8217 }
8218 #endif /* DEBUG */
8219 for (j = argn-1; j >= 0; j--) { /* Uncount empty trailing args */
8220 if (!argp[j])
8221 argn--;
8222 else if (!*(argp[j]))
8223 argn--;
8224 else break;
8225 }
8226 debug(F111,"fneval argn",fn,argn);
8227 /*
8228 \fliteral() and \fcontents() are special functions that do not evaluate
8229 their arguments, and are treated specially here. After these come the
8230 functions whose arguments are evaluated in the normal way.
8231 */
8232 #ifdef COMMENT
8233 /* (moved up) */
8234 if (cx == FN_LIT) { /* literal(arg1) */
8235 debug(F110,"flit",xp,0);
8236 p = xp ? xp : ""; /* Return a pointer to arg itself */
8237 goto fnend;
8238 }
8239 #endif /* COMMENT */
8240 if (cx == FN_CON) { /* Contents of variable, unexpanded. */
8241 char c;
8242 int subscript = 0;
8243 if (!(p = argp[0]) || !*p) {
8244 failed = 1;
8245 p = fnval;
8246 if (fndiags)
8247 sprintf(fnval,"<ERROR:MISSING_ARG:\\fcontents()>");
8248 goto fnend;
8249 }
8250 p = brstrip(p);
8251 if (*p == CMDQ) p++;
8252 if ((c = *p) == '%') { /* Scalar variable. */
8253 c = *++p; /* Get ID character. */
8254 p = ""; /* Assume definition is empty */
8255 if (!c) { /* Double paranoia */
8256 failed = 1;
8257 p = fnval;
8258 if (fndiags)
8259 sprintf(fnval,"<ERROR:ARG_BAD_VARIABLE:\\fcontents()>");
8260 goto fnend;
8261 }
8262 if (c >= '0' && c <= '9') { /* Digit for macro arg */
8263 if (maclvl < 0) /* Digit variables are global */
8264 p = g_var[c]; /* if no macro is active */
8265 else /* otherwise */
8266 p = m_arg[maclvl][c - '0']; /* they're on the stack */
8267 } else if (c == '*') {
8268 #ifdef COMMENT
8269 p = (maclvl > -1) ? m_line[maclvl] : topline;
8270 if (!p) p = "";
8271 #else
8272 int nx = FNVALL;
8273 char * sx = fnval;
8274 p = fnval;
8275 #ifdef COMMENT
8276 if (cmdsrc() == 0 && topline)
8277 p = topline;
8278 else
8279 #endif /* COMMENT */
8280 if (zzstring("\\fjoin(&_[],{ },1)",&sx,&nx) < 0) {
8281 failed = 1;
8282 p = fnval;
8283 if (fndiags)
8284 sprintf(fnval,"<ERROR:OVERFLOW:\\fcontents()>");
8285 debug(F110,"zzstring fcontents(\\%*)",p,0);
8286 }
8287 #endif /* COMMENT */
8288 } else {
8289 if (isupper(c)) c -= ('a'-'A');
8290 p = g_var[c]; /* Letter for global variable */
8291 }
8292 if (!p) p = "";
8293 goto fnend;
8294 } else if (c == '&') { /* Array reference. */
8295 int vbi, d;
8296 if (arraynam(p,&vbi,&d) < 0) { /* Get name and subscript */
8297 failed = 1;
8298 p = fnval;
8299 if (fndiags)
8300 sprintf(fnval,"<ERROR:ARG_BAD_ARRAY:\\fcontents()>");
8301 goto fnend;
8302 }
8303 subscript = chkarray(vbi,d); /* Check the array */
8304 if (subscript >= 0) { /* Array is declared? */
8305 vbi -= ARRAYBASE; /* Convert name to index */
8306 if (a_dim[vbi] >= d) { /* If subscript in range */
8307 char **ap;
8308 ap = a_ptr[vbi]; /* get data pointer */
8309 if (ap) { /* and if there is one */
8310 p = ap[d]; /* return it */
8311 goto fnend;
8312 }
8313 }
8314 } else { /* Array not declared or element */
8315 fnval[0] = NUL; /* out of range - return null string */
8316 p = fnval; /* fdc 2010-12-30 */
8317 goto fnend;
8318 }
8319 } else {
8320 failed = 1;
8321 p = fnval;
8322 if (fndiags)
8323 sprintf(fnval,"<ERROR:ARG_NOT_VARIABLE:\\fcontents()>");
8324 goto fnend;
8325 }
8326 }
8327 p = fnval; /* Default result pointer */
8328 fnval[0] = NUL; /* Default result = empty string */
8329
8330 for (i = 0; i < argn; i++) { /* Loop to expand each argument */
8331 n = MAXARGLEN; /* Allow plenty of space */
8332 bp[i] = s = malloc(n+1); /* Allocate space for this argument */
8333 if (bp[i] == NULL) { /* Handle failure to get space */
8334 failed = 1;
8335 if (fndiags)
8336 ckmakmsg(fnval,FNVALL,"<ERROR:MALLOC_FAILURE:\\f",fn,"()>",NULL);
8337 goto fnend;
8338 }
8339 p = argp[i] ? argp[i] : ""; /* Point to this argument */
8340
8341 /*
8342 Trim leading and trailing spaces from the original argument, before
8343 evaluation. This code new to edit 184. Fixed in edit 199 to trim
8344 blanks BEFORE stripping braces.
8345
8346 */
8347 {
8348 int x, j;
8349 x = strlen(p);
8350 j = x - 1; /* Trim trailing whitespace */
8351 while (j > 0 && (*(p + j) == SP || *(p + j) == HT))
8352 *(p + j--) = NUL;
8353 while (*p == SP || *p == HT) /* Strip leading whitespace */
8354 p++;
8355 x = strlen(p);
8356 if (*p == '{' && *(p+x-1) == '}') { /* NOW strip braces */
8357 p[x-1] = NUL;
8358 p++;
8359 x -= 2;
8360 }
8361 }
8362
8363 /* Now evaluate the argument */
8364
8365 debug(F111,"fneval calling zzstring",p,n);
8366 t = zzstring(p,&s,&n); /* Expand arg into new space */
8367 debug(F101,"fneval zzstring","",t);
8368 debug(F101,"fneval zzstring","",n);
8369 if (t < 0) {
8370 debug(F101,"fneval zzstring fails, arg","",i);
8371 failed = 1;
8372 if (fndiags) {
8373 if (n == 0)
8374 ckmakmsg(fnval,FNVALL,
8375 "<ERROR:ARG_TOO_LONG:\\f",fn,"()>",NULL);
8376 else
8377 ckmakmsg(fnval,FNVALL,
8378 "<ERROR:ARG_EVAL_FAILURE:\\f",fn,"()>",NULL);
8379 }
8380 goto fnend;
8381 }
8382 debug(F111,"fneval arg",bp[i],i);
8383 }
8384
8385 #ifdef DEBUG
8386 if (deblog) {
8387 int j;
8388 debug(F110,"fneval",fn,0);
8389 for (j = 0; j < argn; j++) {
8390 debug(F111,"fneval arg post eval",argp[j],j);
8391 debug(F111,"fneval evaluated arg",bp[j],j);
8392 }
8393 }
8394 #endif /* DEBUG */
8395 {
8396 /* Adjust argn for empty trailing arguments. */
8397 /* For example when an arg is a variable name but the */
8398 /* variable has no value. July 2006. */
8399 int j, old; char *p;
8400 old = argn;
8401 for (j = argn - 1; j >= 0; j--) {
8402 p = bp[j];
8403 if (!p)
8404 argn--;
8405 else if (!*p)
8406 argn--;
8407 else
8408 break;
8409 }
8410 #ifdef DEBUG
8411 if (argn != old)
8412 debug(F101,"fneval adjusted argn","",argn);
8413 #endif /* DEBUG */
8414 }
8415
8416 /*
8417 From this point on, bp[0..argn-1] are not NULL and all must be freed
8418 before returning. BUT NOTE: if no arguments were given, bp[0] *is* NULL.
8419 */
8420 if (argn < 1) { /* Catch required args missing */
8421 switch (cx) {
8422 case FN_DEF:
8423 case FN_EVA:
8424 case FN_EXE:
8425 case FN_CHR:
8426 /* case FN_COD: */
8427 case FN_MAX:
8428 case FN_MIN:
8429 case FN_MOD:
8430 case FN_FD:
8431 case FN_FS:
8432 case FN_TOD:
8433 case FN_FFN:
8434 case FN_BSN:
8435 case FN_RAW:
8436 case FN_CMD:
8437 case FN_2HEX:
8438 case FN_2OCT:
8439 case FN_DNAM:
8440 #ifdef FN_ERRMSG
8441 case FN_ERRMSG:
8442 #endif /* FN_ERRMSG */
8443 #ifdef CK_KERBEROS
8444 case FN_KRB_TK:
8445 case FN_KRB_NX:
8446 case FN_KRB_IV:
8447 case FN_KRB_TT:
8448 case FN_KRB_FG:
8449 #endif /* CK_KERBEROS */
8450 case FN_MJD2:
8451 case FN_N2TIM:
8452 case FN_DIM:
8453 case FN_DATEJ:
8454 case FN_PNCVT:
8455 case FN_PERM:
8456 case FN_ALOOK:
8457 case FN_TLOOK:
8458 case FN_ABS:
8459 case FN_AADUMP:
8460 case FN_JOIN:
8461 #ifdef CKFLOAT
8462 case FN_FPABS:
8463 case FN_FPEXP:
8464 case FN_FPLOG:
8465 case FN_FPLN:
8466 case FN_FPMOD:
8467 case FN_FPSQR:
8468 case FN_FPADD:
8469 case FN_FPDIV:
8470 case FN_FPMUL:
8471 case FN_FPPOW:
8472 case FN_FPSUB:
8473 case FN_FPINT:
8474 case FN_FPROU:
8475 case FN_FPSIN:
8476 case FN_FPCOS:
8477 case FN_FPTAN:
8478 #endif /* CKFLOAT */
8479 #ifdef TCPSOCKET
8480 case FN_HSTADD:
8481 case FN_HSTNAM:
8482 #endif /* TCPSOCKET */
8483 case FN_DELSEC:
8484 #ifdef COMMENT
8485 case FN_KWVAL:
8486 case FN_SLEEP:
8487 case FN_MSLEEP:
8488 #endif /* COMMENT */
8489 #ifdef NT
8490 case FN_SNAME:
8491 case FN_LNAME:
8492 #endif /* NT */
8493 case FN_FILEINF:
8494 case FN_FILECMP:
8495 failed = 1;
8496 p = fnval;
8497 if (fndiags)
8498 ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
8499 goto fnend;
8500 }
8501 }
8502 p = fnval; /* Reset these again. */
8503 fnval[0] = NUL;
8504
8505 switch (cx) { /* Do function on expanded args. */
8506 #ifdef TCPSOCKET
8507 case FN_HSTADD:
8508 p = ckaddr2name(bp[0]);
8509 goto fnend;
8510 case FN_HSTNAM:
8511 p = ckname2addr(bp[0]);
8512 goto fnend;
8513 #endif /* TCPSOCKET */
8514
8515 case FN_DEF: /* \fdefinition(arg1) */
8516 k = isaarray(bp[0]) ?
8517 mxxlook(mactab,bp[0],nmac) :
8518 mxlook(mactab,bp[0],nmac);
8519 p = (k > -1) ? mactab[k].mval : "";
8520 goto fnend;
8521
8522 case FN_EVA: /* \fevaluate(arg1) */
8523 p = *(bp[0]) ? evalx(bp[0]) : "";
8524 if (!*p && fndiags) {
8525 failed = 1;
8526 p = fnval;
8527 evalerr(fn);
8528 }
8529 goto fnend;
8530
8531 case FN_EXE: /* \fexecute(arg1) */
8532 j = (int)strlen(s = bp[0]); /* Length of macro invocation */
8533 p = ""; /* Initialize return value to null */
8534 if (j) { /* If there is a macro to execute */
8535 while (*s == SP) s++,j--; /* strip leading spaces */
8536 p = s; /* remember beginning of macro name */
8537 for (i = 0; i < j; i++) { /* find end of macro name */
8538 if (*s == SP)
8539 break;
8540 s++;
8541 }
8542 if (*s == SP) { /* if there was a space after */
8543 *s++ = NUL; /* terminate the macro name */
8544 while (*s == SP) s++; /* skip past any extra spaces */
8545 } else
8546 s = ""; /* maybe there are no arguments */
8547 if (p && *p) {
8548 k = mlook(mactab,p,nmac); /* Look up the macro name */
8549 debug(F111,"fexec mlook",p,k);
8550 } else
8551 k = -1;
8552 if (k < 0) {
8553 char * p2 = p;
8554 failed = 1;
8555 p = fnval;
8556 if (fndiags)
8557 ckmakxmsg(fnval,FNVALL,
8558 "<ERROR:NO_SUCH_MACRO:\\f",fn,"(",p2,")>",
8559 NULL,NULL,NULL,NULL,NULL,NULL,NULL);
8560 goto fnend;
8561 }
8562 /*
8563 This is just a WEE bit dangerous because we are copying up to 9 arguments
8564 into the space reserved for one. It won't overrun the buffer, but if there
8565 are lots of long arguments we might lose some. The other problem is that if
8566 the macro has more than 3 arguments, the 4th through last are all
8567 concatenated onto the third. (The workaround is to use spaces rather than
8568 commas to separate them.) Leaving it like this to avoid having to allocate
8569 tons more buffers.
8570 */
8571 if (argn > 1) { /* Commas used instead of spaces */
8572 int i;
8573 char *p = bp[0]; /* Reuse this space */
8574 *p = NUL; /* Make into dodo() arg list */
8575 for (i = 1; i < argn; i++) {
8576 ckstrncat(p,bp[i],MAXARGLEN);
8577 ckstrncat(p," ",MAXARGLEN);
8578 }
8579 s = bp[0]; /* Point to new list */
8580 }
8581 p = ""; /* Initialize return value */
8582 if (k >= 0) { /* If macro found in table */
8583 /* Go set it up (like DO cmd) */
8584 if ((j = dodo(k,s,cmdstk[cmdlvl].ccflgs)) > 0) {
8585 if (cmpush() > -1) { /* Push command parser state */
8586 extern int ifc;
8587 int ifcsav = ifc; /* Push IF condition on stack */
8588 k = parser(1); /* Call parser to execute the macro */
8589 cmpop(); /* Pop command parser */
8590 ifc = ifcsav; /* Restore IF condition */
8591 if (k == 0) { /* No errors, ignore action cmds. */
8592 p = mrval[maclvl+1]; /* If OK, set return value. */
8593 if (p == NULL) p = "";
8594 }
8595 } else { /* Can't push any more */
8596 debug(F100,"zzstring fneval fexec failure","",0);
8597 printf("\n?\\fexec() too deeply nested\n");
8598 while (cmpop() > -1) ;
8599 p = "";
8600 }
8601 }
8602 }
8603 }
8604 debug(F110,"zzstring fneval fexecute final p",p,0);
8605 goto fnend;
8606
8607 #ifdef RECURSIVE
8608 case FN_RDIR: /* \frdir..() - Recursive dir count */
8609 case FN_RFIL: /* \frfiles() - Recursive file count */
8610 /* recursive = 2; */ /* fall thru... */
8611 #endif /* RECURSIVE */
8612 case FN_FC: /* \ffiles() - File count. */
8613 case FN_DIR: { /* \ffdir.() - Directory count. */
8614 char abuf[16], *s;
8615 char ** ap = NULL;
8616 int x, xflags = 0;
8617 if (matchdot)
8618 xflags |= ZX_MATCHDOT;
8619 if (cx == FN_RDIR || cx == FN_RFIL) {
8620 xflags |= ZX_RECURSE;
8621 #ifdef CKSYMLINK
8622 /* Recursive - don't follow symlinks */
8623 xflags |= ZX_NOLINKS;
8624 #endif /* CKSYMLINK */
8625 }
8626 failed = 0;
8627 if (argn < 1) {
8628 p = "0";
8629 goto fnend;
8630 }
8631 if (cx == FN_DIR || cx == FN_RDIR) { /* Only list directories */
8632 debug(F100,"FN_DIR or FN_RDIR","",0);
8633 xflags |= ZX_DIRONLY;
8634 #ifdef OS2
8635 zxpn = 1; /* Use the alternate list */
8636 #endif /* OS2 */
8637 } else { /* List only files */
8638 debug(F100,"Not FN_DIR or FN_RDIR","",0);
8639 xflags |= ZX_FILONLY;
8640 #ifdef OS2
8641 zxpn = 1; /* Use the alternate list */
8642 #endif /* OS2 */
8643 }
8644 if (*(bp[0])) {
8645 k = nzxpand(bp[0],xflags);
8646 if (k < 0) k = 0;
8647 sprintf(fnval,"%d",k); /* SAFE */
8648 p = fnval;
8649 } else
8650 p = "0";
8651
8652 if (argn > 1) { /* Assign list to array */
8653 fnval[0] = NUL; /* Initial return value */
8654 ckstrncpy(abuf,bp[1],16); /* Get array reference */
8655 s = abuf;
8656 if (*s == CMDQ) s++;
8657 failed = 1; /* Assume it's bad */
8658 p = fnval; /* Point to result */
8659 if (fndiags) /* Default is this error message */
8660 ckmakmsg(fnval,FNVALL,
8661 "<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
8662 if (s[0] != '&') /* "Address" of array */
8663 goto fnend;
8664 if (s[2])
8665 if (s[2] != '[' || s[3] != ']')
8666 goto fnend;
8667 if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */
8668 s[1] += 32;
8669 if ((x = dclarray(s[1],k)) < 0) /* File list plus count */
8670 goto fnend;
8671 failed = 0; /* Unset failure flag */
8672 ap = a_ptr[x]; /* Point to array we just declared */
8673 sprintf(fnval,"%d",k); /* SAFE */
8674 }
8675 #ifdef OS2
8676 if (ap) { /* We are making an array */
8677 int i;
8678 char tmp[16];
8679 ap[0] = NULL; /* Containing number of files */
8680 makestr(&(ap[0]),ckitoa(k));
8681
8682 ckstrncpy(tmp,fnval,16); /* Save return value */
8683
8684 for (i = 1; i <= k; i++) { /* Fill it */
8685 ap[i] = NULL;
8686 znext(fnval); /* Next filename */
8687 if (!*fnval) /* No more, done */
8688 break; /* In case a premature end */
8689 makestr(&(ap[i]),fnval);
8690 }
8691 #ifdef ZXREWIND
8692 k = zxrewind(); /* Reset the file expansion */
8693 #else
8694 k = nzxpand(bp[0],xflags);
8695 #endif /* ZXREWIND */
8696 ckstrncpy(fnval,tmp,FNVALL); /* Restore return value */
8697 }
8698 #else /* OS2 */
8699 { /* Make copies of the list */
8700 int i; char tmp[16];
8701 if (flist) { /* Free old file list, if any */
8702 for (i = 0; flist[i]; i++) { /* and each string */
8703 free(flist[i]);
8704 flist[i] = NULL;
8705 }
8706 free((char *)flist);
8707 }
8708 ckstrncpy(tmp,fnval,16); /* Save our return value */
8709 flist = (char **) malloc((k+1) * sizeof(char *)); /* New array */
8710 if (flist) {
8711 for (i = 0; i <= k; i++) { /* Fill it */
8712 flist[i] = NULL;
8713 znext(fnval); /* Next filename */
8714 if (!*fnval) /* No more, done */
8715 break;
8716 makestr(&(flist[i]),fnval);
8717 }
8718 if (ap) { /* If array pointer given */
8719 ap[0] = NULL;
8720 makestr(&(ap[0]),ckitoa(k));
8721 for (i = 0; i < k; i++) { /* Copy file list to array */
8722 ap[i+1] = NULL;
8723 makestr(&(ap[i+1]),flist[i]);
8724 }
8725 }
8726 }
8727 ckstrncpy(fnval,tmp,FNVALL); /* Restore return value */
8728 flistn = 0; /* Reset global list pointer */
8729 }
8730 #endif /* OS2 */
8731 #ifdef RECURSIVE
8732 recursive = rsave;
8733 #endif /* RECURSIVE */
8734 #ifdef OS2
8735 zxpn = zsave;
8736 #endif /* OS2 */
8737 }
8738 goto fnend;
8739
8740 case FN_FIL: /* \fnextfile() - Next file in list. */
8741 p = fnval; /* (no args) */
8742 *p = NUL;
8743 #ifdef OS2
8744 zxpn = 1; /* OS/2 - use the alternate list */
8745 znext(p); /* Call system-dependent function */
8746 zxpn = zsave; /* Restore original list */
8747 #else
8748 if (flist) /* Others, use our own list. */
8749 if (flist[flistn])
8750 p = flist[flistn++];
8751 #endif /* OS2 */
8752 goto fnend;
8753
8754 } /* Break up big switch... */
8755
8756 switch (cx) {
8757 case FN_IND: /* \findex(s1,s2,start,occurrence) */
8758 case FN_RIX: /* \frindex(s1,s2,start,occurrence) */
8759 case FN_SEARCH: /* \fsearch(pat,string,start,occ) */
8760 case FN_RSEARCH: /* \frsearch(pat,string,start,occ) */
8761 case FN_COUNT: { /* \fcount(s1,s2,start) */
8762 int i = 0, right = 0, search = 0, count = 0;
8763 int desired = 1;
8764 right = (cx == FN_RIX || cx == FN_RSEARCH);
8765 search = (cx == FN_SEARCH || cx == FN_RSEARCH);
8766 count = (cx == FN_COUNT);
8767 p = "0";
8768 if (argn > 1) { /* Only works if we have 2 or 3 args */
8769 int start = 0;
8770 char * pat = NULL;
8771 len1 = (int)strlen(pat = bp[0]); /* length of string to look for */
8772 len2 = (int)strlen(s = bp[1]); /* length of string to look in */
8773 if (len1 < 1 || len2 < 1) /* Watch out for empty strings */
8774 goto fnend;
8775 start = right ? -1 : 0; /* Default starting position */
8776 if (argn > 2) {
8777 val1 = *(bp[2]) ? evalx(bp[2]) : "1";
8778 if (argn > 3) { /* Occurrence */
8779 val2 = *(bp[3]) ? evalx(bp[3]) : "1";
8780 if (chknum(val2)) desired = atoi(val2);
8781 if (desired * len1 > len2) goto fnend;
8782 }
8783 if (chknum(val1)) {
8784 int t;
8785 t = atoi(val1);
8786 if (!search) { /* Index or Rindex */
8787 j = len2 - len1; /* Length difference */
8788 t--; /* Convert position to 0-based */
8789 if (t < 0) t = 0;
8790 start = t;
8791 if (!right && start < 0) start = 0;
8792 } else { /* Search or Rsearch */
8793 int x;
8794 if (t < 0) t = 0;
8795 if (right) { /* Right to left */
8796 if (t > len2) t = len2;
8797 start = len2 - t - 1;
8798 if (start < 0)
8799 goto fnend;
8800 x = len2 - t;
8801 s[x] = NUL;
8802 } else { /* Left to right */
8803 start = t - 1;
8804 if (start < 0) start = 0;
8805 if (start >= len2)
8806 goto fnend;
8807 }
8808 }
8809 } else {
8810 failed = 1;
8811 evalerr(fn);
8812 p = fnval;
8813 goto fnend;
8814 }
8815 }
8816 if (count) { /* \fcount() */
8817 int j;
8818 for (i = 0; start < len2; i++) {
8819 j = ckindex(pat,bp[1],start,0,inpcas[cmdlvl]);
8820 if (j == 0) break;
8821 start = j;
8822 }
8823
8824 } else if (search) { /* \fsearch() or \frsearch() */
8825
8826 if (right && pat[0] == '^') {
8827 right = 0;
8828 start = 0;
8829 }
8830 if (right) { /* From right */
8831 int k, j = 1;
8832 if (start < 0)
8833 start = len2 - 1;
8834 i = 0;
8835 while (start >= 0 && j <= desired) {
8836 for (i = start;
8837 (i >= 0) &&
8838 !(k = ckmatch(pat,s+i,inpcas[cmdlvl],1+4));
8839 i--) ;
8840 if (k < 1) { /* No match */
8841 i = 0;
8842 break;
8843 }
8844 if (j == desired) { /* The match we want? */
8845 i += k; /* Yes, return string index */
8846 break;
8847 }
8848 j++; /* No, count this match */
8849 s[i] = NUL; /* null it out */
8850 start = i-1; /* move left and look again */
8851 }
8852
8853 } else { /* From left */
8854 int j;
8855 i = 0;
8856 for (j = 1; j <= desired && start < len2; j++) {
8857 i = ckmatch(pat,&s[start],inpcas[cmdlvl],1+4);
8858 if (i == 0 || j == desired) break;
8859 start += i + 1;
8860 }
8861 if (j == desired && i != 0)
8862 i += start;
8863 else
8864 i = 0;
8865 }
8866 } else { /* index or rindex */
8867 int j = 0;
8868 i = 0;
8869 for (j = 1; j <= desired && start < len2; j++) {
8870 i = ckindex(pat,bp[1],start,right,inpcas[cmdlvl]);
8871 if (i == 0 || j == desired) break;
8872 start = (right) ? len2 - i + 1 : i;
8873 }
8874 if (j != desired)
8875 i = 0;
8876 }
8877 sprintf(fnval,"%d",i); /* SAFE */
8878 p = fnval;
8879 }
8880 goto fnend;
8881 }
8882
8883 case FN_RPL: /* \freplace(s1,s2,s3) */
8884 /*
8885 s = bp[0] = source string (len1)
8886 bp[1] = match string (len2)
8887 bp[2] = replacement string (len3)
8888 bp[3] = which occurrence (default = all);
8889 bp[4] = context sensitive ("word mode") 20171005
8890 fnval = p = destination (result) string
8891 */
8892 if (argn < 1) /* Nothing */
8893 goto fnend;
8894 if (argn < 2) { /* Need at least two args */
8895 ckstrncpy(p,bp[0],FNVALL);
8896 } else {
8897 int occur = 0, xx = 0, context = 0, j2;
8898 int left = 0, right = 0, ok = 0;
8899 len1 = (int)strlen(bp[0]); /* length of string to look in */
8900 len2 = (int)strlen(bp[1]); /* length of string to look for */
8901 len3 = (argn < 3) ? 0 : (int)strlen(bp[2]); /* Len of replacemnt */
8902
8903 j = len1 - len2 + 1; /* source - match + 1 */
8904 j2 = j;
8905 if (argn > 3) {
8906 if (chknum(bp[3])) {
8907 occur = atoi(bp[3]);
8908 } else {
8909 failed = 1;
8910 if (fndiags)
8911 ckmakmsg(fnval,FNVALL,
8912 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
8913 goto fnend;
8914 }
8915 }
8916 /*
8917 Context-sensitive "word mode" replace, new for C-Kermit 9.0.304 Dev.23,
8918 October 2017. Can be removed by defining NORPLWORDMODE.
8919 */
8920 #ifdef RPLWORDMODE
8921 if (argn > 4) {
8922 if (chknum(bp[4])) {
8923 context = atoi(bp[4]);
8924 } else {
8925 failed = 1;
8926 if (fndiags)
8927 ckmakmsg(fnval,FNVALL,
8928 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
8929 goto fnend;
8930 }
8931 }
8932 #endif /* RPLWORDMODE */
8933 /* If args out of whack... */
8934 if (j < 1 || len1 == 0 || len2 == 0) {
8935 ckstrncpy(p,bp[0],FNVALL); /* just return original string */
8936 p[FNVALL] = NUL;
8937 } else {
8938 ragain:
8939 s = bp[0]; /* Point to beginning of source string */
8940
8941 xx = 0; /* Match counter */
8942 while (*s) { /* For each character in it...*/
8943 /* Compare current segment with target string */
8944 if (!ckstrcmp(bp[1],s,len2,inpcas[cmdlvl])) {
8945 ok = 1; /* Assume OK to replace */
8946 #ifdef RPLWORDMODE
8947 if (context) { /* New 2017-10-05 */
8948 CHAR c;
8949 left = 0;
8950 right = 0;
8951 ok = 0; /* Mustcheck context before replacing */
8952 if (!strncmp(bp[1],"...",len2)) {
8953 /* Special case for ellipsis */
8954 if (s > bp[0]) { /* Can't begin a line */
8955 c = *(s-1); /* Check preceding char */
8956 if (c != 32 && c != '.')
8957 left = 1;
8958 }
8959 c = *(s+len2); /* Check following char */
8960 if (c != '.' && (c == SP || c == '\0'))
8961 right = 1;
8962 } else if (isalphanum(bp[1])) {
8963 /* Target string is alphanumeric... */
8964 if (s == bp[0]) { /* At beginning of string */
8965 left = 1; /* So left boundary ok */
8966 } else { /* Otherwise */
8967 c = *(s-1); /* Check preceding char */
8968 if (cnonalphanum(c)) /* If not alphamum */
8969 left = 2; /* left boundary ok */
8970 }
8971 c = *(s+len2); /* Check following character */
8972 if (c == '\0') /* If end of string */
8973 right = 1; /* Right boundary OK */
8974 else if (cnonalphanum(c))
8975 right = 2; /* Right boundary OK */
8976 } else if (nonalphanum(bp[1])) {
8977 /* Target is non-salphanumeric */
8978 if (s == bp[0]) { /* At beginning of line */
8979 left = 1; /* Left OK */
8980 } else { /* Otherwise */
8981 c = *(s-1); /* Check preceding char */
8982 if (cisalphanum(c) || c == SP)
8983 left = 2; /* Left OK */
8984 }
8985 c = *(s+len2); /* Check char after target */
8986 if (c == '\0') { /* At end of string */
8987 right = 1; /* Right OK */
8988 } else { /* Otherwise */
8989 if (cisalphanum(c) || c <= SP)
8990 right = 2; /* Right ok */
8991 }
8992 }
8993 /* If none of the above nothing is replaced */
8994 if (left && right) { /* Match accepted */
8995 ok = 1; /* OK to replace */
8996 xx++; /* Count this match */
8997 }
8998 } else
8999 #endif /* RPLWORDMODE */
9000 xx++; /* Straight replace - count every match */
9001
9002 if (ok && (occur == 0 || occur == xx)) {
9003 if (len3) {
9004 ckstrncpy(p,bp[2],FNVALL);
9005 p += len3;
9006 }
9007 s += len2; /* and skip past it. */
9008 } else { /* matched but not selected */
9009 *p++ = *s++; /* Just copy this character */
9010 }
9011 } else { /* Didn't match */
9012 *p++ = *s++; /* just copy this character */
9013 }
9014 }
9015 *p = NUL;
9016 while ((*p++ = *s++)); /* Append the rest */
9017 if (occur < 0) { /* cheap... */
9018 occur = xx + occur + 1;
9019 xx = 0;
9020 p = fnval;
9021 j = j2;
9022 if (occur > 0)
9023 goto ragain;
9024 }
9025 }
9026 }
9027 p = fnval;
9028 goto fnend;
9029
9030 case FN_CHR: /* \fcharacter(arg1) */
9031 val1 = *(bp[0]) ? evalx(bp[0]) : "";
9032 if (chknum(val1)) { /* Must be numeric */
9033 i = atoi(val1);
9034 if (i >= 0 && i < 256) { /* Must be an 8-bit value */
9035 p = fnval;
9036 *p++ = (char) i;
9037 *p = NUL;
9038 p = fnval;
9039 } else {
9040 failed = 1;
9041 if (fndiags)
9042 ckmakmsg(fnval,FNVALL,
9043 "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
9044 }
9045 } else {
9046 failed = 1;
9047 evalerr(fn);
9048 }
9049 goto fnend;
9050
9051 case FN_COD: /* \fcode(string) */
9052 /*
9053 returns decimal character value of first char in string.
9054 or 0 if string empty or no string given.
9055 */
9056 p = "0";
9057 if (!bp[0]) goto fnend; /* No argument given */
9058 if ((int)strlen(bp[0]) < 1) /* Empty argument */
9059 goto fnend;
9060 i = (int) bp[0][0];
9061 debug(F111,"FN_CODE",bp[0],i);
9062 p = fnval;
9063 sprintf(p,"%d",(i & 0xff)); /* SAFE */
9064 debug(F111,"FN_CODE fnval",fnval,i);
9065 goto fnend;
9066
9067 case FN_LEN: /* \flength(arg1) */
9068 if (argn > 0) {
9069 p = fnval;
9070 sprintf(p,"%d",(int)strlen(bp[0])); /* SAFE */
9071 } else p = "0";
9072 goto fnend;
9073
9074 case FN_LOW: /* \flower(arg1) */
9075 s = bp[0] ? bp[0] : "";
9076 p = fnval;
9077 while (*s) {
9078 if (isupper(*s))
9079 *p = (char) tolower(*s);
9080 else
9081 *p = *s;
9082 p++; s++;
9083 }
9084 *p = NUL;
9085 p = fnval;
9086 goto fnend;
9087
9088 case FN_MAX: /* \fmax(arg1,arg2) */
9089 case FN_MIN: /* \fmin(arg1,arg2) */
9090 case FN_MOD: /* \fmod(arg1,arg2) */
9091 val1 = *(bp[0]) ? evalx(bp[0]) : "";
9092 #ifdef COMMENT
9093 /* No longer necessary because evalx() no longer overwrites its */
9094 /* result every time it's called (2000/09/23). */
9095 free(bp[0]);
9096 bp[0] = NULL;
9097 #endif /* COMMENT */
9098 if (argn > 1) {
9099 #ifdef COMMENT
9100 /* Ditto... */
9101 bp[0] = malloc((int)strlen(val1)+1);
9102 if (bp[0])
9103 strcpy(bp[0],val1); /* safe */
9104 val1 = bp[0];
9105 #endif /* COMMENT */
9106 val2 = *(bp[1]) ? evalx(bp[1]) : "";
9107 if (chknum(val1) && chknum(val2)) {
9108 i = atoi(val1);
9109 j = atoi(val2);
9110 switch (y) {
9111 case FN_MAX:
9112 if (j < i) j = i;
9113 break;
9114 case FN_MIN:
9115 if (j > i) j = i;
9116 break;
9117 case FN_MOD:
9118 if (j == 0) {
9119 failed = 1;
9120 if (fndiags)
9121 ckmakmsg(fnval,FNVALL,
9122 "<ERROR:DIVIDE_BY_ZERO:\\f",fn,"()>",NULL);
9123 else
9124 fnval[0] = NUL;
9125 goto fnend;
9126 } else
9127 j = i % j;
9128 }
9129 p = fnval;
9130 sprintf(p,"%d",j); /* SAFE */
9131 } else {
9132 failed = 1;
9133 evalerr(fn);
9134 }
9135 } else p = val1;
9136 goto fnend;
9137 } /* Break up big switch... */
9138
9139 switch (y) {
9140 case FN_SUB: /* \fsubstr(arg1,arg2,arg3) */
9141 case FN_RIG: /* \fright(arg1,arg2) */
9142 case FN_LEF: /* \fleft(arg1,arg2) */
9143 if (argn < 1)
9144 goto fnend;
9145 val1 = "";
9146 if (argn > 1)
9147 if (*(bp[1]))
9148 val1 = evalx(bp[1]);
9149 #ifdef COMMENT
9150 if (bp[1]) free(bp[1]); /* Have to copy this */
9151 bp[1] = malloc((int)strlen(val1)+1);
9152 if (!bp[1]) {
9153 failed = 1;
9154 if (fndiags) {
9155 p = fnval;
9156 ckmakmsg(fnval,FNVALL,
9157 "<ERROR:MALLOC_FAILURE:\\f",fn,"()>",NULL);
9158 }
9159 goto fnend;
9160 }
9161 strcpy(bp[1],val1); /* safe */
9162 val1 = bp[1];
9163 #endif /* COMMENT */
9164 val2 = "";
9165 if (argn > 2)
9166 if (*(bp[2]))
9167 val2 = evalx(bp[2]);
9168 if (
9169 ((argn > 1) && (int)strlen(val1) && !rdigits(val1)) ||
9170 ((cx == FN_SUB) &&
9171 ((argn > 2) && (int)strlen(val2) && !rdigits(val2)))
9172 ) {
9173 failed = 1;
9174 evalerr(fn);
9175 } else {
9176 int lx;
9177 p = fnval; /* pointer to result */
9178 lx = strlen(bp[0]); /* length of arg1 */
9179 if (cx == FN_SUB) { /* substring */
9180 k = (argn > 2) ? atoi(val2) : MAXARGLEN; /* length */
9181 j = (argn > 1) ? atoi(val1) : 1; /* start pos for substr */
9182 } else if (cx == FN_LEF) { /* left */
9183 k = (argn > 1) ? atoi(val1) : lx;
9184 j = 1;
9185 } else { /* right */
9186 k = (argn > 1) ? atoi(val1) : lx; /* length */
9187 j = lx - k + 1; /* start pos for right */
9188 if (j < 1) j = 1;
9189 }
9190 if (k > 0 && j <= lx) { /* if start pos in range */
9191 s = bp[0]+j-1; /* point to source string */
9192 for (i = 0; (i < k) && (*p++ = *s++); i++) ; /* copy */
9193 }
9194 *p = NUL; /* terminate the result */
9195 p = fnval; /* and point to it. */
9196 }
9197 goto fnend;
9198
9199 case FN_UPP: /* \fupper(arg1) */
9200 s = bp[0] ? bp[0] : "";
9201 p = fnval;
9202 while (*s) {
9203 if (islower(*s))
9204 *p = (char) toupper(*s);
9205 else
9206 *p = *s;
9207 p++; s++;
9208 }
9209 *p = NUL;
9210 p = fnval;
9211 goto fnend;
9212
9213 case FN_REP: /* \frepeat(text,number) */
9214 if (argn < 1)
9215 goto fnend;
9216 val1 = "1";
9217 if (argn > 1)
9218 if (*(bp[1]))
9219 val1 = evalx(bp[1]);
9220 if (chknum(val1)) { /* Repeat count */
9221 n = atoi(val1);
9222 debug(F111,"SUNDAY frepeat n",val1,n);
9223 if (n > 0) { /* Make n copies */
9224 p = fnval;
9225 *p = '\0';
9226 k = (int)strlen(bp[0]); /* Make sure string has some length */
9227 debug(F111,"SUNDAY frepeat k","",k);
9228 debug(F111,"SUNDAY frepeat FNVALL","",FNVALL);
9229 if (k * n >= FNVALL) { /* But not too much... */
9230 failed = 1;
9231 if (fndiags)
9232 ckmakmsg(fnval,FNVALL,
9233 "<ERROR:RESULT_TOO_LONG:\\f",fn,"()>",NULL);
9234 else
9235 fnval[0] = NUL;
9236 p = fnval;
9237 goto fnend;
9238 }
9239 if (k > 0) { /* If there is something to copy */
9240 for (i = 0; i < n; i++) { /* Copy loop */
9241 s = bp[0];
9242 for (j = 0; j < k; j++) {
9243 if ((p - fnval) >= FNVALL)
9244 break; /* shouldn't happen... */
9245 else
9246 *p++ = *s++;
9247 }
9248 }
9249 *p = NUL;
9250 }
9251 }
9252 } else {
9253 failed = 1;
9254 evalerr(fn);
9255 }
9256 p = fnval;
9257 goto fnend;
9258
9259 #ifndef NOFRILLS
9260 case FN_REV: /* \freverse() */
9261 if (argn < 1)
9262 goto fnend;
9263 yystring(bp[0],&p);
9264 goto fnend;
9265 #endif /* NOFRILLS */
9266
9267 case FN_RPA: /* \frpad() and \flpad() */
9268 case FN_LPA:
9269 if (argn < 1)
9270 goto fnend;
9271 val1 = "";
9272 if (argn > 1)
9273 if (*(bp[1]))
9274 val1 = evalx(bp[1]);
9275 if (argn == 1) { /* If a number wasn't given */
9276 p = fnval; /* just return the original string */
9277 ckstrncpy(p,bp[0],FNVALL);
9278 } else if (argn > 1 && !*val1) {
9279 failed = 1;
9280 evalerr(fn);
9281 } else /* if (chknum(val1)) */ { /* Repeat count */
9282 char pc;
9283 n = atoi(val1);
9284 if (n >= 0) {
9285 p = fnval;
9286 k = (int)strlen(bp[0]); /* Length of string to be padded */
9287 if (k >= n) { /* It's already long enough */
9288 ckstrncpy(p,bp[0],FNVALL);
9289 } else {
9290 if (n + k <= FNVALL) {
9291 pc = (char) ((argn < 3) ? SP : *bp[2]);
9292 if (!pc) pc = SP;
9293 if (cx == FN_RPA) { /* RPAD */
9294 strncpy(p,bp[0],k); /* (leave it like this) */
9295 p[k] = NUL;
9296 p += k;
9297 for (i = k; i < n; i++)
9298 *p++ = pc;
9299 } else { /* LPAD */
9300 n -= k;
9301 for (i = 0; i < n; i++)
9302 *p++ = pc;
9303 strncpy(p,bp[0],k); /* (leave it like this) */
9304 p[k] = NUL;
9305 p += k;
9306 }
9307 }
9308 *p = NUL;
9309 }
9310 }
9311 }
9312 p = fnval;
9313 goto fnend;
9314
9315 #ifdef ZFCDAT
9316 case FN_FD: /* \fdate(filename) */
9317 p = fnval;
9318 s = zfcdat(bp[0]);
9319 if (!s) s = "";
9320 if (!*s) {
9321 failed = 1;
9322 if (fndiags)
9323 ckmakmsg(fnval,FNVALL,"<ERROR:FILE_NOT_FOUND:\\f",fn,"()>",NULL);
9324 goto fnend;
9325 }
9326 ckstrncpy(fnval,s,FNVALL);
9327 #endif /* ZFCDAT */
9328 goto fnend;
9329
9330 } /* Break up big switch... */
9331
9332 switch (y) {
9333 case FN_FS: { /* \fsize(filename) */
9334 CK_OFF_T z;
9335 p = fnval;
9336 z = zchki(bp[0]);
9337 if (z < (CK_OFF_T)0) {
9338 failed = 1;
9339 if (fndiags) {
9340 if (z == (CK_OFF_T)-1)
9341 ckmakmsg(fnval,FNVALL,
9342 "<ERROR:FILE_NOT_FOUND:\\f",fn,"()>",NULL);
9343 else if (z == (CK_OFF_T)-2)
9344 ckmakmsg(fnval,FNVALL,
9345 "<ERROR:FILE_NOT_READABLE:\\f",fn,"()>",NULL);
9346 else if (z == (CK_OFF_T)-3)
9347 ckmakmsg(fnval,FNVALL,
9348 "<ERROR:FILE_NOT_ACCESSIBLE:\\f",fn,"()>",NULL);
9349 else
9350 ckmakmsg(fnval,FNVALL,
9351 "<ERROR:FILE_ERROR:\\f",fn,"()>",NULL);
9352 }
9353 goto fnend;
9354 }
9355 ckstrncpy(fnval,ckfstoa(z),FNVALL);
9356 goto fnend;
9357 }
9358 case FN_VER: /* \fverify() */
9359 p = "-1";
9360 if (argn == 1) /* No second arg */
9361 goto fnend;
9362 else if (!bp[1]) /* Or second arg null */
9363 goto fnend;
9364 else if (!*(bp[1])) /* or empty. */
9365 goto fnend;
9366 p = "0";
9367 if (argn > 1) { /* Only works if we have 2 or 3 args */
9368 int start;
9369 char *s2, ch1, ch2;
9370 start = 0;
9371 if (argn > 2) { /* Starting position specified */
9372 val1 = *(bp[2]) ? evalx(bp[2]) : "0";
9373 if (chknum(val1)) {
9374 start = atoi(val1) /* - 1 */;
9375 if (start < 0) start = 0;
9376 if (start > (int)strlen(bp[1]))
9377 goto verfin;
9378 } else {
9379 failed = 1;
9380 evalerr(fn);
9381 goto fnend;
9382 }
9383 }
9384 i = start;
9385 p = "0";
9386 for (s = bp[1] + start; *s; s++,i++) {
9387 ch1 = *s;
9388 if (!inpcas[cmdlvl]) if (islower(ch1)) ch1 = toupper(ch1);
9389 j = 0;
9390 for (s2 = bp[0]; *s2; s2++) {
9391 ch2 = *s2;
9392 if (!inpcas[cmdlvl]) if (islower(ch2)) ch2 = toupper(ch2);
9393 if (ch1 == ch2) {
9394 j = 1;
9395 break;
9396 }
9397 }
9398 if (j == 0) {
9399 sprintf(fnval,"%d",i+1); /* SAFE */
9400 p = fnval;
9401 break;
9402 }
9403 }
9404 }
9405 verfin:
9406 goto fnend;
9407
9408 case FN_IPA: /* Find and return IP address */
9409 if (argn > 0) { /* in argument string. */
9410 int start = 0;
9411 if (argn > 1) { /* Starting position specified */
9412 if (chknum(bp[1])) {
9413 start = atoi(bp[1]) - 1;
9414 if (start < 0) start = 0;
9415 } else {
9416 failed = 1;
9417 if (fndiags)
9418 ckmakmsg(fnval,FNVALL,
9419 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
9420 goto fnend;
9421 }
9422 }
9423 p = getip(bp[0]+start);
9424 } else p = "";
9425 goto fnend;
9426
9427 #ifdef OS2
9428 case FN_CRY:
9429 p = "";
9430 if (argn > 0) {
9431 p = fnval;
9432 ckstrncpy(p,bp[0],FNVALL);
9433 ck_encrypt(p);
9434 }
9435 goto fnend;
9436
9437 case FN_OOX:
9438 p = "";
9439 if (argn > 0)
9440 p = (char *) ck_oox(bp[0], (argn > 1) ? bp[1] : "");
9441 goto fnend;
9442 #endif /* OS2 */
9443
9444 case FN_HEX: /* \fhexify(arg1) */
9445 if (argn < 1)
9446 goto fnend;
9447 if ((int)strlen(bp[0]) < (FNVALL / 2)) {
9448 s = bp[0];
9449 p = fnval;
9450 while (*s) {
9451 x = (*s >> 4) & 0x0f;
9452 *p++ = hexdigits[x];
9453 x = *s++ & 0x0f;
9454 *p++ = hexdigits[x];
9455 }
9456 *p = NUL;
9457 p = fnval;
9458 }
9459 goto fnend;
9460
9461 case FN_UNTAB: /* \funtab(arg1) */
9462 if (argn < 1)
9463 goto fnend;
9464 if ((int)strlen(bp[0]) < (FNVALL * 2)) {
9465 s = bp[0];
9466 p = fnval;
9467 if (untabify(bp[0],p,FNVALL) < 0) {
9468 failed = 1;
9469 if (fndiags)
9470 ckmakmsg(fnval,FNVALL,
9471 "<ERROR:OVERFLOW:\\f",fn,"()>",NULL);
9472 }
9473 goto fnend;
9474 }
9475
9476 case FN_UNH: { /* \funhex(arg1) */
9477 int c[2], i;
9478 if (argn < 1)
9479 goto fnend;
9480 if ((int)strlen(bp[0]) < (FNVALL * 2)) {
9481 s = bp[0];
9482 p = fnval;
9483 while (*s) {
9484 for (i = 0; i < 2; i++) {
9485 c[i] = *s++;
9486 if (!c[i]) { p = ""; goto unhexfin; }
9487 if (islower(c[i])) c[i] = toupper(c[i]);
9488 if (c[i] >= '0' && c[i] <= '9') {
9489 c[i] -= 0x30;
9490 } else if (c[i] >= 'A' && c[i] <= 'F') {
9491 c[i] -= 0x37;
9492 } else {
9493 failed = 1;
9494 if (fndiags)
9495 ckmakmsg(fnval,
9496 FNVALL,
9497 "<ERROR:ARG_OUT_OF_RANGE:\\f",
9498 fn,
9499 "()>",
9500 NULL
9501 );
9502 goto fnend;
9503 }
9504 }
9505 *p++ = ((c[0] << 4) & 0xf0) | (c[1] & 0x0f);
9506 }
9507 *p = NUL;
9508 p = fnval;
9509 }
9510 unhexfin:
9511 goto fnend;
9512 }
9513
9514 case FN_BRK: { /* \fbreak() */
9515 char * c; /* Characters to break on */
9516 char c2, s2;
9517 int start = 0;
9518 int done = 0;
9519 if (argn < 1)
9520 goto fnend;
9521 if (argn > 2) {
9522 s = bp[2] ? bp[2] : "0";
9523 if (chknum(s)) {
9524 start = atoi(s);
9525 if (start < 0) start = 0;
9526 if (start > (int)strlen(bp[0]))
9527 goto brkfin;
9528 } else {
9529 failed = 1;
9530 if (fndiags)
9531 ckmakmsg(fnval,FNVALL,
9532 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
9533 goto fnend;
9534 }
9535 }
9536 s = bp[0] + start; /* Source pointer */
9537
9538 while (*s && !done) {
9539 s2 = *s;
9540 if (!inpcas[cmdlvl] && islower(s2)) s2 = toupper(s2);
9541 c = bp[1] ? bp[1] : ""; /* Character to break on */
9542 while (*c) {
9543 c2 = *c;
9544 if (!inpcas[cmdlvl] && islower(c2)) c2 = toupper(c2);
9545 if (c2 == s2) {
9546 done = 1;
9547 break;
9548 }
9549 c++;
9550 }
9551 if (done) break;
9552 *p++ = *s++;
9553 }
9554 *p = NUL; /* terminate the result */
9555 p = fnval; /* and point to it. */
9556 brkfin:
9557 goto fnend;
9558 }
9559
9560 case FN_SPN: { /* \fspan() */
9561 char *q;
9562 char c1, c2;
9563 int start = 0;
9564 if (argn < 1)
9565 goto fnend;
9566 if (argn > 2) { /* Starting position */
9567 s = bp[2] ? bp[2] : "0";
9568 if (chknum(s)) {
9569 start = atoi(s);
9570 if (start < 0) start = 0;
9571 } else {
9572 failed = 1;
9573 if (fndiags)
9574 ckmakmsg(fnval,FNVALL,
9575 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
9576 goto fnend;
9577 }
9578 }
9579 s = bp[0] + start; /* Source pointer */
9580 if (argn > 1 &&
9581 (int)strlen(bp[1]) > 0 &&
9582 start <= (int)strlen(bp[0])) {
9583 while (*s) { /* Loop thru source string */
9584 q = bp[1]; /* Span string */
9585 c1 = *s;
9586 if (!inpcas[cmdlvl])
9587 if (islower(c1)) c1 = toupper(c1);
9588 x = 0;
9589 while ((c2 = *q++)) {
9590 if (!inpcas[cmdlvl])
9591 if (islower(c2)) c2 = toupper(c2);
9592 if (c1 == c2) { x = 1; break; }
9593 }
9594 if (!x) break;
9595 *p++ = *s++;
9596 }
9597 *p = NUL; /* Terminate and return the result */
9598 p = fnval;
9599 }
9600 goto fnend;
9601 }
9602 } /* Break up big switch... */
9603
9604 switch (y) {
9605 case FN_TRM: /* \ftrim(s1[,s2]) */
9606 case FN_LTR: /* \fltrim(s1[,s2]) */
9607 if (argn < 1)
9608 goto fnend;
9609 if ((len1 = (int)strlen(bp[0])) > 0) {
9610 if (len1 > FNVALL)
9611 len1 = FNVALL;
9612 s = " \t\r\n";
9613 if (argn > 1) /* Trim list given */
9614 s = bp[1];
9615 len2 = (int)strlen(s);
9616 if (len2 < 1) { /* or not... */
9617 s = " \t\r\n"; /* Default is to trim whitespace */
9618 len2 = 2;
9619 }
9620 if (cx == FN_TRM) { /* Trim from right */
9621 char * q, p2, q2;
9622 ckstrncpy(fnval,bp[0],FNVALL); /* Copy string to output */
9623 p = fnval + len1 - 1; /* Point to last character */
9624
9625 while (p >= (char *)fnval) { /* Go backwards */
9626 q = s; /* Point to trim list */
9627 p2 = *p;
9628 if (!inpcas[cmdlvl])
9629 if (islower(p2)) p2 = toupper(p2);
9630 while (*q) { /* Is this char in trim list? */
9631 q2 = *q;
9632 if (!inpcas[cmdlvl])
9633 if (islower(q2)) q2 = toupper(q2);
9634 if (p2 == q2) { /* Yes, null it out */
9635 *p = NUL;
9636 break;
9637 }
9638 q++;
9639 }
9640 if (!*q) /* Trim list exhausted */
9641 break; /* So we're done. */
9642 p--; /* Else keep trimming */
9643 }
9644 } else { /* Trim from left */
9645 char * q, p2, q2;
9646 p = bp[0]; /* Source */
9647 while (*p) {
9648 p2 = *p;
9649 if (!inpcas[cmdlvl])
9650 if (islower(p2)) p2 = toupper(p2);
9651 q = s;
9652 while (*q) { /* Is this char in trim list? */
9653 q2 = *q;
9654 if (!inpcas[cmdlvl])
9655 if (islower(q2)) q2 = toupper(q2);
9656 if (p2 == q2) { /* Yes, point past it */
9657 p++; /* and try next source character */
9658 break;
9659 }
9660 q++; /* No, try next trim character */
9661 }
9662 if (!*q) /* Trim list exhausted */
9663 break; /* So we're done. */
9664 }
9665 ckstrncpy(fnval,p,FNVALL);
9666 }
9667 p = fnval;
9668 } else p = "";
9669 goto fnend;
9670
9671 case FN_CAP: /* \fcapitalize(arg1) */
9672 if (argn < 1)
9673 goto fnend;
9674 s = bp[0];
9675 p = fnval;
9676 x = 0;
9677 while ((c = *s++)) {
9678 if (isalpha(c)) {
9679 if (x == 0) {
9680 x = 1;
9681 if (islower(c))
9682 c = toupper(c);
9683 } else if (isupper(c))
9684 c = tolower(c);
9685 }
9686 *p++ = c;
9687 }
9688 *p = NUL;
9689 p = fnval;
9690 goto fnend;
9691
9692 #ifdef COMMENT
9693 case FN_TOD: /* Time of day to secs since midnite */
9694 sprintf(fnval,"%ld",tod2sec(bp[0])); /* SAFE */
9695 goto fnend;
9696 #endif /* COMMENT */
9697
9698 case FN_FFN: /* Full pathname of file */
9699 zfnqfp(bp[0],FNVALL,p);
9700 if (!p) p = "";
9701 goto fnend;
9702
9703 case FN_CHK: { /* \fchecksum() */
9704 long chk = 0;
9705 p = (argn > 0) ? bp[0] : "";
9706 while (*p) chk += *p++;
9707 sprintf(fnval,"%lu",chk); /* SAFE */
9708 p = fnval;
9709 goto fnend;
9710 }
9711
9712 #ifndef NOXFER
9713 case FN_CRC: /* \fcrc16() */
9714 if (argn > 0)
9715 sprintf(fnval,"%u", /* SAFE */
9716 chk3((CHAR *)bp[0],(int)strlen(bp[0])));
9717 else
9718 p = "0";
9719 goto fnend;
9720 #endif /* NOXFER */
9721
9722 case FN_BSN: /* \fbasename() */
9723 zstrip(bp[0],&p);
9724 goto fnend;
9725
9726 #ifndef NOLOCAL
9727 #ifdef OS2
9728 case FN_SCRN_CX: /* \fscrncurx() */
9729 p = fnval;
9730 sprintf(p,"%d",(int)VscrnGetCurPos(VTERM)->x); /* SAFE */
9731 goto fnend;
9732
9733 case FN_SCRN_CY: /* \fscrncury() */
9734 p = fnval;
9735 sprintf(p,"%d",(int)VscrnGetCurPos(VTERM)->y); /* SAFE */
9736 goto fnend;
9737
9738 case FN_SCRN_STR: { /* \fscrnstr() */
9739 videoline * line = NULL;
9740 viocell * cells = NULL;
9741 int row = 0, col = 0, len = 0;
9742 /* NOTE: On Unicode systems, the screen contents are stored in */
9743 /* in Unicode. Therefore, we should really be performing a */
9744 /* conversion to the local character set. */
9745
9746 /* 6/18/2000 - added the translation to lcs */
9747
9748 if (bp[0] == NULL || bp[0][0] == '\0') {
9749 row = 0;
9750 } else {
9751 if (chknum(bp[0])) {
9752 row = atoi(bp[0]);
9753 if (row < 0)
9754 row = 0;
9755 } else {
9756 failed = 1;
9757 if (fndiags)
9758 ckmakmsg(fnval,FNVALL,
9759 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
9760 goto fnend;
9761 }
9762 }
9763 line = VscrnGetLineFromTop( VTERM, (USHORT) row );
9764 if (line != NULL) {
9765 if (bp[1] == NULL || bp[1][0] == '\0')
9766 col = 0;
9767 else {
9768 if (chknum(bp[0])) {
9769 col = atoi(bp[1]);
9770 if (col < 0 || col >= line->width)
9771 col = 0;
9772 } else {
9773 failed = 1;
9774 if (fndiags)
9775 ckmakmsg(fnval,FNVALL,
9776 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
9777 goto fnend;
9778 }
9779 }
9780 if (bp[2] == NULL || bp[2][0] == '\0') {
9781 len = line->width - (col+1);
9782 } else {
9783 if (!chknum(bp[2])) {
9784 failed = 1;
9785 if (fndiags)
9786 ckmakmsg(fnval,FNVALL,
9787 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
9788 goto fnend;
9789 }
9790 len = atoi(bp[2]);
9791 if (len < 0 || len > line->width)
9792 len = line->width;
9793 }
9794 cells = line->cells;
9795 for (i = 0; i < len; i++) {
9796 int pos = i + col;
9797 if (pos < line->width) {
9798 if (isunicode())
9799 fnval[i] = (CHAR) utolxlat(cells[pos].c);
9800 else
9801 fnval[i] = (CHAR) (cells[pos].c & 0xFF);
9802 if (fnval[i] == 0)
9803 fnval[i] = SP;
9804 } else
9805 fnval[i] = SP;
9806 }
9807 fnval[i] = '\0';
9808 } else {
9809 fnval[0] = '\0';
9810 }
9811 p = fnval;
9812 goto fnend;
9813 }
9814 #endif /* OS2 */
9815 #endif /* NOLOCAL */
9816
9817 #ifndef NOPUSH
9818 case FN_RAW: /* \frawcommand() */
9819 case FN_CMD: { /* \fcommand() */
9820 int x, c, n = FNVALL;
9821 x = 0; /* Completion flag */
9822 /*
9823 ZIFILE can be safely used because we can't possibly be transferring a file
9824 while executing this function.
9825 */
9826 if (!nopush && zxcmd(ZIFILE,bp[0]) > 0) { /* Open the command */
9827 while (n-- > -1) { /* Read from it */
9828 if ((c = zminchar()) < 0) {
9829 x = 1; /* EOF - set completion flag */
9830 if (cx == FN_CMD) { /* If not "rawcommand" */
9831 p--; /* remove trailing newlines */
9832 while (*p == CR || *p == LF)
9833 p--;
9834 p++;
9835 }
9836 *p = NUL; /* Terminate the string */
9837 break;
9838 } else /* Command still running */
9839 *p++ = c; /* Copy the bytes */
9840 }
9841 zclose(ZIFILE); /* Close the command */
9842 }
9843 /* Return null string if command's output was too long. */
9844 p = fnval;
9845 if (!x) {
9846 failed = 1;
9847 if (fndiags)
9848 ckmakmsg(fnval,FNVALL,
9849 "<ERROR:RESULT_TOO_LONG:\\f",fn,"()>",NULL);
9850 }
9851 goto fnend;
9852 }
9853 #endif /* NOPUSH */
9854 } /* Break up big switch... */
9855
9856 switch (y) {
9857 case FN_STX: /* \fstripx(string,c) */
9858 if (!(s = bp[0])) /* Make sure there is a string */
9859 goto fnend;
9860 c = '.'; /* Character to strip from */
9861 if (argn > 1) if (*bp[1]) c = *bp[1];
9862 n = ckstrncpy(fnval,bp[0],FNVALL);
9863 while (--n >= 0) {
9864 if (fnval[n] == c) {
9865 fnval[n] = NUL;
9866 break;
9867 }
9868 }
9869 p = fnval;
9870 goto fnend;
9871
9872 case FN_STL: /* \flop(string,c) */
9873 case FN_LOPX: { /* \flopx(string,c) */
9874 int n = 1;
9875 if (!(s = bp[0])) /* Make sure there is a string */
9876 goto fnend;
9877 c = '.'; /* Character to strip to */
9878 if (argn > 1) if (*bp[1]) c = *bp[1];
9879 if (argn > 2) if (*bp[2]) {
9880 #ifndef NOFLOAT
9881 n = 0;
9882 if (isfloat(bp[2],0)) {
9883 n = (int)floatval;
9884 if (n < 0) n = 0;
9885 } else
9886 #endif /* NOFLOAT */
9887 n = atoi(bp[2]);
9888 }
9889 x = 0;
9890 if (cx == FN_LOPX) { /* Lopx (from right) */
9891 if (n == 0)
9892 goto fnend;
9893 s += strlen(s) - 1; /* We already know it's > 0 */
9894 while (s-- >= bp[0]) {
9895 if (*s == c) {
9896 n--;
9897 if (n == 0) {
9898 s++;
9899 x = 1;
9900 break;
9901 }
9902 }
9903 }
9904 if (!x) s = "";
9905 } else { /* Lop (from left) */
9906 if (n == 0) {
9907 p = bp[0];
9908 goto fnend;
9909 }
9910 while (*s++) {
9911 if (*(s-1) == c) {
9912 if (--n == 0) {
9913 x = 1;
9914 break;
9915 }
9916 }
9917 }
9918 if (!x) s = bp[0];
9919 }
9920 ckstrncpy(fnval,s,FNVALL);
9921 p = fnval;
9922 goto fnend;
9923 }
9924 case FN_STN: /* \fstripn(string,n) */
9925 if (argn < 1) /* Remove n chars from right */
9926 goto fnend;
9927 val1 = "0";
9928 if (argn > 1)
9929 if (*(bp[1]))
9930 val1 = evalx(bp[1]);
9931 if (!chknum(val1)) {
9932 failed = 1;
9933 evalerr(fn);
9934 goto fnend;
9935 }
9936 n = atoi(val1);
9937 if (n < 0) n = 0;
9938 k = (int)strlen(s = bp[0]) - n;
9939 if (k < 0) k = 0;
9940 p = fnval;
9941 while (k-- > 0)
9942 *p++ = *s++;
9943 *p = NUL;
9944 p = fnval;
9945 goto fnend;
9946
9947 case FN_STB: { /* \fstripb(string,c) */
9948 char c2 = NUL;
9949 int i, k = 0;
9950 char * gr_opn = "\"{'([<"; /* Group open brackets */
9951 char * gr_cls = "\"}')]>"; /* Group close brackets */
9952
9953 p = fnval;
9954 *p = NUL;
9955 if (!(s = bp[0])) /* Make sure there is a string */
9956 goto fnend;
9957 if ((x = strlen(s)) < 1)
9958 goto fnend;
9959 c = NUL; /* Brace/bracket kind */
9960 if (argn > 1) {
9961 if (*bp[1]) {
9962 if (chknum(bp[1])) {
9963 k = atoi(bp[1]);
9964 if (k < 0) k = 63;
9965 for (i = 0; i < 6; i++) {
9966 if (k & (1<<i)) {
9967 if (s[0] == gr_opn[i] && s[x-1] == gr_cls[i]) {
9968 ckstrncpy(fnval,s+1,FNVALL);
9969 fnval[x-2] = NUL;
9970 goto fnend;
9971 }
9972 }
9973 }
9974 ckstrncpy(fnval,s,FNVALL); /* No match */
9975 goto fnend;
9976 }
9977 }
9978 }
9979 c = !bp[1] ? 0 : *bp[1];
9980 if (!c) c = s[0];
9981 if (argn > 2) if (*bp[2]) c2 = *bp[2];
9982 if (*s == c) {
9983 if (!c2) {
9984 switch (c) {
9985 case '(': c2 = ')'; break;
9986 case '[': c2 = ']'; break;
9987 case '{': c2 = '}'; break;
9988 case '<': c2 = '>'; break;
9989 case '"': c2 = '"'; break;
9990 case 39: c2 = 39; break;
9991 case 96: c2 = 39; break;
9992 default:
9993 if (argn == 2) {
9994 c2 = c;
9995 } else {
9996 strncpy(fnval,s,x); /* Leave it like this */
9997 fnval[x] = NUL;
9998 goto fnend;
9999 }
10000 }
10001 }
10002 if (s[x-1] == c2) {
10003 strncpy(fnval,s+1,x-2); /* Leave it like this */
10004 fnval[x-2] = NUL;
10005 goto fnend;
10006 }
10007 }
10008 strncpy(fnval,s,x);
10009 fnval[x] = NUL;
10010 goto fnend;
10011 }
10012
10013 case FN_2HEX: /* Number to hex */
10014 case FN_2OCT: /* Number to octal */
10015 val1 = evalx(bp[0]);
10016 if (!*val1) {
10017 failed = 1;
10018 evalerr(fn);
10019 goto fnend;
10020 }
10021 sprintf(fnval, cx == FN_2HEX ? "%lx" : "%lo", atol(val1)); /* SAFE */
10022 if (cx == FN_2HEX && (int)(strlen(fnval)&1))
10023 sprintf(fnval,"0%lx",atol(val1)); /* SAFE */
10024 p = fnval;
10025 goto fnend;
10026
10027 case FN_DNAM: { /* Directory part of file name */
10028 char *s;
10029 zfnqfp(bp[0],FNVALL,p); /* Get full name */
10030 if (!isdir(p)) { /* Is it already a directory? */
10031 zstrip(p,&s); /* No get basename */
10032 if (*s) {
10033 x = ckindex(s,p,0,0,0); /* Pos of latter in former */
10034 if (x > 0) p[x-1] = NUL;
10035 }
10036 }
10037 if (!p) p = "";
10038 goto fnend;
10039 }
10040
10041 #ifndef NORANDOM
10042 case FN_RAND: /* Random number */
10043 #ifdef CK_SSL
10044 if (RAND_bytes((unsigned char *)&k,sizeof(k)) < 0)
10045 #endif /* CK_SSL */
10046 k = rand();
10047 x = 0;
10048 if (argn > 0) {
10049 if (!chknum(bp[0])) {
10050 failed = 1;
10051 if (fndiags)
10052 ckmakmsg(fnval,FNVALL,
10053 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
10054 goto fnend;
10055 }
10056 x = atoi(bp[0]);
10057 }
10058 #ifdef COMMENT
10059 sprintf(fnval,"%d", (x > 0 && k > 0) || (x < 0 && k < 0) ? k % x :
10060 (x == 0 ? 0 : (0 - (k % (-x)))));
10061 #else
10062 debug(F111,"rand",ckitoa(x),k);
10063 #ifdef SUNOS4
10064 /* This is really strange but on SunOS, if we are requesting random numbers */
10065 /* between 0 and 4 or less, they always come out in sequence: 0 1 2 3 0 1 2 */
10066 /* Shifting the result of rand() in this case gives a more random result. */
10067 if (x < 5)
10068 k = k >> 5;
10069 #endif /* SUNOS4 */
10070 if ((x > 0 && k > 0) || (x < 0 && k < 0))
10071 x = k % x;
10072 else if (x == 0)
10073 x = 0;
10074 else
10075 x = 0 - (k % (-x));
10076 debug(F101,"rand x","",x);
10077 sprintf(fnval,"%d", x); /* SAFE */
10078 #endif /* COMMENT */
10079 p = fnval;
10080 goto fnend;
10081 #endif /* NORANDOM */
10082 } /* Break up big switch... */
10083
10084 switch (y) {
10085 case FN_SPLIT: /* \fsplit(s1,a,s2,s3,mask) */
10086 case FN_WORD: { /* \fword(s1,n,s2,s3,mask) */
10087 int wordnum = 0;
10088 int splitting = 0;
10089 int x;
10090 int array = 0;
10091 int grouping = 0;
10092 int nocollapse = 0;
10093 char * sep = "";
10094 char * notsep = "";
10095 char * bp0 = NULL;
10096 char * bp1 = NULL;
10097 char abuf[16];
10098 struct stringarray * q = NULL;
10099
10100 splitting = (cx == FN_SPLIT); /* Our job */
10101 debug(F101,"FN_SPLIT splitting","",splitting);
10102
10103 fnval[0] = splitting ? '0' : NUL; /* Initial return value */
10104 fnval[1] = NUL;
10105 p = fnval;
10106 bp0 = bp[0]; /* Source string */
10107 if (!bp0) bp0 = "";
10108 debug(F111,"fsplit bp[0]",bp0,argn);
10109 if (argn < 1 || !*bp0) /* If none, return default value */
10110 goto fnend;
10111
10112 bp1 = bp[1]; /* Function-dependent arg */
10113 if (!bp1) bp1 = ""; /* (array or number) */
10114 debug(F110,"fsplit bp[1]",bp1,0);
10115 if (bp[5]) {
10116 if (!chknum(bp[5])) {
10117 failed = 1;
10118 ckmakmsg(fnval,FNVALL,
10119 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
10120 goto fnend;
10121 }
10122 x = atoi(bp[5]);
10123 nocollapse = x;
10124 }
10125 if (!splitting) { /* \fword(): n = desired word number */
10126 val1 = "1"; /* Default is first word */
10127 if (argn > 1) /* Word number supplied */
10128 if (*bp1)
10129 val1 = evalx(bp1);
10130 if (!chknum(val1)) {
10131 failed = 1;
10132 ckmakmsg(fnval,FNVALL,
10133 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
10134 goto fnend;
10135 }
10136 n = atoi(val1);
10137 } else if (argn > 1 && *bp1) { /* \fsplit(): n = word count */
10138 ckstrncpy(abuf,bp1,16); /* Get array reference */
10139 debug(F110,"fsplit abuf 1",abuf,0);
10140 failed = 1; /* Assume it's bad */
10141 if (fndiags) /* Default is this error message */
10142 ckmakmsg(fnval,FNVALL,
10143 "<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
10144 if (abuf[0] != '&') /* "Address" of array */
10145 goto fnend; /* It's bad */
10146 if (abuf[2]) { /* Check for brackets */
10147 if (abuf[2] != '[' || abuf[3] != ']') {
10148 goto fnend; /* Bad */
10149 }
10150 }
10151 debug(F110,"fsplit abuf 2",abuf,0);
10152 if (abuf[1] > 64 && abuf[1] < 91) /* Convert upper to lower */
10153 abuf[1] += 32;
10154 if (abuf[1] < 97 || abuf[1] > 122) { /* Check for a-z */
10155 goto fnend;
10156 }
10157 debug(F110,"fsplit abuf 3",abuf,0);
10158 array = 1;
10159 fnval[0] = NUL; /* No error, erase message */
10160 failed = 0; /* Unset failure flag */
10161 n = 0; /* Initialize word counter */
10162 }
10163 if (argn > 2) /* Have break set? */
10164 sep = bp[2];
10165 debug(F111,"fsplit sep",sep,argn);
10166 if (argn > 3) /* Have include set? */
10167 notsep = bp[3];
10168 debug(F111,"fsplit notsep",notsep,argn);
10169 if (argn > 4) { /* Have grouping set? */
10170 char * bp4 = bp[4];
10171 debug(F111,"fsplit bp4",bp4,argn);
10172 if (!bp4) bp4 = "0";
10173 if (!*bp4) bp4 = "0";
10174 if (chknum(bp4)) {
10175 grouping = atoi(bp4);
10176 if (grouping == -1)
10177 grouping = 127;
10178 } else {
10179 failed = 1;
10180 if (fndiags)
10181 ckmakmsg(fnval,FNVALL,
10182 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
10183 goto fnend;
10184 }
10185 }
10186 /* Args parsed, now do the work */
10187
10188 debug(F111,"fsplit bp0",bp0,n);
10189 q = cksplit(splitting,n,bp0,sep,notsep,grouping,0,nocollapse,0);
10190
10191 wordnum = q ? q->a_size : -1; /* Check result */
10192 if (wordnum < 0) {
10193 failed = 1; /* Failure */
10194 if (fndiags)
10195 ckmakmsg(fnval,FNVALL,
10196 (wordnum == -1) ?
10197 "<ERROR:MALLOC_FAILURE:\\f" :
10198 "<ERROR:TOO_MANY_WORDS:\\f",
10199 fn,
10200 "()>",
10201 NULL
10202 );
10203 goto fnend;
10204 }
10205 if (splitting) { /* \fsplit() result */
10206 ckstrncpy(fnval,ckitoa(wordnum),FNVALL);
10207 if (array) { /* Array was not declared. */
10208 int i;
10209 if ((x = dclarray(abuf[1],wordnum)) < 0) { /* Declare it. */
10210 failed = 1;
10211 if (fndiags)
10212 ckmakmsg(fnval,FNVALL,
10213 "<ERROR:MALLOC_FAILURE:\\f",fn,"()>",NULL);
10214 goto fnend;
10215 }
10216 for (i = 1; i <= wordnum; i++) { /* Copy results */
10217 makestr(&(a_ptr[x][i]),q->a_head[i]);
10218 }
10219 a_ptr[x][0] = NULL; /* Array is 1-based */
10220 makestr(&(a_ptr[x][0]),fnval); /* Element = size */
10221 }
10222 } else { /* \fword() result */
10223 char * s;
10224 s = q->a_head[1];
10225 if (!s) s = "";
10226 ckstrncpy(fnval,s,FNVALL);
10227 }
10228 goto fnend; /* Done */
10229 }
10230
10231 } /* Break up big switch... */
10232
10233 switch (y) {
10234
10235 #ifdef CK_KERBEROS
10236 case FN_KRB_TK: /* Kerberos tickets */
10237 case FN_KRB_NX: /* Kerberos next ticket */
10238 case FN_KRB_IV: /* Kerberos ticket is valid */
10239 case FN_KRB_FG: /* Kerberos Ticket flags */
10240 case FN_KRB_TT: { /* Kerberos ticket time */
10241 int kv = 0; /* Kerberos version */
10242 int n = 0;
10243 char * s = NULL;
10244 if (rdigits(bp[0])) {
10245 kv = atoi(bp[0]);
10246 } else {
10247 failed = 1;
10248 if (fndiags)
10249 ckmakmsg(fnval,FNVALL,
10250 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
10251 goto fnend;
10252 }
10253 if (kv != 4 && kv != 5) {
10254 failed = 1;
10255 if (fndiags)
10256 ckmakmsg(fnval,FNVALL,
10257 "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
10258 goto fnend;
10259 }
10260 if ((cx == FN_KRB_IV || cx == FN_KRB_TT || cx == FN_KRB_FG) &&
10261 argn < 2) {
10262 failed = 1;
10263 if (fndiags)
10264 ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
10265 goto fnend;
10266 }
10267 switch (y) {
10268 case FN_KRB_TK: /* Number of Kerberos tickets */
10269 #ifdef CK_AUTHENTICATION
10270 switch (kv) {
10271 case 4:
10272 n = ck_krb4_get_tkts();
10273 sprintf(fnval, "%d", (n >= 0) ? n : 0); /* SAFE */
10274 goto fnend;
10275 case 5: {
10276 extern char * krb5_d_cc;
10277 n = ck_krb5_get_tkts(krb5_d_cc);
10278 sprintf(fnval, "%d", (n >= 0) ? n : 0); /* SAFE */
10279 goto fnend;
10280 }
10281 }
10282 #else
10283 sprintf(fnval,"%d",0); /* SAFE */
10284 #endif /* CK_AUTHENTICATION */
10285 goto fnend;
10286
10287 case FN_KRB_NX: /* Kerberos next ticket */
10288 #ifdef CK_AUTHENTICATION
10289 switch (kv) {
10290 case 4:
10291 s = ck_krb4_get_next_tkt();
10292 ckstrncpy(fnval, s ? s : "",FNVALL);
10293 goto fnend;
10294 case 5:
10295 s = ck_krb5_get_next_tkt();
10296 ckstrncpy(fnval, s ? s : "",FNVALL);
10297 goto fnend;
10298 }
10299 #else
10300 sprintf(fnval,"k%d next-ticket-string",kv); /* SAFE */
10301 #endif /* CK_AUTHENTICATION */
10302 goto fnend;
10303
10304 case FN_KRB_IV: /* Kerberos ticket is valid */
10305 #ifdef CK_AUTHENTICATION
10306 /* Return 1 if valid, 0 if not */
10307 switch (kv) {
10308 case 4:
10309 n = ck_krb4_tkt_isvalid(bp[1]);
10310 sprintf(fnval, "%d", n > 0 ? 1 : 0); /* SAVE */
10311 goto fnend;
10312 case 5: {
10313 extern char * krb5_d_cc;
10314 n = ck_krb5_tkt_isvalid(krb5_d_cc,bp[1]);
10315 sprintf(fnval,"%d", n > 0 ? 1 : 0); /* SAFE */
10316 goto fnend;
10317 }
10318 }
10319 #else
10320 sprintf(fnval,"%d",0); /* SAFE */
10321 #endif /* CK_AUTHENTICATION */
10322 goto fnend;
10323
10324 case FN_KRB_TT: /* Kerberos ticket time */
10325 #ifdef CK_AUTHENTICATION
10326 switch (kv) {
10327 case 4:
10328 n = ck_krb4_tkt_time(bp[1]);
10329 sprintf(fnval,"%d", n >= 0 ? n : 0); /* SAFE */
10330 goto fnend;
10331 case 5: {
10332 extern char * krb5_d_cc;
10333 n = ck_krb5_tkt_time(krb5_d_cc,bp[1]);
10334 sprintf(fnval,"%d", n >= 0 ? n : 0); /* SAFE */
10335 goto fnend;
10336 }
10337 }
10338 #else
10339 ckstrncpy(fnval,"600",FNVALL); /* Some time */
10340 #endif /* CK_AUTHENTICATION */
10341 goto fnend;
10342
10343 case FN_KRB_FG: /* Kerberos ticket flags */
10344 #ifdef CK_AUTHENTICATION
10345 switch (kv) {
10346 case 4:
10347 fnval[0] = '\0';
10348 goto fnend;
10349 case 5: {
10350 extern char * krb5_d_cc;
10351 ckstrncpy(fnval,ck_krb5_tkt_flags(krb5_d_cc,bp[1]),FNVALL);
10352 goto fnend;
10353 }
10354 }
10355 #else
10356 fnval[0] = '\0';
10357 #endif /* CK_AUTHENTICATION */
10358 goto fnend;
10359 }
10360 p = fnval;
10361 goto fnend;
10362 }
10363 #endif /* CK_KERBEROS */
10364
10365 #ifdef FN_ERRMSG
10366 case FN_ERRMSG:
10367 if (rdigits(bp[0])) {
10368 k = atoi(bp[0]);
10369 } else {
10370 failed = 1;
10371 if (fndiags)
10372 ckmakmsg(fnval,FNVALL,"<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
10373 goto fnend;
10374 }
10375 #ifdef VMS
10376 ckstrncpy(fnval,ckvmserrstr(k),FNVALL);
10377 #else
10378 x = errno;
10379 errno = k;
10380 ckstrncpy(fnval,ck_errstr(),FNVALL);
10381 errno = x;
10382 #endif /* VMS */
10383 p = fnval;
10384 goto fnend;
10385 #endif /* FN_ERRMSG */
10386
10387 case FN_DIM: {
10388 int max;
10389 char abuf[16], *s;
10390 fnval[0] = NUL; /* Initial return value */
10391 ckstrncpy(abuf,bp[0],16); /* Get array reference */
10392 s = abuf;
10393 if (*s == CMDQ) s++;
10394 failed = 1; /* Assume it's bad */
10395 p = fnval; /* Point to result */
10396 if (fndiags) /* Default is this error message */
10397 ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
10398 if (s[0] != '&') { /* "Address" of array */
10399 goto fnend;
10400 }
10401 if (s[2]) {
10402 if (s[2] != '[' || s[3] != ']') {
10403 goto fnend;
10404 }
10405 }
10406 if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */
10407 s[1] += 32;
10408 if (s[1] < 95 || s[1] > 122) { /* Check for a-z */
10409 goto fnend; /* Bad */
10410 }
10411 if ((max = chkarray(s[1],1)) < 1) /* (second arg was 1) */
10412 max = 0;
10413 failed = 0; /* Unset failure flag */
10414 sprintf(fnval,"%d",max); /* SAFE */
10415 goto fnend;
10416 }
10417 case FN_FILEINF: { /* File information */
10418 #ifdef UNIX
10419 /* from zgetfs in ckufio.c */
10420 extern int zgfs_dir, zgfs_link;
10421 extern char linkname[];
10422 char * tx; /* For tilde expansion */
10423 #else
10424 int zgfs_dir = 0, zgfs_link = 0;
10425 #endif /* UNIX */
10426 char abuf[16], *s;
10427 char ** ap = NULL;
10428 char workbuf[MAXPATHLEN];
10429 int attrs = 9; /* Number of attributes defined */
10430 int k = 0; /* current attribute index */
10431 int i,j,n;
10432 int m; /* For scanfile() */
10433 int dir = -1; /* 1 = arg is a directory file */
10434 CK_OFF_T z, z2; /* For file size */
10435
10436 workbuf[0] = NUL;
10437 workbuf[1] = NUL;
10438 if (argn < 2) { /* An array designator is required */
10439 if (fndiags)
10440 ckmakmsg(fnval,FNVALL,"<ERROR:ARRAY_REQUIRED:\\f",fn,"()>",NULL);
10441 goto fnend;
10442 }
10443 #ifdef UNIX
10444 if (*(bp[0]) == '~') { /* Expand any tildes in filenames. */
10445 tx = tilde_expand(bp[0]); /* We recycle bp[0] */
10446 if (tx) if (*tx) { /* this way so they will be freed */
10447 free(bp[0]); /* automatically later. */
10448 bp[0] = NULL;
10449 makestr(&(bp[0]),tx);
10450 }
10451 }
10452 #endif /* UNIX */
10453
10454 j = ckstrncpy(workbuf,bp[0],MAXPATHLEN); /* Strip any trailing '/' */
10455 if (workbuf[j-1] == '/') {
10456 workbuf[j-1] = NUL;
10457 makestr(&(bp[0]),workbuf);
10458 }
10459 z = zchki(bp[0]); /* Check accessibility */
10460 if (z == -1L || z == -3L) { /* Access denied or whatever */
10461 p = "0";
10462 goto fnend;
10463 /* Note: z > 0 is the file size but only of regular files */
10464 /* Thus the zgetfs call just below */
10465 }
10466 #ifdef UNIX
10467 if ((z2 = zgetfs(bp[0])) > 0) { /* Get size and some attributes */
10468 z = z2; /* Have size */
10469 dir = zgfs_dir; /* File is/isn't a directory */
10470 }
10471 #endif /* UNIX */
10472 if (dir < 0) /* Check if file is a a directory */
10473 dir = isdir(bp[0]); /* if previous clause didn't already */
10474
10475 fnval[0] = NUL; /* Initial return value */
10476 ckstrncpy(abuf,bp[1],16); /* Get array reference */
10477 s = abuf;
10478 if (*s == CMDQ) s++;
10479 failed = 1; /* Assume it's bad */
10480 p = fnval; /* Point to result */
10481 if (fndiags) /* Default is this error message */
10482 ckmakmsg(fnval,FNVALL,
10483 "<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
10484 if (s[0] != '&') /* "Address" of array */
10485 goto fnend;
10486 if (s[2])
10487 if (s[2] != '[' || s[3] != ']')
10488 goto fnend;
10489 if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */
10490 s[1] += 32;
10491 if ((x = dclarray(s[1],attrs)) < 0) /* One element per attribute */
10492 goto fnend;
10493 failed = 0; /* Unset failure flag */
10494 ap = a_ptr[x]; /* Point to array we just declared */
10495 sprintf(fnval,"%d",k); /* SAFE */
10496
10497 /* Element 1 = filename */
10498
10499 s = bp[0]; /* Argument (might include path) */
10500 n = strlen(s);
10501 for (i = n; i > 0; i--) { /* Get filename without path */
10502 if (ISDIRSEP(s[i-1])) { /* Platform independent way */
10503 s += i;
10504 break;
10505 }
10506 }
10507 a_ptr[x][1] = NULL; /* Filename */
10508 makestr(&(a_ptr[x][1]),s);
10509
10510 /* Element 2 - Full pathname */
10511
10512 s = workbuf;
10513 zfnqfp(bp[0],FNVALL,s);
10514 n = strlen(s);
10515 for (i = n; i > 0; i--) { /* Get filename without path */
10516 if (ISDIRSEP(s[i-1])) { /* Platform independent way */
10517 s[i] = NUL;
10518 break;
10519 }
10520 }
10521 a_ptr[x][2] = NULL;
10522 makestr(&(a_ptr[x][2]),s);
10523
10524 /* Element 3 - Modification date-time */
10525
10526 s = zfcdat(bp[0]);
10527 a_ptr[x][3] = NULL;
10528 makestr(&(a_ptr[x][3]),s);
10529
10530 /* Element 4 - Permissions string */
10531
10532 #ifdef UNIX
10533 if (zgfs_link)
10534 s = "lrwxrwxrwx";
10535 else
10536 #endif /* UNIX */
10537
10538 /* [jt] 2013/11/21:
10539 * K-95 doesn't have ziperm. However, I have not read through this
10540 * code thoroughly, and this needs to be double checked to see if there are
10541 * any side effects of commenting this out.
10542 */
10543 #ifdef CK_PERMS
10544 s = ziperm(bp[0]);
10545 a_ptr[x][4] = NULL;
10546 makestr(&(a_ptr[x][4]),s);
10547 ckstrncpy(workbuf,s,32); /* Save for later */
10548 #endif /* CK_PERMS */
10549
10550 /* Element 5 - Permissions numeric code */
10551
10552 s = zgperm(bp[0]);
10553 a_ptr[x][5] = NULL;
10554 makestr(&(a_ptr[x][5]),s);
10555
10556 /* Element 6 - Size in bytes */
10557
10558 #ifdef UNIX /* [fdc] 2021-09-14 only Unix has file links */
10559 s = zgfs_link ? ckitoa((int)strlen((char *)linkname)) : ckfstoa(z);
10560 #else
10561 s = ckfstoa(z);
10562 #endif /* UNIX */
10563 a_ptr[x][6] = NULL;
10564 makestr(&(a_ptr[x][6]),s);
10565
10566 /* Element 7 - File type */
10567
10568 j = 0;
10569 if (dir) j = 3;
10570 #ifdef UNIX
10571 else if (zgfs_link) j = 4;
10572 else if (ckindex("x",(char *)workbuf,0,0,1)) j = 2;
10573 else if (workbuf[1] != '-') j = 1;
10574 #else
10575 #ifdef VMS
10576 else if (ckindex("E",(char *)workbuf,0,0,1)) j = 2;
10577 else j = 1;
10578 #endif /* VMS */
10579 #endif /* UNIX */
10580 a_ptr[x][7] = NULL;
10581 switch (j) {
10582 case 0: s = "unknown"; break;
10583 case 1: s = "regular"; break;
10584 case 2: s = "executable"; break;
10585 case 3: s = "directory"; break;
10586 case 4: s = "link"; break;
10587 default: s = "unknown";
10588 }
10589 makestr(&(a_ptr[x][7]),s);
10590 k = 7;
10591
10592 /* Element 8 - Name of linked-to file (if link) */
10593
10594 a_ptr[x][8] = NULL;
10595 #ifdef UNIX
10596 if (zgfs_link) {
10597 makestr(&(a_ptr[x][8]),(char *)linkname);
10598 k++;
10599 }
10600 #endif /* UNIX */
10601
10602 /* Element 9 - File scan result */
10603
10604 if (j == 1 || j == 2) { /* Regular file */
10605 m = scanfile(bp[0],NULL,nscanfile);
10606 if (m > -1) {
10607 if (k < 8) k = 8; /* Insert empty element for link */
10608 makestr(&(a_ptr[x][8]),"");
10609 k++;
10610 switch (m) {
10611 case FT_7BIT: s = "text:7bit"; break;
10612 case FT_UTF8: s = "text:utf8"; break;
10613 case FT_UCS2: s = "text:ucs2"; break;
10614 case FT_8BIT: s = "text:8bit"; break;
10615 case FT_TEXT: s = "text:unknown"; break;
10616 case FT_BIN: s = "binary"; break;
10617 default: s = "unknown";
10618 }
10619 a_ptr[x][9] = NULL;
10620 makestr(&(a_ptr[x][9]),s);
10621 }
10622 }
10623 /* If adding another change attrs declaration to match */
10624
10625 /* Element 0 = array size */
10626
10627 p = ckitoa(k); /* Number of elements */
10628
10629 a_ptr[x][0] = NULL; /* Put number of elements in [0] */
10630 makestr(&(a_ptr[x][0]),p);
10631 debug(F101,"FILEINF","",attrs);
10632 goto fnend;
10633 }
10634 case FN_FILECMP: { /* File comparison */
10635 FILE *fp1 = NULL;
10636 FILE *fp2 = NULL;
10637 char * s, * s1 = NULL, * s2 = NULL;
10638 #ifdef UNIX
10639 char * tx; /* For tilde expansion */
10640 #endif /* UNIX */
10641 int c1, c2;
10642 int eof1 = 0, eof2 = 0;
10643
10644 failed = 1; /* Assume files differ */
10645 p[0] = '1'; /* Default return value = differ */
10646 p[1] = NUL;
10647 if (argn != 2) { /* Need two args */
10648 if (fndiags)
10649 ckmakmsg(fnval,FNVALL,"<ERROR:ARG_COUNT:\\f",fn,"()>",NULL);
10650 goto fnend;
10651 }
10652 s1 = bp[0];
10653 s2 = bp[1];
10654 #ifdef UNIX
10655 if (*s1 == '~') { /* Expand any tildes in filenames. */
10656 tx = tilde_expand(bp[0]); /* We recycle bp[0] and bp[1] */
10657 if (tx) if (*tx) { /* this way so they will be freed */
10658 free(bp[0]); /* automatically later. */
10659 bp[0] = NULL;
10660 makestr(&(bp[0]),tx);
10661 }
10662 s1 = bp[0];
10663 }
10664 if (*s2 == '~') {
10665 tx = tilde_expand(bp[1]);
10666 if (tx) if (*tx) {
10667 free(bp[1]);
10668 bp[1] = NULL;
10669 makestr(&(bp[1]),tx);
10670 }
10671 s2 = bp[1];
10672 }
10673 #endif /* UNIX */
10674 fp1 = fopen(s1, "r"); /* Open it first file*/
10675 fp2 = fopen(s2, "r"); /* Open it first file*/
10676 failed = 0; /* No failure from here down */
10677 if (fp1 == NULL || fp2 == NULL) { /* Open failure */
10678 p[0] = '-';
10679 p[1] = '1';
10680 p[2] = NUL; /* Return -1 */
10681 if (fp1) fclose(fp1);
10682 if (fp1) fclose(fp2);
10683 goto fnend;
10684 }
10685 while (1) {
10686 if (!eof1) {
10687 c1 = getc(fp1);
10688 if (c1 == (unsigned int)EOF) {
10689 eof1++;
10690 fclose(fp1);
10691 }
10692 }
10693 if (!eof2) {
10694 c2 = getc(fp2);
10695 if (c2 == (unsigned int)EOF) {
10696 eof2++;
10697 fclose(fp2);
10698 }
10699 }
10700 if (eof1 && eof2) {
10701 p[0] = '0'; /* Success */
10702 p[1] = NUL;
10703 failed = 0;
10704 goto fnend;
10705 }
10706 if (eof1 || eof2 || (c1 != c2)) {
10707 if (!eof1) fclose(fp1);
10708 if (!eof2) fclose(fp2);
10709 goto fnend;
10710 }
10711 }
10712 }
10713
10714 } /* Break up big switch... */
10715
10716 switch (y) {
10717 case FN_JDATE:
10718 if (argn < 1) /* Check number of args */
10719 p = ckdate(); /* None, get today's date-time */
10720 else /* Some */
10721 p = bp[0]; /* Use first */
10722 p = ckcvtdate(p,0); /* Convert to standard form */
10723 ckstrncpy(fnval,zjdate(p),FNVALL); /* Convert to Julian */
10724 p = fnval; /* Point to result */
10725 failed = 0;
10726 if (*p == '-') {
10727 failed = 1;
10728 if (fndiags) /* Default is this error message */
10729 ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_DATE:\\f",fn,"()>",NULL);
10730 }
10731 goto fnend;
10732
10733 case FN_DATEJ:
10734 ckstrncpy(fnval,jzdate(bp[0]),FNVALL); /* Convert to yyyy<dayofyear> */
10735 p = fnval; /* Point to result */
10736 failed = 0;
10737 if (*p == '-') {
10738 failed = 1;
10739 if (fndiags) /* Default is this error message */
10740 ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_DATE:\\f",fn,"()>",NULL);
10741 }
10742 goto fnend;
10743
10744 case FN_DTIM: /* \fcvtdate() */
10745 case FN_TIME: /* Free-format time to hh:mm:ss */
10746 case FN_NTIM: /* Time to sec since midnight */
10747 s = (argn > 0) ? bp[0] : "";
10748 if (!s) s = "";
10749 if (!*s)
10750 p = ckdate(); /* None, get today's date */
10751 else /* Some */
10752 p = bp[0]; /* Use first */
10753 {
10754 char * s;
10755 s = p;
10756 while (*s) { /* Strip leading spaces/ctrls */
10757 if (*s < 32) {
10758 *s = NUL;
10759 break;
10760 }
10761 s++;
10762 }
10763 /* do { if (*s < '!') *s = NUL; break; } while (*s++); */
10764 }
10765 p = ckcvtdate(p,2); /* Convert to standard form */
10766 if (*p == '<') {
10767 failed = 1;
10768 if (fndiags) /* Default is this error message */
10769 ckmakmsg(fnval,FNVALL,
10770 "<ERROR:ARG_BAD_DATE_OR_TIME:\\f",fn,"()>",NULL);
10771 p = fnval;
10772 goto fnend;
10773 }
10774 if (argn > 1) { /* Format code */
10775 s = evalx(bp[1]);
10776 if (!s) s = "";
10777 if (!*s) s = "0";
10778 if (!chknum(s)) {
10779 failed = 1;
10780 if (fndiags)
10781 ckmakmsg(fnval,FNVALL,
10782 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
10783 p = fnval;
10784 goto fnend;
10785 }
10786 x = atoi(s);
10787 /* if (x) */ p = shuffledate(p,x);
10788 }
10789 if (cx == FN_TIME) {
10790 p += 9;
10791 } else if (cx == FN_NTIM) {
10792 long sec = 0L;
10793 p[11] = NUL;
10794 p[14] = NUL;
10795 sec = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
10796 sprintf(fnval,"%ld",sec); /* SAFE */
10797 p = fnval;
10798 }
10799 goto fnend;
10800
10801 case FN_MJD: /* Modified Julian Date */
10802 if (argn < 1) /* Check number of args */
10803 p = zzndate(); /* None, get today's date-time */
10804 else /* Some */
10805 p = bp[0]; /* Use first */
10806 p = ckcvtdate(p,0); /* Convert to standard form */
10807 if (*p == '-') {
10808 failed = 1;
10809 if (fndiags) /* Default is this error message */
10810 ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_DATE:\\f",fn,"()>",NULL);
10811 goto fnend;
10812 }
10813 /* Convert to modified Julian date */
10814 sprintf(fnval,"%ld",mjd(p)); /* SAFE */
10815 p = fnval; /* Point to result */
10816 goto fnend;
10817
10818 case FN_MJD2: {
10819 long k = 0L;
10820 int n = 0;
10821 p = evalx(bp[0]);
10822 if (*p == '-') {
10823 p++;
10824 n = 1;
10825 }
10826 if (!rdigits(p)) {
10827 failed = 1;
10828 evalerr(fn);
10829 p = fnval;
10830 goto fnend;
10831 } else {
10832 k = atol(p);
10833 if (n) k = -k;
10834 }
10835 ckstrncpy(fnval,mjd2date(k),FNVALL); /* Convert to Date */
10836 p = fnval; /* Point to result */
10837 failed = 0;
10838 goto fnend;
10839 }
10840
10841 #ifndef NODIAL
10842 case FN_PNCVT: { /* Convert phone number */
10843 extern char * pncvt();
10844 failed = 0;
10845 p = pncvt(bp[0]);
10846 if (!p) p = "";
10847 if (!*p) {
10848 failed = 1;
10849 if (fndiags) /* Default is this error message */
10850 ckmakmsg(fnval,FNVALL,
10851 "<ERROR:ARG_BAD_PHONENUM:\\f",fn,"()>",NULL);
10852 }
10853 goto fnend;
10854 }
10855 #endif /* NODIAL */
10856
10857 case FN_DAY:
10858 case FN_NDAY:
10859 if (argn < 1) /* Check number of args */
10860 p = zzndate(); /* None, get today's date-time */
10861 else /* Some */
10862 p = bp[0]; /* Use first */
10863 p = ckcvtdate(p,0); /* Convert to standard form */
10864 if (*p == '-') {
10865 failed = 1;
10866 if (fndiags) /* Default is this error message */
10867 ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_DATE:\\f",fn,"()>",NULL);
10868 goto fnend;
10869 }
10870 failed = 0;
10871 z = mjd(p); /* Convert to modified Julian date */
10872 z = z % 7L;
10873 if (z < 0) {
10874 z = 0 - z;
10875 k = 6 - ((int)z + 3) % 7;
10876 } else {
10877 k = ((int)z + 3) % 7; /* Day of week */
10878 }
10879 p = fnval; /* Point to result */
10880 if (cx == FN_NDAY)
10881 sprintf(fnval,"%d",k); /* SAFE */
10882 else
10883 ckstrncpy(fnval,wkdays[k],FNVALL);
10884 goto fnend;
10885
10886 case FN_N2TIM: { /* Sec since midnight to hh:mm:ss */
10887 long k = 0L;
10888 int n = 0, hh, mm, ss;
10889 char * s = bp[0];
10890 if (argn < 1) /* If no arg substitute 0 */
10891 s = "0";
10892 p = evalx(s); /* Evaluate expression silently */
10893 if (*p == '-') { /* Check result for minus sign */
10894 p++;
10895 n = 1;
10896 }
10897 if (!rdigits(p)) { /* Check for numeric */
10898 failed = 1;
10899 ckmakmsg(fnval,FNVALL,
10900 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
10901 p = fnval;
10902 goto fnend;
10903 } else {
10904 k = atol(p);
10905 if (n) k = -k;
10906 }
10907 if (k < 0) { /* Check for negative */
10908 failed = 1;
10909 if (fndiags)
10910 ckmakmsg(fnval,FNVALL,
10911 "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
10912 p = fnval;
10913 goto fnend;
10914 }
10915 hh = k / 3600L; /* Have positive number */
10916 mm = (k % 3600L) / 60L; /* break it down... */
10917 ss = ((k % 3600L) % 60L);
10918
10919 sprintf(fnval,"%02d:%02d:%02d",hh,mm,ss); /* SAFE */
10920 p = fnval;
10921 failed = 0;
10922 goto fnend;
10923 }
10924
10925 case FN_PERM: { /* File permissions */
10926 p = fnval;
10927 z = zchki(bp[0]);
10928 if (z < 0) {
10929 failed = 1;
10930 if (fndiags) {
10931 if (z == -1)
10932 ckmakmsg(fnval,FNVALL,
10933 "<ERROR:FILE_NOT_FOUND:\\f",fn,"()>",NULL);
10934 else if (z == -2)
10935 ckmakmsg(fnval,FNVALL,
10936 "<ERROR:FILE_NOT_READABLE:\\f",fn,"()>",NULL);
10937 else if (z == -3)
10938 ckmakmsg(fnval,FNVALL,
10939 "<ERROR:FILE_NOT_ACCESSIBLE:\\f",fn,"()>",NULL);
10940 else
10941 ckmakmsg(fnval,FNVALL,
10942 "<ERROR:FILE_ERROR:\\f",fn,"()>",NULL);
10943 }
10944 goto fnend;
10945 }
10946 #ifdef CK_PERMS
10947 ckstrncpy(fnval,ziperm(bp[0]),FNVALL);
10948 #else
10949 ckstrncpy(fnval,"(unknown)",FNVALL);
10950 #endif /* CK_PERMS */
10951 goto fnend;
10952 }
10953 case FN_TLOOK: /* tablelook() */
10954 case FN_ALOOK: { /* arraylook() */
10955 int i, x, hi, lo, max, cmdlen;
10956 char abuf[16], *s, *pat;
10957 char kwbuf[256];
10958 char delim = ':';
10959 failed = 1; /* Assume failure */
10960 ckstrncpy(fnval,"-1",FNVALL);
10961 pat = bp[0]; /* Point to search pattern */
10962 if (!pat) pat = ""; /* Watch out for NULL pointer */
10963 cmdlen = strlen(pat); /* Get pattern length */
10964 if (argn < 2 /* || cmdlen < 1 */ ) { /* Need two args */
10965 if (fndiags)
10966 ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
10967 goto fnend;
10968 }
10969 ckstrncpy(abuf,bp[1],16); /* Get array reference */
10970 if (argn > 2)
10971 delim = *(bp[2]);
10972 s = abuf;
10973 if ((x = arraybounds(s,&lo,&hi)) < 0) { /* Get index and bounds */
10974 if (fndiags)
10975 ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
10976 goto fnend;
10977 }
10978 p = fnval; /* Point to result */
10979 max = a_dim[x]; /* Size of array */
10980 if (lo < 0) lo = 0; /* Use given range if any */
10981 if (lo > max) lo = max;
10982 if (hi < 0) hi = max;
10983 if (hi > max) hi = max;
10984 failed = 0; /* Unset failure flag */
10985 if (max < 1)
10986 goto fnend;
10987 kwbuf[255] = NUL;
10988 for (i = lo; i <= hi; i++) {
10989 if (!a_ptr[x][i])
10990 continue;
10991 if (cx == FN_ALOOK) {
10992 if (ckmatch(pat,a_ptr[x][i],inpcas[cmdlvl],1+4)) {
10993 sprintf(fnval,"%d",i); /* SAFE */
10994 goto fnend;
10995 }
10996 } else if (cx == FN_TLOOK) {
10997 char * aa;
10998 int j = 0, v = 0, len;
10999 if (i == hi)
11000 break;
11001 aa = a_ptr[x][i]; /* Point to this array element */
11002 if (!aa) aa = "";
11003 while (j < 254 && *aa) { /* Isolate keyword */
11004 if (*aa == delim)
11005 break;
11006 kwbuf[j++] = *aa++;
11007 }
11008 kwbuf[j] = NUL;
11009 len = j;
11010 v = 0;
11011 if ((len == cmdlen && !ckstrcmp(kwbuf,pat,len,0)) ||
11012 ((v = !ckstrcmp(kwbuf,pat,cmdlen,0)) &&
11013 ckstrcmp(a_ptr[x][i+1],pat,cmdlen,0))) {
11014 sprintf(fnval,"%d",i); /* SAFE */
11015 goto fnend;
11016 }
11017 if (v) { /* Ambiguous */
11018 ckstrncpy(fnval,"-2",FNVALL);
11019 goto fnend;
11020 }
11021 }
11022 }
11023 if (cx == FN_TLOOK) { /* tablelook() last element */
11024 ckstrncpy(fnval,"-1",FNVALL);
11025 if (!ckstrcmp(a_ptr[x][hi],pat,cmdlen,0))
11026 sprintf(fnval,"%d",hi); /* SAFE */
11027 }
11028 goto fnend;
11029 }
11030 case FN_TOB64: /* Base-64 conversion */
11031 case FN_FMB64:
11032 p = fnval;
11033 *p = NUL;
11034 if (argn < 1)
11035 goto fnend;
11036 if (cx == FN_TOB64) {
11037 x = b8tob64(bp[0],-1,fnval,FNVALL);
11038 } else {
11039 x = strlen(bp[0]);
11040 if (x % 4) { /* length must be multiple of 4 */
11041 failed = 1;
11042 ckmakmsg(fnval,FNVALL,
11043 "<ERROR:ARG_INCOMPLETE:\\f",fn,"()>",NULL);
11044 goto fnend;
11045 }
11046 b64tob8(NULL,0,NULL,0); /* Reset */
11047 x = b64tob8(bp[0],-1,fnval,FNVALL);
11048 b64tob8(NULL,0,NULL,0); /* Reset again */
11049 }
11050 if (x < 0) {
11051 failed = 1;
11052 if (fndiags) {
11053 char * m = "INTERNAL_ERROR";
11054 switch (x) {
11055 case -1: m = "ARG_TOO_LONG"; break;
11056 case -2: m = "ARG_OUT_OF_RANGE"; break;
11057 }
11058 if (ckmakmsg(fnval,FNVALL,"<ERROR:",m,"\\f",fn) > 0)
11059 ckstrncat(fnval,"()>",FNVALL);
11060 }
11061 }
11062 goto fnend;
11063
11064 case FN_ABS: {
11065 char * s;
11066 s = bp[0];
11067 if (*s == '-' || *s == '+')
11068 s++;
11069 if (!rdigits(s)) {
11070 if (fndiags)
11071 ckmakmsg(fnval,FNVALL,
11072 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
11073 goto fnend;
11074 }
11075 ckstrncpy(fnval,s,FNVALL);
11076 goto fnend;
11077 }
11078
11079 case FN_AADUMP: {
11080 char abuf[16], *s = NULL, **ap = NULL, **vp = NULL;
11081 char pattern[VNAML];
11082 int slen, i, j, k, first = -1;
11083 extern int xdelmac();
11084 p = fnval;
11085 if (argn < 2) {
11086 if (fndiags)
11087 ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG2:\\f",fn,"()>",NULL);
11088 goto fnend;
11089 }
11090 debug(F101,"aaconvert argn","",argn);
11091 s = bp[0];
11092 slen = strlen(s);
11093
11094 /* Count elements so we can create the array */
11095
11096 ckmakmsg(pattern,VNAML,s,"<*>",NULL,NULL);
11097 for (k = 0, i = 0; i < nmac; i++) {
11098 if (ckmatch(pattern,mactab[i].kwd,0,1)) {
11099 if (first < 0) /* Remember location of first match */
11100 first = i;
11101 k++;
11102 }
11103 }
11104 debug(F101,"aaconvert matches","",k);
11105 debug(F101,"aaconvert first","",first);
11106 fnval[0] = NUL; /* Initial return value */
11107 ckstrncpy(abuf,bp[1],16); /* Get array reference */
11108 s = abuf;
11109 if (*s == CMDQ) s++;
11110 p = fnval; /* Point to result */
11111 if (fndiags) /* Default is this error message */
11112 ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
11113 if (s[0] != '&') /* Address of array */
11114 goto fnend;
11115 if (s[2])
11116 if (s[2] != '[' || s[3] != ']')
11117 goto fnend;
11118 if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */
11119 s[1] += 32;
11120 if ((x = dclarray(s[1],k)) < 0) /* Declare array to size */
11121 goto fnend;
11122 ap = a_ptr[x]; /* Point to array we just declared */
11123 /* debug(F111,"aaconvert array 1",abuf,ap); */
11124 abuf[0] = NUL;
11125 if (argn > 2) {
11126 ckstrncpy(abuf,bp[2],16); /* Get value array reference */
11127 s = abuf;
11128 if (*s == CMDQ) s++;
11129 if (s[0] != '&') /* Address of array */
11130 goto fnend;
11131 if (s[2])
11132 if (s[2] != '[' || s[3] != ']')
11133 goto fnend;
11134 if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */
11135 s[1] += 32;
11136 if ((x = dclarray(s[1],k)) < 0)
11137 goto fnend;
11138 vp = a_ptr[x]; /* Point to array we just declared */
11139 }
11140 /* debug(F111,"aaconvert array 2",abuf,vp); */
11141 makestr(&ap[0],ckitoa(k));
11142 if (vp) makestr(&vp[0],ckitoa(k));
11143 if (fndiags)
11144 ckmakmsg(fnval,FNVALL,"<ERROR:ASSOCIATIVE_ARRAY:\\f",fn,"()>",NULL);
11145
11146 /* Copy macro index & value to the arrays and then remove the */
11147 /* macro, so the 'first' pointer keeps indicating the next one. */
11148 /* We could combine the initial counting loop with this one but */
11149 /* then it would be harder to create the array and anyway this */
11150 /* function is plenty fast as it is. */
11151
11152 for (i = 1; i <= k; ) {
11153 if (!ckmatch(pattern,mactab[first].kwd,0,1)) {
11154 debug(F111,"aaconvert oddball",mactab[first].kwd,first);
11155 first++;
11156 continue;
11157 }
11158 ckstrncpy(tmpbuf,mactab[first].kwd,TMPBUFSIZ); /* Macro name */
11159 s = tmpbuf; /* Make writeable copy */
11160 s += slen; /* Isolate "index" */
11161 j = strlen(s) - 1;
11162 if (*s != '<' || *(s+j) != '>') { /* Check syntax */
11163 /* This shouldn't happen */
11164 debug(F111,"aaconvert ERROR",mactab[first].kwd,first);
11165 goto fnend;
11166 }
11167 *(s+j) = NUL; /* Remove final '>' */
11168 debug(F111,"aaconvert",s+1,i);
11169 makestr(&(ap[i]),s+1); /* Set first array to index */
11170 if (vp)
11171 makestr(&(vp[i]),mactab[first].mval); /* 2nd to value */
11172 if (xdelmac(first) < 0)
11173 goto fnend;
11174 i++;
11175 }
11176 sprintf(fnval,"%d",k); /* SAFE */
11177 p = fnval; /* Return size of array */
11178 debug(F110,"aaconvert return",p,0);
11179 failed = 0; /* Unset failure flag */
11180 goto fnend;
11181 }
11182
11183 } /* End of switch() */
11184
11185 #ifdef FNFLOAT
11186 /*
11187 Floating-point functions. To be included only if FNFLOAT is defined, which
11188 should happen only if CKFLOAT is also defined, and if the math library is
11189 linked in. Even then, we might have float-vs-double confusion as well as
11190 confusion about what the final "%f" format effector is supposed to reference
11191 (32 bits, 64 bits, etc). Expect trouble if CKFLOAT does not match the data
11192 type of math library functions or args.
11193 */
11194 if (cx == FN_FPABS || /* Floating-point functions */
11195 cx == FN_FPADD ||
11196 cx == FN_FPDIV ||
11197 cx == FN_FPEXP ||
11198 cx == FN_FPLOG ||
11199 cx == FN_FPLN ||
11200 cx == FN_FPMOD ||
11201 cx == FN_FPMAX ||
11202 cx == FN_FPMIN ||
11203 cx == FN_FPMUL ||
11204 cx == FN_FPPOW ||
11205 cx == FN_FPSQR ||
11206 cx == FN_FPINT ||
11207 cx == FN_FPSUB ||
11208 cx == FN_FPROU ||
11209 cx == FN_FPSIN ||
11210 cx == FN_FPCOS ||
11211 cx == FN_FPTAN) {
11212 CKFLOAT farg[2], fpresult = 0.0;
11213 char fpbuf[64], * bp0;
11214 double dummy;
11215 /* int sign = 0; */
11216 int i, j, places = 0;
11217 int argcount = 1;
11218
11219 failed = 1;
11220 p = fnval;
11221 bp0 = bp[0];
11222 if (!bp0)
11223 bp0 = "0";
11224 else if (!*bp0)
11225 bp0 = "0";
11226 if (!isfloat(bp0,0)) {
11227 k = mxlook(mactab,bp0,nmac);
11228 bp0 = (k > -1) ? mactab[k].mval : NULL;
11229 if (bp0) {
11230 if (!isfloat(bp0,0)) {
11231 if (fndiags)
11232 ckmakmsg(fnval,FNVALL,
11233 "<ERROR:ARG_NOT_FLOAT:\\f",fn,"()>",NULL);
11234 goto fnend;
11235 }
11236 }
11237 }
11238 if (cx == FN_FPINT) { /* Float to int */
11239 failed = 0;
11240 ckstrncpy(fnval,bp0,FNVALL);
11241 for (i = 0; fnval[i]; i++) {
11242 if (fnval[i] == '.') {
11243 fnval[i] = NUL;
11244 break;
11245 }
11246 }
11247 goto fnend;
11248 }
11249 switch (y) { /* These need 2 args */
11250 case FN_FPADD:
11251 case FN_FPDIV:
11252 case FN_FPMOD:
11253 case FN_FPMAX:
11254 case FN_FPMIN:
11255 case FN_FPMUL:
11256 case FN_FPPOW:
11257 case FN_FPSUB:
11258 argcount = 2;
11259 }
11260 /* Missing arguments are supplied as 0.0 */
11261
11262 debug(F111,fn,"argcount",argcount);
11263 for (i = 0; i < argcount; i++) { /* Get floating-point args */
11264 #ifdef DEBUG
11265 if (deblog) {
11266 ckmakmsg(fpbuf,
11267 64,
11268 "bp[",
11269 ckitoa(i),
11270 bp[i] ? bp[i] : "(null)",
11271 "]"
11272 );
11273 debug(F100,fpbuf,"",0);
11274 }
11275 #endif /* DEBUG */
11276 if (!bp[i]) {
11277 farg[i] = 0.0;
11278 } else if (!*(bp[i])) {
11279 farg[i] = 0.0;
11280 } else if (!isfloat(bp[i],0)) {
11281 char * tmp;
11282 k = mxlook(mactab,bp[i],nmac);
11283 tmp = (k > -1) ? mactab[k].mval : NULL;
11284 if (tmp) {
11285 if (!isfloat(tmp,0)) {
11286 if (fndiags)
11287 ckmakmsg(fnval,FNVALL,
11288 "<ERROR:ARG_NOT_FLOAT:\\f",fn,"()>",NULL);
11289 goto fnend;
11290 }
11291 }
11292 }
11293 farg[i] = floatval;
11294
11295 #ifdef DEBUG
11296 if (deblog) {
11297 sprintf(fpbuf,"farg[%d]=%f",i,farg[i]); /* SAFE */
11298 debug(F100,fpbuf,"",0);
11299 }
11300 #endif /* DEBUG */
11301 }
11302 if (bp[argcount]) { /* Get decimal places */
11303 char * s;
11304 s = bp[argcount];
11305 if (!s) s = "";
11306 if (!*s) s = "0";
11307 s = evalx(s);
11308 if (!s) s = "";
11309 if (!*s) {
11310 evalerr(fn);
11311 goto fnend;
11312 }
11313 places = atoi(s);
11314 }
11315 errno = 0;
11316 failed = 0;
11317 switch (y) { /* Now do the requested function */
11318 case FN_FPABS: /* Floating-point absolute value */
11319 #ifndef COMMENT
11320 fpresult = fabs(farg[0]);
11321 #else
11322 if (farg[0] < 0.0)
11323 fpresult = 0.0 - farg[0];
11324 #endif /* COMMENT */
11325 break;
11326 case FN_FPADD: /* FP add */
11327 fpresult = farg[0] + farg[1];
11328 break;
11329 case FN_FPDIV: /* FP divide */
11330 case FN_FPMOD: /* FP modulus */
11331 if (!farg[1]) {
11332 failed = 1;
11333 if (fndiags)
11334 ckmakmsg(fnval,FNVALL,
11335 "<ERROR:DIVIDE_BY_ZERO:\\f",fn,"()>",NULL);
11336 } else
11337 fpresult = (cx == FN_FPDIV) ?
11338 (farg[0] / farg[1]) :
11339 fmod(farg[0],farg[1]);
11340 break;
11341 case FN_FPEXP: /* FP e to the x */
11342 fpresult = (CKFLOAT) exp(farg[0]);
11343 break;
11344 case FN_FPLOG: /* FP base-10 logarithm */
11345 case FN_FPLN: /* FP natural logarithm */
11346 if (farg[0] < 0.0) {
11347 failed = 1;
11348 if (fndiags)
11349 ckmakmsg(fnval,FNVALL,
11350 "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
11351 } else
11352 fpresult = (cx == FN_FPLOG) ? log10(farg[0]) : log(farg[0]);
11353 break;
11354 case FN_FPMUL: /* FP multiply */
11355 fpresult = farg[0] * farg[1];
11356 break;
11357 case FN_FPPOW: /* FP raise to a power */
11358 fpresult = modf(farg[1],&dummy);
11359 if ((!farg[0] && farg[1] <= 0.0) ||
11360 (farg[0] < 0.0 && fpresult)) {
11361 failed = 1;
11362 if (fndiags)
11363 ckmakmsg(fnval,FNVALL,
11364 "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
11365 } else
11366 fpresult = pow(farg[0],farg[1]);
11367 break;
11368 case FN_FPSQR: /* FP square root */
11369 if (farg[0] < 0.0) {
11370 failed = 1;
11371 if (fndiags)
11372 ckmakmsg(fnval,FNVALL,
11373 "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
11374 } else
11375 fpresult = sqrt(farg[0]);
11376 break;
11377 case FN_FPSUB: /* FP subtract */
11378 fpresult = farg[0] - farg[1];
11379 break;
11380 case FN_FPROU: /* FP round */
11381 fpresult = farg[0];
11382 break;
11383 case FN_FPSIN: /* FP sine */
11384 fpresult = (CKFLOAT) sin(farg[0]);
11385 break;
11386 case FN_FPCOS: /* FP cosine */
11387 fpresult = (CKFLOAT) cos(farg[0]);
11388 break;
11389 case FN_FPTAN: /* FP tangent */
11390 fpresult = (CKFLOAT) tan(farg[0]);
11391 break;
11392 case FN_FPMAX:
11393 fpresult = (farg[0] > farg[1]) ? farg[0] : farg[1];
11394 break;
11395 case FN_FPMIN:
11396 fpresult = (farg[0] < farg[1]) ? farg[0] : farg[1];
11397 break;
11398 }
11399
11400 /* Get here with fpresult = function result */
11401
11402 if (errno) { /* If range or domain error */
11403 failed = 1;
11404 if (fndiags)
11405 ckmakmsg(fnval,FNVALL,
11406 "<ERROR:FLOATING-POINT-OP:\\f",fn,"()>",NULL);
11407 }
11408 if (failed) /* and/or any other kind of error, */
11409 goto fnend; /* fail. */
11410 #ifndef COMMENT
11411 /* Call routine containing code that was formerly inline */
11412 ckstrncpy(fnval,fpformat(fpresult,places,cx == FN_FPROU),FNVALL);
11413 #else
11414 {
11415 char fbuf[16]; /* For creating printf format */
11416 if (!fp_rounding && /* If printf doesn't round, */
11417 (places > 0 || /* round result to decimal places. */
11418 (places == 0 && cx == FN_FPROU)))
11419 fpresult += (0.5 / pow(10.0,(CKFLOAT)places));
11420 if (places > 0) { /* If places specified */
11421 /* use specified places to write given number of digits */
11422 sprintf(fbuf,"%%0.%df",places); /* SAFE */
11423 sprintf(fnval,fbuf,fpresult); /* SAFE */
11424 } else { /* Otherwise... */
11425 #ifdef COMMENT
11426 /*
11427 Here we want to print exactly fp_digits significant digits, no matter which
11428 side of the decimal point they are on. That is, we want want the default
11429 format to show the maximum number of non-garbage digits, AND we want the last
11430 such digit to be rounded. Of course there is no way to do that, since the
11431 digit after the last non-garbage digit is, well, garbage. So the following
11432 clever ruse does no good.
11433 */
11434 int sign = 0, m = 0;
11435 sprintf(fnval,"%f",fpresult);
11436 if (fnval[0] == '-') sign = 1;
11437 for (i = sign; i < FNVALL; i++) {
11438 if (isdigit(fnval[i]))
11439 m++;
11440 else
11441 break;
11442 }
11443 if (m > 1) {
11444 int d = fp_digits - m;
11445 if (d < 1) d = 1;
11446 sprintf(fbuf,"%%%d.%df",fp_digits+sign+1,d);
11447 } else {
11448 sprintf(fbuf,"%%0.%df",fp_digits);
11449 }
11450 sprintf(fnval,fbuf,fpresult);
11451 #else
11452 /* Go for max precision */
11453 sprintf(fbuf,"%%0.%df",fp_digits); /* SAFE */
11454 sprintf(fnval,fbuf,fpresult); /* SAFE */
11455
11456 #endif /* COMMENT */
11457 }
11458 if (fnval[0] == '-') sign = 1;
11459 }
11460 debug(F111,"fpresult 1",fnval,errno); /* Check for over/underflow */
11461 for (i = sign; fnval[i]; i++) { /* Give requested decimal places */
11462 if (fnval[i] == '.') /* First find the decimal point */
11463 break;
11464 else if (i > fp_digits + sign - 1) /* replacing garbage */
11465 fnval[i] = '0'; /* digits with 0... */
11466 }
11467 if (fnval[i] == '.') { /* Have decimal point */
11468 int gotend = 0;
11469 /* d < 0 so truncate fraction */
11470 if (places < 0 || (places == 0 && cx == FN_FPROU)) {
11471 fnval[i] = NUL;
11472 } else if (places > 0) { /* d > 0 so this many decimal places */
11473 i++; /* First digit after decimal */
11474 for (j = 0; j < places; j++) { /* Truncate after d decimal */
11475 if (!fnval[j+i]) /* places or extend to d */
11476 gotend = 1; /* decimal places. */
11477 if (gotend || j+i+sign > fp_digits)
11478 fnval[j+i] = '0';
11479 }
11480 fnval[j+i] = NUL;
11481 } else { /* d == 0 so Do The Right Thing */
11482 for (j = (int)strlen(fnval) - 1; j > i+1; j--) {
11483 if ((j - sign) > fp_digits)
11484 fnval[j] = '0';
11485 if (fnval[j] == '0')
11486 fnval[j] = NUL; /* Strip useless trailing 0's. */
11487 else
11488 break;
11489 }
11490 }
11491 }
11492 #endif /* COMMENT */
11493 debug(F111,"fpresult 2",fnval,errno);
11494 goto fnend;
11495
11496 }
11497 #endif /* FNFLOAT */
11498
11499 #ifdef CKCHANNELIO
11500 if (cx == FN_FSTAT || /* File functions */
11501 cx == FN_FPOS ||
11502 cx == FN_FEOF ||
11503 cx == FN_FGCHAR ||
11504 cx == FN_FGLINE ||
11505 cx == FN_FGBLK ||
11506 cx == FN_FPCHAR ||
11507 cx == FN_FPLINE ||
11508 cx == FN_FPBLK ||
11509 cx == FN_NLINE ||
11510 cx == FN_FERMSG ||
11511 cx == FN_FILNO) {
11512 int x = 0, t = 0, channel;
11513 long z;
11514 extern int z_maxchan;
11515
11516 failed = 1; /* Assume failure */
11517 p = fnval; /* until we validate args */
11518 if (cx == FN_FERMSG) {
11519 extern int z_error;
11520 if (argn < 1) {
11521 x = z_error;
11522 } else if (chknum(bp[0])) {
11523 x = atoi(bp[0]);
11524 } else if (fndiags)
11525 ckmakmsg(fnval,FNVALL,
11526 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
11527 failed = 0;
11528 ckstrncpy(fnval,ckferror(x),FNVALL);
11529 goto fnend;
11530 }
11531 if (argn < 1) { /* All file functions need channel */
11532 if (cx == FN_FSTAT) { /* Except f_status(), e.g. when */
11533 fnval[0] = '0'; /* called with a variable that */
11534 fnval[1] = NUL; /* hasn't been defined yet. */
11535 failed = 0;
11536 } else {
11537 if (fndiags)
11538 ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
11539 }
11540 goto fnend;
11541 }
11542 if (rdigits(bp[0])) { /* Channel must be numeric */
11543 channel = atoi(bp[0]);
11544 } else { /* Fail if it isn't */
11545 if (fndiags)
11546 ckmakmsg(fnval,FNVALL,
11547 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
11548 goto fnend;
11549 }
11550 if (channel < 0 || channel > z_maxchan) { /* Check channel range */
11551 if (fndiags)
11552 ckmakmsg(fnval,FNVALL,
11553 "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
11554 goto fnend;
11555 }
11556 x = z_getmode(channel); /* Find out about the channel */
11557
11558 failed = 0; /* Assume success from here down */
11559 if (cx == FN_FSTAT) { /* Status / modes of channel */
11560 if (x > -1)
11561 x &= FM_RWB; /* Mask out irrelevant bits */
11562 else /* In this case not open is OK */
11563 x = 0; /* 0 if not open, 1-7 if open */
11564 sprintf(fnval,"%d",x); /* SAFE */
11565 goto fnend;
11566 } else if (x < 1) { /* Not \f_status() so must be open */
11567 failed = 1;
11568 if (fndiags)
11569 ckmakmsg(fnval,FNVALL,"<ERROR:FILE_NOT_OPEN:\\f",fn,"()>",NULL);
11570 goto fnend;
11571 }
11572 switch (y) { /* Do the requested function */
11573 case FN_FPOS: /* Get position */
11574 z = z_getpos(channel); /* FIX THIS */
11575 sprintf(fnval,"%ld",z); /* SAFE */
11576 goto fnend;
11577
11578 case FN_NLINE: /* Get line number */
11579 z = z_getline(channel); /* FIX THIS */
11580 sprintf(fnval,"%ld",z); /* SAFE */
11581 goto fnend;
11582
11583 case FN_FEOF: /* Check EOF */
11584 t = 0;
11585 if (x & FM_EOF) t = 1;
11586 sprintf(fnval,"%d",t); /* SAFE */
11587 goto fnend;
11588
11589 case FN_FILNO: /* Get file handle */
11590 x = z_getfnum(channel);
11591 sprintf(fnval,"%d",x); /* SAFE */
11592 goto fnend;
11593
11594 case FN_FPBLK: /* Read or write block */
11595 case FN_FGBLK:
11596 if (argn < 2) {
11597 if (fndiags)
11598 ckmakmsg(fnval,FNVALL,
11599 "<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
11600 goto fnend;
11601 }
11602 if (rdigits(bp[1])) {
11603 t = atoi(bp[1]);
11604 } else {
11605 if (fndiags)
11606 ckmakmsg(fnval,FNVALL,
11607 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
11608 goto fnend;
11609 }
11610 case FN_FGCHAR: /* Read or write character or line */
11611 case FN_FPCHAR:
11612 case FN_FGLINE:
11613 case FN_FPLINE:
11614 fnval[0] = NUL;
11615 switch (y) {
11616 case FN_FGCHAR: t = z_in(channel,fnval,FNVALL,1,1); break;
11617 case FN_FGLINE: t = z_in(channel,fnval,FNVALL,FNVALL-1,0); break;
11618 case FN_FGBLK:
11619 if (t >= FNVALL) t = FNVALL - 1;
11620 t = z_in(channel,fnval,FNVALL,t,1);
11621 break;
11622 case FN_FPCHAR: t = z_out(channel,bp[1],1,1); break;
11623 case FN_FPLINE: t = z_out(channel,bp[1],-1,0); break;
11624 case FN_FPBLK: t = z_out(channel,bp[1],-1,1); break;
11625 }
11626 if (t < 0) { /* Handle read/write error */
11627 failed = 1;
11628 if (fndiags && t != FX_EOF)
11629 ckmakmsg(fnval,FNVALL,
11630 "<ERROR:FILE_ERROR_%d:\\f",fn,"()>",NULL);
11631 goto fnend;
11632 }
11633 if (cx == FN_FGCHAR) /* Null terminate char */
11634 fnval[1] = NUL;
11635 /* Write (put) functions return numeric status code */
11636 if (cx == FN_FPCHAR || cx == FN_FPLINE || cx == FN_FPBLK)
11637 sprintf(fnval,"%d",t); /* SAFE */
11638 goto fnend;
11639 }
11640 }
11641 #endif /* CKCHANNELIO */
11642
11643 if (cx == FN_SQUEEZE) { /* String function \fsqueeze() */
11644 /* Squeeze out whitespace */
11645 /* Add options later for whether to trim leading and trailing blanks */
11646 /* and what to do about control characters, 8-bit whitespace, etc */
11647 int started = 0; /* Flag for first non-whitespace */
11648 int n = 0; /* Blank/Tab counter */
11649 s = bp[0] ? bp[0] : "";
11650 p = fnval; /* Result buffer */
11651 while (*s) { /* While there is input */
11652 if (!started && (*s == ' ' || *s == '\011')) {
11653 s++; /* Skip past leading whitespace */
11654 continue;
11655 }
11656 started++; /* Leading whitespace was skipped */
11657 if (*s != ' ' && *s != '\011') { /* Have a nonspace char */
11658 n = 0; /* reset space counter */
11659 *p++ = *s++; /* copy char to destination */
11660 continue;
11661 }
11662 if (n++ > 0) { /* Have blank or tab */
11663 s++; /* don't copy more than one */
11664 continue;
11665 }
11666 *p++ = ' '; /* Deposit one space */
11667 s++; /* and go to next source char */
11668 }
11669 if (*(p-1) == ' ') p--; /* Remove trailing space */
11670 *p = NUL; /* Terminate string */
11671 p = fnval; /* point to beginning */
11672 goto fnend; /* Done. */
11673 }
11674 if (cx == FN_PATTERN) { /* \fpattern() for INPUT */
11675 itsapattern = 1;
11676 if (argn > 0) {
11677 p = fnval;
11678 ckstrncpy(fnval,bp[0],FNVALL);
11679 } else p = "";
11680 goto fnend;
11681 }
11682 if (cx == FN_HEX2N || cx == FN_OCT2N) { /* \fhex2n(), \foct2n() */
11683 p = "0";
11684 if (argn < 1)
11685 goto fnend;
11686 p = ckradix(bp[0], ((cx == FN_HEX2N) ? 16 : 8), 10);
11687 if (!p) {
11688 if (fndiags)
11689 ckmakmsg(fnval,FNVALL,
11690 "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
11691 goto fnend;
11692 }
11693 failed = 0;
11694 ckstrncpy(fnval,p,FNVALL);
11695 p = fnval;
11696 goto fnend;
11697 }
11698
11699 if (cx == FN_HEX2IP) {
11700 int c[2], ip[4], i, k;
11701 p = "0";
11702 if (argn < 1)
11703 goto fnend;
11704 s = bp[0];
11705 if ((int)strlen(s) != 8) {
11706 failed = 1;
11707 if (fndiags)
11708 ckmakmsg(fnval,FNVALL,
11709 "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
11710 goto fnend;
11711 }
11712 p = fnval;
11713 for (k = 0; k < 8; k += 2) {
11714 for (i = 0; i < 2; i++) {
11715 c[i] = *s++;
11716 if (islower(c[i])) c[i] = toupper(c[i]);
11717 if (c[i] >= '0' && c[i] <= '9') {
11718 c[i] -= 0x30;
11719 } else if (c[i] >= 'A' && c[i] <= 'F') {
11720 c[i] -= 0x37;
11721 } else {
11722 failed = 1;
11723 if (fndiags)
11724 ckmakmsg(fnval,FNVALL,
11725 "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
11726 goto fnend;
11727 }
11728 ip[k/2] = c[0] << 4 | c[1];
11729 }
11730 sprintf(p,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]); /* SAFE */
11731 }
11732 goto fnend;
11733 }
11734 if (cx == FN_IP2HEX) {
11735 int ip[4], i;
11736 char * q;
11737 p = "00000000";
11738 if (argn < 1)
11739 goto fnend;
11740 s = bp[0];
11741 p = fnval;
11742 for (i = 0; i < 3; i++) {
11743 q = ckstrchr(s,'.');
11744 if (q) {
11745 *q++ = NUL;
11746 ip[i] = atoi(s);
11747 s = q;
11748 } else {
11749 failed = 1;
11750 if (fndiags)
11751 ckmakmsg(fnval,FNVALL,
11752 "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
11753 goto fnend;
11754 }
11755 }
11756 ip[3] = atoi(s);
11757 sprintf(p,"%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]); /* SAFE */
11758 goto fnend;
11759 }
11760 if (cx == FN_RADIX) {
11761 failed = 1;
11762 p = fnval;
11763 if (argn < 3) {
11764 if (fndiags)
11765 ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
11766 goto fnend;
11767 }
11768 if (!rdigits(bp[1]) || !rdigits(bp[2])) {
11769 if (fndiags)
11770 ckmakmsg(fnval,FNVALL,
11771 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
11772 goto fnend;
11773 }
11774 p = ckradix(bp[0],atoi(bp[1]),atoi(bp[2]));
11775 if (!p) {
11776 if (fndiags)
11777 ckmakmsg(fnval,FNVALL,
11778 "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
11779 goto fnend;
11780 }
11781 failed = 0;
11782 ckstrncpy(fnval,p,FNVALL);
11783 p = fnval;
11784 goto fnend;
11785 }
11786 if (cx == FN_JOIN) {
11787 int i, x, y, z, flag, flag2, hi, lo, max, seplen, grouping = 0;
11788 char abuf[16], c, *s, *q, *sep = NULL;
11789 char * gr_opn = "\"{'([<"; /* Group open brackets */
11790 char * gr_cls = "\"}')]>"; /* Group close brackets */
11791 char lb[2], rb[2]; /* Selected left and right brackets */
11792 int csv = 0, tsv = 0; /* Function flags */
11793 char specialchar = 0; /* Field char that triggers grouping */
11794 char *s2 = NULL; /* Address of malloc'd storage */
11795
11796 failed = 1; /* Assume failure */
11797 fnval[0] = NUL;
11798 debug(F101,"FNJOIN ARGN","",argn);
11799
11800 ckstrncpy(abuf,bp[0],16); /* Get array reference */
11801 s = abuf;
11802 if ((x = arraybounds(s,&lo,&hi)) < 0) { /* Get index and bounds */
11803 if (fndiags)
11804 ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
11805 goto fnend;
11806 }
11807 p = fnval; /* Point to result */
11808 max = a_dim[x]; /* Size of array */
11809 if (lo < 0) lo = 1; /* Use given range if any */
11810 if (lo > max) lo = max;
11811 #ifdef COMMENT
11812 hi = max;
11813 #else
11814 /*
11815 This is a workaround for the problem in which the dimension of the \&_[]
11816 array (but not its contents) grows upon entry to a SWITCH block. But this
11817 code prevents the dimension from growing. Go figure.
11818 */
11819 if (hi < 0) { /* Bounds not given */
11820 if (x) /* Regular array */
11821 hi = max;
11822 else /* Argument vector array */
11823 for (hi = max; hi >= lo; hi--) { /* ignore any trailing */
11824 if (!a_ptr[x][hi]) continue; /* empty elements */
11825 if (!*(a_ptr[x][hi])) continue;
11826 break;
11827 }
11828 }
11829 #endif /* COMMENT */
11830 if (hi > max) hi = max;
11831 failed = 0; /* Unset failure flag */
11832 if (max < 1)
11833 goto fnend;
11834 sep = " "; /* Separator */
11835 lb[0] = NUL; /* Group start char (as string) */
11836 rb[0] = NUL;
11837 lb[1] = NUL; /* Group end char as string */
11838 rb[1] = NUL;
11839
11840 if (argn > 1) {
11841 if (bp[1]) if (*bp[1]) { /* If arg1 given and not empty */
11842 if (!strcmp(bp[1],"CSV")) { /* Special "CSV" symbolic arg */
11843 csv++; /* Make a comma separated list */
11844 sep = ","; /* Comma */
11845 specialchar = *sep; /* Separator is special character */
11846 grouping = 1; /* Group with doublequotes */
11847 lb[0] = '"'; /* and here */
11848 rb[0] = '"'; /* they are */
11849 } else if (!strcmp(bp[1],"TSV")) { /* "TSV" symbolic arg */
11850 tsv++; /* Make a Tab separated list */
11851 sep = "\011"; /* Tab */
11852 specialchar = *sep;
11853 grouping = 0; /* No grouping */
11854 } else /* Normal case */
11855 sep = bp[1]; /* use the separator char specified */
11856 }
11857 }
11858 if (argn > 2 && !csv && !tsv) { /* Grouping? */
11859 char * bp2 = bp[2];
11860 if (!bp2) bp2 = "0";
11861 if (!*bp2) bp2 = "0";
11862 if (chknum(bp2)) {
11863 grouping = atoi(bp2);
11864 if (grouping < 0 || grouping > 63)
11865 grouping = 1;
11866 } else {
11867 failed = 1;
11868 if (fndiags)
11869 ckmakmsg(fnval,FNVALL,
11870 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
11871 goto fnend;
11872 }
11873 if (grouping) { /* Take lowest-order one */
11874 int j, k; /* and set the others to 0 */
11875 for (k = 0; k < 6; k++) {
11876 j = 1 << k;
11877 if (grouping & j) {
11878 lb[0] = gr_opn[k];
11879 rb[0] = gr_cls[k];
11880 break;
11881 }
11882 }
11883 }
11884 }
11885 if (!csv && !tsv) { /* Normal case, not CSV or TSV */
11886 specialchar = SP; /* Special character is space */
11887 if (argn > 3) /* Nonzero 4th arg for no separator */
11888 if (chknum(bp[3]))
11889 if (atoi(bp[3]) > 0)
11890 sep = NULL;
11891 if (!sep) {
11892 sep = "";
11893 seplen = 0;
11894 } else
11895 seplen = strlen(sep);
11896 }
11897 for (i = lo; i <= hi; i++) { /* Loop thru selected array elements */
11898 s = a_ptr[x][i]; /* Get next element */
11899 if (!s)
11900 s = "";
11901 flag = 0; /* Flag to indicate grouping needed */
11902 flag2 = 0; /* Flag for internal doublequotes */
11903 if (grouping) { /* Does this element need quoting? */
11904 q = s; /* Look for special character */
11905 while ((c = *q++)) { /* If found */
11906 if (c == specialchar) /* grouping is required */
11907 flag++;
11908 if (csv && (c == '"')) /* Character that needs doubling */
11909 flag2++; /* in comma-separated list */
11910 if (flag && !csv) /* Exit early if no more to do */
11911 break;
11912 }
11913 }
11914 y = strlen(s); /* Get length of this element */
11915 if ((y > 0) && csv && !flag) { /* CSV item needs grouping */
11916 if (s[0] == SP || s[y-1] == SP || /* if it has leading */
11917 s[0] == HT || s[y-1] == HT) /* or trailing whitespace */
11918 flag++; /* then it needs grouping */
11919 }
11920 if (flag || flag2) { /* String needs grouping or quoting */
11921 char *ss = s;
11922 q = (char *)malloc(y + flag2 + 3); /* Make new buffer */
11923 if (q) {
11924 s2 = q; /* and this is what to free */
11925 if (flag) /* If grouping */
11926 *q++ = lb[0]; /* put opening group quote */
11927 while (*ss) { /* Loop through string */
11928 if (flag2 && (*ss == '"')) /* If CSV and this a '"' */
11929 *q++ = *ss; /* double it. */
11930 *q++ = *ss++; /* Copy the character */
11931 }
11932 if (flag) /* If grouping */
11933 *q++ = rb[0]; /* add closing group quote */
11934 *q = NUL; /* terminate the result. */
11935 s = s2;
11936 y = strlen(s);
11937 }
11938 }
11939 z = 0; /* Number of chars copied */
11940 flag = 0; /* flag is now buffer-overrun flag */
11941 if (y > 0) /* If this string is not empty */
11942 z = ckstrncat(fnval,s,FNVALL); /* copy it. */
11943 if (s2) free(s2); /* Free temp storage */
11944 if (z < y) /* Now check for buffer overrun. */
11945 flag++;
11946 if (!flag && *sep && i < hi) { /* If buffer still has room */
11947 z = ckstrncat(fnval,sep,FNVALL); /* copy delimiter */
11948 if (z < seplen)
11949 flag++;
11950 }
11951 if (flag) {
11952 failed = 1;
11953 if (fndiags)
11954 ckmakmsg(fnval,FNVALL,
11955 "<ERROR:RESULT_TOO_LONG:\\f",fn,"()>",NULL);
11956 goto fnend;
11957 }
11958 }
11959 isjoin = 1;
11960 goto fnend;
11961 }
11962 if (cx == FN_SUBST) { /* \fsubstitute() */
11963 CHAR c, * s, * r, * tp[2], buf1[256], buf2[256], buf3[256];
11964 int len, i, j, state = 0, lo = 0, hi = 0;
11965
11966 failed = 0;
11967 p = fnval; /* Result pointer */
11968 *p = NUL;
11969 if (!bp[0]) /* No target, no result*/
11970 goto fnend;
11971
11972 len = strlen(bp[0]); /* Length of source */
11973 if (len == 0)
11974 goto fnend;
11975 if (len > FNVALL) {
11976 failed = 1;
11977 if (fndiags)
11978 ckmakmsg(fnval,FNVALL,
11979 "<ERROR:RESULT_TOO_LONG:\\f",fn,"()>",NULL);
11980 goto fnend;
11981 }
11982 if (!bp[1]) {
11983 ckstrncpy(bp[0],fnval,FNVALL);
11984 goto fnend;
11985 }
11986 tp[0] = buf1; /* For s2-s3 interpretation loop */
11987 tp[1] = buf2;
11988
11989 for (i = 0; i < 256; i++) { /* Initialize working buffers */
11990 buf1[i] = 0; /* s2 expansion buffer */
11991 buf2[i] = 0; /* s3 expansion buffer */
11992 buf3[i] = i; /* Translation table */
11993 }
11994 for (i = 0; i < 2; i++) { /* Interpret s2 and s3 */
11995 s = (CHAR *)bp[i+1]; /* Arg pointer */
11996 if (!s) s = (CHAR *)"";
11997 r = tp[i]; /* To construct interpreted arg */
11998 j = 0; /* Output buf pointer */
11999 state = 0; /* Initial state */
12000 while (c = *s++) { /* Loop thru arg chars */
12001 if (j > 255) /* Output buf full */
12002 break;
12003 switch (state) {
12004 case 0: /* Normal state */
12005 switch (c) {
12006 case '\\': /* Have quote */
12007 state = 1;
12008 break;
12009 case '[': /* Have range starter */
12010 state = 2;
12011 break;
12012 default: /* Anything else */
12013 r[j++] = c;
12014 break;
12015 }
12016 continue;
12017 case 1: /* Quoted char */
12018 r[j++] = c;
12019 state = 0;
12020 continue;
12021 case 2: /* Range bottom */
12022 lo = c;
12023 state++;
12024 continue;
12025 case 3: /* Range separater */
12026 if (c != '-') {
12027 failed = 1;
12028 if (fndiags)
12029 ckmakmsg(fnval,FNVALL,
12030 "<ERROR:BAD_RANGE:\\f",fn,"()>",NULL);
12031 goto fnend;
12032 }
12033 state++;
12034 continue;
12035 case 4: /* Range top */
12036 hi = c;
12037 state++;
12038 continue;
12039 case 5: /* Range end */
12040 if (c != ']') {
12041 failed = 1;
12042 if (fndiags)
12043 ckmakmsg(fnval,FNVALL,
12044 "<ERROR:BAD_RANGE:\\f",fn,"()>",NULL);
12045 goto fnend;
12046 }
12047 for (k = lo; k <= hi && j < 255; k++) /* Fill in */
12048 r[j++] = k;
12049 lo = 0; hi = 0; /* Reset */
12050 state = 0;
12051 continue;
12052 }
12053 }
12054 }
12055 for (i = 0; i < 256 && buf1[i]; i++) { /* Create translation table */
12056 k = (unsigned)buf1[i];
12057 buf3[k] = buf2[i];
12058 }
12059 s = (CHAR *)bp[0]; /* Point to source string */
12060 for (i = 0; i < len; i++) { /* Translation loop */
12061 k = (unsigned)s[i]; /* Get next char */
12062 if (!buf3[k]) /* Remove this char */
12063 continue;
12064 *p++ = buf3[k]; /* Substitute this char */
12065 }
12066 *p = NUL;
12067 p = fnval;
12068 goto fnend;
12069 }
12070
12071 #ifndef NOSEXP
12072 if (cx == FN_SEXP) { /* \fsexpression(arg1) */
12073 char * p2;
12074 fsexpflag++;
12075 p = (argn > 0) ? dosexp(bp[0]) : "";
12076 fsexpflag--;
12077 p2 = fnval;
12078 while ((*p2++ = *p++)) ;
12079 p = fnval;
12080 goto fnend;
12081 }
12082 #endif /* NOSEXP */
12083
12084 if (cx == FN_CMDSTK) { /* \fcmdstack(n1,n2) */
12085 int i, j, k;
12086 char * s;
12087
12088 if (bp[0])
12089 val1 = *(bp[0]) ? evalx(bp[0]) : ckitoa(cmdlvl);
12090 else
12091 val1 = ckitoa(cmdlvl);
12092 #ifdef COMMENT
12093 free(bp[0]); /* (evalx() always uses same buffer) */
12094 bp[0] = NULL; /* (not any more!) */
12095 #endif /* COMMENT */
12096 failed = 1;
12097 if (argn > 1) {
12098 #ifdef COMMENT
12099 makestr(&(bp[0]),val1);
12100 val1 = bp[0];
12101 #endif /* COMMENT */
12102 val2 = *(bp[1]) ? evalx(bp[1]) : "0";
12103 if (!(chknum(val1) && chknum(val2))) {
12104 if (fndiags)
12105 ckmakmsg(fnval,FNVALL,
12106 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
12107 goto fnend;
12108 }
12109 } else {
12110 val1 = ckitoa(cmdlvl);
12111 val2 = "0";
12112 }
12113 i = atoi(val1); /* Level */
12114 j = atoi(val2); /* Flags */
12115 if (i < 0 || i > cmdlvl) {
12116 if (fndiags)
12117 ckmakmsg(fnval,FNVALL,
12118 "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
12119 goto fnend;
12120 }
12121 failed = 0;
12122 p = fnval;
12123 k = cmdstk[i].src; /* What (prompt, file, macro) */
12124 if (j) {
12125 ckstrncpy(fnval,ckitoa(k),FNVALL);
12126 goto fnend;
12127 }
12128 switch (k) {
12129 case CMD_KB:
12130 ckstrncpy(fnval,"(prompt)",FNVALL);
12131 break;
12132 case CMD_TF:
12133 s = tfnam[cmdstk[i].lvl];
12134 if (!zfnqfp(s,FNVALL,fnval))
12135 ckstrncpy(fnval,s,FNVALL);
12136 break;
12137 case CMD_MD:
12138 ckstrncpy(fnval,m_arg[cmdstk[i].lvl][0],FNVALL);
12139 break;
12140 }
12141 goto fnend;
12142 }
12143 #ifdef CKFLOAT
12144 if (cx == FN_DIFDATE) { /* \fdiffdates(d1,d2) */
12145 char * d1, * d2;
12146 d1 = bp[0] ? bp[0] : ckdate();
12147 d2 = bp[1] ? bp[1] : ckdate();
12148 p = (char *)cmdiffdate(d1,d2);
12149 if (!p) {
12150 failed = 1;
12151 if (fndiags) {
12152 ckmakmsg(fnval,FNVALL,"<ERROR:BAD_DATE:\\f",fn,"()>",NULL);
12153 p = fnval;
12154 }
12155 }
12156 goto fnend;
12157 }
12158 #endif /* CKFLOAT */
12159 if (cx == FN_CMPDATE) { /* \fcmddates(d1,d2) */
12160 int x = 0;
12161 char d1[18], d2[18], * dp;
12162 failed = 0;
12163 d1[0] = NUL;
12164 d2[0] = NUL;
12165 p = fnval;
12166 dp = cmcvtdate(bp[0],1);
12167 if (dp) {
12168 ckstrncpy(d1,dp,18);
12169 if ((dp = cmcvtdate(bp[1],1))) {
12170 ckstrncpy(d2,dp,18);
12171 x = 1;
12172 }
12173 }
12174 if (x == 0) {
12175 failed = 1;
12176 if (fndiags)
12177 ckmakmsg(fnval,FNVALL,"<ERROR:BAD_DATE:\\f",fn,"()>",NULL);
12178 } else {
12179 x = strcmp(d1,d2);
12180 if (x > 0)
12181 x = 1;
12182 else if (x < 0)
12183 x = -1;
12184 sprintf(fnval,"%d",x);
12185 }
12186 goto fnend;
12187 }
12188 if (cx == FN_TOGMT) { /* \futcdate(d1) */
12189 char * d1, * dp;
12190 char datebuf[32];
12191 char d2[32];
12192 p = fnval;
12193 failed = 1;
12194 if ((dp = cmcvtdate(bp[0],1))) { /* The given date */
12195 ckstrncpy(datebuf,dp,18);
12196 ckstrncpy(d2,dp,18); /* local time */
12197 ckstrncat(datebuf,"Z",19); /* Same time GMT */
12198 if ((dp = cmcvtdate(datebuf,1))) /* converted to local time */
12199 ckstrncpy(datebuf,dp,18);
12200 if ((p = (char *)cmdiffdate(d2,datebuf))) { /* Get offset */
12201 ckstrncat(d2,p,32); /* Append offset to local time */
12202 if ((dp = cmcvtdate(d2,1))) {
12203 failed = 0;
12204 ckstrncpy(fnval,dp,FNVALL);
12205 p = fnval;
12206 }
12207 }
12208 }
12209 if (failed && fndiags)
12210 ckmakmsg(fnval,FNVALL,"<ERROR:BAD_DATE:\\f",fn,"()>",NULL);
12211 goto fnend;
12212 }
12213 if (cx == FN_DELSEC) { /* \fdelta2secs(delta-time) */
12214 long secs;
12215 p = fnval;
12216 if ((x = delta2sec(bp[0],&secs)) < 0) {
12217 failed = 1;
12218 if (fndiags)
12219 ckmakmsg(fnval,FNVALL,
12220 (x == -1) ?
12221 "<ERROR:BAD_DELTA_TIME:\\f" :
12222 "<ERROR:OVERFLOW:\\f",
12223 fn,
12224 "()>",
12225 NULL
12226 );
12227 goto fnend;
12228 }
12229 sprintf(p,"%ld",secs);
12230 goto fnend;
12231 }
12232 if (cx == FN_PC_DU) {
12233 char c, * s = bp[0];
12234 if (!s) s = "";
12235 p = fnval;
12236 while ((c = *s++)) {
12237 if (c == ':') {
12238 if (*s != '\\')
12239 *p++ = '/';
12240 } else if (c == '\\') {
12241 *p++ = '/';
12242 } else {
12243 *p++ = c;
12244 }
12245 }
12246 *p = NUL;
12247 p = fnval;
12248 goto fnend;
12249 }
12250 if (cx == FN_PC_UD) { /* Unix to DOS path */
12251 char c, * s = bp[0];
12252 if (!s) s = "";
12253 if (*s == '~') { /* Skip leading tilde */
12254 s++;
12255 if (*s == '/')
12256 s++;
12257 }
12258 p = fnval;
12259 while ((c = *s++))
12260 *p ++ = (c == '/') ? '\\' : c;
12261 *p = NUL;
12262 p = fnval;
12263 goto fnend;
12264 }
12265 if (cx == FN_KWVAL) { /* Keyword=Value */
12266 p = dokwval(bp[0],bp[1]?bp[1]:"=");
12267 goto fnend;
12268 }
12269 #ifdef COMMENT
12270 /* Cute idea but doesn't work */
12271 if (cx == FN_SLEEP || cx == FN_MSLEEP) {
12272 p = "";
12273 if (chknum(bp[0])) {
12274 x = atoi(bp[0]);
12275 } else {
12276 failed = 1;
12277 if (fndiags) {
12278 ckmakmsg(fnval,FNVALL,
12279 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
12280 p = fnval;
12281 }
12282 goto fnend;
12283 }
12284 if (cx == FN_SLEEP)
12285 x *= 1000;
12286 msleep(x);
12287 goto fnend;
12288 }
12289 #endif /* COMMENT */
12290
12291 #ifdef NT
12292 if (cx == FN_SNAME) {
12293 GetShortPathName(bp[0],fnval,FNVALL);
12294 goto fnend;
12295 }
12296 if (cx == FN_LNAME) {
12297 ckGetLongPathName(bp[0],fnval,FNVALL);
12298 goto fnend;
12299 }
12300 #endif /* NT */
12301
12302 /*
12303 \femailaddress():
12304 Picks the email address out of an RFC 2822 From: or Sender: header.
12305 Added 26 Nov 2005. Handles all common, and some uncommon, cases but
12306 doesn't totally bother about nested comments. Needed this for fetching
12307 email from a POP server and then constructing the BSD "From " line.
12308 Works with or without the "From: " or "Sender: " tag.
12309 */
12310 if (cx == FN_EMAIL) {
12311 char c, * s = bp[0], * s2, * s3, * ap = "";
12312 int k, state = 0, quote = 0, infield = 0;
12313 int pc = 0; /* For nested comments */
12314 if (!s) s = "";
12315 if (!*s) goto xemail;
12316
12317 if (ckindex("From: ",s,0,0,0) == 1) s += 5;
12318 if (ckindex("Sender: ",s,0,0,0) == 1) s += 7;
12319
12320 k = strlen(s); /* Strip junk from end */
12321 if (k < 1) goto xemail;
12322 k--;
12323 while (k >= 0 && s[k] == CR || s[k] == LF)
12324 s[k--] = NUL;
12325 while (k >= 0 && s[k] == SP || s[k] == HT)
12326 s[k--] = NUL;
12327 if (k == 0)
12328 goto xemail;
12329
12330 #ifndef COMMENT /* Simple method if not 100% foolproof */
12331 k = 0;
12332 for (s2 = s; *s2; s2++) { /* Find at-sign */
12333 if (*s2 == '@') {
12334 k++; /* If more than one use rightmost */
12335 s3 = s2;
12336 }
12337 }
12338 if (k < 1) /* No at-sign */
12339 goto xemail;
12340
12341 for (ap = s3-1; ap >= s; ap--) { /* Back up to beginning of address */
12342 if (isspace(*ap) || *ap == '<') {
12343 ap++;
12344 break;
12345 }
12346 if (ap == s)
12347 break;
12348 }
12349 for (s2 = s3+1; *s2; s2++) { /* Find end of address */
12350 if (isspace(*s2) || *s2 == '>')
12351 break;
12352 }
12353 *s2-- = NUL;
12354 if (*ap == '[' && *s2 == ']') { /* Handle [blah@blah.blah] */
12355 ap++;
12356 *s2 = NUL;
12357 }
12358 if (!ckstrcmp(ap,"mailto:",7,0)) /* Handle mailto: URLs */
12359 ap += 7;
12360
12361 #else /* Too complicated and error-prone */
12362
12363 k = 0;
12364 for (s2 = s; *s2; s2++) { /* Strip leading whitespace */
12365 if (*s2 == SP || *s2 == HT) {
12366 k = 1;
12367 break;
12368 }
12369 }
12370 if (!k) { /* Simple address */
12371 ap = s;
12372 goto xemail;
12373 }
12374 do { /* Not simple, have to extract it */
12375 if (quote) {
12376 quote = 0;
12377 continue;
12378 } else if (*s == '\\') {
12379 quote = 1;
12380 continue;
12381 }
12382 switch (state) {
12383 case 0:
12384 if (!infield && *s == '"') { /* Quoted string */
12385 infield = 1;
12386 c = '"';
12387 state = 1;
12388 } else if (!infield && *s == '(') { /* Comment in parens */
12389 pc++;
12390 infield = 1;
12391 c = ')';
12392 if (*ap) *s = NUL;
12393 state = 1;
12394 } else if (!infield && *s == '<') { /* Address */
12395 infield = 1;
12396 c = '>';
12397 ap = s+1;
12398 state = 2;
12399 } else if (infield && (*s == SP || *s == HT)) {
12400 infield = 0;
12401 } else { /* One or more bare words */
12402 infield = 1; /* Could be an address */
12403 if (!*ap) ap = s; /* Could be comments */
12404 }
12405 continue;
12406 case 1: /* In Quoted string or Comment */
12407 if (infield && *s == c) { /* Look for end */
12408 infield = 0;
12409 *s++ = NUL;
12410 while (*s == SP || *s == HT) s++;
12411 if (!*ap)
12412 ap = s;
12413 state = 0;
12414 }
12415 continue;
12416 case 2: /* In address */
12417 if (infield && *s == c) { /* Looking for end */
12418 infield = 0;
12419 *s = NUL;
12420 break;
12421 }
12422 }
12423 } while (*s++);
12424
12425 xemail:
12426 if (*ap) {
12427 while (*ap == SP || *ap == HT) ap++;
12428 }
12429 k = strlen(ap) - 1;
12430 while (k >= 0 && (ap[k] == SP || ap[k] == HT))
12431 ap[k--] = NUL;
12432 if (*ap) {
12433 failed = 0;
12434 if (*ap == '<') {
12435 k = strlen(ap);
12436 if (*(ap+k-1) == '>') {
12437 ap[k-1] = NUL;
12438 ap++;
12439 }
12440 }
12441 } else
12442 failed = 1;
12443 /* Here we might also want check against "*@*.*" */
12444 #endif /* COMMENt */
12445 xemail:
12446 ckstrncpy(fnval,ap,FNVALL);
12447 goto fnend;
12448 }
12449
12450 #ifdef SEEK_CUR
12451 /*
12452 \fpictureinfo(): Get dimensions of GIF or JPG image - fdc June 2006.
12453 NOTE: The height and width of a JPG image do not necessarily indicate
12454 an image's actual orientation. This is given by the Exif Orientation
12455 tag (0x0122). But locating it in a JPG file without having a full-blown
12456 Exif parser is probably not possible.
12457 */
12458 if (cx == FN_PICTURE) {
12459 FILE *fp = NULL;
12460 int c, x, w = 0, h = 0, eof = 0;
12461 unsigned int i, j, k;
12462 unsigned char buf[1024];
12463 char abuf[16], * p, * s;
12464 char ** ap = NULL;
12465 #ifdef UNIX
12466 char * tx;
12467 #endif /* UNIX */
12468
12469 p = fnval; /* Point to result */
12470 failed = 1; /* Assume failure */
12471 s = bp[0];
12472 #ifdef UNIX
12473 if (*s == '~') {
12474 tx = tilde_expand(bp[0]);
12475 if (tx) if (*tx) {
12476 free(bp[0]);
12477 bp[0] = NULL;
12478 makestr(&(bp[0]),tx);
12479 }
12480 s = bp[0];
12481 }
12482 #endif /* UNIX */
12483
12484 if (argn > 1) {
12485 int xi;
12486 ckstrncpy(abuf,bp[1],16); /* Get array reference */
12487 s = abuf;
12488 if (*s == CMDQ) s++;
12489 if (fndiags) /* Default is this error message */
12490 ckmakmsg(fnval,FNVALL,
12491 "<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
12492 if (s[0] != '&') /* "Address" of array */
12493 goto fnend;
12494 if (s[2])
12495 if (s[2] != '[' || s[3] != ']')
12496 goto fnend;
12497 if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */
12498 s[1] += 32;
12499 if ((xi = dclarray(s[1],3)) < 0) /* three elements */
12500 goto fnend;
12501 ap = a_ptr[xi]; /* Point to array we just declared */
12502 }
12503 s = bp[0]; /* Filename */
12504 failed = 0; /* From here on we don't fail */
12505 p[0] = '0'; /* Default return value */
12506 p[1] = NUL;
12507
12508 /* Tail anchor removed 2013-10-15 -fdc */
12509 if (!ckmatch("*.{jpg,jpeg,gif}",s,0,1)) /* Appropriate name? */
12510 goto fnend; /* No, fail */
12511
12512 fp = fopen(s, "r"); /* Open it */
12513 if (fp == NULL) { /* Can't, fail */
12514 p[0] = '-';
12515 p[1] = '1';
12516 p[2] = NUL; /* Return -1 */
12517 goto fnend;
12518 }
12519 k = strlen(s);
12520 if (!ckstrcmp(&s[k-4],".gif",4,0)) { /* GIF file */
12521 if (fread(buf,1,10,fp) != 10) {
12522 fclose(fp);
12523 goto fnend;
12524 }
12525 /* Check signature */
12526 if (ckstrcmp((char *)buf,"GIF87a",6,0) &&
12527 ckstrcmp((char *)buf,"GIF89a",6,0)) {
12528 fclose(fp);
12529 goto fnend;
12530 }
12531 w = buf[6] + 256 * buf[7];
12532 h = buf[8] + 256 * buf[9];
12533 goto picend;
12534 } else if (!ckstrcmp(&s[k-4],".jpg",4,0) || /* JPEG file */
12535 !ckstrcmp(&s[k-5],".jpeg",5,0)) { /* (according to name) */
12536 if (fread(buf,1,2,fp) != 2) { /* Read 1st bytes */
12537 fclose(fp);
12538 goto fnend;
12539 }
12540 if (buf[0] != 0xff || buf[1] != 0xd8) { /* Check signature */
12541 fclose(fp); /* Should be FFD8 */
12542 goto fnend;
12543 }
12544 eof = 0;
12545 while (!eof) { /* Loop for each marker */
12546 while (!eof) { /* Find next marker */
12547 c = getc(fp);
12548 if (c == (unsigned int)EOF) {
12549 eof++;
12550 break;
12551 }
12552 if (c == 0xff) {
12553 buf[0] = c;
12554 c = getc(fp);
12555 if (c == (unsigned int)EOF) {
12556 eof++;
12557 break;
12558 }
12559 buf[1] = c;
12560 if (c == 0xd9) /* FFD9 means End of Image */
12561 eof++;
12562 if (c >= 0xc0 && c <= 0xfe)
12563 break;
12564 }
12565 }
12566 if (eof) break;
12567 x = buf[1];
12568 if (x == 0xc0 || x == 0xc1 || x == 0xc2 || x == 0xc3 ||
12569 x == 0xc9 || x == 0xca || x == 0xcb) {
12570 if (fread(buf,1,7,fp) != 7) {
12571 fclose(fp);
12572 goto fnend;
12573 }
12574 h = buf[3] * 256 + buf[4];
12575 w = buf[5] * 256 + buf[6];
12576 goto picend;
12577 } else { /* Not a desired field */
12578 if (feof(fp)) {
12579 eof++;
12580 break;
12581 }
12582 if (fread(buf,1,2,fp) != 2) { /* Length of this field */
12583 fclose(fp);
12584 goto fnend;
12585 }
12586 j = 256 * buf[0] + buf[1] - 2; /* Skip next field */
12587 if (CKFSEEK(fp,(CK_OFF_T)j,SEEK_CUR) != 0) {
12588 fclose(fp);
12589 goto fnend;
12590 }
12591 }
12592 }
12593 }
12594 picend:
12595
12596 if (ap) {
12597 char * s;
12598 makestr(&(ap[0]),"2");
12599 makestr(&(ap[1]),ckitoa(w));
12600 makestr(&(ap[2]),ckitoa(h));
12601 s = jpgdate(fp);
12602 debug(F110,"jpgdate",s,0);
12603 if (s) if (*s) makestr(&(ap[3]),s);
12604 }
12605 fclose(fp);
12606 if (w > 0 && h > 0) {
12607 if (w > h) p[0] = '1'; /* Landscape */
12608 else if (h > w) p[0] = '2'; /* Portrait */
12609 else p[0] = '3'; /* Square - 2013-10-05 */
12610 }
12611 goto fnend;
12612 }
12613 #endif /* SEEK_CUR */
12614
12615 if (cx == FN_PID) {
12616 int x = -1;
12617 if (chknum(bp[0])) { /* Need numeric argument */
12618 int pid;
12619 pid = atoi(bp[0]); /* Convert to int */
12620 #ifdef UNIX
12621 if (kill(pid,0) < 0) { /* Test it */
12622 if (errno ==
12623 #ifdef ESRCH
12624 ESRCH /* No such process */
12625 #else
12626 3
12627 #endif /* ESRCH */
12628 )
12629 x = 0;
12630 } else /* Process exists */
12631 x = 1;
12632 #endif /* UNIX */
12633 }
12634 sprintf(fnval,"%d",x); /* SAFE */
12635 goto fnend;
12636 }
12637
12638 if (cx == FN_FUNC) {
12639 char * s = bp[0];
12640 p = "0";
12641 debug(F111,"ffunc",s,argn);
12642 if (argn > 0) {
12643 int x, y;
12644 for (p = s; *p; p++) { /* Chop off trailing parens if any */
12645 if (*p == '(') {
12646 *p = NUL;
12647 break;
12648 }
12649 }
12650 /* Chop off leading "\\f" or "\f" or "f" */
12651 p = s;
12652 if (*p == CMDQ) /* Allow for \\f... */
12653 p++;
12654 if (*p == CMDQ && (*(p+1) == 'f' || *(p+1) == 'F')) { /* or \f */
12655 p += 2;
12656 } else if (*p == 'f' || *p == 'F') { /* or just f */
12657 p++;
12658 }
12659 y = lookup(fnctab,p,nfuncs,&x); /* Look up the result */
12660 debug(F111,"ffunc",p,y);
12661 p = (y > -1) ? "1" : "0";
12662 }
12663 goto fnend;
12664 }
12665 if (cx == FN_RECURSE) {
12666 int t, n;
12667 char * s;
12668 fnval[0] = NUL; /* Default result is empty string */
12669 s = bp[0]; /* Check for null argument */
12670 if (!s) s = ""; /* or empty argument */
12671 if (!*s) goto fnend; /* in which case return empty string */
12672 n = FNVALL; /* Not empty, max size for result */
12673 s = fnval; /* Location of result */
12674 {
12675 /* Force VARIABLE-EVALUATION SIMPLE RECURSIVE */
12676 /* NOTE: This is vulnerable to SIGINT and whatnot... */
12677 int tmp = vareval; /* Save VARIABLE-EVALUATION setting */
12678 vareval = 1; /* Force it to RECURSIVE */
12679 zzstring(bp[0],&s,&n); /* Expand arg into result space */
12680 vareval = tmp; /* Restore VARIABLE-EVALUATION */
12681 }
12682 goto fnend;
12683 }
12684
12685 if (cx == FN_XLATE) { /* f_cvtcset() */
12686 #ifdef NOFRILLS
12687 ckstrncpy(fnval,bp[0],FNVALL);
12688 #else
12689 #ifndef NOUNICODE
12690 _PROTOTYP( char * cvtstring, (char *, int, int) );
12691 char * string, * cset1, * cset2;
12692 int id1, id2;
12693 #endif /* NOUNICODE */
12694 fnval[0] = NUL;
12695 #ifdef NOUNICODE
12696 ckstrncpy(fnval,bp[0],FNVALL);
12697 #else
12698 string = bp[0] ? bp[0] : ""; /* String to convert */
12699 if (!*string) goto fnend; /* It's empty */
12700
12701 cset1 = bp[1] ? bp[1] : "ascii"; /* Current charset of string */
12702 cset2 = bp[2] ? bp[2] : "ascii"; /* Charset to convert to */
12703
12704 id1 = lookup(fcstab,cset1,nfilc,NULL); /* Lookup 'from' set */
12705 if (id1 < 0) {
12706 failed = 1;
12707 ckmakmsg(fnval,FNVALL,"<ERROR:UNKNOWN_CHARSET:\\f",fn,"()>",NULL);
12708 goto fnend;
12709 }
12710 id2 = lookup(fcstab,cset2,nfilc,NULL); /* Lookup 'to' set */
12711 if (id2 < 0) {
12712 failed = 1;
12713 ckmakmsg(fnval,FNVALL,"<ERROR:UNKNOWN_CHARSET:\\f",fn,"()>",NULL);
12714 goto fnend;
12715 }
12716 string = cvtstring(string,id1,id2);
12717 ckstrncpy(fnval,string,FNVALL);
12718 #endif /* NOUNICODE */
12719 #endif /* NOFRILLS */
12720 goto fnend;
12721 }
12722
12723 /* Decode strings containing hex escapes */
12724
12725 if (cx == FN_UNPCT) { /* \fdecodehex() */
12726 char *s1, *s2;
12727 char *prefix; /* Can be 1 or 2 chars */
12728 char buf[3];
12729 int n = 0, k;
12730
12731 p = fnval;
12732 *p = NUL;
12733 if (argn < 1) goto fnend; /* Empty string */
12734
12735 s1 = bp[0] ? bp[0] : ""; /* Original string */
12736 prefix = bp[1] ? bp[1] : "%%"; /* Hex byte prefix */
12737 n = (int)strlen(prefix); /* Length of prefix */
12738 if (n < 1 || n > 2) { /* must be 1 or 2 */
12739 ckmakmsg(fnval,FNVALL,
12740 "<ERROR:INVALID_HEX_PREFIX:\\f",fn,"()>",NULL);
12741 goto xunpct;
12742 }
12743 while (*s1) {
12744 if (!ckstrcmp(s1,prefix,n,0)) { /* Case-independent */
12745 if (!*(s1+n)) {
12746 ckmakmsg(fnval,FNVALL,
12747 "<ERROR:INCOMPLETE_SEQUENCE:\\f",fn,"()>",NULL);
12748 goto xunpct;
12749 }
12750 buf[0] = *(s1+n); /* First hex character */
12751 buf[1] = *(s1+n+1); /* Second hex character */
12752 buf[2] = NUL;
12753 if ((k = ckhexbytetoint((char *)buf)) > -1) {
12754 *p++ = (char) k; /* Deposit decoded result */
12755 s1 += 2+n; /* and advance the source pointer */
12756 } else { /* Fail on conversion error */
12757 ckmakmsg(fnval,FNVALL,
12758 "<ERROR:NON_HEX_CHARS:\\f",fn,"()>",NULL);
12759 goto xunpct;
12760 }
12761 } else { /* Not a hex escape sequence */
12762 *p++ = *s1++; /* Just copy the character */
12763 }
12764 }
12765 *p = NUL; /* Terminate the result string */
12766 failed = 0; /* Say we didn't fail */
12767 p = fnval; /* Set up result pointer */
12768 goto fnend; /* and finish */
12769
12770 xunpct: /* Error exit */
12771 p = fnval;
12772 failed = 1;
12773 goto fnend;
12774 }
12775
12776 /* Check a string for encoding family */
12777
12778 if (cx == FN_STRINGT) { /* \fstringtype() */
12779 p = "UNK";
12780 switch (scanstring(bp[0])) {
12781 case FT_7BIT: p = "7BIT"; break;
12782 case FT_8BIT: p = "8BIT"; break;
12783 case FT_UTF8: p = "UTF8"; break;
12784 case FT_UCS2: p = "UCS2"; break;
12785 case FT_TEXT: p = "TEXT"; break;
12786 case FT_BIN: p = "BINARY"; break;
12787 }
12788 ckstrncpy(fnval,p,FNVALL);
12789 p = fnval;
12790 goto fnend;
12791 }
12792
12793 /* String compare s1, s2, [ case ], [ start ] , [ len ] */
12794
12795 if (cx == FN_STRCMP) {
12796 int docase = 0; /* Case matters or not */
12797 int start = 0; /* Start of substring */
12798 int len = -1; /* Length of substring to compare */
12799 int x; char * s1, * s2; /* workers */
12800
12801 p = "0"; /* Return value */
12802 if (argn == 0) { /* Two null strings are equal */
12803 ckstrncpy(fnval,p,FNVALL);
12804 p = fnval;
12805 goto fnend;
12806 }
12807 if (argn == 1) { /* Non-null string > null string */
12808 p = "1";
12809 ckstrncpy(fnval,p,FNVALL);
12810 p = fnval;
12811 goto fnend;
12812 }
12813 if (argn > 2) {
12814 s = *(bp[2]) ? evalx(bp[2]) : "0"; /* 0 = caseless */
12815 if (chknum(s)) docase = atoi(s);
12816 if (argn > 3) {
12817 s = *(bp[3]) ? evalx(bp[3]) : "1"; /* start is 1-based */
12818 if (chknum(s)) start = atoi(s);
12819 if (argn > 4) {
12820 s = *(bp[4]) ? evalx(bp[4]) : "-1"; /* -1 = whole thing */
12821 if (chknum(s)) len = atoi(s);
12822 }
12823 }
12824 }
12825 if (start > 0) start--; /* start is 0-based internally */
12826 s1 = bp[0]; /* Get length of first arg */
12827 x = (int)strlen(s1);
12828 if (x > start) /* Point to start position of s1 */
12829 s1 += start;
12830 else
12831 s1 = "";
12832 s2 = bp[1]; /* Get length of second arg */
12833 x = (int)strlen(s2);
12834 if (x > start) /* Point to start position of s2 */
12835 s2 += start;
12836 else
12837 s2 = "";
12838 x = ckstrcmp(s,s2,len,docase);
12839 p = ckitoa(x);
12840 ckstrncpy(fnval,p,FNVALL);
12841 p = fnval;
12842 goto fnend;
12843 }
12844 #ifdef HAVE_LOCALE
12845 /* \fdayname() - Returns locale-dependent day name string - 2013/07/23 */
12846
12847 if (cx == FN_DAYNAME) {
12848 _PROTOTYP( char * locale_dayname, (int, int) );
12849 char *s1, *s2;
12850 char buf[3];
12851 int fc = 0, day = 999;
12852
12853 s1 = bp[0];
12854 s2 = bp[1];
12855 p = fnval;
12856 *p = NUL;
12857
12858 if (!s1) s1 = "";
12859 if (!*s1) {
12860 s1 = ckdate();
12861 } else if (rdigits(s1) && (int)strlen(s1) < 8) {
12862 day = atoi(s1);
12863 if (day == 0) day = 7; /* In case \v(nday) used as arg */
12864 if (day < 1 || day > 7) {
12865 ckmakmsg(fnval,FNVALL,"<ERROR:BAD_DAYNUM\\f",fn,"()>",NULL);
12866 goto fnend;
12867 }
12868 day--; /* Adjust to zero-based */
12869 } else if (!(s1 = cmcvtdate(s1,1))) {
12870 ckmakmsg(fnval,FNVALL,"<ERROR:BAD_DATE\\f",fn,"()>",NULL);
12871 goto fnend;
12872 }
12873 if (!s2) s2 = ""; /* Parse function code */
12874 if (!*s2) {
12875 fc = 0;
12876 } else if (rdigits(s2)) {
12877 fc = atoi(s2);
12878 } else {
12879 failed = 1;
12880 ckmakmsg(fnval,FNVALL,"<ERROR:FUNCTION_CODE:\\f",fn,"()>",NULL);
12881 goto fnend;
12882 }
12883 if (day > 6) { /* Day number was not given */
12884 day = (mjd(s1) % 7) + 2; /* Get day number */
12885 if (day > 6) day -= 7; /* Adjust to 0=Sunday */
12886 }
12887 s1 = locale_dayname(day,fc); /* Get locale-based day name */
12888 if (!s1) {
12889 failed = 1;
12890 ckmakmsg(fnval,FNVALL,"<ERROR:NO_RESULT:\\f",fn,"()>",NULL);
12891 goto fnend;
12892 }
12893 ckstrncpy(fnval,s1,FNVALL);
12894 goto fnend;
12895 }
12896 /* \fmonthname() - Returns locale-dependent month name string 2013/07/24 */
12897
12898 if (cx == FN_MONNAME) {
12899 _PROTOTYP( char * locale_monthname, (int, int) );
12900 char *s1, *s2;
12901 char buf[3];
12902 int fc = 0, month = 999;
12903
12904 s1 = bp[0];
12905 s2 = bp[1];
12906 p = fnval;
12907 *p = NUL;
12908
12909 if (!s1) s1 = "";
12910 if (!*s1) {
12911 s1 = ckdate();
12912 } else if (rdigits(s1) && (int)strlen(s1) < 8) {
12913 month = atoi(s1);
12914 if (month == 0) month = 12;
12915 if (month < 1 || month > 12) {
12916 ckmakmsg(fnval,FNVALL,"<ERROR:BAD_MONTHNUM:\\f",fn,"()>",NULL);
12917 goto fnend;
12918 }
12919 month--; /* Adjust to zero-based */
12920 } else if (!(s1 = cmcvtdate(s1,1))) {
12921 ckmakmsg(fnval,FNVALL,"<ERROR:BAD_DATE\\f",fn,"()>",NULL);
12922 goto fnend;
12923 }
12924 if (month > 12) {
12925 char mn[3];
12926 mn[0] = s1[4];
12927 mn[1] = s1[5];
12928 mn[2] = NUL;
12929 month = atoi((char *)mn) - 1;
12930 }
12931 if (!s2) s2 = ""; /* Parse function code */
12932 if (!*s2) {
12933 fc = 0;
12934 } else if (rdigits(s2)) {
12935 fc = atoi(s2);
12936 } else {
12937 failed = 1;
12938 ckmakmsg(fnval,FNVALL,"<ERROR:FUNCTION_CODE:\\f",fn,"()>",NULL);
12939 goto fnend;
12940 }
12941 s1 = locale_monthname(month,fc); /* Get locale-based month name */
12942 if (!s1) {
12943 failed = 1;
12944 ckmakmsg(fnval,FNVALL,"<ERROR:NO_RESULT:\\f",fn,"()>",NULL);
12945 goto fnend;
12946 }
12947 ckstrncpy(fnval,s1,FNVALL);
12948 goto fnend;
12949 }
12950 #endif /* HAVE_LOCALE */
12951
12952 /* Note: when adding new functions remember to update dohfunc in ckuus2.c. */
12953
12954 failed = 1;
12955 if (fndiags)
12956 ckmakmsg(fnval,FNVALL,"<ERROR:UNKNOWN_FUNCTION:\\f",fn,"()>",NULL);
12957
12958 fnend:
12959 /* Free temporary storage for aguments */
12960 for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
12961 fndepth--;
12962 if (failed) { /* Handle failure */
12963 debug(F111,"fnend",fnval,errno);
12964 if (!p) p = "";
12965 if (p[0]) {
12966 /* In case this wasn't caught above... */
12967 k = strlen(p);
12968 if (p[0] != '<' && p[k-1] != '>') {
12969 ckmakmsg(fnval,FNVALL,"<ERROR:BAD_ARG:\\f",fn,"()>",NULL);
12970 p = fnval;
12971 }
12972 } else {
12973 ckmakmsg(fnval,FNVALL,"<ERROR:UNKNOWN:\\f",fn,"()>",NULL);
12974 p = fnval;
12975 }
12976 if (fnerror) /* SET FUNCTION ERROR ON */
12977 fnsuccess = 0; /* Make command fail (see ckuus5.c) */
12978 debug(F111,"fneval failed",p,fnsuccess);
12979 if (fndiags) /* SET FUNCTION DIAGNOSTICS ON */
12980 printf("?%s\n",p); /* Print error message now. */
12981 else
12982 return(""); /* Return nothing. */
12983 }
12984 return(p);
12985 }
12986 #endif /* NOSPL */
12987
12988 static char ckpidbuf[32] = "????";
12989
12990 #ifdef VMS
12991 _PROTOTYP(long zgpid,(void));
12992 #endif /* VMS */
12993
12994 char *
ckgetpid()12995 ckgetpid() { /* Return pid as string */
12996 #ifdef CK_PID
12997 #ifdef OS2
12998 #define getpid _getpid
12999 unsigned long zz;
13000 #else
13001 long zz;
13002 #endif /* OS2 */
13003 #ifdef VMS
13004 zz = zgpid();
13005 #else
13006 zz = getpid();
13007 #endif /* VMS */
13008 sprintf(ckpidbuf,"%ld",zz); /* SAFE */
13009 #endif /* CK_PID */
13010 return((char *)ckpidbuf);
13011 }
13012
13013 #ifndef NOSPL
13014 #define EMBUFLEN 128 /* Error message buffer length */
13015
13016 static char embuf[EMBUFLEN+1];
13017
13018 char * /* Evaluate builtin variable */
nvlook(s)13019 nvlook(s) char *s; {
13020 int x, y, cx;
13021 long z;
13022 char *p;
13023 #ifndef NODIAL
13024 MDMINF * m;
13025 #endif /* NODIAL */
13026 #ifndef NOKVERBS /* Keyboard macro material */
13027 extern int keymac, keymacx;
13028 #endif /* NOKVERBS */
13029 #ifdef CK_LOGIN
13030 extern int isguest;
13031 #endif /* CK_LOGIN */
13032 if (!s) s = "";
13033 x = strlen(s);
13034 if (fndiags) { /* FUNCTION DIAGNOSTIC ON */
13035 if (x + 32 < EMBUFLEN)
13036 sprintf(embuf,"<ERROR:NO_SUCH_VARIABLE:\\v(%s)>",s); /* SAFE */
13037 else
13038 sprintf(embuf,"<ERROR:NO_SUCH_VARIABLE>"); /* SAFE */
13039 } else /* FUNCTION DIAGNOSTIC OFF */
13040 embuf[0] = NUL;
13041 x = VVBUFL;
13042 p = vvbuf;
13043 if (zzstring(s,&p,&x) < 0) { /* e.g. for \v(\%a) */
13044 y = -1;
13045 } else {
13046 s = vvbuf;
13047 y = lookup(vartab,s,nvars,&x);
13048 }
13049 cx = y; /* y is too generic */
13050 #ifndef NODIAL
13051 m = (mdmtyp > 0) ? modemp[mdmtyp] : NULL; /* For \v(m_xxx) variables */
13052 #endif /* NODIAL */
13053
13054 debug(F101,"nvlook y","",y);
13055
13056 switch (y) {
13057 case VN_ARGC: /* ARGC */
13058 sprintf(vvbuf,"%d",maclvl < 0 ? topargc : macargc[maclvl]); /* SAFE */
13059 return(vvbuf);
13060
13061 case VN_ARGS: /* ARGS */
13062 sprintf(vvbuf,"%d",xargs); /* SAFE */
13063 return(vvbuf);
13064
13065 case VN_COUN: /* COUNT */
13066 sprintf(vvbuf,"%d",count[cmdlvl]); /* SAFE */
13067 return(vvbuf);
13068
13069 case VN_DATE: /* DATE */
13070 ztime(&p); /* Get "asctime" string */
13071 if (p == NULL || *p == NUL) return(NULL);
13072 vvbuf[0] = p[8]; /* dd */
13073 vvbuf[1] = p[9];
13074 vvbuf[2] = SP;
13075 vvbuf[3] = p[4]; /* mmm */
13076 vvbuf[4] = p[5];
13077 vvbuf[5] = p[6];
13078 vvbuf[6] = SP;
13079 for (x = 20; x < 24; x++) /* yyyy */
13080 vvbuf[x - 13] = p[x];
13081 vvbuf[11] = NUL;
13082 return(vvbuf);
13083
13084 case VN_NDAT: /* Numeric date */
13085 ckstrncpy(vvbuf,zzndate(),VVBUFL);
13086 return(vvbuf);
13087
13088 case VN_DIRE: /* DIRECTORY */
13089 s = zgtdir(); /* Get current directory */
13090 if (!s)
13091 #ifdef UNIXOROSK
13092 s = "./";
13093 #else
13094 #ifdef VMS
13095 s = "[]";
13096 #else
13097 s = "";
13098 #endif /* VMS */
13099 #endif /* UNIXOROSK */
13100 ckstrncpy(vvbuf,s,VVBUFL);
13101 s = vvbuf;
13102 #ifdef UNIXOROSK
13103 x = strlen(s);
13104 if (x < VVBUFL - 1) {
13105 if (s[x-1] != '/') {
13106 s[x] = '/';
13107 s[x+1] = NUL;
13108 }
13109 }
13110 #endif /* UNIXOROSK */
13111 return(s);
13112
13113 case VN_FILE: /* filespec */
13114 return(fspec);
13115
13116 case VN_HOST: /* host name */
13117 if (*myhost) { /* If known */
13118 return(myhost); /* return it. */
13119 } else { /* Otherwise */
13120 ckstrncpy(vvbuf,"unknown",VVBUFL); /* just say "unknown" */
13121 return(vvbuf);
13122 }
13123
13124 case VN_SYST: /* System type */
13125 #ifdef UNIX
13126 ckstrncpy(vvbuf,"UNIX",VVBUFL);
13127 #else
13128 #ifdef VMS
13129 ckstrncpy(vvbuf,"VMS",VVBUFL);
13130 #else
13131 #ifdef OSK
13132 ckstrncpy(vvbuf,"OS9/68K",VVBUFL);
13133 #else
13134 #ifdef AMIGA
13135 ckstrncpy(vvbuf,"Amiga",VVBUFL);
13136 #else
13137 #ifdef MAC
13138 ckstrncpy(vvbuf,"Macintosh",VVBUFL);
13139 #else
13140 #ifdef OS2
13141 #ifdef NT
13142 ckstrncpy(vvbuf,"WIN32",VVBUFL) ;
13143 #else /* NT */
13144 ckstrncpy(vvbuf,"OS/2",VVBUFL);
13145 #endif /* NT */
13146 #else
13147 #ifdef datageneral
13148 ckstrncpy(vvbuf,"AOS/VS",VVBUFL);
13149 #else
13150 #ifdef GEMDOS
13151 ckstrncpy(vvbuf,"Atari_ST",VVBUFL);
13152 #else
13153 #ifdef STRATUS
13154 ckstrncpy(vvbuf,"Stratus_VOS",VVBUFL);
13155 #else
13156 ckstrncpy(vvbuf,"unknown",VVBUFL);
13157 #endif /* STRATUS */
13158 #endif /* GEMDOS */
13159 #endif /* datageneral */
13160 #endif /* OS2 */
13161 #endif /* MAC */
13162 #endif /* AMIGA */
13163 #endif /* OSK */
13164 #endif /* VMS */
13165 #endif /* UNIX */
13166 return(vvbuf);
13167
13168 case VN_SYSV: /* System herald */
13169 #ifdef IKSD
13170 #ifdef CK_LOGIN
13171 if (inserver && isguest)
13172 return("");
13173 #endif /* CK_LOGIN */
13174 #endif /* IKSD */
13175 for (x = y = 0; x < VVBUFL; x++) {
13176 if (ckxsys[x] == SP && y == 0) continue;
13177 vvbuf[y++] = (char) ((ckxsys[x] == SP) ? '_' : ckxsys[x]);
13178 }
13179 vvbuf[y] = NUL;
13180 return(vvbuf);
13181 } /* Break up long switch statements... */
13182
13183 switch(y) {
13184 case VN_TIME: /* TIME. Assumes that ztime returns */
13185 ztime(&p); /* "Thu Feb 8 12:00:00 1990" */
13186 if (p == NULL || *p == NUL) /* like asctime()! */
13187 return("");
13188 for (x = 11; x < 19; x++) /* copy hh:mm:ss */
13189 vvbuf[x - 11] = p[x]; /* to vvbuf */
13190 vvbuf[8] = NUL; /* terminate */
13191 return(vvbuf); /* and return it */
13192
13193 case VN_NTIM: /* Numeric time */
13194 ztime(&p); /* "Thu Feb 8 12:00:00 1990" */
13195 if (p == NULL || *p == NUL) /* like asctime()! */
13196 return(NULL);
13197 z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
13198 sprintf(vvbuf,"%ld",z); /* SAFE */
13199 return(vvbuf);
13200
13201 #ifdef CK_TTYFD
13202 case VN_TTYF: /* TTY file descriptor */
13203 sprintf(vvbuf,"%d", /* SAFE */
13204 #ifdef VMS
13205 vmsttyfd()
13206 #else
13207 ttyfd
13208 #endif /* VMS */
13209 );
13210 return(vvbuf);
13211 #endif /* CK_TTYFD */
13212
13213 case VN_VERS: /* Numeric Kermit version number */
13214 sprintf(vvbuf,"%ld",vernum); /* SAFE */
13215 return(vvbuf);
13216
13217 case VN_XVNUM: /* Product-specific version number */
13218 sprintf(vvbuf,"%ld",xvernum); /* SAFE */
13219 return(vvbuf);
13220
13221 case VN_HOME: /* Home directory */
13222 return(homepath());
13223
13224 case VN_IBUF: /* INPUT buffer */
13225 return((char *)inpbuf);
13226
13227 case VN_ICHR: /* INPUT character */
13228 inchar[1] = NUL;
13229 return((char *)inchar);
13230
13231 case VN_ICNT: /* INPUT character count */
13232 sprintf(vvbuf,"%d",incount); /* SAFE */
13233 return(vvbuf);
13234
13235 case VN_SPEE: { /* Transmission SPEED */
13236 long t;
13237 t = ttgspd();
13238 if (t < 0L)
13239 sprintf(vvbuf,"unknown"); /* SAFE */
13240 else
13241 sprintf(vvbuf,"%ld",t); /* SAFE */
13242 return(vvbuf);
13243 }
13244
13245 case VN_SUCC: /* SUCCESS flag */
13246 /* Note inverted sense */
13247 sprintf(vvbuf,"%d",(success == 0) ? 1 : 0); /* SAFE */
13248 return(vvbuf);
13249
13250 case VN_LINE: { /* LINE */
13251 #ifdef DEBUG
13252 if (deblog) {
13253 debug(F111,"\\v(line) local",ttname,local);
13254 debug(F111,"\\v(line) inserver","",inserver);
13255 #ifdef TNCODE
13256 debug(F111,"\\v(line) tcp_incoming","",tcp_incoming);
13257 #endif /* TNCODE */
13258 #ifdef CK_TAPI
13259 debug(F111,"\\v(line) tttapi","",tttapi);
13260 #endif /* CK_TAPI */
13261 }
13262 #endif /* DEBUG */
13263
13264 #ifdef CK_TAPI
13265 if (tttapi) { /* If I have made a TAPI connection */
13266 int i; /* return the TAPI device name */
13267 for (i = 0; i < ntapiline; i++) {
13268 if (!strcmp(ttname,tapilinetab[i].kwd)) {
13269 p = _tapilinetab[i].kwd;
13270 return(p);
13271 }
13272 }
13273 }
13274 #endif /* CK_TAPI */
13275 #ifndef NOXFER
13276 if (inserver /* If I am a TCP server */
13277 #ifdef TNCODE
13278 || tcp_incoming
13279 #endif /* TNCODE */
13280 )
13281 #ifdef TCPSOCKET
13282 p = ckgetpeer(); /* return peer name */
13283 else
13284 #endif /* TCPSOCKET */
13285 #endif /* NOXFER */
13286 if (local) /* Otherwise if in local mode */
13287 p = (char *) ttname; /* return SET LINE / SET HOST name */
13288 else /* Otherwise */
13289 p = ""; /* return empty string */
13290 if (!p) /* In case ckgetpeer() returns */
13291 p = ""; /* null pointer... */
13292 debug(F110,"\\v(line) p",p,0);
13293 if (!*p)
13294 p = (char *) ttname;
13295 return(p);
13296 }
13297 case VN_PROG: /* Program name */
13298 return("C-Kermit");
13299
13300 } /* Break up long switch statements... */
13301
13302 switch(y) {
13303 case VN_RET: /* Value of most recent RETURN */
13304 debug(F111,"\\v(return)",mrval[maclvl+1],maclvl+1);
13305 p = mrval[maclvl+1];
13306 if (p == NULL) p = "";
13307 return(p);
13308
13309 case VN_FFC: /* Size of most recent file */
13310 sprintf(vvbuf, "%s", ckfstoa(ffc)); /* SAFE */
13311 return(vvbuf);
13312
13313 case VN_TFC: /* Size of most recent file group */
13314 sprintf(vvbuf, "%s", ckfstoa(tfc)); /* SAFE */
13315 return(vvbuf);
13316
13317 case VN_CPU: /* CPU type */
13318 #ifdef IKSD
13319 #ifdef CK_LOGIN
13320 if (inserver && isguest)
13321 return("");
13322 #endif /* CK_LOGIN */
13323 #endif /* IKSD */
13324 #ifdef OS2
13325 {
13326 char * getcpu(void) ;
13327 return getcpu();
13328 }
13329 #else /* OS2 */
13330 #ifdef CKCPU
13331 return(CKCPU); /* Traditionally, compile-time value */
13332 #else
13333 #ifdef CK_UTSNAME
13334 { /* But if none, try runtime value */
13335 extern char unm_mch[];
13336 return((char *)unm_mch);
13337 }
13338 #else
13339 p = getenv("HOSTTYPE"); /* 20091116 */
13340 if (p) if (*p) return(p);
13341 return("unknown");
13342 #endif /* CK_UTSNAME */
13343 #endif /* CKCPU */
13344 #endif /* OS2 */
13345
13346 case VN_CMDL: /* Command level */
13347 sprintf(vvbuf, "%d", cmdlvl); /* SAFE */
13348 return(vvbuf);
13349
13350 case VN_DAY: /* Current day of the week */
13351 ztime(&p); /* three-letter abbreviation */
13352 if (p != NULL && *p != NUL) /* ztime() succeeded. */
13353 ckstrncpy(vvbuf,p,4);
13354 else
13355 vvbuf[0] = NUL; /* ztime() failed. */
13356 return(vvbuf); /* Return what we got. */
13357
13358 case VN_NDAY: { /* Numeric day of week */
13359 long k;
13360 z = mjd(zzndate()); /* Get modified Julian date */
13361 k = (((int)(z % 7L)) + 3) % 7; /* Get day number */
13362 sprintf(vvbuf,"%ld",k); /* SAFE */
13363 return(vvbuf);
13364
13365 case VN_MONTH:
13366 ztime(&p); /* three-letter abbreviation */
13367 if (p != NULL && *p != NUL) /* ztime() succeeded. */
13368 ckstrncpy(vvbuf,p+4,5);
13369 else
13370 vvbuf[0] = NUL; /* ztime() failed. */
13371 return(vvbuf); /* Return what we got. */
13372
13373 case VN_NMONTH: { /* Numeric month (1-12) */
13374 int x;
13375 ztime(&p); /* asctime three-letter abbreviation */
13376 for (x = 0; x < 12; x++)
13377 if (!strncmp(p+4,months[x],3)) break;
13378 if (x == 12) {
13379 vvbuf[0] = '?';
13380 vvbuf[1] = '?';
13381 } else {
13382 x++;
13383 vvbuf[0] = (char) ((x < 10) ? '0' : '1');
13384 vvbuf[1] = (char) ((x % 10) + 48);
13385 }
13386 vvbuf[2] = NUL;
13387 return(vvbuf); /* Return what we got. */
13388 }
13389
13390 case VN_YEAR: /* Current year */
13391 ztime(&p);
13392 if (p != NULL && *p != NUL) /* ztime() succeeded. */
13393 ckstrncpy(vvbuf,p+20,5);
13394 else
13395 vvbuf[0] = NUL; /* ztime() failed. */
13396 return(vvbuf); /* Return what we got. */
13397
13398
13399 }
13400
13401 case VN_LCL: /* Local (vs remote) mode */
13402 ckstrncpy(vvbuf, local ? "1" : "0",VVBUFL);
13403 return(vvbuf);
13404
13405 case VN_CMDS: /* Command source */
13406 if (cmdstk[cmdlvl].src == CMD_KB)
13407 ckstrncpy(vvbuf,"prompt",VVBUFL);
13408 else if (cmdstk[cmdlvl].src == CMD_MD)
13409 ckstrncpy(vvbuf,"macro",VVBUFL);
13410 else if (cmdstk[cmdlvl].src == CMD_TF)
13411 ckstrncpy(vvbuf,"file",VVBUFL);
13412 else
13413 ckstrncpy(vvbuf,"unknown",VVBUFL);
13414 return(vvbuf);
13415
13416 case VN_CMDF: /* Current command file name */
13417 #ifdef COMMENT /* (see comments above) */
13418 if (tfnam[tlevel]) { /* (near dblbs declaration) */
13419 dblbs(tfnam[tlevel],vvbuf,VVBUFL);
13420 return(vvbuf);
13421 } else return("");
13422 #else
13423 if (tlevel < 0)
13424 return("");
13425 else
13426 return(tfnam[tlevel] ? tfnam[tlevel] : "");
13427 #endif /* COMMENT */
13428
13429 case VN_MAC: /* Current macro name */
13430 return((maclvl > -1) ? m_arg[maclvl][0] : "");
13431
13432 case VN_EXIT:
13433 sprintf(vvbuf,"%d",xitsta); /* SAFE */
13434 return(vvbuf);
13435
13436 } /* Break up long switch statements... */
13437
13438 switch(y) {
13439 case VN_PRTY: { /* Parity */
13440 char *ss;
13441 switch (parity) {
13442 case 0: ss = "none"; break;
13443 case 'e': ss = "even"; break;
13444 case 'm': ss = "mark"; break;
13445 case 'o': ss = "odd"; break;
13446 case 's': ss = "space"; break;
13447 default: ss = "unknown"; break;
13448 }
13449 ckstrncpy(vvbuf,ss,VVBUFL);
13450 return(vvbuf);
13451 }
13452
13453 case VN_DIAL:
13454 sprintf(vvbuf,"%d", /* SAFE */
13455 #ifndef NODIAL
13456 dialsta
13457 #else
13458 -1
13459 #endif /* NODIAL */
13460 );
13461 return(vvbuf);
13462
13463 #ifndef NODIAL
13464 case VN_DMSG:
13465 #ifdef BIGBUFOK
13466 ckstrncpy(vvbuf,
13467 ((dialsta < 0) ? "(none)" : dialmsg[dialsta]),
13468 VVBUFL); /* Safe if src == NULL.. mdw 20140213 */
13469 #endif /* BIGBUFOK */
13470 return((char *)vvbuf);
13471 #endif /* NODIAL */
13472
13473 #ifdef OS2
13474 case VN_KEYB:
13475 ckstrncpy(vvbuf,conkbg(),VVBUFL);
13476 return(vvbuf);
13477 case VN_SELCT: {
13478 #ifndef NOLOCAL
13479 const char * selection = GetSelection();
13480 return( (char *) (selection ? selection : "" )) ;
13481 #else
13482 return("");
13483 #endif /* NOLOCAL */
13484 }
13485 #endif /* OS2 */
13486
13487 #ifndef NOXFER
13488 case VN_CPS:
13489 sprintf(vvbuf,"%ld",tfcps); /* SAFE */
13490 return(vvbuf);
13491 #endif /* NOXFER */
13492
13493 case VN_MODE: /* File transfer mode */
13494 switch (binary) {
13495 case XYFT_T: ckstrncpy(vvbuf,"text",VVBUFL); break;
13496 case XYFT_B:
13497 case XYFT_U: ckstrncpy(vvbuf,"binary",VVBUFL); break;
13498 case XYFT_I: ckstrncpy(vvbuf,"image",VVBUFL); break;
13499 case XYFT_L: ckstrncpy(vvbuf,"labeled",VVBUFL); break;
13500 case XYFT_M: ckstrncpy(vvbuf,"macbinary",VVBUFL); break;
13501 default: ckstrncpy(vvbuf,"unknown",VVBUFL);
13502 }
13503 return(vvbuf);
13504
13505 #ifdef CK_REXX
13506 case VN_REXX:
13507 return(rexxbuf);
13508 #endif /* CK_REXX */
13509
13510 case VN_NEWL: /* System newline char or sequence */
13511 #ifdef UNIX
13512 ckstrncpy(vvbuf,"\n",VVBUFL);
13513 #else
13514 #ifdef datageneral
13515 ckstrncpy(vvbuf,"\n",VVBUFL);
13516 #else
13517 #ifdef OSK
13518 ckstrncpy(vvbuf,"\15",VVBUFL); /* Remember, these are octal... */
13519 #else
13520 #ifdef MAC
13521 ckstrncpy(vvbuf,"\15",VVBUFL);
13522 #else
13523 #ifdef OS2
13524 ckstrncpy(vvbuf,"\15\12",VVBUFL);
13525 #else
13526 #ifdef STRATUS
13527 ckstrncpy(vvbuf,"\n",VVBUFL);
13528 #else
13529 #ifdef VMS
13530 ckstrncpy(vvbuf,"\15\12",VVBUFL);
13531 #else
13532 #ifdef AMIGA
13533 ckstrncpy(vvbuf,"\n",VVBUFL);
13534 #else
13535 #ifdef GEMDOS
13536 ckstrncpy(vvbuf,"\n",VVBUFL);
13537 #else
13538 ckstrncpy(vvbuf,"\n",VVBUFL);
13539 #endif /* GEMDOS */
13540 #endif /* AMIGA */
13541 #endif /* VMS */
13542 #endif /* STRATUS */
13543 #endif /* OS2 */
13544 #endif /* MAC */
13545 #endif /* OSK */
13546 #endif /* datageneral */
13547 #endif /* UNIX */
13548 return(vvbuf);
13549
13550 case VN_ROWS: /* ROWS */
13551 case VN_COLS: /* COLS */
13552 ckstrncpy(vvbuf,(cx == VN_ROWS) ? "24" : "80",VVBUFL); /* Default */
13553 #ifdef CK_TTGWSIZ
13554 #ifdef OS2
13555 if (tt_cols[VTERM] < 0 || tt_rows[VTERM] < 0)
13556 ttgwsiz();
13557 sprintf(vvbuf,"%d", /* SAFE */
13558 (cx == VN_ROWS) ? tt_rows[VTERM] : tt_cols[VTERM]);
13559 #else /* OS2 */
13560 if (ttgwsiz() > 0) /* Get window size */
13561 if (tt_cols > 0 && tt_rows > 0) /* sets tt_rows, tt_cols */
13562 sprintf(vvbuf,"%d", /* SAFE */
13563 (cx == VN_ROWS) ? tt_rows : tt_cols);
13564 #endif /* OS2 */
13565 #endif /* CK_TTGWSIZ */
13566 return(vvbuf);
13567
13568 case VN_TTYP:
13569 #ifdef NOTERM
13570 ckstrncpy(vvbuf,"unknown",VVBUFL);
13571 #else
13572 #ifdef OS2
13573 sprintf(vvbuf, "%s", /* SAFE */
13574 (tt_type >= 0 && tt_type <= max_tt) ?
13575 tt_info[tt_type].x_name :
13576 "unknown"
13577 );
13578 #else
13579 #ifdef MAC
13580 ckstrncpy(vvbuf,"vt320",VVBUFL);
13581 #else
13582 p = getenv("TERM");
13583 ckstrncpy(vvbuf,p ? p : "unknown",VVBUFL+1);
13584 #endif /* MAC */
13585 #endif /* OS2 */
13586 #endif /* NOTERM */
13587 return(vvbuf);
13588
13589 case VN_MINP: /* MINPUT */
13590 sprintf(vvbuf, "%d", m_found); /* SAFE */
13591 return(vvbuf);
13592 } /* Break up long switch statements... */
13593
13594 switch(y) {
13595 case VN_CONN: /* CONNECTION */
13596 if (!local) {
13597 ckstrncpy(vvbuf,"remote",VVBUFL);
13598 } else {
13599 if (!network)
13600 ckstrncpy(vvbuf,"serial",VVBUFL);
13601 #ifdef TCPSOCKET
13602 else if (nettype == NET_TCPB || nettype == NET_TCPA) {
13603 if (ttnproto == NP_TELNET)
13604 ckstrncpy(vvbuf,"tcp/ip_telnet",VVBUFL);
13605 #ifdef CK_SSL
13606 else if (ttnproto == NP_SSL || ttnproto == NP_SSL_RAW)
13607 ckstrncpy(vvbuf,"tcp/ip_ssl",VVBUFL);
13608 else if (ttnproto == NP_TLS || ttnproto == NP_SSL_RAW)
13609 ckstrncpy(vvbuf,"tcp/ip_tls",VVBUFL);
13610 #endif /* CK_SSL */
13611 else
13612 ckstrncpy(vvbuf,"tcp/ip",VVBUFL);
13613 }
13614 #endif /* TCPSOCKET */
13615 #ifdef SSHBUILTIN
13616 else if (nettype == NET_SSH)
13617 ckstrncpy(vvbuf,"tcp/ip_ssh",VVBUFL);
13618 #endif /* SSHBUILTIN */
13619 #ifdef ANYX25
13620 else if (nettype == NET_SX25 ||
13621 nettype == NET_VX25 ||
13622 nettype == NET_IX25
13623 )
13624 ckstrncpy(vvbuf,"x.25",VVBUFL);
13625 #endif /* ANYX25 */
13626 #ifdef DECNET
13627 else if (nettype == NET_DEC) {
13628 if (ttnproto == NP_LAT)
13629 ckstrncpy(vvbuf,"decnet_lat",VVBUFL);
13630 else if ( ttnproto == NP_CTERM )
13631 ckstrncpy(vvbuf,"decnet_cterm",VVBUFL);
13632 else
13633 ckstrncpy(vvbuf,"decnet",VVBUFL);
13634 }
13635 #endif /* DECNET */
13636 #ifdef SUPERLAT
13637 else if (nettype == NET_SLAT)
13638 ckstrncpy(vvbuf,"superlat",VVBUFL);
13639 #endif /* SUPERLAT */
13640 #ifdef NETFILE
13641 else if (nettype == NET_FILE)
13642 ckstrncpy(vvbuf,"local_file",VVBUFL);
13643 #endif /* NETFILE */
13644 #ifdef NETCMD
13645 else if (nettype == NET_CMD)
13646 ckstrncpy(vvbuf,"pipe",VVBUFL);
13647 #endif /* NETCMD */
13648 #ifdef NETPTY
13649 else if (nettype == NET_PTY)
13650 ckstrncpy(vvbuf,"pseudoterminal",VVBUFL);
13651 #endif /* NETPTY */
13652 #ifdef NETDLL
13653 else if (nettype == NET_DLL)
13654 ckstrncpy(vvbuf,"dynamic_link_library",VVBUFL);
13655 #endif /* NETDLL */
13656
13657 #ifdef NPIPE
13658 else if (nettype == NET_PIPE)
13659 ckstrncpy(vvbuf,"named_pipe",VVBUFL);
13660 #endif /* NPIPE */
13661 #ifdef CK_NETBIOS
13662 else if (nettype == NET_BIOS)
13663 ckstrncpy(vvbuf,"netbios",VVBUFL);
13664 #endif /* CK_NETBIOS */
13665 else
13666 ckstrncpy(vvbuf,"unknown",VVBUFL);
13667 }
13668 return(vvbuf);
13669
13670 #ifndef NOXFER
13671 case VN_SYSI: /* System ID, Kermit code */
13672 return((char *)cksysid);
13673 #endif /* NOXFER */
13674
13675 #ifdef OS2
13676 case VN_SPA: {
13677 unsigned long space = zdskspace(0);
13678 if (space > 0 && space < 1024)
13679 sprintf(vvbuf,"-1");
13680 else
13681 sprintf(vvbuf,"%lu",space); /* SAFE */
13682 return(vvbuf);
13683 }
13684 #endif /* OS2 */
13685
13686 #ifndef NOXFER
13687 case VN_QUE: {
13688 extern char querybuf[];
13689 return(querybuf);
13690 }
13691 #endif /* NOXFER */
13692
13693 #ifndef NOCSETS
13694 case VN_CSET:
13695 #ifdef OS2
13696 sprintf(vvbuf,"cp%d",os2getcp()); /* SAFE */
13697 #else
13698 ckstrncpy(vvbuf,fcsinfo[fcharset].keyword,VVBUFL+1);
13699 #endif /* OS2 */
13700 return(vvbuf);
13701 #endif /* NOCSETS */
13702
13703 #ifdef OS2
13704 case VN_EXEDIR:
13705 return(exedir);
13706 case VN_STAR:
13707 return(startupdir);
13708 #else
13709 case VN_EXEDIR:
13710 return(exedir ? exedir : "");
13711 #ifdef VMSORUNIX
13712 case VN_STAR:
13713 return(startupdir);
13714 #endif /* VMSORUNIX */
13715 #endif /* OS2 */
13716
13717 case VN_INI:
13718 return(inidir);
13719
13720 case VN_MDM:
13721 return(gmdmtyp());
13722
13723 case VN_EVAL:
13724 return(evalbuf);
13725
13726 #ifndef NODIAL
13727 case VN_D_CC: /* DIAL COUNTRY-CODE */
13728 return(diallcc ? diallcc : "");
13729
13730 case VN_D_AC: /* DIAL AREA-CODE */
13731 return(diallac ? diallac : "");
13732
13733 case VN_D_IP: /* DIAL INTERNATIONAL-PREFIX */
13734 return(dialixp ? dialixp : "");
13735
13736 case VN_D_LP: /* DIAL LD-PREFIX */
13737 return(dialldp ? dialldp : "");
13738
13739 case VN_D_LCP: /* DIAL LOCAL-PREFIX */
13740 return(diallcp ? diallcp : "");
13741
13742 case VN_D_PXX: /* DIAL PBX-EXCHANGE that matched */
13743 return(matchpxx ? matchpxx : "");
13744 #else
13745 case VN_D_CC: /* DIAL COUNTRY-CODE */
13746 case VN_D_AC: /* DIAL AREA-CODE */
13747 case VN_D_IP: /* DIAL INTERNATIONAL-PREFIX */
13748 case VN_D_LP: /* DIAL LD-PREFIX */
13749 case VN_D_LCP: /* DIAL LOCAL-PREFIX */
13750 case VN_D_PXX: /* DIAL PBX-EXCHANGE */
13751 return("");
13752 #endif /* NODIAL */
13753 case VN_UID:
13754 #ifdef UNIX
13755 {
13756 #ifdef IKSD
13757 if (inserver)
13758 return((char *)uidbuf);
13759 else
13760 #endif /* IKSD */
13761 if (uidbuf[0])
13762 return((char *)uidbuf);
13763 else
13764 return(whoami());
13765 }
13766 #else
13767 return((char *)uidbuf);
13768 #endif /* UNIX */
13769 } /* Break up long switch statements... */
13770
13771 switch(y) {
13772 case VN_PWD:
13773 #ifdef OS2
13774 if (activecmd == XXOUT || activecmd == XXLNOUT) {
13775 ckstrncpy(vvbuf,pwbuf,VVBUFL);
13776 ck_encrypt((char *)vvbuf);
13777 return((char *)vvbuf);
13778 } else
13779 #endif /* OS2 */
13780 return((char *)pwbuf);
13781
13782 case VN_PRM:
13783 return((char *)prmbuf);
13784
13785 case VN_PROTO:
13786 #ifdef NOXFER
13787 return("none");
13788 #else
13789 #ifdef CK_XYZ
13790 return(ptab[protocol].p_name);
13791 #else
13792 return("kermit");
13793 #endif /* CK_XYZ */
13794 #endif /* NOXFER */
13795
13796 #ifndef NOXFER
13797 #ifdef CK_TMPDIR
13798 case VN_DLDIR:
13799 return(dldir ? dldir : "");
13800 #endif /* CK_TMPDIR */
13801 #endif /* NOXFER */
13802
13803 #ifndef NODIAL
13804 case VN_M_INI: /* Modem init string */
13805 return(dialini ? dialini : (m ? m->wake_str : ""));
13806
13807 case VN_M_DCM: /* Modem dial command */
13808 return(dialcmd ? dialcmd : (m ? m->dial_str : ""));
13809
13810 case VN_M_DCO: /* Modem data compression on */
13811 return(dialdcon ? dialdcon : (m ? m->dc_on_str : ""));
13812
13813 case VN_M_DCX: /* Modem data compression off */
13814 return(dialdcoff ? dialdcoff : (m ? m->dc_off_str : ""));
13815
13816 case VN_M_ECO: /* Modem error correction on */
13817 return(dialecon ? dialecon : (m ? m->ec_on_str : ""));
13818
13819 case VN_M_ECX: /* Modem error correction off */
13820 return(dialecoff ? dialecoff : (m ? m->ec_off_str : ""));
13821
13822 case VN_M_AAO: /* Modem autoanswer on */
13823 return(dialaaon ? dialaaon : (m ? m->aa_on_str : ""));
13824
13825 case VN_M_AAX: /* Modem autoanswer off */
13826 return(dialaaoff ? dialaaoff : (m ? m->aa_off_str : ""));
13827
13828 case VN_M_HUP: /* Modem hangup command */
13829 return(dialhcmd ? dialhcmd : (m ? m->hup_str : ""));
13830
13831 case VN_M_HWF: /* Modem hardware flow command */
13832 return(dialhwfc ? dialhwfc : (m ? m->hwfc_str : ""));
13833
13834 case VN_M_SWF: /* Modem software flow command */
13835 return(dialswfc ? dialswfc : (m ? m->swfc_str : ""));
13836
13837 case VN_M_NFC: /* Modem no flow-control command */
13838 return(dialnofc ? dialnofc : (m ? m->nofc_str : ""));
13839
13840 case VN_M_PDM: /* Modem pulse dialing mode */
13841 return(dialpulse ? dialpulse : (m ? m->pulse : ""));
13842
13843 case VN_M_TDM: /* Modem tone dialing mode */
13844 return(dialtone ? dialtone : (m ? m->tone : ""));
13845
13846 case VN_M_NAM: /* Modem full name */
13847 return(dialname ? dialname : (m ? m->name : ""));
13848 #else
13849 case VN_M_INI: /* Modem init string */
13850 case VN_M_DCM: /* Modem dial command */
13851 case VN_M_DCO: /* Modem data compression on */
13852 case VN_M_DCX: /* Modem data compression off */
13853 case VN_M_ECO: /* Modem error correction on */
13854 case VN_M_ECX: /* Modem error correction off */
13855 case VN_M_AAO: /* Modem autoanswer on */
13856 case VN_M_AAX: /* Modem autoanswer off */
13857 case VN_M_HUP: /* Modem hangup command */
13858 case VN_M_HWF: /* Modem hardware flow command */
13859 case VN_M_SWF: /* Modem software flow command */
13860 case VN_M_NFC: /* Modem no flow-control command */
13861 case VN_M_PDM: /* Modem pulse dialing mode */
13862 case VN_M_TDM: /* Modem tone dialing mode */
13863 case VN_M_NAM:
13864 return("");
13865 #endif /* NODIAL */
13866
13867 case VN_ISTAT: /* INPUT status */
13868 sprintf(vvbuf, "%d", instatus); /* SAFE */
13869 return(vvbuf);
13870
13871 case VN_TEMP: /* Temporary directory */
13872 if (tempdir) { /* This is where SET TEMP-DIRECTORY */
13873 p = tempdir; /* puts it -- just use what's here */
13874 ckstrncpy(vvbuf,tempdir,VVBUFL);
13875 } else {
13876 char c;
13877 /*
13878 If tempdir was empty, we have to figure out what the temp directory should
13879 be here and then put the result where we should have found it in the first
13880 place. This is done by checking environment variables (or logical names
13881 in VMS, same thing from the API point of view), and if that fails using
13882 platform-specific conventions, like the /tmp directory in Unix.
13883 */
13884 #ifdef OS2
13885 #ifdef NT
13886 p = getenv("K95TMP");
13887 #else
13888 p = getenv("K2TMP");
13889 #endif /* NT */
13890 if ( !p )
13891 #endif /* OS2 */
13892 p = getenv("CK_TMP");
13893 if (!p) p = getenv("TMPDIR");
13894 if (!p) p = getenv("TEMP");
13895 if (!p) p = getenv("TMP");
13896
13897 #ifdef OS2ORUNIX
13898 if (p) {
13899 int len = strlen(p);
13900 if (p[len-1] != '/'
13901 #ifdef OS2
13902 && p[len-1] != '\\'
13903 #endif /* OS2 */
13904 ) {
13905 ckstrncpy(vvbuf,p,VVBUFL);
13906 if (vvbuf[0]) ckstrncat(vvbuf,"/",CKMAXPATH);
13907 p = vvbuf;
13908 }
13909 }
13910 #endif /* OS2ORUNIX */
13911
13912 if (!p) {
13913 #ifdef UNIX /* Systems that have a standard */
13914 p = "/tmp/"; /* temporary directory... */
13915 #else
13916 #ifdef datageneral
13917 p = ":TMP:";
13918 #else
13919 p = "";
13920 #endif /* datageneral */
13921 #endif /* UNIX */
13922 ckstrncpy(vvbuf,p,VVBUFL);
13923 p = vvbuf;
13924 }
13925 /*
13926 If the result does not end with a directory separator, tack on the
13927 appropriate one. This way scripts can be written in a platform-independent
13928 way, without having to hardwire a particlar OS's directory separator;
13929 e.g. \v(tmpfile)foo.bar instead of \v(tmpfile)/foo.bar, which would not be
13930 portable to (say) VMS. In a better world the following code would be in the
13931 platform-specific modules, ck?fio.c, but it's too late to go back and redo
13932 them all. Note: Windows and OS/2 use backslash (\) as the directory
13933 separate in the user interface, but accept slash(/) in their APIs.
13934 */
13935 while (*p) { /* For Windows and OS/2 */
13936 #ifdef OS2 /* flip the backslash */
13937 if (*p == '\\') *p = '/';
13938 #endif /* OS2 */
13939 p++;
13940 }
13941 p = vvbuf;
13942 #ifndef VMS
13943 if (p > vvbuf) { /* Directory termination character */
13944 c =
13945 #ifdef MAC
13946 ':'
13947 #else
13948 #ifdef datageneral
13949 ':'
13950 #else
13951 #ifdef STRATUS
13952 '>'
13953 #else
13954 '/'
13955 #endif /* STRATUS */
13956 #endif /* datageneral */
13957 #endif /* MAC */
13958 ;
13959 if (*(p-1) != c) { /* Add it to the end of the */
13960 *p++ = c; /* string if it was not already */
13961 *p = NUL; /* there */
13962 }
13963 }
13964 #endif /* Not VMS */
13965 /*
13966 But if the result is just the one character, e.g. '/' in Unix, erase it
13967 because that's the root directory and obviously can't be used for temporary
13968 files.
13969 */
13970 if (vvbuf[0] == c && vvbuf[1] == NUL) {
13971 vvbuf[0] = NUL;
13972 }
13973 }
13974 makestr(&tempdir,p); /* Save result where we can find it next time */
13975 return(vvbuf);
13976 }
13977 /* Break up long switch statements... */
13978
13979 switch(y) {
13980 case VN_ERRNO: /* Error number */
13981 #ifdef VMS
13982 {
13983 extern int vms_lasterr;
13984 sprintf(vvbuf, "%d", vms_lasterr); /* SAFE */
13985 }
13986 #else
13987 sprintf(vvbuf, "%d", errno); /* SAFE */
13988 #endif /* VMS */
13989 return(vvbuf);
13990
13991 case VN_ERSTR: /* Error string */
13992 ckstrncpy(vvbuf,ck_errstr(),VVBUFL);
13993 return(vvbuf);
13994
13995 #ifndef NOXFER
13996 case VN_RPSIZ: /* RECEIVE packet-length */
13997 sprintf(vvbuf,"%d",urpsiz); /* SAFE */
13998 return(vvbuf);
13999
14000 case VN_WINDO: /* WINDOW slots */
14001 sprintf(vvbuf,"%d",wslotr); /* SAFE */
14002 return(vvbuf);
14003 #endif /* NOXFER */
14004
14005 case VN_TFLN: /* TAKE-file line number */
14006 if (tlevel > -1) {
14007 sprintf(vvbuf, "%d", tfline[tlevel]); /* SAFE */
14008 return(vvbuf);
14009 } else
14010 return("0");
14011
14012 case VN_MDMSG: /* DIALRESULT */
14013 #ifndef NODIAL
14014 return((char *)modemmsg);
14015 #else
14016 return("");
14017 #endif /* NODIAL */
14018
14019 case VN_DNUM: /* DIALNUMBER */
14020 #ifndef NODIAL
14021 return(dialnum ? (char *) dialnum : "");
14022 #else
14023 return("");
14024 #endif /* NODIAL */
14025
14026 case VN_APC:
14027 sprintf(vvbuf, "%d", /* SAFE */
14028 #ifdef CK_APC
14029 apcactive
14030 #else
14031 0
14032 #endif /* CK_APC */
14033 );
14034 return((char *)vvbuf);
14035
14036 #ifdef OS2
14037 #ifndef NOKVERBS
14038 case VN_TRMK:
14039 sprintf(vvbuf, "%d", keymac); /* SAFE */
14040 return((char *)vvbuf);
14041 #endif /* NOKVERBS */
14042 #endif /* OS2 */
14043
14044 case VN_IPADDR:
14045 #ifdef TCPSOCKET
14046 #ifndef OSK
14047 /* This dumps core on OS-9 for some reason, but only if executed */
14048 /* before we have made a TCP connection. This is obviously not */
14049 /* the ideal fix. */
14050 if (!myipaddr[0])
14051 getlocalipaddr();
14052 #endif /* OSK */
14053 #endif /* TCPSOCKET */
14054 ckstrncpy(vvbuf,
14055 #ifdef TCPSOCKET
14056 (char *)myipaddr,
14057 #else
14058 "",
14059 #endif /* TCPSOCKET */
14060 VVBUFL);
14061 return((char *)vvbuf);
14062
14063 #ifndef NOXFER
14064 case VN_CRC16: /* CRC-16 of most recent transfer */
14065 sprintf(vvbuf,"%d",crc16); /* SAFE */
14066 return(vvbuf);
14067 #endif /* NOXFER */
14068
14069 #ifdef CK_PID
14070 case VN_PID:
14071 #ifdef IKSD
14072 #ifdef CK_LOGIN
14073 if (inserver && isguest)
14074 return("");
14075 #endif /* CK_LOGIN */
14076 #endif /* IKSD */
14077 return(ckgetpid());
14078 #endif /* CK_PID */
14079
14080 #ifndef NOXFER
14081 case VN_FNAM: { /* \v(filename) */
14082 extern char filnam[], ofn1[], *sfspec, *rrfspec;
14083 char * tmp;
14084 switch (what) { /* File transfer is in progress */
14085 #ifdef NEWFTP
14086 case (W_FTP|W_RECV):
14087 case (W_FTP|W_SEND):
14088 return((char *)filnam);
14089 #endif /* NEWFTP */
14090 case W_RECV:
14091 case W_REMO:
14092 return((char *)ofn1);
14093 default: /* Most recent file transferred */
14094 if (filnam[0]) { /* (if any) */
14095 return((char *)filnam);
14096 } else if (lastxfer & W_SEND && sfspec) {
14097 if (fnspath == PATH_OFF)
14098 zstrip(sfspec,&tmp);
14099 else
14100 tmp = sfspec;
14101 return(tmp);
14102 } else if (lastxfer & W_RECV && rrfspec) {
14103 if (fnrpath == PATH_OFF)
14104 zstrip(rrfspec,&tmp);
14105 else
14106 tmp = rrfspec;
14107 return(tmp);
14108 } else
14109 return("");
14110 }
14111 }
14112 case VN_FNUM: /* \v(filenum) */
14113 sprintf(vvbuf,"%ld",filcnt); /* SAFE */
14114 return((char *)vvbuf);
14115 #endif /* NOXFER */
14116
14117 #ifdef PEXITSTAT
14118 case VN_PEXIT: {
14119 extern int pexitstat;
14120 sprintf(vvbuf,"%d",pexitstat); /* SAFE */
14121 return((char *)vvbuf);
14122 }
14123 #endif /* PEXITSTAT */
14124
14125 #ifndef NOXFER
14126 case VN_P_8BIT:
14127 vvbuf[0] = parity ? ebq : NUL;
14128 vvbuf[1] = NUL;
14129 return((char *)vvbuf);
14130
14131 case VN_P_CTL: {
14132 extern CHAR myctlq;
14133 vvbuf[0] = myctlq;
14134 vvbuf[1] = NUL;
14135 return((char *)vvbuf);
14136 }
14137 case VN_P_RPT: {
14138 extern int rptena;
14139 vvbuf[0] = rptena ? rptq : NUL;
14140 vvbuf[1] = NUL;
14141 return((char *)vvbuf);
14142 }
14143 #endif /* NOXFER */
14144
14145 } /* Break up long switch statements... */
14146
14147 switch(y) {
14148 case VN_XPROG:
14149 #ifndef COMMENT
14150 /* C-Kermit 9.0 and later for Windows and OS/2 is just C-Kermit */
14151 return("C-Kermit");
14152 #else
14153 #ifdef OS2
14154 #ifdef NT
14155 #ifdef KUI
14156 return("K-95G");
14157 #else
14158 return("K-95");
14159 #endif /* KUI */
14160 #else
14161 return("K/2");
14162 #endif /* NT */
14163 #else
14164 return("C-Kermit");
14165 #endif /* OS2 */
14166 #endif /* COMMENT */
14167
14168 case VN_EDITOR:
14169 #ifdef NOFRILLS
14170 return("");
14171 #else
14172 #ifdef NOPUSH
14173 return("");
14174 #else
14175 {
14176 extern char editor[];
14177 char *ss;
14178 if (!editor[0]) {
14179 ss = getenv("EDITOR");
14180 if (ss) {
14181 ckstrncpy(editor,ss,CKMAXPATH);
14182 }
14183 }
14184 debug(F110,"\\v(editor)",editor,0);
14185 return(editor[0] ? (char *)editor : "");
14186 }
14187 #endif /* NOPUSH */
14188 #endif /* NOFRILLS */
14189
14190 case VN_EDOPT:
14191 #ifdef NOFRILLS
14192 return("");
14193 #else
14194 #ifdef NOPUSH
14195 return("");
14196 #else
14197 {
14198 extern char editopts[];
14199 return(editopts[0] ? (char *)editopts : "");
14200 }
14201 #endif /* NOPUSH */
14202 #endif /* NOFRILLS */
14203
14204 case VN_EDFILE:
14205 #ifdef NOFRILLS
14206 return("");
14207 #else
14208 #ifdef NOPUSH
14209 return("");
14210 #else
14211 {
14212 extern char editfile[];
14213 return(editfile[0] ? (char *)editfile : "");
14214 }
14215 #endif /* NOPUSH */
14216 #endif /* NOFRILLS */
14217
14218 #ifdef BROWSER
14219 case VN_BROWSR: {
14220 extern char browser[];
14221 if (!browser[0]) {
14222 s = getenv("BROWSER");
14223 if (s) ckstrncpy(browser,s,CKMAXPATH);
14224 }
14225 return(browser[0] ? (char *)browser : "");
14226 }
14227 case VN_BROPT: {
14228 extern char browsopts[];
14229 return(browsopts[0] ? (char *)browsopts : "");
14230 }
14231 case VN_URL: {
14232 extern char browsurl[];
14233 return(browsurl[0] ? (char *)browsurl : "");
14234 }
14235 #endif /* BROWSER */
14236 case VN_HERALD:
14237 return((char *)versio);
14238
14239 case VN_TEST: { /* test */
14240 extern char * ck_s_test, * ck_s_tver;
14241 if (!ck_s_test) ck_s_test = "";
14242 if (!ck_s_tver) ck_s_tver = "";
14243 if (*ck_s_test) {
14244 ckstrncpy(vvbuf,ck_s_test,VVBUFL);
14245 if (*ck_s_tver) {
14246 ckstrncat(vvbuf,".",VVBUFL);
14247 ckstrncat(vvbuf,ck_s_tver,VVBUFL);
14248 }
14249 } else
14250 ckstrncpy(vvbuf,"0",VVBUFL);
14251 return((char *)vvbuf);
14252 }
14253
14254 #ifndef NOXFER
14255 case VN_XFSTAT: /* xferstatus */
14256 x = xferstat; /* Like success */
14257 if (x > -1) x = (x == 0) ? 1 : 0; /* External value is reversed */
14258 sprintf(vvbuf,"%d",x); /* SAFE */
14259 return((char *)vvbuf);
14260
14261 case VN_XFMSG: /* xfermsg */
14262 return((char *)epktmsg);
14263
14264 #ifndef NOMSEND
14265 case VN_SNDL: { /* sendlist */
14266 extern int filesinlist;
14267 sprintf(vvbuf,"%d",filesinlist); /* SAFE */
14268 return((char *)vvbuf);
14269 }
14270 #endif /* NOMSEND */
14271 #endif /* NOXFER */
14272
14273 #ifdef CK_TRIGGER
14274 case VN_TRIG: {
14275 extern char * triggerval;
14276 return(triggerval ? triggerval : "");
14277 }
14278 #endif /* CK_TRIGGER */
14279 #ifdef OS2MOUSE
14280 #ifdef OS2
14281 case VN_MOU_X: {
14282 extern int MouseCurX;
14283 sprintf(vvbuf,"%d",MouseCurX); /* SAFE */
14284 return((char *)vvbuf);
14285 }
14286 case VN_MOU_Y: {
14287 extern int MouseCurY;
14288 sprintf(vvbuf,"%d",MouseCurY); /* SAFE */
14289 return((char *)vvbuf);
14290 }
14291 #endif /* OS2 */
14292 #endif /* OS2MOUSE */
14293 case VN_PRINT: {
14294 extern int printpipe;
14295 extern char * printername;
14296 #ifdef PRINTSWI
14297 extern int noprinter;
14298 if (noprinter) return("");
14299 #endif /* PRINTSWI */
14300 ckmakmsg(vvbuf,VVBUFL,
14301 printpipe ? "|" : "",
14302 printername ? printername :
14303 #ifdef OS2
14304 "PRN",
14305 #else
14306 "(default)",
14307 #endif /* OS2 */
14308 NULL,
14309 NULL
14310 );
14311 return((char *)vvbuf);
14312 }
14313 } /* Break up long switch statements... */
14314
14315 switch(y) {
14316 case VN_ESC: /* Escape character */
14317 sprintf(vvbuf,"%d",escape); /* SAFE */
14318 return((char *)vvbuf);
14319
14320 case VN_INTIME:
14321 sprintf(vvbuf,"%ld",inetime); /* SAFE */
14322 return((char *)vvbuf);
14323
14324 case VN_INTMO:
14325 sprintf(vvbuf,"%d",inwait); /* SAFE */
14326 return((char *)vvbuf);
14327
14328 case VN_SECURE:
14329 if (0
14330 #ifdef SSHBUILTIN
14331 || IS_SSH()
14332 #endif /* SSHBUILTIN */
14333 #ifdef CK_ENCRYPTION
14334 || ck_tn_encrypting() && ck_tn_decrypting()
14335 #endif /* CK_ENCRYPTION */
14336 #ifdef CK_SSL
14337 || tls_active_flag || ssl_active_flag
14338 #endif /* CK_SSL */
14339 )
14340 return("1");
14341 else
14342 return("0");
14343
14344 case VN_AUTHN:
14345 #ifdef CK_AUTHENTICATION
14346 {
14347 extern char szUserNameAuthenticated[];
14348 return((char *)szUserNameAuthenticated);
14349 }
14350 #else /* CK_AUTHENTICATION */
14351 return((char *)"");
14352 #endif /* CK_AUTHENTICATION */
14353
14354 case VN_AUTHS:
14355 #ifdef CK_AUTHENTICATION
14356 switch (ck_tn_auth_valid()) {
14357 case AUTH_UNKNOWN:
14358 return((char *)"unknown");
14359 case AUTH_OTHER:
14360 return((char *)"other");
14361 case AUTH_USER:
14362 return((char *)"user");
14363 case AUTH_VALID:
14364 return((char *)"valid");
14365 case AUTH_REJECT:
14366 default:
14367 return((char *)"rejected");
14368 }
14369 #else /* CK_AUTHENTICATION */
14370 return((char *)"rejected");
14371 #endif /* CK_AUTHENTICATION */
14372
14373 case VN_AUTHT:
14374 #ifdef CK_AUTHENTICATION
14375 #ifdef CK_SSL
14376 if ((ssl_active_flag || tls_active_flag) &&
14377 ck_tn_auth_valid() == AUTH_VALID &&
14378 (sstelnet ? (!TELOPT_U(TELOPT_AUTHENTICATION)) :
14379 (!TELOPT_ME(TELOPT_AUTHENTICATION))) ||
14380 ck_tn_authenticated() == AUTHTYPE_NULL ||
14381 ck_tn_authenticated() == AUTHTYPE_AUTO)
14382 return("X_509_CERTIFICATE");
14383 else
14384 #endif /* CK_SSL */
14385 return(AUTHTYPE_NAME(ck_tn_authenticated()));
14386 #else /* CK_AUTHENTICATION */
14387 return((char *)"NULL");
14388 #endif /* CK_AUTHENTICATION */
14389
14390 #ifdef CK_KERBEROS
14391 case VN_K4PRN: {
14392 extern char * krb4_d_principal;
14393 if (krb4_d_principal)
14394 ckstrncpy(vvbuf,krb4_d_principal,VVBUFL+1);
14395 else
14396 *vvbuf = NUL;
14397 return((char *)vvbuf);
14398 }
14399 case VN_K5PRN: {
14400 extern char * krb5_d_principal;
14401 if (krb5_d_principal)
14402 ckstrncpy(vvbuf,krb5_d_principal,VVBUFL+1);
14403 else
14404 *vvbuf = NUL;
14405 return((char *)vvbuf);
14406 }
14407 case VN_K4RLM: {
14408 extern char * krb4_d_realm;
14409 if (krb4_d_realm) {
14410 ckstrncpy(vvbuf,krb4_d_realm,VVBUFL+1);
14411 } else {
14412 char * s = ck_krb4_getrealm();
14413 ckstrncpy(vvbuf,s ? s : "",VVBUFL+1);
14414 }
14415 return((char *)vvbuf);
14416 }
14417 case VN_K4SRV: {
14418 extern char * krb4_d_srv;
14419 if (krb4_d_srv)
14420 ckstrncpy(vvbuf,krb4_d_srv,VVBUFL+1);
14421 else
14422 ckstrncpy(vvbuf,"rcmd",VVBUFL);
14423 return((char *)vvbuf);
14424 }
14425 case VN_K5RLM: {
14426 extern char * krb5_d_realm;
14427 extern char * krb5_d_cc;
14428 if (krb5_d_realm) {
14429 ckstrncpy(vvbuf,krb5_d_realm,VVBUFL+1);
14430 } else {
14431 char * s = ck_krb5_getrealm(krb5_d_cc);
14432 ckstrncpy(vvbuf,s,VVBUFL+1);
14433 }
14434 return((char *)vvbuf);
14435 }
14436 case VN_K5CC: {
14437 extern char * krb5_d_cc;
14438 if (krb5_d_cc)
14439 ckstrncpy(vvbuf,krb5_d_cc,VVBUFL+1);
14440 else
14441 ckstrncpy(vvbuf,ck_krb5_get_cc_name(),VVBUFL+1);
14442 return((char *)vvbuf);
14443 }
14444 case VN_K5SRV: {
14445 extern char * krb5_d_srv;
14446 if (krb5_d_srv)
14447 ckstrncpy(vvbuf,krb5_d_srv,VVBUFL+1);
14448 else
14449 ckstrncpy(vvbuf,"host",VVBUFL);
14450 return((char *)vvbuf);
14451 }
14452 case VN_K4ENO: {
14453 extern int krb4_errno;
14454 sprintf(vvbuf,"%d",krb4_errno); /* SAFE */
14455 return((char *)vvbuf);
14456 }
14457 case VN_K5ENO: {
14458 extern int krb5_errno;
14459 sprintf(vvbuf,"%d",krb5_errno); /* SAFE */
14460 return((char *)vvbuf);
14461 }
14462 case VN_K4EMSG: {
14463 extern char * krb4_errmsg;
14464 ckstrncpy(vvbuf,krb4_errmsg?krb4_errmsg:"",VVBUFL+1);
14465 return((char *)vvbuf);
14466 }
14467 case VN_K5EMSG: {
14468 extern char * krb5_errmsg;
14469 ckstrncpy(vvbuf,krb5_errmsg,VVBUFL+1);
14470 return((char *)vvbuf);
14471 }
14472 #endif /* CK_KERBEROS */
14473 #ifdef CK_SSL
14474 case VN_X509_S:
14475 if (ssl_active_flag)
14476 ckstrncpy(vvbuf,ssl_get_subject_name(ssl_con),VVBUFL+1);
14477 else if (tls_active_flag)
14478 ckstrncpy(vvbuf,ssl_get_subject_name(tls_con),VVBUFL+1);
14479 else
14480 ckstrncpy(vvbuf,"",VVBUFL+1);
14481 return((char *)vvbuf);
14482 case VN_X509_I:
14483 if (ssl_active_flag)
14484 ckstrncpy(vvbuf,ssl_get_issuer_name(ssl_con),VVBUFL+1);
14485 else if (tls_active_flag)
14486 ckstrncpy(vvbuf,ssl_get_issuer_name(tls_con),VVBUFL+1);
14487 else
14488 ckstrncpy(vvbuf,"",VVBUFL+1);
14489 return((char *)vvbuf);
14490 #endif /* CK_SSL */
14491
14492 case VN_OSNAM:
14493 #ifdef IKSD
14494 #ifdef CK_LOGIN
14495 if (inserver && isguest)
14496 return("");
14497 #endif /* CK_LOGIN */
14498 #endif /* IKSD */
14499 #ifdef CK_UTSNAME
14500 {
14501 extern char unm_nam[];
14502 return((char *)unm_nam);
14503 }
14504 #else
14505 for (x = y = 0; x < VVBUFL; x++) {
14506 if (ckxsys[x] == SP && cx == 0) continue;
14507 vvbuf[y++] = (char) ((ckxsys[x] == SP) ? '_' : ckxsys[x]);
14508 }
14509 vvbuf[y] = NUL;
14510 return(vvbuf);
14511 #endif /* CK_UTSNAME */
14512
14513 case VN_OSVER: {
14514 #ifdef CK_UTSNAME
14515 extern char unm_ver[];
14516 #ifdef IKSD
14517 #ifdef CK_LOGIN
14518 if (inserver && isguest)
14519 return("");
14520 #endif /* CK_LOGIN */
14521 #endif /* IKSD */
14522 return((char *)unm_ver);
14523 #else
14524 return("");
14525 #endif /* CK_UTSNAME */
14526 }
14527
14528 case VN_OSREL: {
14529 #ifdef CK_UTSNAME
14530 extern char unm_rel[];
14531 #ifdef IKSD
14532 #ifdef CK_LOGIN
14533 if (inserver && isguest)
14534 return("");
14535 #endif /* CK_LOGIN */
14536 #endif /* IKSD */
14537 return((char *)unm_rel);
14538 #else
14539 return("");
14540 #endif /* CK_UTSNAME */
14541 }
14542 } /* Break up long switch statements... */
14543
14544 switch(y) {
14545 case VN_NAME: {
14546 extern char * myname;
14547 return(myname);
14548 }
14549
14550 case VN_MODL: {
14551 #ifdef CK_UTSNAME
14552 extern char unm_mod[], unm_mch[];
14553 int y = VVBUFL - 1;
14554 char * s = unm_mod;
14555 #endif /* CK_UTSNAME */
14556 #ifdef IKSD
14557 #ifdef CK_LOGIN
14558 if (inserver && isguest)
14559 return("");
14560 #endif /* CK_LOGIN */
14561 #endif /* IKSD */
14562
14563 #ifdef COMMENT /* was HPUX */
14564 if (!unm_mod[0] && !nopush)
14565 zzstring("\\fcommand(model)",&s,&y);
14566 /*
14567 Another possibility would be:
14568 "\\fcommand(ksh -c 'whence model 1>&- && model || uname -m')"
14569 But that would depend on having ksh.
14570 */
14571 #else
14572 #ifdef OSF32 /* Digital UNIX 3.2 and higher... */
14573 /* Note: Ultrix has /etc/sizer, but it is not publicly executable. */
14574 /* sizer -c outputs 'cpu:<tab><tab>"DECxxxx"' */
14575 if (!unm_mod[0]) {
14576 char * p;
14577 int flag = 0;
14578 zzstring("\\fcommand(/usr/sbin/sizer -c)",&s,&y);
14579 debug(F110,"DU model",unm_mod,0);
14580 s = unm_mod;
14581 p = unm_mod;
14582 while (*p) { /* Extract the part in quotes */
14583 if (*p == '"') {
14584 if (flag)
14585 break;
14586 flag = 1;
14587 p++;
14588 continue;
14589 }
14590 if (flag)
14591 *s++ = *p;
14592 p++;
14593 }
14594 *s = NUL;
14595 }
14596 #endif /* OSF32 */
14597 #endif /* COMMENT */
14598
14599 #ifdef CK_UTSNAME
14600 if (unm_mod[0])
14601 return((char *)unm_mod);
14602 else
14603 return((char *)unm_mch);
14604 #else
14605 return("");
14606 #endif /* CK_UTSNAME */
14607 }
14608
14609 #ifdef IBMX25
14610 /* X.25 variables (local and remote address) */
14611 case VN_X25LA:
14612 if (!local_nua[0] && !x25local_nua(local_nua))
14613 *vvbuf = NULL;
14614 else
14615 ckstrncpy(vvbuf,local_nua,VVBUFL+1);
14616 return((char *)vvbuf);
14617
14618 case VN_X25RA:
14619 if (!remote_nua[0])
14620 *vvbuf = NULL;
14621 else
14622 ckstrncpy(vvbuf,remote_nua,VVBUFL+1);
14623 return((char *)vvbuf);
14624 #endif /* IBMX25 */
14625
14626 #ifndef NODIAL
14627 case VN_PDSFX: {
14628 extern char pdsfx[];
14629 return((char *)pdsfx);
14630 }
14631 case VN_DTYPE: {
14632 extern int dialtype;
14633 sprintf(vvbuf,"%d",dialtype); /* SAFE */
14634 return((char *)vvbuf);
14635 }
14636 #endif /* NODIAL */
14637
14638 #ifdef UNIX
14639 case VN_LCKPID: {
14640 extern char lockpid[];
14641 return((char *)lockpid);
14642 }
14643 #endif /* UNIX */
14644
14645 #ifndef NOXFER
14646 case VN_BLK:
14647 sprintf(vvbuf,"%d",bctr); /* SAFE */
14648 return((char *)vvbuf);
14649
14650 case VN_TFTIM:
14651 sprintf(vvbuf, /* SAFE */
14652 #ifdef GFTIMER
14653 "%ld", (long)(fptsecs + 0.5)
14654 #else
14655 "%d", tsecs
14656 #endif /* GFTIMER */
14657 );
14658 return((char *)vvbuf);
14659 #endif /* NOXFER */
14660
14661 case VN_HWPAR:
14662 case VN_SERIAL: {
14663 int sb;
14664 char c, * ss;
14665 extern int stopbits;
14666 vvbuf[0] = NUL;
14667 if (hwparity && local && !network)
14668 ss = parnam((char)hwparity);
14669 else
14670 ss = parnam((char)parity);
14671 if (cx == VN_HWPAR) {
14672 ckstrncpy(vvbuf,ss,VVBUFL);
14673 return((char *)vvbuf);
14674 }
14675 c = ss[0];
14676 if (islower(c)) c = toupper(c);
14677 sb = stopbits;
14678 if (sb < 1)
14679 sb = (speed > 0 && speed <= 110L) ? 2 : 1;
14680 if (hwparity)
14681 sprintf(vvbuf," 8%c%d",c,sb); /* SAFE */
14682 else if (parity)
14683 sprintf(vvbuf," 7%c%d",c,sb); /* SAFE */
14684 else
14685 sprintf(vvbuf," 8N%d",sb); /* SAFE */
14686 return((char *)vvbuf);
14687 }
14688
14689 #ifdef UNIX
14690 case VN_LCKDIR: {
14691 #ifndef NOUUCP
14692 extern char * uucplockdir;
14693 ckstrncpy(vvbuf,uucplockdir,VVBUFL);
14694 x = strlen(vvbuf);
14695 if (x > 0) {
14696 if (vvbuf[x-1] != '/') {
14697 vvbuf[x] = '/';
14698 vvbuf[x+1] = NUL;
14699 }
14700 }
14701 #else
14702 vvbuf[0] = NUL;
14703 #endif /* NOUUCP */
14704 return((char *)vvbuf);
14705 }
14706 #endif /* UNIX */
14707 } /* Break up long switch statements... */
14708
14709 switch(y) {
14710 #ifndef NODIAL
14711 case VN_DM_LP:
14712 case VN_DM_SP:
14713 case VN_DM_PD:
14714 case VN_DM_TD:
14715 case VN_DM_WA:
14716 case VN_DM_WD:
14717 case VN_DM_HF:
14718 case VN_DM_WB:
14719 case VN_DM_RC: {
14720 extern char * getdm();
14721 ckstrncpy(vvbuf,getdm(y),VVBUFL);
14722 return((char *)vvbuf);
14723 }
14724 #endif /* NODIAL */
14725
14726 case VN_TY_LN:
14727 case VN_TY_LC: {
14728 extern int typ_lines;
14729 sprintf(vvbuf,"%d",typ_lines); /* SAFE */
14730 return((char *)vvbuf);
14731 }
14732 case VN_TY_LM: {
14733 extern int typ_mtchs;
14734 sprintf(vvbuf,"%d",typ_mtchs); /* SAFE */
14735 return((char *)vvbuf);
14736 }
14737 case VN_MACLVL:
14738 sprintf(vvbuf,"%d",maclvl); /* SAFE */
14739 return((char *)vvbuf);
14740 } /* Break up long switch statements... */
14741
14742 switch(y) {
14743 #ifndef NOLASTFILE
14744 case VN_LASTFIL: {
14745 extern char * lastfile;
14746 return(lastfile ? lastfile : "");
14747 }
14748 #endif /* NOLASTFILE */
14749 #ifndef NOXFER
14750 case VN_XF_BC:
14751 sprintf(vvbuf,"%d",crunched); /* SAFE */
14752 return((char *)vvbuf);
14753
14754 case VN_XF_TM:
14755 sprintf(vvbuf,"%d",timeouts); /* SAFE */
14756 return((char *)vvbuf);
14757
14758 case VN_XF_RX:
14759 sprintf(vvbuf,"%d",retrans); /* SAFE */
14760 return((char *)vvbuf);
14761 #endif /* NOXFER */
14762
14763 case VN_MS_CD: /* Modem signals */
14764 case VN_MS_CTS:
14765 case VN_MS_DSR:
14766 case VN_MS_DTR:
14767 case VN_MS_RI:
14768 case VN_MS_RTS: {
14769 int x, z = -1;
14770 x = ttgmdm(); /* Try to get them */
14771 if (x > -1) {
14772 switch (y) {
14773 case VN_MS_CD: z = (x & BM_DCD) ? 1 : 0; break;
14774 case VN_MS_DSR: z = (x & BM_DSR) ? 1 : 0; break;
14775 case VN_MS_CTS: z = (x & BM_CTS) ? 1 : 0; break;
14776 #ifdef MAC
14777 case VN_MS_DTR: z = (x & BM_DTR) ? 1 : 0; break;
14778 #else
14779 #ifndef STRATUS
14780 case VN_MS_RI: z = (x & BM_RNG) ? 1 : 0; break;
14781 #ifndef NT
14782 case VN_MS_DTR: z = (x & BM_DTR) ? 1 : 0; break;
14783 case VN_MS_RTS: z = (x & BM_RTS) ? 1 : 0; break;
14784 #endif /* NT */
14785 #endif /* STRATUS */
14786 #endif /* MAC */
14787 }
14788 }
14789 sprintf(vvbuf,"%d",z); /* SAFE */
14790 return((char *)vvbuf);
14791 }
14792 case VN_MATCH: /* INPUT MATCH */
14793 return(inpmatch ? inpmatch : "");
14794
14795 #ifdef CKFLOAT
14796 case VN_ISCALE: /* INPUT SCALE-FACTOR */
14797 return(inpscale ? inpscale : "1.0");
14798 #endif /* CKFLOAT */
14799
14800 case VN_SLMSG: { /* SET LINE / HOST message */
14801 extern char * slmsg;
14802 vvbuf[0] = NUL;
14803 if (slmsg)
14804 ckstrncpy(vvbuf,slmsg,VVBUFL);
14805 return(vvbuf);
14806 }
14807
14808 case VN_TXTDIR: /* TEXTDIR */
14809 return(k_info_dir ? k_info_dir : "");
14810
14811 #ifdef FNFLOAT
14812 case VN_MA_PI:
14813 return(math_pi);
14814
14815 case VN_MA_E:
14816 return(math_e);
14817
14818 case VN_MA_PR:
14819 sprintf(vvbuf,"%d",fp_digits); /* SAFE */
14820 return(vvbuf);
14821 #endif /* FNFLOAT */
14822
14823 case VN_CMDBL:
14824 sprintf(vvbuf,"%d",CMDBL); /* SAFE */
14825 return(vvbuf);
14826
14827 #ifdef CKCHANNELIO
14828 case VN_FERR: {
14829 extern int z_error;
14830 sprintf(vvbuf,"%d",z_error); /* SAFE */
14831 return(vvbuf);
14832 }
14833 case VN_FMAX: {
14834 extern int z_maxchan;
14835 sprintf(vvbuf,"%d",z_maxchan); /* SAFE */
14836 return(vvbuf);
14837 }
14838 case VN_FCOU: {
14839 extern int z_filcount;
14840 sprintf(vvbuf,"%d",z_filcount); /* SAFE */
14841 return(vvbuf);
14842 }
14843 #endif /* CKCHANNELIO */
14844
14845 #ifndef NODIAL
14846 case VN_DRTR: {
14847 extern int dialcount;
14848 sprintf(vvbuf,"%d",dialcount); /* SAFE */
14849 return(vvbuf);
14850 }
14851 #endif /* NODIAL */
14852
14853 #ifndef NOLOGDIAL
14854 #ifndef NOLOCAL
14855 case VN_CXTIME:
14856 sprintf(vvbuf,"%ld",dologshow(0)); /* SAFE */
14857 return(vvbuf);
14858 #endif /* NOLOCAL */
14859 #endif /* NOLOGDIAL */
14860
14861 case VN_BYTE:
14862 sprintf(vvbuf,"%d",byteorder); /* SAFE */
14863 return(vvbuf);
14864
14865 case VN_KBCHAR:
14866 vvbuf[0] = NUL;
14867 vvbuf[1] = NUL;
14868 if (kbchar > 0)
14869 vvbuf[0] = (kbchar & 0xff);
14870 return(vvbuf);
14871
14872 case VN_TTYNAM: {
14873 #ifdef HAVECTTNAM
14874 extern char cttnam[];
14875 return((char *)cttnam);
14876 #else
14877 return(CTTNAM);
14878 #endif /* HAVECTTNAM */
14879 }
14880
14881 case VN_PROMPT:
14882 return(cmgetp());
14883
14884 case VN_BUILD: {
14885 extern char * buildid;
14886 return(buildid);
14887 }
14888
14889 #ifndef NOSEXP
14890 case VN_SEXP: {
14891 extern char * lastsexp;
14892 return(lastsexp ? lastsexp : "");
14893 }
14894 case VN_VSEXP: {
14895 extern char * sexpval;
14896 return(sexpval ? sexpval : "");
14897 }
14898 case VN_LSEXP: {
14899 extern int sexpdep;
14900 ckstrncpy(vvbuf,ckitoa(sexpdep),VVBUFL);
14901 return(vvbuf);
14902 }
14903 #endif /* NOSEXP */
14904
14905 #ifdef GFTIMER
14906 case VN_FTIME: {
14907 CKFLOAT f;
14908 ztime(&p);
14909 if (p == NULL || *p == NUL)
14910 return(NULL);
14911 z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
14912 f = (CKFLOAT)z + ((CKFLOAT)ztusec) / 1000000.0;
14913 sprintf(vvbuf,"%f",f); /* SAFE */
14914 return(vvbuf);
14915 }
14916 #endif /* GFTIMER */
14917
14918 #ifndef NOHTTP
14919 case VN_HTTP_C: { /* HTTP Code */
14920 extern int http_code;
14921 return(ckitoa(http_code));
14922 }
14923 case VN_HTTP_N: /* HTTP Connected */
14924 return( http_isconnected() ? "1" : "0");
14925 case VN_HTTP_H: /* HTTP Host */
14926 return( (char *)http_host() );
14927 case VN_HTTP_M: { /* HTTP Message */
14928 extern char http_reply_str[];
14929 return((char *)http_reply_str);
14930 }
14931 case VN_HTTP_S: /* HTTP Security */
14932 return((char *)http_security());
14933 #endif /* NOHTTP */
14934
14935 #ifdef NEWFTP
14936 case VN_FTP_B:
14937 return((char *)ftp_cpl_mode());
14938 case VN_FTP_D:
14939 return((char *)ftp_dpl_mode());
14940 case VN_FTP_Z:
14941 return((char *)ftp_authtype());
14942 case VN_FTP_C: {
14943 extern int ftpcode;
14944 return(ckitoa(ftpcode));
14945 }
14946 case VN_FTP_M: {
14947 extern char ftp_reply_str[];
14948 if (isdigit(ftp_reply_str[0]) &&
14949 isdigit(ftp_reply_str[1]) &&
14950 isdigit(ftp_reply_str[2]) &&
14951 ftp_reply_str[3] == ' ')
14952 return(&ftp_reply_str[4]);
14953 else
14954 return(ftp_reply_str);
14955 }
14956 case VN_FTP_S: {
14957 extern char ftp_srvtyp[];
14958 return((char *)ftp_srvtyp);
14959 }
14960 case VN_FTP_H: {
14961 extern char * ftp_host;
14962 return(ftp_host ? ftp_host : "");
14963 }
14964 case VN_FTP_X: { /* FTP Connected */
14965 return(ftpisconnected() ? "1" : "0");
14966 }
14967 case VN_FTP_L: { /* FTP Logged in */
14968 return(ftpisloggedin() ? "1" : "0");
14969 }
14970 case VN_FTP_G: { /* FTP GET-PUT-REMOTE */
14971 extern int ftpget;
14972 char * s = "";
14973 switch (ftpget) {
14974 case 0: s = "kermit"; break;
14975 case 1: s = "ftp"; break;
14976 case 2: s = "auto"; break;
14977 }
14978 return(s);
14979 }
14980 #endif /* NEWFTP */
14981
14982 #ifndef NOLOCAL
14983 case VN_CX_STA: { /* CONNECT status */
14984 extern int cx_status;
14985 return(ckitoa(cx_status));
14986 }
14987 #endif /* NOLOCAL */
14988 case VN_NOW: /* Timestamp */
14989 return(ckcvtdate(p,0));
14990
14991 case VN_HOUR: /* Hour of the day */
14992 ztime(&p); /* "Thu Feb 8 12:00:00 1990" */
14993 if (!p) p = "";
14994 if (!*p) return(p);
14995 vvbuf[0] = p[11];
14996 vvbuf[1] = p[12];
14997 vvbuf[2] = NUL;
14998 return(vvbuf); /* and return it */
14999
15000 case VN_BITS: /* Bits (16, 32, 64) */
15001 if (sizeof(long) > 4)
15002 return(ckitoa(8*sizeof(long)));
15003 else
15004 return(ckitoa(8*sizeof(int)));
15005
15006 case VN_LASTKWV: /* 212 */
15007 return(lastkwval ? lastkwval : "");
15008
15009 case VN_HOSTIP: { /* 212 */
15010 #ifdef TCPSOCKET
15011 extern char hostipaddr[];
15012 return((char *)hostipaddr);
15013 #else
15014 return("");
15015 #endif /* TCPSOCKET */
15016 }
15017 case VN_INPMSG:
15018 switch (instatus) {
15019 case INP_OK: return("SUCCESS");
15020 case INP_TO: return("Timed out");
15021 case INP_UI: return("Keyboard interrupt");
15022 case INP_IE: return("Internal error");
15023 case INP_IO: return("I/O error or connection lost");
15024 case INP_IKS: return("INPUT disabled");
15025 case INP_BF: return("Buffer filled and /NOWRAP set");
15026 default: return("Unknown");
15027 }
15028
15029 case VN_VAREVAL: /* 212 */
15030 return(vareval ? "recursive" : "simple");
15031
15032 case VN_LOG_CON: /* \v(...) for log files */
15033 #ifdef CKLOGDIAL
15034 return(diafil);
15035 #else
15036 return("");
15037 #endif
15038 case VN_LOG_PKT:
15039 #ifndef NOXFER
15040 return(pktfil);
15041 #else
15042 return("");
15043 #endif
15044 case VN_LOG_SES:
15045 #ifndef NOLOCAL
15046 return(sesfil);
15047 #else
15048 return("");
15049 #endif
15050 case VN_LOG_TRA:
15051 #ifdef TLOG
15052 return(trafil);
15053 #else
15054 return("");
15055 #endif
15056 case VN_LOG_DEB:
15057 #ifdef DEBUG
15058 return(debfil);
15059 #else
15060 return("");
15061 #endif
15062 case VN_PREVCMD: {
15063 extern char * prevcmd;
15064 return(prevcmd ? prevcmd : "");
15065 }
15066 }
15067
15068 #ifndef NODIAL
15069 switch (y) { /* Caller ID values */
15070 extern char
15071 * callid_date, * callid_time, * callid_name,
15072 * callid_nmbr, * callid_mesg;
15073
15074 case VN_CI_DA:
15075 return(callid_date ? callid_date : "");
15076
15077 case VN_CI_TI:
15078 return(callid_time ? callid_time : "");
15079
15080 case VN_CI_NA:
15081 return(callid_name ? callid_name : "");
15082
15083 case VN_CI_NU:
15084 return(callid_nmbr ? callid_nmbr : "");
15085
15086 case VN_CI_ME:
15087 return(callid_mesg ? callid_mesg : "");
15088
15089 } /* End of variable-name switches */
15090 #endif /* NODIAL */
15091
15092 #ifdef NT
15093 switch (y) {
15094 case VN_PERSONAL:
15095 p = (char *)GetPersonal();
15096 if (p) {
15097 GetShortPathName(p,vvbuf,VVBUFL);
15098 return(vvbuf);
15099 }
15100 return("");
15101 case VN_DESKTOP:
15102 p = (char *)GetDesktop();
15103 if (p) {
15104 GetShortPathName(p,vvbuf,VVBUFL);
15105 return(vvbuf);
15106 }
15107 return("");
15108 case VN_COMMON:
15109 p = (char *)GetAppData(1);
15110 if (p) {
15111 ckmakmsg(vvbuf,VVBUFL,p,"Kermit 95/",NULL,NULL);
15112 GetShortPathName(vvbuf,vvbuf,VVBUFL);
15113 return(vvbuf);
15114 }
15115 return("");
15116 case VN_APPDATA:
15117 p = (char *)GetAppData(0);
15118 if (p) {
15119 ckmakmsg(vvbuf,VVBUFL,p,"Kermit 95/",NULL,NULL);
15120 GetShortPathName(vvbuf,vvbuf,VVBUFL);
15121 return(vvbuf);
15122 }
15123 return("");
15124 }
15125 #endif /* NT */
15126
15127 #ifdef TN_COMPORT
15128 switch (y) {
15129 case VN_TNC_SIG: {
15130 p = (char *) tnc_get_signature();
15131 ckstrncpy(vvbuf,p ? p : "",VVBUFL);
15132 return(vvbuf);
15133 }
15134 }
15135 #endif /* TN_COMPORT */
15136
15137 #ifdef KUI
15138 switch (y) {
15139 case VN_GUI_RUN: {
15140 extern HWND getHwndKUI();
15141 if ( IsIconic(getHwndKUI()) )
15142 return("minimized");
15143 if ( IsZoomed(getHwndKUI()) )
15144 return("maximized");
15145 return("restored");
15146 }
15147 case VN_GUI_XP:
15148 sprintf(vvbuf,"%d",get_gui_window_pos_x()); /* SAFE */
15149 return(vvbuf);
15150 case VN_GUI_YP:
15151 sprintf(vvbuf,"%d",get_gui_window_pos_y()); /* SAFE */
15152 return(vvbuf);
15153 case VN_GUI_XR:
15154 sprintf(vvbuf,"%d",GetSystemMetrics(SM_CXSCREEN)); /* SAFE */
15155 return(vvbuf);
15156 case VN_GUI_YR:
15157 sprintf(vvbuf,"%d",GetSystemMetrics(SM_CYSCREEN)); /* SAFE */
15158 return(vvbuf);
15159 case VN_GUI_FNM:
15160 if ( ntermfont > 0 ) {
15161 int i;
15162 for (i = 0; i < ntermfont; i++) {
15163 if (tt_font == term_font[i].kwval) {
15164 ckstrncpy(vvbuf,term_font[i].kwd,VVBUFL);
15165 return(vvbuf);
15166 }
15167 }
15168 }
15169 return("(unknown)");
15170 case VN_GUI_FSZ:
15171 ckstrncpy(vvbuf,ckitoa(tt_font_size/2),VVBUFL);
15172 if ( tt_font_size % 2 )
15173 ckstrncat(vvbuf,".5",VVBUFL);
15174 return(vvbuf);
15175 }
15176 #endif /* KUI */
15177
15178 fnsuccess = 0;
15179 if (fnerror) {
15180 fnsuccess = 0;
15181 }
15182 if (fndiags) {
15183 if (!embuf[0])
15184 ckstrncpy(embuf,"<ERROR:NO_SUCH_VARIABLE>",EMBUFLEN);
15185 printf("?%s\n",embuf);
15186 return((char *)embuf);
15187 } else
15188 return("");
15189 }
15190 #endif /* NOSPL */
15191
15192 /* warning, this won't work for VMS */
15193 char *
getbasename(s)15194 getbasename(s) char *s; {
15195 int n, i;
15196 if (!s) s = "";
15197 if (!*s) return("");
15198 n = (int)strlen(s);
15199 for (i = n-2; i >= 0; i--) {
15200 if (ISDIRSEP(s[i]))
15201 return(s+i+1);
15202 }
15203 return(s);
15204 }
15205
15206 /*
15207 X X S T R I N G -- Expand variables and backslash codes.
15208
15209 int xxtstring(s,&s2,&n);
15210
15211 Expands \ escapes via recursive descent.
15212 Argument s is a pointer to string to expand (source).
15213 Argument s2 is the address of where to put result (destination).
15214 Argument n is the length of the destination string (to prevent overruns).
15215 Returns -1 on failure, 0 on success,
15216 with destination string null-terminated and s2 pointing to the
15217 terminating null, so that subsequent characters can be added.
15218 Failure reasons include destination buffer is filled up.
15219 */
15220
15221 #define XXDEPLIM 100 /* Recursion depth limit */
15222 /*
15223 In Windows the stack is limited to 256K so big character arrays like
15224 vnambuf can't be on the stack in recursive functions like zzstring().
15225 But that's no reason use malloc() in Unix or VMS, which don't have
15226 this kind of restriction.
15227 */
15228 #ifdef DVNAMBUF /* Dynamic vnambuf[] */
15229 #undef DVNAMBUF /* Clean slate */
15230 #endif /* DVNAMBUF */
15231
15232 #ifndef NOSPL /* Only if SPL included */
15233 #ifdef OS2 /* Only for K95 */
15234 #define DVNAMBUF
15235 #endif /* OS2 */
15236 #endif /* NOSPL */
15237
15238 int
zzstring(s,s2,n)15239 zzstring(s,s2,n) char *s; char **s2; int *n; {
15240 int x, /* Current character */
15241 xx, /* Worker */
15242 y, /* Worker */
15243 pp, /* Paren level */
15244 kp, /* Brace level */
15245 argn, /* Function argument counter */
15246 n2, /* Local copy of n */
15247 d, /* Array dimension */
15248 vbi, /* Variable id (integer form) */
15249 argl, /* String argument length */
15250 nx, /* Save original length */
15251 quoting = 0; /* 299 */
15252
15253 char vb, /* Variable id (char form) */
15254 *vp, /* Pointer to variable definition */
15255 *new, /* Local pointer to target string */
15256 #ifdef COMMENT
15257 *old, /* Save original target pointer */
15258 #endif /* COMMENT */
15259 *p, /* Worker */
15260 *q, /* Worker */
15261 *s3; /* Worker */
15262 int x3; /* Worker */
15263 char *r = (char *)0; /* For holding function args */
15264 char *r2 = (char *)0;
15265 char *r3p;
15266
15267 #ifndef NOSPL
15268 #ifdef DVNAMBUF
15269 char * vnambuf = NULL; /* Buffer for variable/function name */
15270 #else /* DVNAMBUF */
15271 char vnambuf[VNAML]; /* Buffer for variable/function name */
15272 #endif /* DVNAMBUF */
15273 char *argp[FNARGS]; /* Pointers to function args */
15274 #endif /* NOSPL */
15275
15276 static int depth = 0; /* Call depth, avoid overflow */
15277
15278 n2 = *n; /* Make local copies of args */
15279 nx = n2;
15280
15281 #ifdef COMMENT
15282 /* This is always 32K in BIGBUFOK builds */
15283 if (depth == 0)
15284 debug(F101,"zzstring top-level n","",n2);
15285 #endif /* COMMENT */
15286
15287 new = *s2; /* for one less level of indirection */
15288 #ifdef COMMENT
15289 old = new;
15290 #endif /* COMMENT */
15291
15292 #ifndef NOSPL
15293 itsapattern = 0; /* For \fpattern() */
15294 isjoin = 0; /* For \fjoin() */
15295 #endif /* NOSPL */
15296 depth++; /* Sink to a new depth */
15297 if (depth > XXDEPLIM) { /* Too deep? */
15298 (VOID) newerrmsg("Definition is circular or too deep");
15299 debug(F111,"zzstring","Definition is circular or too deep",XXDEPLIM);
15300 depth = 0;
15301 *new = NUL;
15302 return(-1);
15303 }
15304 if (!s || !new) { /* Watch out for null pointers */
15305 debug(F101,"zzstring fail 2","",depth);
15306 if (new)
15307 *new = NUL;
15308 depth = 0;
15309 return(-1);
15310 }
15311 s3 = s;
15312 argl = 0;
15313 while (*s3++) argl++; /* Get length of source string */
15314 debug(F010,"zzstring entry",s,0);
15315 if (argl == 0) { /* Empty string */
15316 debug(F111,"zzstring empty arg",s,argl);
15317 depth = 0;
15318 *new = NUL;
15319 return(0);
15320 }
15321 if (argl < 0) { /* Watch out for garbage */
15322 debug(F101,"zzstring fail 3","",depth);
15323 *new = NUL;
15324 depth = 0;
15325 return(-1);
15326 }
15327 #ifdef DVNAMBUF
15328 debug(F100,"vnambuf malloc...","",0);
15329 vnambuf = malloc(VNAML);
15330 if (vnambuf == NULL) {
15331 printf("?Out of memory");
15332 return(-1);
15333 }
15334 debug(F100,"vnambuf malloc ok","",0);
15335 #endif /* DVNAMBUF */
15336
15337 while ((x = *s)) { /* Loop for all characters */
15338 if (x != CMDQ) { /* Is it the command-quote char? */
15339 *new++ = *s++; /* No, normal char, just copy */
15340 if (--n2 < 0) { /* and count it, careful of overflow */
15341 debug(F101,"zzstring overflow 1","",depth);
15342 depth = 0;
15343 #ifdef DVNAMBUF
15344 if (vnambuf) free(vnambuf);
15345 #endif /* DVNAMBUF */
15346 return(-1);
15347 }
15348 continue;
15349 }
15350
15351 /* We have the command-quote character. */
15352
15353 x = *(s+1); /* Get the following character. */
15354 if (isupper(x)) x = tolower(x);
15355 switch (x) { /* Act according to variable type */
15356 #ifndef NOSPL
15357 case 0: /* It's a lone backslash */
15358 *new++ = *s++;
15359 if (--n2 < 0) {
15360 debug(F101,"zzstring overflow 2","",0);
15361 #ifdef DVNAMBUF
15362 if (vnambuf) free(vnambuf);
15363 #endif /* DVNAMBUF */
15364 return(-1);
15365 }
15366 break;
15367 case '%': /* Variable */
15368 s += 2; /* Get the letter or digit */
15369 vb = *s++; /* and move source pointer past it */
15370 vp = NULL; /* Assume definition is empty */
15371 if (vb >= '0' && vb <= '9') { /* Digit for macro arg */
15372 if (maclvl < 0) /* Digit variables are global */
15373 vp = g_var[vb]; /* if no macro is active */
15374 else /* otherwise */
15375 vp = m_arg[maclvl][vb - '0']; /* they're on the stack */
15376 } else if (vb == '*') { /* Macro args string */
15377 #ifdef COMMENT
15378 /* This doesn't take changes into account */
15379 vp = (maclvl >= 0) ? m_line[maclvl] : topline;
15380 if (!vp) vp = "";
15381 #else
15382 char * ss = new;
15383 if (zzstring("\\fjoin(&_[],,1)",&new,&n2) < 0) {
15384 #ifdef DVNAMBUF
15385 if (vnambuf) free(vnambuf);
15386 #endif /* DVNAMBUF */
15387 return(-1);
15388 }
15389 debug(F110,"zzstring \\%*",ss,0);
15390 break;
15391 #endif /* COMMENT */
15392 } else {
15393 if (isupper(vb)) vb += ('a'-'A');
15394 vp = g_var[vb]; /* Letter for global variable */
15395 }
15396 if (!vp) vp = "";
15397 #ifdef COMMENT
15398 if (vp) { /* If definition not empty */
15399 #endif /* COMMENT */
15400 if (vareval) {
15401 debug(F010,"zzstring %n vp",vp,0);
15402 /* call self to evaluate it */
15403 if (zzstring(vp,&new,&n2) < 0) {
15404 debug(F101,"zzstring fail 6","",depth);
15405 #ifdef DVNAMBUF
15406 if (vnambuf) free(vnambuf);
15407 #endif /* DVNAMBUF */
15408 return(-1); /* Pass along failure */
15409 }
15410 } else {
15411 while ((*new++ = *vp++)) /* copy it to output string. */
15412 if (--n2 < 0) {
15413 if (q) free(q);
15414 debug(F101,"zzstring overflow 4.5","",depth);
15415 #ifdef DVNAMBUF
15416 if (vnambuf) free(vnambuf);
15417 #endif /* DVNAMBUF */
15418 return(-1);
15419 }
15420 new--; /* Back up over terminating null */
15421 n2++; /* to allow for further deposits. */
15422 }
15423 #ifdef COMMENT
15424 } else {
15425 debug(F110,"zzstring %n vp","(NULL)",0);
15426 n2 = nx;
15427 new = old;
15428 *new = NUL;
15429 }
15430 #endif /* COMMENT */
15431 break;
15432 case '&': /* An array reference */
15433 x = arraynam(s,&vbi,&d); /* Get name and subscript */
15434 debug(F111,"zzstring arraynam",s,x);
15435 if (x < 0) {
15436 debug(F101,"zzstring fail 7","",depth);
15437 #ifdef DVNAMBUF
15438 if (vnambuf) free(vnambuf);
15439 #endif /* DVNAMBUF */
15440 return(-1);
15441 }
15442 pp = 0; /* Bracket counter */
15443 while (*s) { /* Advance source pointer... */
15444 if (*s == '[') pp++;
15445 if (*s == ']' && --pp == 0) break;
15446 s++;
15447 }
15448 if (*s == ']') s++; /* ...past the closing bracket. */
15449
15450 xx = chkarray(vbi,d); /* Array is declared? */
15451 debug(F101,"zzstring chkarray","",x);
15452 if (xx > -1) {
15453 #ifdef COMMENT
15454 char * s1 = NULL;
15455 #endif /* COMMENT */
15456 vbi -= ARRAYBASE; /* Convert name to index */
15457
15458 if (a_dim[vbi] >= d) { /* If subscript in range */
15459 char **ap;
15460 ap = a_ptr[vbi]; /* get data pointer */
15461 if (ap) { /* and if there is one */
15462 if (ap[d]) { /* If definition not empty */
15463 debug(F111,"zzstring ap[d]",ap[d],d);
15464 if (vareval) {
15465 if (zzstring(ap[d],&new,&n2) < 0) {
15466 debug(F101,"zzstring fail 8","",depth);
15467 #ifdef DVNAMBUF
15468 if (vnambuf) free(vnambuf);
15469 #endif /* DVNAMBUF */
15470 return(-1); /* Pass along failure */
15471 }
15472 } else {
15473 vp = ap[d];
15474 while ((*new++ = *vp++)) /* copy to result */
15475 if (--n2 < 0) {
15476 if (q) free(q);
15477 debug(F101,
15478 "zzstring overflow 8.5","",depth);
15479 #ifdef DVNAMBUF
15480 if (vnambuf) free(vnambuf);
15481 #endif /* DVNAMBUF */
15482 return(-1);
15483 }
15484 new--; /* Back up over terminating null */
15485 n2++; /* to allow for further deposits. */
15486 }
15487 }
15488
15489 } else {
15490 /* old = new; */
15491 n2 = nx;
15492 }
15493 }
15494 }
15495 break;
15496
15497 case 'f': /* A builtin function */
15498 q = vnambuf; /* Copy the name */
15499 y = 0; /* into a separate buffer */
15500 s += 2; /* point past 'F' */
15501 while (y++ < VNAML) {
15502 if (*s == '(') { s++; break; } /* Look for open paren */
15503 if ((*q = *s) == NUL) break; /* or end of string */
15504 s++; q++;
15505 }
15506 *q = NUL; /* Terminate function name */
15507 if (y >= VNAML) { /* Handle pathological case */
15508 while (*s && (*s != '(')) /* of very long string entered */
15509 s++; /* as function name. */
15510 if (*s == ')') s++; /* Skip past it. */
15511 }
15512 r = r2 = malloc(argl+2); /* And make a place to copy args */
15513 /* debug(F101,"zzstring r2","",r2); */
15514 if (!r2) { /* Watch out for malloc failure */
15515 debug(F101,"zzstring fail 9","",depth);
15516 *new = NUL;
15517 depth = 0;
15518 #ifdef DVNAMBUF
15519 if (vnambuf) free(vnambuf);
15520 #endif /* DVNAMBUF */
15521 return(-1);
15522 }
15523 if (r3) free(r3); /* And another to copy literal arg string */
15524 r3 = malloc(argl+2);
15525 /* debug(F101,"zzstring r3","",r3); */
15526 if (!r3) {
15527 debug(F101,"zzstring fail 10","",depth);
15528 depth = 0;
15529 *new = NUL;
15530 if (r2) free(r2);
15531 #ifdef DVNAMBUF
15532 if (vnambuf) free(vnambuf);
15533 #endif /* DVNAMBUF */
15534 return(-1);
15535 } else
15536 r3p = r3;
15537 argn = 0; /* Argument counter */
15538 argp[argn++] = r; /* Point to first argument */
15539 y = 0; /* Completion flag */
15540 pp = 1; /* Paren level (already have one). */
15541 kp = 0;
15542 while (1) { /* Copy each argument, char by char. */
15543 *r3p++ = *s; /* This is a literal copy for \flit */
15544 if (!*s) break;
15545
15546 if (*s == '{') { /* Left brace */
15547 kp++;
15548 }
15549 if (*s == '}') { /* Right brace */
15550 kp--;
15551 }
15552 if (*s == '(' && kp <= 0) { /* Open paren not in brace */
15553 pp++; /* Count it */
15554 }
15555 *r = *s; /* Now copy resulting byte */
15556 if (!*r) /* If NUL, done. */
15557 break;
15558 if (*r == ')' && kp <= 0) { /* Closing paren, count it. */
15559 if (--pp == 0) { /* Final one? */
15560 *r = NUL; /* Make it a terminating null */
15561 *(r3p - 1) = NUL;
15562 s++; /* Point past it in source string */
15563 y = 1; /* Flag we've got all the args */
15564 break; /* Done with while loop */
15565 }
15566 }
15567 if (*r == ',' && kp <= 0) { /* Comma */
15568 if (pp == 1) { /* If not within ()'s, */
15569 if (argn >= FNARGS) { /* Too many args */
15570 s++; r++; /* Keep collecting flit() string */
15571 continue;
15572 }
15573 *r = NUL; /* New arg, skip past comma */
15574 argp[argn++] = r+1; /* In range, point to new arg */
15575 } /* Otherwise just skip past */
15576 }
15577 s++; r++; /* Advance pointers */
15578 }
15579 if (!y) /* If we didn't find closing paren */
15580 argn = -1;
15581 #ifdef DEBUG
15582 if (deblog) {
15583 char buf[24];
15584 debug(F111,"zzstring function name",vnambuf,y);
15585 debug(F010,"zzstring function r3",r3,0);
15586 for (y = 0; y < argn; y++) {
15587 sprintf(buf,"arg %2d ",y);
15588 debug(F010,buf,argp[y],0);
15589 }
15590 }
15591 #endif /* DEBUG */
15592 {
15593 /* In case the function name itself is constructed */
15594 char buf[64]; char * p = buf; int n = 64;
15595 if (zzstring(vnambuf,&p,&n) > -1)
15596 ckstrncpy(vnambuf,buf,64);
15597 }
15598 vp = fneval(vnambuf,argp,argn,r3); /* Evaluate the function. */
15599 if (vp) { /* If definition not empty */
15600 while ((*new++ = *vp++)) { /* copy it to output string */
15601 if (--n2 < 0) { /* watch out for overflow */
15602 debug(F101,"zzstring fail 12","",depth);
15603 if (r2) { free(r2); r2 = NULL; }
15604 if (r3) { free(r3); r3 = NULL; }
15605 #ifdef DVNAMBUF
15606 if (vnambuf) free(vnambuf);
15607 #endif /* DVNAMBUF */
15608 return(-1);
15609 }
15610 }
15611 new--; /* Back up over terminating null */
15612 n2++; /* to allow for further deposits. */
15613 }
15614 if (r2) { free(r2); r2 = NULL; }
15615 if (r3) { free(r3); r3 = NULL; }
15616 break;
15617 case 'q': /* 299 String to be take literally */
15618 quoting = 1; /* 299 */
15619 case '$': /* An environment variable */
15620 case 'v': /* Or a named builtin variable. */
15621 case 'm': /* Or a macro /long variable */
15622 case 's': /* 196 Macro substring */
15623 case ':': /* 196 \-variable substring */
15624 pp = 0;
15625 p = s+2; /* $/V/M must be followed by (name) */
15626 if (*p != '(') { /* as in \$(HOME) or \V(count) */
15627 *new++ = *s++; /* If not, just copy it */
15628 if (--n2 < 0) {
15629 debug(F101,"zzstring overflow 3","",depth);
15630 #ifdef DVNAMBUF
15631 if (vnambuf) free(vnambuf);
15632 #endif /* DVNAMBUF */
15633 return(-1);
15634 }
15635 break;
15636 }
15637 pp++;
15638 p++; /* Point to 1st char of name */
15639 q = vnambuf; /* Copy the name */
15640 y = 0; /* into a separate buffer */
15641 debug(F110,">>>> \\q(ARG)",p,0);
15642 while (y++ < VNAML) { /* Watch out for name too long */
15643 if (*p == '(') { /* Parens can be nested... */
15644 if (*(p-1) != CMDQ) /* 299 */
15645 pp++;
15646 } else if (*p == ')') { /* Name properly terminated with ')' */
15647 if (*(p-1) != CMDQ) /* 299 */
15648 pp--;
15649 if (pp == 0) {
15650 p++; /* Move source pointer past ')' */
15651 break;
15652 }
15653 }
15654 if ((*q = *p) == NUL) /* String ends before ')' */
15655 break;
15656 p++; q++; /* Advance pointers */
15657 }
15658 *q = NUL; /* Terminate the variable name */
15659 if (y >= VNAML) { /* Handle pathological case */
15660 while (*p && (*p != ')')) /* of very long string entered */
15661 p++; /* as variable name. */
15662 if (*p == ')') p++; /* Skip ahead to the end of it. */
15663 }
15664 /* At this point vnambuf contains the macro name from inside the parens */
15665
15666 s = p; /* Adjust global source pointer */
15667 s3 = vnambuf;
15668 x3 = 0;
15669 while (*s3++) x3++; /* Length needed */
15670
15671 /* The following is in case the macro name itself contains variables */
15672
15673 p = malloc(x3 + 1); /* Make temporary space */
15674 if (p && !quoting) { /* If we got the space */
15675 vp = vnambuf; /* Point to original */
15676 strcpy(p,vp); /* (safe) Make a copy of it */
15677 y = VNAML; /* Length of name buffer */
15678 zzstring(p,&vp,&y); /* Evaluate the copy */
15679 free(p); /* Free the temporary space */
15680 p = NULL;
15681 }
15682 /* At this point vnambuf contains the fully evaluated macro name */
15683
15684 debug(F110,"zzstring macro name",vnambuf,0);
15685 q = NULL;
15686 if (x == 'q') { /* 299 Quoting this string */
15687 vp = vnambuf; /* 299 */
15688 debug(F110,">>> VP",vp,0);
15689 } else if (x == '$') { /* Look up its value */
15690 vp = getenv(vnambuf); /* This way for environment variable */
15691 } else if (x == 'm' || x == 's' || x == ':') { /* Macro / substr */
15692 int k, x1 = -1, x2 = -1;
15693 char c = NUL;
15694 k = strlen(vnambuf);
15695 /* \s(name[n:m]) -- Compact substring notation */
15696 if ((x == 's' || x == ':') && (k > 1)) { /* Substring wanted */
15697 int bprc;
15698 if (vnambuf[k-1] == ']') {
15699 int i;
15700 for (i = 0; i < k-1; i++) {
15701 if (vnambuf[i] == '[') {
15702 bprc = boundspair(vnambuf,":_.",&x1,&x2,&c);
15703 debug(F111,"zzstring boundspair",vnambuf,bprc);
15704 debug(F000,"zzstring boundspair c","",c);
15705 if (bprc > -1) {
15706 vnambuf[i] = NUL;
15707 if (x1 < 1)
15708 x1 = 1;
15709 x1--; /* Adjust to 0-base */
15710 }
15711 break;
15712 }
15713 }
15714 }
15715 }
15716 if (x == ':') { /* Variable type (s or :) */
15717 vp = vnambuf;
15718 } else { /* Regular macro or associative array*/
15719 y = isaarray(vnambuf) ?
15720 mxxlook(mactab,vnambuf,nmac) : /* Assoc Array */
15721 mxlook(mactab,vnambuf,nmac); /* Macro */
15722 if (y > -1) { /* Got definition */
15723 vp = mactab[y].mval;
15724 } else {
15725 vp = NULL;
15726 }
15727 }
15728 debug(F111,"zzstring vp",vp,(vp==NULL)?0:strlen(vp));
15729
15730 if (vp) {
15731 if ((x == 's' || x == ':') && (k > 1)) {
15732 /* Compact substring notation */
15733 if (x2 == 0) { /* Length */
15734 vp = NULL;
15735 } else if (x1 > -1) { /* Start */
15736 k = strlen(vp);
15737 debug(F101,">>> k","",k);
15738 /* If it's off the end, result is empty */
15739 if (x1 > k) {
15740 vp = NULL;
15741 } else if (k > 0) {
15742 /* Stay in bounds */
15743 if (c == '_' && x2 > k) /* startpos_endpos */
15744 x2 = k;
15745 if (c == ':' && x1 + x2 > k) /* start:length */
15746 x2 = -1;
15747 debug(F101,">>> x2","",x2);
15748 debug(F000,">>> c","",c);
15749 if ((q = malloc(k+1))) {
15750 strcpy(q,vp); /* safe */
15751 if (c == '.') {
15752 q[x1+1] = NUL;
15753 debug(F000,"XXX. q",q,c);
15754 }
15755 if (c == ':') { /* start:length */
15756 if ((x2 > -1) && ((x1 + x2) <= k)) {
15757 q[x1+x2] = NUL;
15758 }
15759 debug(F000,"XXX: q",q,c);
15760 } else if (c == '_') { /* start_endpos */
15761 if (x1 >= x2) {
15762 q[x1 = 0] = NUL;
15763 } else if (x2 < k && x2 > -1) {
15764 q[x2] = NUL;
15765 }
15766 debug(F000,"XXX_ q",q,c);
15767 }
15768 vp = q+x1;
15769 } else vp = NULL;
15770 } else vp = NULL;
15771 }
15772
15773 debug(F110,"XXX vnambuf",vnambuf,0);
15774 debug(F000,"XXX c","",c);
15775 debug(F101,"XXX x1","",x1);
15776 debug(F101,"XXX x2","",x2);
15777 debug(F110,"XXX result",vp,0);
15778 #ifdef DEBUG
15779 if (deblog) {
15780 if (!vp) {
15781 } else {
15782 k = strlen(vp);
15783 }
15784 }
15785 #endif /* DEBUG */
15786 }
15787 }
15788 } else { /* or */
15789 vp = nvlook(vnambuf); /* this way for builtin variable */
15790 }
15791 if (vp) { /* If definition not empty */
15792 while ((*new++ = *vp++)) /* copy it to output string. */
15793 if (--n2 < 0) {
15794 if (q) free(q);
15795 debug(F101,"zzstring overflow 4","",depth);
15796 #ifdef DVNAMBUF
15797 if (vnambuf) free(vnambuf);
15798 #endif /* DVNAMBUF */
15799 return(-1);
15800 }
15801 new--; /* Back up over terminating null */
15802 n2++; /* to allow for further deposits. */
15803 }
15804 if (q) {
15805 free(q);
15806 q = NULL;
15807 }
15808 break;
15809 #endif /* NOSPL */ /* Handle \nnn even if NOSPL. */
15810
15811 #ifndef NOKVERBS
15812 case 'K':
15813 case 'k': {
15814 extern struct keytab kverbs[];
15815 extern int nkverbs;
15816 #define K_BUFLEN 30
15817 char kbuf[K_BUFLEN + 1]; /* Key verb name buffer */
15818 int x, y, z, brace = 0;
15819 s += 2;
15820 /*
15821 We assume that the verb name is {braced}, or it extends to the end of the
15822 string, s, or it ends with a space, control character, or backslash.
15823 */
15824 p = kbuf; /* Copy verb name into local buffer */
15825 x = 0;
15826 if (*s == '{') {
15827 s++;
15828 brace++;
15829 }
15830 while ((x++ < K_BUFLEN) && (*s > SP) && (*s != CMDQ)) {
15831 if (brace && *s == '}') {
15832 s++;
15833 break;
15834 }
15835 *p++ = *s++;
15836 }
15837 brace = 0;
15838 *p = NUL; /* Terminate. */
15839 p = kbuf; /* Point back to beginning */
15840 debug(F110,"zzstring kverb",p,0);
15841 y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */
15842 debug(F101,"zzstring lookup",0,y);
15843 if (y > -1) {
15844 dokverb(VCMD,y);
15845 #ifndef NOSPL
15846 } else { /* Is it a macro? */
15847 y = mxlook(mactab,p,nmac);
15848 if (y > -1) {
15849 debug(F111,"zzstring mxlook",p,y);
15850 if ((z = dodo(y,NULL,cmdstk[cmdlvl].ccflgs)) > 0) {
15851 if (cmpush() > -1) { /* Push command parser state */
15852 extern int ifc;
15853 int ifcsav = ifc; /* Push IF condition on stack */
15854 y = parser(1); /* New parser to execute macro */
15855 cmpop(); /* Pop command parser */
15856 ifc = ifcsav; /* Restore IF condition */
15857 if (y == 0) { /* No errors, ignore actions */
15858 p = mrval[maclvl+1]; /* If OK set return val */
15859 if (p == NULL) p = "";
15860 }
15861 } else { /* Can't push any more */
15862 debug(F101,"zzstring pushed too deep","",depth);
15863 printf(
15864 "\n?Internal error: zzstring stack overflow\n"
15865 );
15866 while (cmpop() > -1);
15867 p = "";
15868 }
15869 }
15870 }
15871 #endif /* NOSPL */
15872 }
15873 break;
15874 }
15875 #endif /* NOKVERBS */
15876
15877 default: /* Maybe it's a backslash code */
15878 y = xxesc(&s); /* Go interpret it */
15879 if (y < 0) { /* Upon failure */
15880 *new++ = (char) x; /* Just quote the next character */
15881 s += 2; /* Move past the pair */
15882 n2 -= 2;
15883 if (n2 < 0) {
15884 debug(F101,"zzstring overflow 5","",depth);
15885 #ifdef DVNAMBUF
15886 if (vnambuf) free(vnambuf);
15887 #endif /* DVNAMBUF */
15888 return(-1);
15889 }
15890 continue; /* and go back for more */
15891 } else {
15892 *new++ = (char) y; /* else deposit interpreted value */
15893 if (--n2 < 0) {
15894 debug(F101,"zzstring overflow 6","",depth);
15895 #ifdef DVNAMBUF
15896 if (vnambuf) free(vnambuf);
15897 #endif /* DVNAMBUF */
15898 return(-1);
15899 }
15900 }
15901 }
15902 }
15903 *new = NUL; /* Terminate the new string */
15904 debug(F010,"zzstring while exit",*s2,0);
15905
15906 depth--; /* Adjust stack depth gauge */
15907 *s2 = new; /* Copy results back into */
15908 *n = n2; /* the argument addresses */
15909 debug(F101,"zzstring ok","",depth);
15910 #ifdef DVNAMBUF
15911 if (vnambuf) free(vnambuf);
15912 #endif /* DVNAMBUF */
15913 return(0); /* and return. */
15914 }
15915 #endif /* NOICP */
15916