apply 010_makefile-destdir-support
[ckermit.git] / ckuus6.c
1 #include "ckcsym.h"
2 #ifndef NOICP
3
4 /*  C K U U S 6 --  "User Interface" for Unix Kermit (Part 6)  */
5
6 /*
7   Authors:
8     Frank da Cruz <fdc@columbia.edu>,
9       The Kermit Project, Columbia University, New York City
10     Jeffrey E Altman <jaltman@secure-endpoints.com>
11       Secure Endpoints Inc., New York City
12
13   Copyright (C) 1985, 2004,
14     Trustees of Columbia University in the City of New York.
15     All rights reserved.  See the C-Kermit COPYING.TXT file or the
16     copyright text in the ckcmai.c module for disclaimer and permissions.
17 */
18
19 /* Includes */
20
21 #include "ckcdeb.h"
22 #include "ckcasc.h"
23 #include "ckcker.h"
24 #include "ckuusr.h"
25 #include "ckcxla.h"
26 #include "ckcnet.h"                     /* Network symbols */
27 #include <signal.h>
28
29 #ifdef VMS
30 #ifndef TCPSOCKET
31 #include <errno.h>
32 #endif /* TCPSOCKET */
33 #endif /* VMS */
34
35 #ifdef datageneral
36 #define fgets(stringbuf,max,fd) dg_fgets(stringbuf,max,fd)
37 #endif /* datageneral */
38
39 #ifdef QNX6
40 #define readblock kreadblock
41 #endif /* QNX6 */
42
43 /* External Kermit Variables, see ckmain.c for description. */
44
45 extern xx_strp xxstring;
46
47 extern int local, xitsta, binary, parity, escape, flow, cmd_rows, turn,
48   turnch, duplex, ckxech, seslog, dfloc, cnflg, tlevel, pflag, msgflg, mdmtyp,
49   zincnt, quiet, repars, techo, network, nzxopts, what, filepeek, recursive;
50
51 extern int xaskmore, tt_rows, tt_cols, cmd_cols, g_matchdot, diractive,
52   xcmdsrc, nscanfile, reliable, nolinks;
53
54 #ifdef VMSORUNIX
55 extern int zgfs_dir, zgfs_link;
56 #endif /* VMSORUNIX */
57
58 #ifdef CK_IFRO
59   extern int remonly;
60 #endif /* CK_IFRO */
61
62 #ifdef OS2
63 extern int StartedFromDialer ;
64 extern int vmode;
65 extern int k95stdout;
66 #ifndef NT
67 #define INCL_NOPM
68 #define INCL_VIO                        /* Needed for ckocon.h */
69 #include <os2.h>
70 #undef COMMENT
71 #else
72 #define APIRET ULONG
73 #include <windows.h>
74 #include <tapi.h>
75 #include "ckntap.h"
76 #endif /* NT */
77 #include "ckocon.h"
78 #endif /* OS2 */
79
80 extern long vernum, speed;
81 extern char *versio, *protv, *ckxv, *ckzv, *fnsv, *connv, *dftty, *cmdv;
82 extern char *dialv, *loginv, *for_def[], *whil_def[], *xif_def[], *sw_def[];
83 extern char *foz_def[];
84 extern char *ckxsys, *ckzsys;
85 #ifndef OS2
86 extern char *DIRCMD;
87 #ifndef UNIX
88 extern char *DELCMD;
89 #endif /* UNIX */
90 #endif /* OS2 */
91 extern char ttname[], filnam[];
92 extern CHAR sstate, feol;
93 extern char *zinptr;
94
95 #ifdef UNIX
96 extern char ** mtchs;                   /* zxpand() file list */
97 #endif /* UNIX */
98
99 #ifndef NOXFER
100 extern int oopts, omode, oname, opath;  /* O-Packet options */
101
102 extern int stdinf, sndsrc, size, rpsiz, urpsiz, fncnv, fnrpath, displa,
103   stdouf, isguest, pktlog, nfils, keep, maxrps, fblksiz, frecl, frecfm,
104   atcapr, atdiso, spsizf, spsiz, spsizr, spmax, wslotr, prefixing,
105   fncact, fnspath, nprotos, g_proto, g_urpsiz, g_spsizf,
106   g_spsiz, g_spsizr, g_spmax, g_wslotr, g_prefixing, g_fncact, g_fncnv,
107   g_fnspath, g_fnrpath, xfrxla, g_xfrxla;
108
109 extern char *cmarg, *cmarg2;
110
111 #ifndef NOMSEND                         /* Multiple SEND */
112 extern char *msfiles[];
113 #endif /* NOMSEND */
114 extern char fspec[];                    /* Most recent filespec */
115 extern int fspeclen;
116
117 #ifdef CK_TMPDIR
118 extern int f_tmpdir;                    /* Directory changed temporarily */
119 extern char savdir[];                   /* For saving current directory */
120 #endif /* CK_TMPDIR */
121
122 extern struct keytab protos[];          /* File transfer protocols */
123 extern struct ck_p ptab[NPROTOS];
124 #endif /* NOXFER */
125
126 #ifdef DCMDBUF                          /* Declarations from cmd package */
127 extern char *cmdbuf, *atmbuf;           /* Command buffers */
128 #else
129 extern char cmdbuf[], atmbuf[];         /* Command buffers */
130 #endif /* DCMDBUF */
131
132 extern int nopush;
133
134 #ifndef NOSPL
135 int askflag = 0;                        /* ASK-class command active */
136 extern char **a_ptr[];
137 extern int a_dim[];
138 extern char **m_xarg[];
139 extern int n_xarg[];
140 extern struct mtab *mactab;
141 extern int nmac;
142 extern long ck_alarm;
143 extern char alrm_date[], alrm_time[];
144 extern int x_ifnum;
145 #endif /* NOSPL */
146
147 extern int inserver;                    /* I am IKSD */
148 extern int backgrd;                     /* Kermit executing in background */
149 extern char psave[];                    /* For saving & restoring prompt */
150 extern char *tp;                        /* Temporary buffer */
151
152 int readblock = 4096;                   /* READ buffer size */
153 CHAR * readbuf = NULL;                  /* Pointer to read buffer */
154 int readsize = 0;                       /* Number of chars actually read */
155 int getcmd = 0;                         /* GET-class command was given */
156
157 extern int zchkod, zchkid;
158
159 struct keytab deltab[] = {              /* DELETE Command Options */
160     { "/all",           DEL_ALL,  CM_INV },
161     { "/after",         DEL_AFT,  CM_ARG },
162     { "/ask",           DEL_ASK,  0 },
163     { "/before",        DEL_BEF,  CM_ARG },
164     { "/directories",   DEL_DIR,  0 },
165     { "/dotfiles",      DEL_DOT,  0 },
166     { "/except",        DEL_EXC,  CM_ARG },
167     { "/heading",       DEL_HDG,  0 },
168     { "/l",             DEL_LIS,  CM_INV|CM_ABR },
169     { "/larger-than",   DEL_LAR,  CM_ARG },
170     { "/list",          DEL_LIS,  0 },
171     { "/log",           DEL_LIS,  CM_INV },
172     { "/noask",         DEL_NAS,  0 },
173     { "/nodotfiles",    DEL_NOD,  0 },
174     { "/noheading",     DEL_NOH,  0 },
175     { "/nol",           DEL_NOL,  CM_INV|CM_ABR },
176     { "/nolist",        DEL_NOL,  0 },
177     { "/nolog",         DEL_NOL,  CM_INV },
178     { "/nopage",        DEL_NOP,  0 },
179     { "/not-after",     DEL_NAF,  CM_ARG },
180     { "/not-before",    DEL_NBF,  CM_ARG },
181     { "/not-since",     DEL_NAF,  CM_INV|CM_ARG },
182     { "/page",          DEL_PAG,  0 },
183     { "/quiet",         DEL_QUI,  CM_INV },
184     { "/recursive",     DEL_REC,  0 },
185     { "/simulate",      DEL_SIM,  0 },
186     { "/since",         DEL_AFT,  CM_ARG|CM_INV },
187     { "/smaller-than",  DEL_SMA,  CM_ARG },
188     { "/summary",       DEL_SUM,  0 },
189     { "/tree",          DEL_ALL,  0 },
190     { "/type",          DEL_TYP,  CM_ARG },
191     { "/verbose",       DEL_VRB,  CM_INV }
192 };
193 int ndeltab = sizeof(deltab)/sizeof(struct keytab);
194
195 /* /QUIET-/VERBOSE (/LIST-/NOLIST) (/LOG-/NOLOG) table */
196
197 struct keytab qvswtab[] = {
198     { "/l",           DEL_LIS,  CM_INV|CM_ABR },
199     { "/list",        DEL_LIS,  0 },
200     { "/log",         DEL_LIS,  CM_INV },
201     { "/nol",         DEL_NOL,  CM_INV|CM_ABR },
202     { "/nolist",      DEL_NOL,  0 },
203     { "/nolog",       DEL_NOL,  CM_INV },
204     { "/quiet",       DEL_QUI,  CM_INV },
205     { "/verbose",     DEL_VRB,  CM_INV }
206 };
207 int nqvswtab = sizeof(qvswtab)/sizeof(struct keytab);
208
209 struct keytab copytab[] = {
210     { "/append",      998,      0 },
211 #ifndef NOSPL
212     { "/fromb64",     997,      0 },
213 #endif /* NOSPL */
214     { "/l",           DEL_LIS,  CM_INV|CM_ABR },
215     { "/list",        DEL_LIS,  0 },
216     { "/log",         DEL_LIS,  CM_INV },
217     { "/nol",         DEL_NOL,  CM_INV|CM_ABR },
218     { "/nolist",      DEL_NOL,  0 },
219     { "/nolog",       DEL_NOL,  CM_INV },
220     { "/quiet",       DEL_QUI,  CM_INV },
221     { "/swap-bytes",  999,      0 },
222 #ifndef NOSPL
223     { "/tob64",       996,      0 },
224 #endif /* NOSPL */
225     { "/verbose",     DEL_VRB,  CM_INV }
226 };
227 int ncopytab = sizeof(copytab)/sizeof(struct keytab);
228
229 #ifndef NOXFER
230 static struct keytab gettab[] = {       /* GET options */
231     { "/as-name",         SND_ASN, CM_ARG },
232     { "/binary",          SND_BIN, 0 },
233 #ifdef CALIBRATE
234     { "/calibrate",       SND_CAL, CM_INV },
235 #endif /* CALIBRATE */
236 #ifdef PIPESEND
237     { "/command",         SND_CMD, CM_PSH },
238 #endif /* PIPESEND */
239     { "/delete",          SND_DEL, 0 },
240     { "/except",          SND_EXC, CM_ARG },
241     { "/filenames",       SND_NAM, CM_ARG },
242 #ifdef PIPESEND
243     { "/filter",          SND_FLT, CM_ARG|CM_PSH },
244 #endif /* PIPESEND */
245 #ifdef VMS
246     { "/image",           SND_IMG, 0 },
247     { "/labeled",         SND_LBL, 0 },
248 #else
249     { "/image",           SND_BIN, CM_INV },
250 #endif /* VMS */
251 #ifdef CK_TMPDIR
252     { "/move-to",         SND_MOV, CM_ARG },
253 #endif /* CK_TMPDIR */
254     { "/pathnames",       SND_PTH, CM_ARG },
255     { "/pipes",           SND_PIP, CM_ARG|CM_PSH },
256     { "/quiet",           SND_SHH, 0 },
257 #ifdef CK_RESEND
258     { "/recover",         SND_RES, 0 },
259 #endif /* CK_RESEND */
260     { "/recursive",       SND_REC, 0 },
261     { "/rename-to",       SND_REN, CM_ARG },
262 #ifdef COMMENT
263     { "/smaller-than",    SND_SMA, CM_ARG },
264 #endif /* COMMENT */
265     { "/subdirectories",  SND_REC, CM_INV },
266     { "/text",            SND_TXT, 0 },
267     { "/transparent",     SND_XPA, 0 }
268 };
269 #define NGETTAB sizeof(gettab)/sizeof(struct keytab)
270 static int ngettab = NGETTAB;
271
272 static struct keytab rcvtab[] = {       /* RECEIVE options */
273     { "/as-name",         SND_ASN, CM_ARG },
274     { "/binary",          SND_BIN, 0 },
275 #ifdef CALIBRATE
276     { "/calibrate",       SND_CAL, CM_INV },
277 #endif /* CALIBRATE */
278 #ifdef PIPESEND
279     { "/command",         SND_CMD, CM_PSH },
280 #endif /* PIPESEND */
281     { "/except",          SND_EXC, CM_ARG },
282     { "/filenames",       SND_NAM, CM_ARG },
283 #ifdef PIPESEND
284     { "/filter",          SND_FLT, CM_ARG|CM_PSH },
285 #endif /* PIPESEND */
286 #ifdef VMS
287     { "/image",           SND_IMG, 0 },
288     { "/labeled",         SND_LBL, 0 },
289 #else
290     { "/image",           SND_BIN, CM_INV },
291 #endif /* VMS */
292 #ifdef CK_TMPDIR
293     { "/move-to",         SND_MOV, CM_ARG },
294 #endif /* CK_TMPDIR */
295     { "/pathnames",       SND_PTH, CM_ARG },
296     { "/pipes",           SND_PIP, CM_ARG|CM_PSH },
297 #ifdef CK_XYZ
298     { "/protocol",        SND_PRO, CM_ARG },
299 #else
300     { "/protocol",        SND_PRO, CM_ARG|CM_INV },
301 #endif /* CK_XYZ */
302     { "/quiet",           SND_SHH, 0 },
303     { "/recursive",       SND_REC, 0 },
304     { "/rename-to",       SND_REN, CM_ARG },
305     { "/text",            SND_TXT, 0 },
306     { "/transparent",     SND_XPA, 0 }
307 };
308 #define NRCVTAB sizeof(rcvtab)/sizeof(struct keytab)
309 static int nrcvtab = NRCVTAB;
310 #endif /* NOXFER */
311
312 /* WAIT table */
313
314 #define WAIT_FIL 997
315 #define WAIT_MDM 998
316
317 struct keytab waittab[] = {
318     { "cd",            BM_DCD,   CM_INV }, /* (Carrier Detect) */
319     { "cts",           BM_CTS,   CM_INV }, /* (Clear To Send)  */
320     { "dsr",           BM_DSR,   CM_INV }, /* (Data Set Ready) */
321     { "file",          WAIT_FIL, 0 },      /* New category selector keywords */
322     { "modem-signals", WAIT_MDM, 0 },      /* ... */
323     { "ri",            BM_RNG,   CM_INV }  /* (Ring Indicator) */
324 };
325 int nwaittab = (sizeof(waittab) / sizeof(struct keytab));
326
327 /* Modem signal table */
328
329 struct keytab mstab[] = {
330     { "cd",    BM_DCD, 0 },             /* Carrier Detect */
331     { "cts",   BM_CTS, 0 },             /* Clear To Send  */
332     { "dsr",   BM_DSR, 0 },             /* Data Set Ready */
333     { "ri",    BM_RNG, 0 }              /* Ring Indicator */
334 };
335 int nms = (sizeof(mstab) / sizeof(struct keytab));
336
337 #define WF_MOD 1
338 #define WF_DEL 2
339 #define WF_CRE 3
340
341 struct keytab wfswi[] = {               /* WAIT FILE switches */
342     { "creation",     WF_CRE, 0 },      /* Wait for file to be created */
343     { "deletion",     WF_DEL, 0 },      /* Wait for file to be deleted */
344     { "modification", WF_MOD, 0 }       /* Wait for file to be modified */
345 };
346 int nwfswi = (sizeof(wfswi) / sizeof(struct keytab));
347
348 #ifndef NOSPL
349 struct keytab asgtab[] = {              /* Assignment operators for "." */
350     { "::=", 2, 0 },                    /* ASSIGN and EVALUATE */
351     { ":=",  1, 0 },                    /* ASSIGN */
352     { "=",   0, 0 }                     /* DEFINE */
353 };
354 int nasgtab = (sizeof(asgtab) / sizeof(struct keytab));
355
356 struct keytab opntab[] = {
357 #ifndef NOPUSH
358     { "!read",  OPN_PI_R, CM_INV },
359     { "!write", OPN_PI_W, CM_INV },
360 #endif /* NOPUSH */
361     { "append", OPN_FI_A, 0 },
362     { "host",   OPN_NET,  0 },
363 #ifdef OS2
364     { "line",   OPN_SER,  CM_INV },
365     { "port",   OPN_SER,  0 },
366 #else
367     { "line",   OPN_SER,  0 },
368     { "port",   OPN_SER,  CM_INV },
369 #endif /* OS2 */
370     { "read",   OPN_FI_R, 0 },
371     { "write",  OPN_FI_W, 0 }
372 };
373 int nopn = (sizeof(opntab) / sizeof(struct keytab));
374
375 /* IF conditions */
376
377 #define  XXIFCO 0       /* IF COUNT */
378 #define  XXIFER 1       /* IF ERRORLEVEL */
379 #define  XXIFEX 2       /* IF EXIST */
380 #define  XXIFFA 3       /* IF FAILURE */
381 #define  XXIFSU 4       /* IF SUCCESS */
382 #define  XXIFNO 5       /* IF NOT */
383 #define  XXIFDE 6       /* IF DEFINED */
384 #define  XXIFEQ 7       /* IF EQUAL (strings) */
385 #define  XXIFAE 8       /* IF = (numbers) */
386 #define  XXIFLT 9       /* IF < (numbers) */
387 #define  XXIFGT 10      /* IF > (numbers) */
388 #define  XXIFLL 11      /* IF Lexically Less Than (strings) */
389 #define  XXIFLG 12      /* IF Lexically Greater Than (strings) */
390 #define  XXIFEO 13      /* IF EOF (READ file) */
391 #define  XXIFBG 14      /* IF BACKGROUND */
392 #define  XXIFNU 15      /* IF NUMERIC */
393 #define  XXIFFG 16      /* IF FOREGROUND */
394 #define  XXIFDI 17      /* IF DIRECTORY */
395 #define  XXIFNE 18      /* IF NEWER */
396 #define  XXIFRO 19      /* IF REMOTE-ONLY */
397 #define  XXIFAL 20      /* IF ALARM */
398 #define  XXIFSD 21      /* IF STARTED-FROM-DIALER */
399 #define  XXIFTR 22      /* IF TRUE */
400 #define  XXIFNT 23      /* IF FALSE */
401 #define  XXIFTM 24      /* IF TERMINAL-MACRO */
402 #define  XXIFEM 25      /* IF EMULATION */
403 #define  XXIFOP 26      /* IF OPEN */
404 #define  XXIFLE 27      /* IF <= */
405 #define  XXIFGE 28      /* IF >= */
406 #define  XXIFIP 29      /* IF INPATH */
407 #define  XXIFTA 30      /* IF TAPI */
408 #define  XXIFMA 31      /* IF MATCH */
409 #define  XXIFFL 32      /* IF FLAG */
410 #define  XXIFAB 33      /* IF ABSOLUTE */
411 #define  XXIFAV 34      /* IF AVAILABLE */
412 #define  XXIFAT 35      /* IF ASKTIMEOUT */
413 #define  XXIFRD 36      /* IF READABLE */
414 #define  XXIFWR 37      /* IF WRITEABLE */
415 #define  XXIFAN 38      /* IF ... AND ... */
416 #define  XXIFOR 39      /* IF ... OR ... */
417 #define  XXIFLP 40      /* IF left parenthesis */
418 #define  XXIFRP 41      /* IF right parenthesis */
419 #define  XXIFNQ 42      /* IF != (== "NOT =") */
420 #define  XXIFQU 43      /* IF QUIET */
421 #define  XXIFCK 44      /* IF C-KERMIT */
422 #define  XXIFK9 45      /* IF K-95 */
423 #define  XXIFMS 46      /* IF MS-KERMIT */
424 #define  XXIFWI 47      /* IF WILD */
425 #define  XXIFLO 48      /* IF LOCAL */
426 #define  XXIFCM 49      /* IF COMMAND */
427 #define  XXIFFP 50      /* IF FLOAT */
428 #define  XXIFIK 51      /* IF IKS */
429 #define  XXIFKB 52      /* IF KBHIT */
430 #define  XXIFKG 53      /* IF KERBANG */
431 #define  XXIFVE 54      /* IF VERSION */
432 #define  XXIFDC 55      /* IF DECLARED */
433 #define  XXIFGU 56      /* IF GUI */
434
435 struct keytab iftab[] = {               /* IF commands */
436     { "!",          XXIFNO, 0 },
437     { "!=",         XXIFNQ, 0 },
438     { "&&",         XXIFAN, 0 },
439     { "(",          XXIFLP, 0 },
440     { ")",          XXIFRP, 0 },
441     { "<",          XXIFLT, 0 },
442     { "<=",         XXIFLE, 0 },
443     { "=",          XXIFAE, 0 },
444     { "==",         XXIFAE, CM_INV },
445     { ">",          XXIFGT, 0 },
446     { ">=",         XXIFGE, 0 },
447     { "absolute",   XXIFAB, 0 },
448     { "alarm",      XXIFAL, 0 },
449     { "and",        XXIFAN, 0 },
450     { "asktimeout", XXIFAT, 0 },
451     { "available",  XXIFAV, 0 },
452     { "background", XXIFBG, 0 },
453     { "c-kermit",   XXIFCK, 0 },
454     { "command",    XXIFCM, 0 },
455     { "count",      XXIFCO, 0 },
456     { "dcl",        XXIFDC, CM_INV },
457     { "declared",   XXIFDC, 0 },
458     { "defined",    XXIFDE, 0 },
459 #ifdef CK_TMPDIR
460     { "directory",  XXIFDI, 0 },
461 #endif /* CK_TMPDIR */
462     { "emulation",  XXIFEM, 0 },
463 #ifdef COMMENT
464     { "eof",        XXIFEO, 0 },
465 #endif /* COMMENT */
466     { "equal",      XXIFEQ, 0 },
467     { "error",      XXIFFA, CM_INV },
468     { "exist",      XXIFEX, 0 },
469     { "failure",    XXIFFA, 0 },
470     { "false",      XXIFNT, 0 },
471     { "flag",       XXIFFL, 0 },
472 #ifdef CKFLOAT
473     { "float",      XXIFFP, 0 },
474 #endif /* CKFLOAT */
475     { "foreground", XXIFFG, 0 },
476 #ifdef OS2
477     { "gui",        XXIFGU, 0 },
478 #else
479     { "gui",        XXIFGU, CM_INV },
480 #endif /* OS2 */
481 #ifdef IKSD
482     { "iksd",       XXIFIK, 0 },
483 #else
484     { "iksd",       XXIFIK, CM_INV },
485 #endif /* IKSD */
486     { "integer",    XXIFNU, CM_INV },
487     { "k-95",       XXIFK9, 0 },
488     { "kbhit",      XXIFKB, 0 },
489 #ifdef UNIX
490     { "kerbang",    XXIFKG, 0 },
491 #else
492     { "kerbang",    XXIFKG, CM_INV },
493 #endif /* UNIX */
494     { "lgt",        XXIFLG, 0 },
495     { "llt",        XXIFLL, 0 },
496     { "local",      XXIFLO, 0 },
497     { "match",      XXIFMA, 0 },
498     { "ms-kermit",  XXIFMS, CM_INV },
499 #ifdef ZFCDAT
500     { "newer",      XXIFNE, 0 },
501 #endif /* ZFCDAT */
502     { "not",        XXIFNO, 0 },
503     { "numeric",    XXIFNU, 0 },
504     { "ok",         XXIFSU, CM_INV },
505     { "open",       XXIFOP, 0 },
506     { "or",         XXIFOR, 0 },
507     { "quiet",      XXIFQU, 0 },
508     { "readable",   XXIFRD, 0 },
509     { "remote-only",XXIFRO, 0 },
510     { "started-from-dialer",XXIFSD, CM_INV },
511     { "success",    XXIFSU, 0 },
512     { "tapi",       XXIFTA, 0 },
513 #ifdef OS2
514     { "terminal-macro", XXIFTM, 0 },
515 #else
516     { "terminal-macro", XXIFTM, CM_INV },
517 #endif /* OS2 */
518     { "true",       XXIFTR, 0 },
519     { "version",    XXIFVE, 0 },
520     { "wild",       XXIFWI, 0 },
521     { "writeable",  XXIFWR, 0 },
522     { "||",         XXIFOR, 0 },
523     { "", 0, 0 }
524 };
525 int nif = (sizeof(iftab) / sizeof(struct keytab)) - 1;
526
527 struct keytab iotab[] = {               /* Keywords for IF OPEN */
528     { "!read-file",      ZRFILE, CM_INV },
529     { "!write-file",     ZWFILE, CM_INV },
530     { "append-file",     ZWFILE, CM_INV },
531     { "connection",      8888,   0 },
532 #ifdef CKLOGDIAL
533     { "cx-log",          7777,   0 },
534 #endif /* CKLOGDIAL */
535     { "debug-log",       ZDFILE, 0 },
536     { "error",           9999,   0 },
537     { "packet-log",      ZPFILE, 0 },
538     { "read-file",       ZRFILE, 0 },
539     { "screen",          ZSTDIO, 0 },
540     { "session-log",     ZSFILE, 0 },
541     { "transaction-log", ZTFILE, 0 },
542     { "write-file",      ZWFILE, 0 }
543 };
544 int niot = (sizeof(iotab) / sizeof(struct keytab));
545 #endif /* NOSPL */
546
547 /* Variables and prototypes */
548
549 #ifdef NETCONN
550 extern int nnetdir;                     /* How many network directories */
551 #endif /* NETCONN */
552 #ifdef CK_SECURITY
553 _PROTOTYP(int ck_krb4_is_installed,(void));
554 _PROTOTYP(int ck_krb5_is_installed,(void));
555 _PROTOTYP(int ck_ntlm_is_installed,(void));
556 _PROTOTYP(int ck_srp_is_installed,(void));
557 _PROTOTYP(int ck_ssleay_is_installed,(void));
558 _PROTOTYP(int ck_ssh_is_installed,(void));
559 _PROTOTYP(int ck_crypt_is_installed,(void));
560 #else
561 #define ck_krb4_is_installed() (0)
562 #define ck_krb5_is_installed() (0)
563 #define ck_ntlm_is_installed() (0)
564 #define ck_srp_is_installed() (0)
565 #define ck_ssleay_is_installed() (0)
566 #define ck_ssh_is_installed() (0)
567 #define ck_crypt_is_installed() (0)
568 #endif /* CK_SECURITY */
569
570 #define AV_KRB4   1
571 #define AV_KRB5   2
572 #define AV_NTLM   3
573 #define AV_SRP    4
574 #define AV_SSL    5
575 #define AV_CRYPTO 6
576 #define AV_SSH    7
577
578 struct keytab availtab[] = {             /* Available authentication types */
579     { "crypto",     AV_CRYPTO, CM_INV }, /* and encryption */
580     { "encryption", AV_CRYPTO, 0 },
581     { "k4",         AV_KRB4,   CM_INV },
582     { "k5",         AV_KRB5,   CM_INV },
583     { "kerberos4",  AV_KRB4,   0 },
584     { "kerberos5",  AV_KRB5,   0 },
585     { "krb4",       AV_KRB4,   CM_INV },
586     { "krb5",       AV_KRB5,   CM_INV },
587     { "ntlm",       AV_NTLM,   0 },
588     { "srp",        AV_SRP,    0 },
589     { "ssh",        AV_SSH,    0 },
590     { "ssl",        AV_SSL,    0 },
591     { "tls",        AV_SSL,    0 },
592     { "",           0,         0 }
593 };
594 int availtabn = sizeof(availtab)/sizeof(struct keytab)-1;
595
596 #ifndef NODIAL
597 _PROTOTYP(static int ddcvt, (char *, FILE *, int) );
598 _PROTOTYP(static int dncvt, (int, int, int, int) );
599 _PROTOTYP(char * getdname, (void) );
600
601 static int partial  = 0;                /* For partial dial */
602 static char *dscopy = NULL;
603 int dialtype = -1;
604
605 char *dialnum = (char *)0;              /* Remember DIAL number for REDIAL */
606 int dirline = 0;                        /* Dial directory line number */
607 extern char * dialdir[];                /* Dial directory file names */
608 extern int dialdpy;                     /* DIAL DISPLAY on/off */
609 extern int ndialdir;                    /* How many dial directories */
610 extern int ntollfree;                   /* Toll-free call info */
611 extern int ndialpxx;                    /* List of PBX exchanges */
612 extern char *dialtfc[];
613 char * matchpxx = NULL;                 /* PBX exchange that matched */
614 extern int nlocalac;                    /* Local area-code list */
615 extern char * diallcac[];
616 extern int tttapi;
617 #ifdef CK_TAPI
618 extern int tapiconv;                    /* TAPI Conversions */
619 extern int tapipass;                    /* TAPI Passthrough */
620 #endif /* CK_TAPI */
621 extern int dialatmo;
622 extern char * dialnpr, * dialsfx;
623 extern char * dialixp, * dialixs, * dialmac;
624 extern char * dialldp, * diallds, * dialtfp;
625 extern char * dialpxi, * dialpxo, * diallac;
626 extern char * diallcp, * diallcs, * diallcc;
627 extern char * dialpxx[];
628
629 extern int dialcnf;                     /* DIAL CONFIRMATION */
630 int dialfld = 0;                        /* DIAL FORCE-LONG-DISTANCE */
631 int dialsrt = 1;                        /* DIAL SORT ON */
632 int dialrstr = 6;                       /* DIAL RESTRICTION */
633 int dialtest = 0;                       /* DIAL TEST */
634 int dialcount = 0;                      /* \v(dialcount) */
635
636 extern int dialsta;                     /* Dial status */
637 int dialrtr = -1,                       /* Dial retries */
638     dialint = 10;                       /* Dial retry interval */
639 extern long dialcapas;                  /* Modem capabilities */
640 extern int dialcvt;                     /* DIAL CONVERT-DIRECTORY */
641 #endif /* NODIAL */
642
643 #ifndef NOSPL
644 #define IFCONDLEN 256
645 int ifc,                                /* IF case */
646     not = 0,                            /* Flag for IF NOT */
647     ifargs = 0;                         /* Count of IF condition words */
648 char ifcond[IFCONDLEN];                 /* IF condition text */
649 char *ifcp;                             /* Pointer to IF condition text */
650 #ifdef DCMDBUF
651 extern int
652  *ifcmd,  *count,  *iftest, *intime,
653  *inpcas, *takerr, *merror, *xquiet;
654 #else
655 extern int ifcmd[];                     /* Last command was IF */
656 extern int iftest[];                    /* Last IF was true */
657 extern int count[];                     /* For IF COUNT, one for each cmdlvl */
658 extern int intime[];                    /* Ditto for other stackables... */
659 extern int inpcas[];
660 extern int takerr[];
661 extern int merror[];
662 extern int xquiet[];
663 #endif /* DCMDBUF */
664 #else
665 extern int takerr[];
666 #endif /* NOSPL */
667
668 #ifdef DCMDBUF
669 extern char *line;                      /* Character buffer for anything */
670 extern char *tmpbuf;
671 #else
672 extern char line[], tmpbuf[];
673 #endif /* DCMDBUF */
674 extern char *lp;                        /* Pointer to line buffer */
675
676 int cwdf = 0;                           /* CWD has been done */
677
678 /* Flags for ENABLE/DISABLE */
679 extern int en_cwd, en_cpy, en_del, en_dir, en_fin,
680    en_get, en_hos, en_ren, en_sen, en_set, en_spa, en_typ, en_who, en_bye,
681    en_asg, en_que, en_ret, en_mai, en_pri, en_mkd, en_rmd, en_xit, en_ena;
682
683 extern FILE *tfile[];                   /* File pointers for TAKE command */
684 extern char *tfnam[];                   /* Names of TAKE files */
685 extern int tfline[];                    /* TAKE-file line number */
686
687 extern int success;                     /* Command success/failure flag */
688 extern int cmdlvl;                      /* Current position in command stack */
689
690 #ifndef NOSPL
691 extern int maclvl;                      /* Macro to execute */
692 extern char *macx[];                    /* Index of current macro */
693 extern char *mrval[];                   /* Macro return value */
694 extern char *macp[];                    /* Pointer to macro */
695 extern int macargc[];                   /* ARGC from macro invocation */
696
697 #ifdef COMMENT
698 extern char *m_line[];
699 #endif /* COMMENT */
700
701 extern char *m_arg[MACLEVEL][NARGS];    /* Stack of macro arguments */
702 extern char *g_var[];                   /* Global variables %a, %b, etc */
703
704 #ifdef DCMDBUF
705 extern struct cmdptr *cmdstk;           /* The command stack itself */
706 #else
707 extern struct cmdptr cmdstk[];          /* The command stack itself */
708 #endif /* DCMDBUF */
709 #endif /* NOSPL */
710
711 #define xsystem(s) zsyscmd(s)
712
713 static int x, y, z = 0;
714 static char *s, *p;
715
716 #ifdef OS2
717 _PROTOTYP( int os2settitle, (char *, int) );
718 #endif /* OS2 */
719
720 extern struct keytab yesno[], onoff[], fntab[];
721 extern int nyesno, nfntab;
722
723 #ifndef NOSPL
724
725 /* Do the ASK, ASKQ, GETOK, and READ commands */
726
727 int asktimedout = 0;
728
729 #define ASK_PUP 1
730 #define ASK_TMO 2
731 #define ASK_GUI 3
732 #define ASK_QUI 4
733 #define ASK_DEF 5
734
735 static struct keytab asktab[] = {
736     {  "/default", ASK_DEF, CM_ARG },
737     {  "/gui",     ASK_GUI,      
738 #ifdef KUI
739            0
740 #else /* KUI */
741            CM_INV
742 #endif /* KUI */
743     },
744     { "/popup",    ASK_PUP,   
745 #ifdef OS2
746            0
747 #else /* OS2 */
748            CM_INV
749 #endif /* OS2 */
750     },
751     { "/quiet",    ASK_QUI, 0 },
752     { "/timeout",  ASK_TMO, CM_ARG },
753     { "", 0, 0 }
754 };
755 static int nasktab = sizeof(asktab)/sizeof(struct keytab)-1;
756
757 int
758 doask(cx) int cx; {
759     extern int cmflgs, asktimer, timelimit;
760 #ifdef CK_RECALL
761     extern int on_recall;
762 #endif /* CK_RECALL */
763     int popupflg = 0;
764     int guiflg = 0;
765     int nomsg = 0;
766     int mytimer = 0;
767 #ifdef CK_APC
768     extern int apcactive, apcstatus;
769 #endif /* CK_APC */
770
771     char dfbuf[1024];                   /* Buffer for default answer */
772     char * dfanswer = NULL;             /* Pointer to it */
773
774     char vnambuf[VNAML+1];              /* Buffer for variable names */
775     char *vnp = NULL;                   /* Pointer to same */
776     
777     dfbuf[0] = NUL;
778     vnambuf[0] = NUL;
779
780 #ifdef CK_APC
781     if ( apcactive != APC_INACTIVE && (apcstatus & APC_NOINP) ) {
782         return(success = 0);
783     }
784 #endif /* CK_APC */
785
786     mytimer = asktimer;                 /* Inherit global ASK timer */
787
788     if (cx == XXASK || cx == XXASKQ) {
789         struct FDB sw, fl;
790         int getval;
791         char c;
792         if (cx == XXASKQ)               /* Don't log ASKQ response */
793           debok = 0;
794         cmfdbi(&sw,                     /* First FDB - command switches */
795                _CMKEY,                  /* fcode */
796                "Variable name or switch",
797                "",                      /* default */
798                "",                      /* addtl string data */
799                nasktab,                 /* addtl numeric data 1: tbl size */
800                4,                       /* addtl numeric data 2: 4 = cmswi */
801                xxstring,                /* Processing function */
802                asktab,                  /* Keyword table */
803                &fl                      /* Pointer to next FDB */
804                );
805         cmfdbi(&fl,                     /* Anything that doesn't match */
806                _CMFLD,                  /* fcode */
807                "",                      /* hlpmsg */
808                "",                      /* default */
809                "",                      /* addtl string data */
810                0,                       /* addtl numeric data 1 */
811                0,                       /* addtl numeric data 2 */
812                NULL,
813                NULL,
814                NULL
815                );
816         while (1) {                     /* Parse 0 or more switches */
817             x = cmfdb(&sw);             /* Parse something */
818             if (x < 0)
819               return(x);
820             if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
821               break;
822             c = cmgbrk();
823             if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
824                 printf("?This switch does not take an argument\n");
825                 return(-9);
826             }
827             if (!getval && (cmgkwflgs() & CM_ARG)) {
828                 printf("?This switch requires an argument\n");
829                 return(-9);
830             }
831             switch (cmresult.nresult) {
832               case ASK_QUI:
833                 nomsg = 1;
834                 break;
835               case ASK_PUP:
836                 popupflg = 1;
837                 break;
838               case ASK_GUI:
839                 guiflg = 1;
840                 break;
841               case ASK_TMO: {
842                   if ((y = cmnum("seconds","1",10,&x,xxstring)) < 0)
843                     return(y);
844                   if (x < 0)
845                     x = 0;
846                   mytimer = x;
847                   break;
848               }
849               case ASK_DEF: {
850                   if ((y = cmfld("Text to supply if reply is empty",
851                                  "",&s,xxstring)) < 0)
852                     return(y);
853                   ckstrncpy(dfbuf,s,1024);
854                   dfanswer = dfbuf;
855                   break;
856               }
857               default: return(-2);
858             }
859         }
860         /* Have variable name, make copy. */
861         ckstrncpy(vnambuf,cmresult.sresult,VNAML);
862         vnp = vnambuf;
863         if (vnambuf[0] == CMDQ &&
864             (vnambuf[1] == '%' || vnambuf[1] == '&'))
865           vnp++;
866         y = 0;
867         if (*vnp == '%' || *vnp == '&') {
868             if ((y = parsevar(vnp,&x,&z)) < 0)
869               return(y);
870         }
871     } else if (cx != XXGOK && cx != XXRDBL) { /* Get variable name */
872         if ((y = cmfld("Variable name","",&s,NULL)) < 0) {
873             if (y == -3) {
874                 printf("?Variable name required\n");
875                 return(-9);
876             } else return(y);
877         }
878         ckstrncpy(vnambuf,s,VNAML);     /* Make a copy. */
879         vnp = vnambuf;
880         if (vnambuf[0] == CMDQ &&
881             (vnambuf[1] == '%' || vnambuf[1] == '&'))
882           vnp++;
883         y = 0;
884         if (*vnp == '%' || *vnp == '&') {
885             if ((y = parsevar(vnp,&x,&z)) < 0)
886               return(y);
887         }
888     }
889     if (cx == XXREA || cx == XXRDBL) {  /* READ or READBLOCK command */
890         if ((y = cmcfm()) < 0)          /* Get confirmation */
891           return(y);
892         if (chkfn(ZRFILE) < 1) {        /* File open? */
893             printf("?Read file not open\n");
894             return(success = 0);
895         }
896         if (!(s = (char *)readbuf)) {           /* Where to read into. */
897             printf("?Oops, no READ buffer!\n");
898             return(success = 0);
899         }
900         y = zsinl(ZRFILE, s, readblock); /* Read a line. */
901         debug(F111,"read zsinl",s,y);
902         if (y < 0) {                    /* On EOF or other error, */
903             zclose(ZRFILE);             /* close the file, */
904             delmac(vnp,0);              /* delete the variable, */
905             return(success = 0);        /* and return failure. */
906         } else {                        /* Read was OK. */
907             readsize = (int) strlen(s);
908             success = (addmac(vnp,s) < 0 ? 0 : 1); /* Define variable */
909             debug(F111,"read addmac",vnp,success);
910             return(success);            /* Return success. */
911         }
912     }
913
914     /* ASK, ASKQ, GETOK, or GETC */
915
916     if (cx == XXGOK) {                  /* GETOK can take switches */
917         struct FDB sw, fl;
918         int getval;
919         char c;
920         cmfdbi(&sw,                     /* First FDB - command switches */
921                _CMKEY,                  /* fcode */
922                "Variable name or question prompt",
923                "",                      /* default */
924                "",                      /* addtl string data */
925                nasktab,                 /* addtl numeric data 1: tbl size */
926                4,                       /* addtl numeric data 2: 4 = cmswi */
927                xxstring,                /* Processing function */
928                asktab,                  /* Keyword table */
929                &fl                      /* Pointer to next FDB */
930                );
931         cmfdbi(&fl,                     /* Anything that doesn't match */
932                _CMTXT,                  /* fcode */
933                "",                      /* hlpmsg */
934                "",                      /* default */
935                "",                      /* addtl string data */
936                0,                       /* addtl numeric data 1 */
937                0,                       /* addtl numeric data 2 */
938                NULL,
939                NULL,
940                NULL
941                );
942         while (1) {                     /* Parse 0 or more switches */
943             x = cmfdb(&sw);             /* Parse something */
944             if (x < 0)
945               return(x);
946             if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
947               break;
948             c = cmgbrk();
949             if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
950                 printf("?This switch does not take an argument\n");
951                 return(-9);
952             }
953             if (!getval && (cmgkwflgs() & CM_ARG)) {
954                 printf("?This switch requires an argument\n");
955                 return(-9);
956             }
957             switch (cmresult.nresult) {
958               case ASK_PUP:
959                 popupflg = 1;
960                 break;
961               case ASK_GUI:
962                 guiflg = 1;
963                 break;
964               case ASK_TMO: {
965                   if ((y = cmnum("seconds","1",10,&x,xxstring)) < 0)
966                     return(y);
967                   if (x < 0)
968                     x = 0;
969                   mytimer = x;
970                   break;
971               }
972               case ASK_DEF: {
973                   if ((y = cmfld("Text to supply if reply is empty",
974                                  "",&s,xxstring)) < 0)
975                     return(y);
976                   ckstrncpy(dfbuf,s,1024);
977                   dfanswer = dfbuf;
978                   break;
979               }
980               case ASK_QUI:
981                 nomsg = 1;
982                 break;
983               default: return(-2);
984             }
985         }
986         p = cmresult.sresult;
987     } else
988       if ((y = cmtxt(
989 "Prompt,\n\
990  enclose in { braces } or \" quotes \" to preserve leading and trailing\n\
991  spaces, precede question mark with backslash (\\).",
992                    "",&p,xxstring)) < 0)
993         return(y);
994
995     if (!p) p = "";
996 #ifndef NOLOCAL
997 #ifdef OS2
998     if (popupflg) {                     /* Popup requested */
999         int len = -1;
1000         ckstrncpy(tmpbuf,brstrip(p),TMPBUFSIZ);
1001         p = tmpbuf;
1002         if (cx == XXASK || cx == XXASKQ) {
1003             if (cx == XXASK)
1004               len = popup_readtext(vmode,NULL,p,line,LINBUFSIZ,mytimer);
1005             else
1006               len = popup_readpass(vmode,NULL,p,line,LINBUFSIZ,mytimer);
1007             asktimedout = ( len < 0 && mytimer );
1008         } else if (cx == XXGOK) {
1009             printf("?Sorry, GETOK /POPUP not implemented yet\n");
1010             timelimit = 0;
1011             return(-9);
1012         }
1013         if (len >= 0) {
1014             y = addmac(vnp,(char *)line); /* Add it to the macro table. */
1015         } else if ( asktimedout && dfanswer ) {
1016             y = addmac(vnp,dfanswer);       /* Add it to the macro table. */
1017             asktimedout = 0;
1018             len = 0;
1019         }
1020         timelimit = 0;
1021         return(success = ((len >= 0) && (y >= 0)) && !asktimedout);
1022     }
1023 #ifdef KUI
1024     if (guiflg) {                       /* GUI requested */
1025         int rc, n;
1026         char * s1;
1027         s1 = tmpbuf;
1028         n = TMPBUFSIZ-1;
1029         zzstring(brstrip(p),&s1,&n);
1030         p = tmpbuf;
1031         if (cx == XXASK || cx == XXASKQ) {
1032             rc = gui_txt_dialog(NULL,p,(cx == XXASK),
1033                                 line,LINBUFSIZ,dfanswer,mytimer);
1034             asktimedout = (rc == -1 && mytimer);
1035             if (rc == 1) {
1036                 y = addmac(vnp,(char *)line); /* Add it to the macro table. */
1037             } else if ( asktimedout && dfanswer ) {
1038                 y = addmac(vnp,dfanswer); /* Add default to macro table. */
1039                 asktimedout = 0;
1040                 rc = 1;
1041             }
1042             timelimit = 0;
1043             return(success = (rc == 1 && (y >= 0)) && !asktimedout);
1044         } else if (cx == XXGOK) {
1045             int x;
1046             x = lookup(yesno,dfanswer,nyesno,NULL);
1047             if (x != 1) x = 2;
1048             rc = uq_ok(NULL, p, 3, NULL, x);
1049             return(success = (rc == 1));
1050         }
1051     }
1052 #endif /* KUI */
1053 #endif /* OS2 */
1054 #endif /* NOLOCAL */
1055
1056     concb((char)escape);                /* Enter CBREAK mode */
1057     cmsavp(psave,PROMPTL);              /* Save old prompt */
1058     cmsetp(brstrip(p));                 /* Make new prompt */
1059 reprompt:
1060     if (cx == XXASKQ) {                 /* For ASKQ, */
1061         cmini(0);                       /* no-echo mode. */
1062     } else {                            /* For others, regular echoing. */
1063         cmini(ckxech);
1064     }
1065     askflag = 1;
1066     x = -1;                             /* This means to reparse. */
1067     cmflgs = 0;
1068     if (pflag)
1069       prompt(xxstring);                 /* Issue prompt. */
1070
1071     asktimedout = 0;                    /* Handle timed responses. */
1072     timelimit = mytimer;
1073 reparse:
1074     cmres();
1075     if (cx == XXGOK) {                  /* GETOK */
1076 #ifdef CK_RECALL
1077         on_recall = 0;
1078 #endif /* CK_RECALL */
1079         askflag = 0;
1080         /* GETOK uses keyword table */
1081         x = cmkey(yesno,nyesno,"",dfanswer,xxstring);
1082         if (x < 0) {                    /* Parse error */
1083             if (x == -10) {
1084                 char * ds;
1085                 ds = dfanswer ? dfanswer : "No";
1086                 if (!nomsg)
1087                   printf("?Timed out, assuming \"%s\"",ds);
1088                 printf("\n");
1089                 asktimedout = 1;
1090                 x = lookup(yesno,ds,nyesno,NULL);
1091                 if (x != 1) x = 0;
1092                 goto gokdone;
1093             } else if (x == -3) {       /* No answer? */
1094                 printf("Please respond Yes or No\n"); /* Make them answer */
1095                 cmini(ckxech);
1096                 goto reprompt;
1097             } else if (x == -1) {
1098                 goto reparse;
1099             } else
1100               goto reprompt;
1101         }
1102         if (cmcfm() < 0)                /* Get confirmation */
1103           goto reparse;
1104   gokdone:
1105         askflag = 0;
1106         cmsetp(psave);                  /* Restore prompt */
1107 #ifdef VMS
1108         if (cmdlvl > 0)                 /* In VMS and not at top level, */
1109           conres();                     /*  restore console again. */
1110 #endif /* VMS */
1111         timelimit = 0;
1112         return(x);                      /* Return success or failure */
1113     } else if (cx == XXGETC             /* GETC */
1114 #ifdef OS2
1115                || cx == XXGETK          /* or GETKEYCODE */
1116 #endif /* OS2 */
1117                ) {                      /* GETC */
1118         char tmp[16];
1119         conbin((char)escape);           /* Put keyboard in raw mode */
1120 #ifndef NOSETKEY
1121 #ifdef OS2
1122         if (cx == XXGETK) {             /* GETKEYCODE */
1123             extern int os2gks;
1124             int t;
1125             t = os2gks;                 /* Turn off kverb recognition */
1126             os2gks = 0;
1127             x = congks(timelimit);      /* Read a key event, blocking */
1128             os2gks = t;                 /* Put back kverb recognition */
1129         } else                          /* GETC */
1130 #endif /* OS2 */
1131 #endif /* NOSETKEY */
1132         {
1133             debug(F101,"GETC conchk","",conchk());
1134             x = coninc(timelimit);      /* Just read one character */
1135             debug(F101,"GETC coninc","",x);
1136         }
1137         concb((char)escape);            /* Put keyboard back in cbreak mode */
1138         if (x > -1) {
1139             if (xcmdsrc == 0)
1140               printf("\r\n");
1141 #ifdef OS2
1142             if (cx == XXGETK) {         /* GETKEYCODE */
1143                 sprintf(tmp,"%d",x);    /* SAFE */
1144             } else {
1145 #endif /* OS2 */
1146                 tmp[0] = (char) (x & 0xff);
1147                 tmp[1] = NUL;
1148 #ifdef OS2
1149             }
1150 #endif /* OS2 */
1151             y = addmac(vnp,tmp);        /* Add it to the macro table. */
1152             debug(F111,"getc/getk addmac",vnp,y);
1153         } else y = -1;
1154         cmsetp(psave);                  /* Restore old prompt. */
1155         if (x < -1) {
1156             asktimedout = 1;
1157             if (!quiet && !nomsg)
1158               printf("?Timed out");
1159             printf("\n");
1160         }
1161         timelimit = 0;
1162         return(success = ((y < 0 ? 0 : 1) && (asktimedout == 0)));
1163     } else {                            /* ASK or ASKQ */
1164 #ifdef CK_RECALL
1165         on_recall = 0;
1166 #endif /* CK_RECALL */
1167         y = cmdgquo();                  /* Get current quoting */
1168         cmdsquo(0);                     /* Turn off quoting */
1169         while (x == -1) {               /* Prompt till they answer */
1170             x = cmtxt("Please respond.",dfanswer,&s,NULL);
1171             debug(F111,"ASK cmtxt",s,x);
1172             cmres();
1173         }
1174         cmdsquo(y);                     /* Restore previous quoting */
1175         if (cx == XXASKQ)               /* ASKQ must echo CRLF here */
1176           printf("\r\n");
1177         if (x == -10 && dfanswer) {     /* Don't fail on timeout if */
1178             s = dfanswer;               /* a default was specified */
1179             asktimedout = 0;            /* and don't fail */
1180             x = 0;
1181         }
1182         if (x < 0) {                    /* If cmtxt parse error, */
1183             cmsetp(psave);              /* restore original prompt */
1184 #ifdef VMS
1185             if (cmdlvl > 0)             /* In VMS and not at top level, */
1186               conres();                 /*  restore console again. */
1187 #endif /* VMS */
1188             if (x == -10) {             /* Timed out with no response */
1189                 if (!nomsg)
1190                   printf("?Timed out");
1191                 printf("\n");
1192                 asktimedout = 1;
1193                 if (dfanswer)           /* Supply default answer if any */
1194                   s = dfanswer;
1195                 success = x = 0;        /* (was "x = -9;") */
1196             }
1197             timelimit = 0;
1198             return(x);                  /* and return cmtxt's error code. */
1199         }
1200         if (!s || *s == NUL) {          /* If user typed a bare CR, */
1201             cmsetp(psave);              /* Restore old prompt, */
1202             delmac(vnp,0);              /* delete variable if it exists, */
1203 #ifdef VMS
1204             if (cmdlvl > 0)             /* In VMS and not at top level, */
1205               conres();                 /*  restore console again. */
1206 #endif /* VMS */
1207             timelimit = 0;
1208             return(success = 1);        /* and return. */
1209         }
1210         y = addmac(vnp,s);              /* Add it to the macro table. */
1211         debug(F111,"ask addmac",vnp,y);
1212         cmsetp(psave);                  /* Restore old prompt. */
1213 #ifdef VMS
1214         if (cmdlvl > 0)                 /* In VMS and not at top level, */
1215           conres();                     /*  restore console again. */
1216 #endif /* VMS */
1217         timelimit = 0;
1218         return(success = (y < 0 ? 0 : 1) && (asktimedout == 0));
1219     }
1220 }
1221 #endif /* NOSPL */
1222
1223 #ifndef NOSPL
1224 int
1225 doincr(cx) int cx; {                    /* INCREMENT, DECREMENT */
1226     char vnambuf[VNAML+1];              /* Buffer for variable names */
1227     int eval = 0;
1228     eval = (cx == XX_DECR || cx == XX_INCR);
1229
1230     if ((y = cmfld("Variable name","",&s, eval ? xxstring : NULL)) < 0) {
1231         if (y == -3) {
1232             printf("?Variable name required\n");
1233             return(-9);
1234         } else return(y);
1235     }
1236     ckstrncpy(vnambuf,s,VNAML);
1237     if ((y = cmnum("by amount","1",10,&x,xxstring)) < 0)
1238       return(y);
1239     if ((y = cmcfm()) < 0)
1240       return(y);
1241
1242     z = (cx == XX_INCR || cx == XXINC) ? 1 : 0; /* Increment or decrement? */
1243
1244     if (incvar(vnambuf,x,z) < 0) {
1245         printf("?Variable %s not defined or not numeric\n",vnambuf);
1246         return(success = 0);
1247     }
1248     return(success = 1);
1249 }
1250
1251 /* Used by doundef() */
1252 static int
1253 xxundef(s,verbose,simulate) char * s; int verbose, simulate; {
1254     int rc = 0;
1255     if (!s) return(0);
1256     if (*s == CMDQ && *(s+1) == '%') {
1257         char c = *(s+2), * p = NULL;
1258         if (c >= '0' && c <= '9') {
1259             if (maclvl < 0)
1260               p = g_var[c];
1261             else
1262               p = m_arg[maclvl][c - '0'];
1263         } else {
1264             if (isupper(c)) c += ('a'-'A');
1265             if (c >= 'a' && c <= 'z')
1266               p = g_var[c];
1267         }
1268         if (!p) return(-1);
1269     }
1270     if (verbose)
1271       printf(" %s ",s);
1272     if (simulate) {
1273         printf("(SELECTED)\n");
1274     } else if ((x = delmac(s,1)) > -1) { /* Full name required */
1275         rc = 1;
1276         if (verbose) printf("(OK)\n");
1277     } else if (verbose)
1278       printf("(FAILED)\n");
1279     return(rc);
1280 }
1281
1282 /* Do the (_)DEFINE, (_)ASSIGN, and UNDEFINE commands */
1283
1284 #define UND_MAT 1
1285 #define UND_VRB 2
1286 #define UND_EXC 3
1287 #define UND_SIM 3
1288
1289 static struct keytab undefswi[] = {
1290     { "/list",     UND_VRB, 0 },
1291 #ifdef COMMENT
1292     { "/except",   UND_EXC, CM_ARG },
1293 #endif /* COMMENT */
1294     { "/matching", UND_MAT, 0 },
1295     { "/simulate", UND_SIM, 0 },
1296     { "/verbose",  UND_VRB, CM_INV }
1297 };
1298 static int nundefswi = sizeof(undefswi) / sizeof(struct keytab);
1299
1300 #define UNDEFMAX 64
1301 static char ** undeflist = NULL;
1302 int
1303 doundef(cx) int cx; {                   /* UNDEF, _UNDEF */
1304     int i, j, n, rc = 0, arraymsg = 0;
1305     int domatch = 0, verbose = 0, errors = 0, simulate = 0, flag = 0;
1306     char *vnp, vnbuf[4];
1307 #ifdef COMMENT
1308     char *except = NULL;
1309 #endif /* COMMENT */
1310     struct FDB sw, fl;
1311     int getval;
1312     char c;
1313
1314     if (!undeflist) {                   /* Allocate list if necessary */
1315         undeflist = (char **)malloc(UNDEFMAX * sizeof(char *));
1316         if (!undeflist) {
1317             printf("?Memory allocation failure\n");
1318             return(-9);
1319         }
1320         for (i = 0; i < UNDEFMAX; i++)
1321           undeflist[i] = NULL;
1322     }
1323     cmfdbi(&sw,                         /* First FDB - command switches */
1324            _CMKEY,                      /* fcode */
1325            "Variable name or switch",
1326            "",                          /* default */
1327            "",                          /* addtl string data */
1328            nundefswi,                   /* addtl numeric data 1: tbl size */
1329            4,                           /* addtl numeric data 2: 4 = cmswi */
1330            xxstring,                    /* Processing function */
1331            undefswi,                    /* Keyword table */
1332            &fl                          /* Pointer to next FDB */
1333            );
1334     cmfdbi(&fl,                         /* Anything that doesn't match */
1335            _CMFLD,                      /* fcode */
1336            "",                          /* hlpmsg */
1337            "",                          /* default */
1338            "",                          /* addtl string data */
1339            0,                           /* addtl numeric data 1 */
1340            0,                           /* addtl numeric data 2 */
1341            (cx == XXUNDEF) ? NULL : xxstring,
1342            NULL,
1343            NULL
1344            );
1345     while (1) {                         /* Parse 0 or more switches */
1346         x = cmfdb(&sw);                 /* Parse something */
1347         if (x < 0)
1348           return(x);
1349         if (cmresult.fcode != _CMKEY)   /* Break out if not a switch */
1350           break;
1351         c = cmgbrk();
1352         if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
1353             printf("?This switch does not take an argument\n");
1354             return(-9);
1355         }
1356         switch (cmresult.nresult) {
1357           case UND_MAT: domatch  = 1; break;
1358           case UND_SIM: simulate = 1; /* fall thru on purpose */
1359           case UND_VRB: verbose  = 1; break;
1360
1361 #ifdef COMMENT
1362           case UND_EXC:
1363             if (!getval) break;
1364             if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
1365                 if (x == -3) {
1366                     printf("?Pattern required\n");
1367                     x = -9;
1368                 }
1369                 goto xgetx;
1370             }
1371             makestr(&except,cmresult.sresult);
1372             break;
1373 #endif /* COMMENT */
1374
1375           default:
1376             return(-2);
1377         }
1378     }
1379     n = 0;
1380     makestr(&(undeflist[n++]),cmresult.sresult);
1381     for (i = 1; i < UNDEFMAX; i++) {
1382         x = cmfld("Macro or variable name","",&s,
1383                   ((cx == XXUNDEF) ? NULL : xxstring)
1384                   );
1385         if (x == -3) {
1386             if ((y = cmcfm()) < 0)
1387               return(y);
1388             break;
1389         } else if (y < 0) {
1390             return(y);
1391         }
1392         makestr(&(undeflist[n++]),s);
1393     }
1394     /* Now we have a list of n variables or patterns to undefine */
1395
1396     for (i = 0; i < n; i++) {
1397         flag = 0;
1398         if (!(vnp = undeflist[i]))
1399           continue;
1400         if (vnp[0] == CMDQ && (vnp[1] == '%' || vnp[1] == '&')) {
1401             flag++;
1402             vnp++;
1403         }
1404         if (!domatch) {                 /* Pattern match not requested */
1405             if (flag) {
1406                 if ((y = parsevar(vnp,&x,&z)) < 0) {
1407                     vnp--;
1408                     if (verbose) printf(" %s...error\n",vnp);
1409                     continue;
1410                 }
1411                 vnp--;
1412             }
1413             x = xxundef(vnp,verbose,simulate);
1414             if (x > -1) {
1415                 if (!x && !simulate) errors++;
1416                 rc += x;
1417             }
1418             continue;
1419         }
1420         /* Pattern match requested */
1421
1422         if (!flag) {                    /* It's a macro */
1423             for (j = 0; j < nmac; j++) {
1424                 if (ckmatch(vnp,mactab[j].kwd,0,1)) {
1425                     x = xxundef(mactab[j].kwd,verbose,simulate);
1426                     if (x > -1) {
1427                         rc += x;
1428                         if (!x) errors++;
1429                     }
1430                     if (!simulate)
1431                       j--;              /* Because mactab shifted up */
1432                 }
1433             }
1434         } else if (vnp[0] == '%') {     /* It's a \%x variable */
1435             vnbuf[0] = CMDQ;
1436             vnbuf[1] = '%';
1437             vnbuf[3] = NUL;
1438             for (j = '0'; j <= 'z'; j++) { /* 0..9 a..z */
1439                 vnbuf[2] = j;
1440                 if (ckmatch(vnp,&vnbuf[1],0,1)) {
1441                     x = xxundef(vnbuf,verbose,simulate);
1442                     if (x > -1) {
1443                         if (!x) errors++;
1444                         rc += x;
1445                     }
1446                 }
1447                 if (j == '9') j = (int)'a' - 1; /* 9 -> a */
1448             }
1449         } else if (vnp[0] == '&') {
1450             if (!arraymsg && !quiet) {
1451                 printf("?UNDEFINE /MATCH can't be used with arrays.\n");
1452                 printf("(Type HELP ARRAY to see other methods.)\n");
1453             }
1454             arraymsg++;
1455             errors++;
1456         }
1457     }
1458     if (verbose)
1459       printf("undefined: %d, errors: %d\n",rc,errors);
1460
1461     for (i = 0; i < UNDEFMAX; i++) {    /* Check them all */
1462         if (undeflist[i]) {             /* in case we were interrupted */
1463             free(undeflist[i]);         /* previously... */
1464             undeflist[i] = NULL;
1465         }
1466     }
1467     return(success = (errors == 0) ? 1 : 0);
1468 }
1469
1470 int
1471 dodef(cx) int cx; {
1472     extern int xxdot;
1473     extern char ppvnambuf[];
1474     int doeval = 0;
1475     char vnambuf[VNAML+1];              /* Buffer for variable names */
1476     char *vnp;                          /* Pointer to same */
1477     int k, mydot;
1478     mydot = xxdot;                      /* Copy */
1479     xxdot = 0;                          /* and reset */
1480 /*
1481   In case we got here from a command that begins like ".\%a", cmkey() has
1482   already evaluated \%a, but we don't want that, so we retrieve the variable
1483   name from a special pre-evaluation buffer in the command module, and we
1484   undo the "unget word" that would be done because of the token, because if
1485   the variable was defined, it will unget its value rather than its name.
1486 */
1487     s = NULL;
1488
1489     if (mydot && ppvnambuf[0] == '.' && ppvnambuf[1]) {
1490         s = ppvnambuf+1;
1491         unungw();
1492     }
1493     if (!s) {
1494         if (cx == XXDFX || cx == XXASX)
1495           /* Evaluate variable name */
1496           y = cmfld("Macro or variable name","",&s,xxstring);
1497         else
1498           /* Don't evaluate the variable name */
1499           y = cmfld("Macro or variable name","",&s,NULL);
1500         if (y < 0) {
1501             if (y == -3) {
1502                 printf("?Variable name required\n");
1503                 return(-9);
1504             } else return(y);
1505         }
1506     }
1507     k = strlen(s);
1508     if (k > VNAML) {
1509         printf("?Name too long: \"%s\"\n",s);
1510         return(-9);
1511     }
1512     ckstrncpy(vnambuf,s,VNAML);
1513     vnambuf[VNAML] = NUL;
1514     vnp = vnambuf;
1515     if (vnambuf[0] == CMDQ && (vnambuf[1] == '%' || vnambuf[1] == '&')) vnp++;
1516     if (*vnp == '%' || *vnp == '&') {
1517         if ((y = parsevar(vnp,&x,&z)) < 0) return(y);
1518 #ifdef COMMENT
1519         if (cx == XXUNDEF) {            /* Undefine */
1520             if ((y = cmtxt("Text to be ignored","",&s,NULL)) < 0) return(y);
1521             delmac(vnp,0);
1522             return(success = 1);
1523         }
1524 #endif /* COMMENT */
1525         debug(F101,"dodef parsevar x","",x);
1526         if (mydot) {
1527             if ((doeval = cmkey(asgtab,nasgtab,"operator","=",NULL)) < 0)
1528               return(doeval);
1529             if (doeval > 0)             /* Type of assignment */
1530               cx = XXASS;
1531         }
1532         if (y == 1) {                   /* Simple variable */
1533             if ((y = cmtxt("Definition of variable","",&s,NULL)) < 0)
1534               return(y);
1535             s = brstrip(s);
1536             debug(F110,"xxdef var name",vnp,0);
1537             debug(F110,"xxdef var def",s,0);
1538         } else if (y == 2) {            /* Array element */
1539             if ((y = arraynam(vnp,&x,&z)) < 0) return(y);
1540             if (x == 96) {
1541                 printf("?Argument vector array is read-only\n");
1542                 return(-9);
1543             }
1544             if (chkarray(x,z) < 0) return(-2);
1545             if ((y = cmtxt("Definition of array element","",&s,NULL)) < 0)
1546               return(y);
1547             debug(F110,"xxdef array ref",vnp,0);
1548             debug(F110,"xxdef array def",s,0);
1549         }
1550     } else {                            /* Macro */
1551 #ifdef COMMENT
1552         if (cx == XXUNDEF) {            /* Undefine */
1553             if ((y = cmtxt("Text to be ignored","",&s,NULL)) < 0) return(y);
1554             delmac(vnp,0);
1555             return(success = 1);
1556         }
1557 #endif /* COMMENT */
1558         if (mydot) {
1559             if ((doeval = cmkey(asgtab,nasgtab,"operator","=",NULL)) < 0)
1560               return(doeval);
1561             if (doeval > 0)
1562               cx = XXASS;
1563         }
1564         if ((y = cmtxt("Definition of macro","",&s,NULL)) < 0) return(y);
1565 #ifdef DEBUG
1566         if (deblog) {
1567             debug(F110,"xxdef macro name",vnp,0);
1568             debug(F010,"xxdef macro def",s,0);
1569         }
1570 #endif /* DEBUG */
1571         s = brstrip(s);
1572     }
1573     if (*s == NUL) {                    /* No arg given, undefine */
1574         delmac(vnp,1);                  /* silently... */
1575         return(success = 1);            /* even if it doesn't exist... */
1576     }
1577     /* Defining a new macro or variable */
1578
1579     if (cx == XXASS || cx == XXASX) {   /* ASSIGN rather than DEFINE? */
1580         int t;
1581         t = LINBUFSIZ-1;
1582         lp = line;                      /* If so, expand its value now */
1583         zzstring(s,&lp,&t);
1584         s = line;
1585     }
1586     if (doeval == 2) {                  /* Arithmetic evaluation wanted too? */
1587         ckstrncpy(line,evala(s),LINBUFSIZ);
1588         line[LINBUFSIZ] = NUL;
1589     }
1590     /* debug(F111,"calling addmac",s,(int)strlen(s)); */
1591
1592     y = addmac(vnp,s);                  /* Add it to the appropriate table. */
1593     if (y < 0) {
1594         printf("?%s failed\n",(cx == XXASS || cx == XXASX) ?
1595                "ASSIGN" : "DEFINE");
1596         return(success = 0);
1597     } else if (cx == XXASX || cx == XXDFX) /* For _ASG or _DEF, */
1598       return(1);                           /* don't change success variable */
1599     else
1600       return(success = 1);
1601 }
1602 #endif /* NOSPL */
1603
1604
1605 #ifndef NODIAL
1606 /*
1607    L U D I A L  --  Lookup up dialing directory entry.
1608
1609    Call with string to look up and file descriptor of open dialing directory
1610    file.  On success, returns number of matches found, with numbers stored
1611    in an array accessible via getdnum().
1612 */
1613 static char *dn_p[MAXDNUMS + 1];        /* Dial Number pointers */
1614 static char *dn_p2[MAXDNUMS + 1];       /* Converted dial number pointers */
1615 static int dn_x[MAXDNUMS + 1];          /* Type of call */
1616 static int dncount = 0;
1617 char * d_name = NULL;                   /* Dial name pointer */
1618
1619 char *                                  /* Get dial directory entry name */
1620 getdname() {
1621     return(d_name ? d_name : "");
1622 }
1623
1624 char *
1625 getdnum(n) int n; {                     /* Get dial number n from directory */
1626     if (n < 0 || n > dncount || n > MAXDNUMS)
1627       return("");
1628     else
1629       return(dn_p[n]);
1630 }
1631
1632 char *                  /* Check area code for spurious leading digit */
1633 chk_ac(i,buf) int i; char buf[]; {
1634     char *p;
1635     if (!buf)
1636       return("");
1637     p = (char *) buf;                   /* Country we are calling: */
1638     if (i ==  44 ||                     /* UK */
1639         i ==  49 ||                     /* Germany */
1640         i ==  39 ||                     /* Italy */
1641         i ==  31 ||                     /* Netherlands */
1642         i == 351 ||                     /* Portugal */
1643         i ==  55 ||                     /* Brazil */
1644         i == 972 ||                     /* Israel */
1645         i ==  41 ||                     /* Switzerland */
1646         i ==  43 ||                     /* Austria */
1647         i ==  42 ||                     /* Czech Republic */
1648         i ==  36 ||                     /* Hungary */
1649         i ==  30 ||                     /* Greece */
1650         i == 352 ||                     /* Luxembourg */
1651         i ==  48 ||                     /* Poland */
1652         i ==  27 ||                     /* South Africa */
1653         i ==  33 ||                     /* France (as of 1997) */
1654         i ==  358                       /* Finland (ditto) */
1655         ) {
1656         if (buf[0] == '0')
1657           p++;
1658     }
1659     return(p);
1660 }
1661
1662 /* Call Is Long Distance -- Expand this to cover 10-digit local dialing etc */
1663 /*
1664    src  = area code of caller
1665    dest = area code of callee
1666    Returns:
1667      0 if call is local
1668      1 if call is long distance
1669      2 if call is local but area code must be dialed anyway
1670 */
1671 static int
1672 callisld(src, dest) char * src, * dest; {
1673     int i;
1674     if (dialfld)                        /* Force long distance? */
1675       return(1);
1676     if (!strcmp(src,dest)) {            /* Area codes are the same */
1677         for (i = 0; i < nlocalac; i++)  /* Is AC in the lc-area-codes list? */
1678           if (!strcmp(src,diallcac[i]))
1679             return(2);                  /* Yes so must be dialed */
1680         return(0);                      /* No so don't dial it. */
1681     }
1682     for (i = 0; i < nlocalac; i++)      /* ACs not the same so look in list */
1683       if (!strcmp(dest,diallcac[i]))    /* Match */
1684         return(2);                      /* So local call with area code */
1685     return(1);                          /* Not local so long-distance */
1686 }
1687
1688 char pdsfx[64] = { NUL, NUL };
1689
1690 #ifndef NOSPL
1691 static char *
1692 xdial(s) char *s; {                     /* Run dial string thru macro */
1693     int x, m;
1694     if (!dialmac)                       /* Dial macro name given? */
1695       return(NULL);
1696     if ((x = mxlook(mactab,dialmac,nmac)) < 0) /* Is the macro defined? */
1697       return(NULL);
1698     m = maclvl;
1699     x = dodo(x,s,0);                    /* Set up the macro */
1700     if (x > 0) {
1701         while (maclvl > m)              /* Execute the parser */
1702           parser(1);
1703         return(mrval[maclvl+1]);        /* Return the result */
1704     }
1705     return(NULL);
1706 }
1707 #endif /* NOSPL */
1708
1709 static int
1710 dncvt(k,cx, prefix, suffix)
1711     int k, cx, prefix, suffix; {        /* Dial Number Convert */
1712     int i, j, n, what;                  /* cx is top-level command index */
1713     char *ss;                           /* prefix - add prefixes? */
1714     char *p, *p2, *pxo;                 /* suffix - add suffixes? */
1715     char *lac;
1716     char *npr;
1717     char *sfx;
1718     /* char *psfx; */
1719     char ccbuf[128];
1720     int cc;
1721     char acbuf[24];
1722     char *acptr;
1723     char outbuf[256];
1724 /*
1725   First pass for strict (punctuation-based) interpretation.
1726   If it fails, we try the looser (length-based) one.
1727 */
1728     dialtype = -1;
1729     what = 0;                           /* Type of call */
1730     s = dn_p[k];                        /* Number to be converted. */
1731     debug(F111,"dncvt",s,k);
1732     if (dn_p2[k]) {
1733         free(dn_p2[k]);
1734         dn_p2[k] = NULL;
1735     }
1736     if (!s) {
1737         printf("Error - No phone number to convert\n");
1738         return(-1);
1739     }
1740     if ((int)strlen(s) > 200) {
1741         ckstrncpy(outbuf,s,40);
1742         printf("?Too long: \"%s...\"\n",outbuf);
1743         return(-1);
1744     }
1745     npr = (prefix && dialnpr) ? dialnpr : "";
1746     sfx = (suffix && dialsfx) ? dialsfx : "";
1747     /* if (partial) psfx = dialsfx ? dialsfx : ""; */
1748     pxo = (prefix && dialpxo) ? dialpxo : "";
1749     lac = diallac ? diallac : "";       /* Local area code */
1750
1751     outbuf[0] = NUL;                    /* Initialize conversion buffer */
1752     ss = s;                             /* Remember original string */
1753
1754     if (*s != '+') {                    /* Literal number */
1755         dn_x[k] = DN_UNK;               /* Sort key is "unknown". */
1756         ckmakmsg(outbuf,256,            /* Sandwich it between */
1757                  pxo,npr,s,sfx          /* DIAL PREFIX and SUFFIX */
1758                 );
1759 #ifdef CK_TAPI
1760         if (tttapi &&                   /* TAPI does its own conversions */
1761             !tapipass &&                /* if not in passthru mode */
1762             tapiconv == CK_AUTO ||      /* and TAPI conversions are AUTO */
1763             tapiconv == CK_ON           /* OR if TAPI conversions are ON */
1764             ) {
1765             char * p = NULL;
1766             dialtype = -2;
1767             if (!cktapiConvertPhoneNumber(dn_p[k], &p))
1768               return(-1);
1769             makestr(&dn_p2[k], p);
1770             if (p) free(p);
1771             return(0);
1772         } else
1773 #endif /* CK_TAPI */
1774           makestr(&dn_p2[k], outbuf);   /* Not TAPI */
1775         dialtype = what;
1776         return(0);                      /* Done. */
1777     }
1778     i = 0;                              /* Portable number */
1779     s++;                                /* Tiptoe past the plus sign */
1780     ccbuf[0] = NUL;                     /* Do country code first */
1781
1782     if (!diallcc) {                     /* Do we know our own? */
1783         if (cx != XXLOOK)
1784           printf("Error - prior SET DIAL COUNTRY-CODE command required\n");
1785         return(-1);
1786     }
1787
1788     /* Parse the number */
1789
1790     while (1) {                         /* Get the country code */
1791         while (*s == HT || *s == SP)
1792           s++;
1793         if (!s)                         /* Not in standard format */
1794           break;
1795         if (*s == '(') {                /* Beginning of area code  */
1796             s++;                        /* Skip past parenthesis   */
1797             ccbuf[i] = NUL;             /* End of country code */
1798             if (!s) {                   /* Check for end of string */
1799                 printf("Error - phone number ends prematurely: \"%s\"\n",ss);
1800                 return(-1);
1801             }
1802             break;
1803         } else {                        /* Collect country code */
1804             if (isdigit(*s))
1805               ccbuf[i++] = *s;          /* copy this character */
1806             s++;
1807             if (!*s || i > 127)         /* watch out for memory leak */
1808               break;
1809         }
1810     }
1811     cc = atoi(ccbuf);                   /* Numeric version of country code */
1812
1813     i = 0;                              /* Now get area code */
1814     acbuf[0] = NUL;                     /* Initialize area-code buffer */
1815     acptr = acbuf;                      /* and pointer. */
1816     while (1) {
1817         while (*s == HT || *s == SP)    /* Ignore whitespace */
1818           s++;
1819         if (!s)                         /* String finished */
1820           break;
1821         if (*s == ')') {                /* End of area code  */
1822             s++;                        /* Skip past parenthesis   */
1823             acbuf[i] = NUL;             /* Terminate area-code buffer */
1824             break;
1825         } else {                        /* Part of area code */
1826             if (isdigit(*s))            /* If it's a digit, */
1827               acbuf[i++] = *s;          /* copy this character */
1828             s++;                        /* Point to next */
1829             if (!*s || i > 23)          /* Watch out for overflow */
1830               break;
1831         }
1832     }
1833
1834 /*
1835    Here we strip any leading 0 for countries that we know have
1836    0 as a long-distance prefix and do not have any area codes that
1837    start with 0 (formerly also ditto for "9" in Finland...)
1838 */
1839     i = atoi(ccbuf);
1840     acptr = chk_ac(i,acbuf);
1841
1842     while (*s == HT || *s == SP)        /* Skip whitespace */
1843       s++;
1844
1845 /* printf("S=[%s], ACPTR=[%s]\n",s,acptr); */
1846
1847     if (*s && *acptr) {                 /* Area code was delimited */
1848
1849         while (*s == '-' || *s == '.')  /* Skip past gratuitious punctuation */
1850           s++;
1851         if (!*s) s--;                   /* But not to end of string */
1852
1853         if (strcmp(diallcc,ccbuf)) {    /* Out of country? */
1854             if (!dialixp) {             /* Need intl-prefix */
1855                 if (cx != XXLOOK)
1856                   printf("Error - No international dialing prefix defined\n");
1857                 return(-1);
1858             }
1859             what = dn_x[k] = DN_INTL;
1860             p  = (prefix && dialixp) ? dialixp : ""; /* Intl-prefix */
1861             p2 = (suffix && dialixs) ? dialixs : ""; /* Intl-suffix */
1862
1863             /* Form the final phone number */
1864 #ifdef COMMENT
1865             sprintf(pdsfx,"%s%s",p2,sfx); /* UNSAFE */
1866             sprintf(outbuf,
1867                     "%s%s%s%s%s%s%s%s",
1868                     pxo,npr,p,ccbuf,acptr,s,p2,sfx
1869                     );
1870 #else
1871             ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
1872             ckmakxmsg(outbuf,256,pxo,npr,p,ccbuf,acptr,s,p2,sfx,
1873                       NULL,NULL,NULL,NULL);
1874 #endif /* COMMENT */
1875
1876         } else if ((x = callisld(lac,acptr)) >= 1) { /* In-country LD */
1877             if (!diallac && cx != XXLOOK) { /* Don't know my own area code */
1878                 if (cc == 1)
1879                   printf("WARNING - Prior SET DIAL AREA-CODE needed\n");
1880             }
1881             if (x == 2) {               /* Local call with area code */
1882                 what = dn_x[k] = DN_LOCAL;      /* Local-call */
1883                 p  = (prefix && diallcp) ? diallcp : ""; /* local-prefix */
1884                 p2 = (suffix && diallcs) ? diallcs : ""; /* local-suffix */
1885             } else {
1886                 what = dn_x[k] = DN_LONG;       /* Long-distance */
1887                 for (i = 0; i < ntollfree; i++) { /* But toll-free too? */
1888                     if (!strcmp(acptr,dialtfc[i])) {
1889                         what = dn_x[k] = DN_FREE;
1890                         break;
1891                     }
1892                 }
1893                 if (what == DN_FREE) {  /* Toll-free call */
1894                     p = (prefix && dialtfp) ? dialtfp :
1895                         ((prefix && dialldp) ? dialldp : "");
1896                     p2 = "";            /* no suffix */
1897                 } else {                        /* normal long distance */
1898                     p  = (prefix && dialldp) ? dialldp : ""; /* ld-prefix */
1899                     p2 = (suffix && diallds) ? diallds : ""; /* ld-suffix */
1900                 }
1901             }
1902             /* Form the number to be dialed */
1903 #ifdef COMMENT
1904             sprintf(outbuf,"%s%s%s%s%s%s%s",
1905                     pxo,npr,p,acptr,s,p2,sfx
1906                     );
1907             sprintf(pdsfx,"%s%s",p2,sfx);
1908 #else
1909             ckmakxmsg(outbuf,256,
1910                       pxo,npr,p,acptr,s,p2,sfx,
1911                       NULL,NULL,NULL,NULL,NULL);
1912             ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
1913 #endif /* COMMENT */
1914         } else {                        /* Same country, same area code */
1915             what = dn_x[k] = DN_LOCAL;  /* So it's a local call. */
1916             if (!prefix || !(dialpxo || ndialpxx)) { /* Not dialing from PBX */
1917                 p  = (prefix && diallcp) ? diallcp : ""; /* local-prefix */
1918                 p2 = (suffix && diallcs) ? diallcs : ""; /* local-suffix */
1919 #ifdef COMMENT
1920                 if (x == 2)
1921                   sprintf(outbuf,"%s%s%s%s%s%s",npr,p,acptr,s,p2,sfx);
1922                 else
1923                   sprintf(outbuf,"%s%s%s%s%s",npr,p,s,p2,sfx);
1924                 sprintf(pdsfx,"%s%s",p2,sfx);
1925 #else
1926                 if (x == 2)
1927                   ckmakxmsg(outbuf,256,
1928                             npr,p,acptr,s,p2,sfx,
1929                             NULL,NULL,NULL,NULL,NULL,NULL);
1930                 else
1931                   ckmakxmsg(outbuf,256,
1932                             npr,p,s,p2,sfx,
1933                             NULL,NULL,NULL,NULL,NULL,NULL,NULL);
1934                 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
1935 #endif /* COMMENT */
1936
1937             } else {                    /* Dialing from a PBX and not TAPI */
1938                 if (ndialpxx) {         /* Is it internal? */
1939 #ifdef COMMENT
1940                     i = (int) strlen(dialpxx);
1941                     j = (int) strlen(s);
1942                     x = -1;
1943                     if (j > i)
1944                       x = ckstrcmp(dialpxx,s,i,0);
1945 #else
1946                     int kx;
1947                     x = -1;
1948                     j = (int) strlen(s);
1949                     for (kx = 0; kx < ndialpxx; kx++) {
1950                         i = (int) strlen(dialpxx[kx]);
1951                         if (j > i)
1952                           if (!(x = ckstrcmp(dialpxx[kx],s,i,0)))
1953                             break;
1954                     }
1955 #endif /* COMMENT */
1956                     if (!x) {
1957                         char * icp, buf[32];
1958                         makestr(&matchpxx,dialpxx[kx]);
1959                         debug(F111,"dncvt matchpxx",matchpxx,kx);
1960                         what = dn_x[kx] = DN_INTERN;   /* Internal call. */
1961                         s += i;
1962                         /* Internal-call prefix */
1963                         icp = dialpxi;
1964 #ifndef NOSPL
1965                         if (icp) {
1966                             if (*icp == '\\') {
1967                                 char c, *bp;
1968                                 int n;
1969                                 c = *(icp+1);
1970                                 if (isupper(c)) c = tolower(c);
1971                                 if (c == 'v' || c == 'f') {
1972                                     n = 32;
1973                                     bp = buf;
1974                                     zzstring(icp,&bp,&n);
1975                                     icp = buf;
1976                                 }
1977                             }
1978                         }
1979 #endif /* NOSPL */
1980                         p = (prefix && icp) ? icp : "";
1981 #ifdef COMMENT
1982                         sprintf(outbuf,"%s%s%s%s",npr,p,s,sfx);
1983 #else
1984                         ckmakmsg(outbuf,256,npr,p,s,sfx);
1985 #endif /* COMMENT */
1986                     } else {            /* External local call */
1987                         /* local-prefix */
1988                         p  = (prefix && diallcp) ? diallcp : "";
1989                         /* local-suffix */
1990                         p2 = (prefix && diallcs) ? diallcs : "";
1991 #ifdef COMMENT
1992                         if (x == 2)
1993                           sprintf(outbuf,"%s%s%s%s%s%s%s",
1994                                   dialpxo ? dialpxo : "",
1995                                   npr,p,acptr,s,p2,sfx);
1996                         else
1997                           sprintf(outbuf,
1998                                   "%s%s%s%s%s%s",
1999                                   dialpxo ? dialpxo : "",
2000                                   npr,p,s,p2,sfx
2001                                   );
2002 #else
2003                         if (x == 2)
2004                           ckmakxmsg(outbuf, 256,
2005                                    dialpxo ? dialpxo : "",
2006                                    npr,p,acptr,s,p2,sfx,
2007                                    NULL,NULL,NULL,NULL,NULL);
2008                         else
2009                           ckmakxmsg(outbuf, 256,
2010                                     dialpxo ? dialpxo : "",
2011                                     npr,p,s,p2,sfx,
2012                                     NULL,NULL,NULL,NULL,NULL,NULL);
2013 #endif /* COMMENT */
2014                     }
2015                 }
2016             }
2017         }
2018
2019     } else {                            /* Area code was not delimited */
2020
2021         char xbuf[256];                 /* Comparison based only on length */
2022         char ybuf[256];
2023         int x, j;
2024
2025         s = ss;
2026
2027         for (i = 0; i < 255; i++) {
2028             if (!*s) break;
2029             while (!isdigit(*s)) {      /* Pay attention only to digits */
2030                 s++;
2031                 if (!*s) break;
2032             }
2033             xbuf[i] = *s++;
2034         }
2035         xbuf[i] = NUL;
2036
2037         x = 1;                          /* Assume LD */
2038         n = 0;
2039         if (!dialfld) {                 /* If LD not forced */
2040             for (j = 0; j < nlocalac; j++) { /* check local AC list? */
2041                 ckmakmsg(ybuf,256,diallcc,diallcac[j],NULL,NULL);
2042                 n = (int) strlen(ybuf);
2043                 if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0)) {
2044                     x = 2;
2045                     break;
2046                 }
2047             }
2048             if (x == 1) {               /* Or exact match with local CC+AC? */
2049                 ckmakmsg(ybuf,256,diallcc,lac,NULL,NULL);
2050                 n = (int) strlen(ybuf);
2051                 if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0))
2052                   x = 0;
2053             }
2054         }
2055         if (x == 0 || x == 2) {         /* Local call */
2056             int xx,kx;                  /* Begin 1 Dec 2001... */
2057             /* Account for PBX internal calls */
2058             if (ndialpxx) {
2059                 xx = -1;
2060                 j = (int) strlen(ybuf);
2061                 for (kx = 0; kx < ndialpxx; kx++) {
2062                     i = (int) strlen(dialpxx[kx]);
2063                     if (j >= i)
2064                       if (!(xx = ckstrcmp(dialpxx[kx],&xbuf[j],i,0)))
2065                         break;
2066                 }
2067             }
2068             if (!xx) {
2069                 char * icp, buf[32];
2070                 makestr(&matchpxx,dialpxx[kx]);
2071                 debug(F111,"dncvt matchpxx",matchpxx,kx);
2072                 what = dn_x[kx] = DN_INTERN; /* Internal call. */
2073                 s = xbuf + j + i;
2074                 icp = dialpxi;          /* Internal-call prefix */
2075 #ifndef NOSPL
2076                 if (icp) {
2077                     if (*icp == '\\') {
2078                         char c, *bp;
2079                         int n;
2080                         c = *(icp+1);
2081                         if (isupper(c)) c = tolower(c);
2082                         if (c == 'v' || c == 'f') {
2083                             n = 32;
2084                             bp = buf;
2085                             zzstring(icp,&bp,&n);
2086                             icp = buf;
2087                         }
2088                     }
2089                 }
2090 #endif /* NOSPL */
2091                 p = (prefix && icp) ? icp : "";
2092                 ckmakmsg(outbuf,256,npr,p,s,sfx);
2093                 /* End 1 Dec 2001... */
2094
2095             } else {                    /* Not PBX internal */
2096
2097                 dn_x[k] = DN_LOCAL;
2098                 p = (prefix && diallcp) ? diallcp : "";
2099                 p2 = (suffix && diallcs) ? diallcs : "";
2100                 s = (char *) (xbuf + ((x == 0) ? n : (int)strlen(diallcc)));
2101                 ckmakxmsg(outbuf,256,
2102                           pxo,npr,p,s,p2,sfx,
2103                           NULL,NULL,NULL,NULL,NULL,NULL);
2104                 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
2105             }
2106         } else {                        /* Not local */
2107             n = ckstrncpy(ybuf,diallcc,256);
2108             if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0)) { /* Long distance */
2109                 dn_x[k] = DN_LONG;
2110                 p = (prefix && dialldp) ? dialldp : "";
2111                 p2 = (suffix && diallds) ? diallds : "";
2112                 s = xbuf + n;
2113                 while (*s == '-' || *s == '.')
2114                   s++;
2115 #ifdef COMMENT
2116                 sprintf(outbuf,"%s%s%s%s%s%s",pxo,npr,p,s,p2,sfx);
2117                 sprintf(pdsfx,"%s%s",p2,sfx);
2118 #else
2119                 ckmakxmsg(outbuf,256,
2120                           pxo,npr,p,s,p2,sfx,
2121                          NULL,NULL,NULL,NULL,NULL,NULL);
2122                 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
2123 #endif /* COMMENT */
2124             } else {
2125                 dn_x[k] = DN_INTL;      /* International */
2126                 if (!dialixp) {
2127                     if (cx != XXLOOK) {
2128                         printf(
2129                           "Error - No international dialing prefix defined\n"
2130                                );
2131                         return(-1);
2132                     }
2133                 }
2134                 p = (prefix && dialixp) ? dialixp : "";
2135                 p2 = (suffix && dialixs) ? dialixs : "";
2136 #ifdef COMMENT
2137                 sprintf(outbuf,"%s%s%s%s%s%s",pxo,npr,p,xbuf,p2,sfx);
2138                 sprintf(pdsfx,"%s%s",p2,sfx);
2139 #else
2140                 ckmakxmsg(outbuf,256,
2141                           pxo,npr,p,xbuf,p2,sfx,
2142                           NULL,NULL,NULL,NULL,NULL,NULL);
2143                 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
2144 #endif /* COMMENT */
2145             }
2146         }
2147     }
2148 #ifdef CK_TAPI
2149     if (tttapi &&                       /* TAPI performs the conversions */
2150         !tapipass &&
2151         tapiconv == CK_AUTO ||
2152         tapiconv == CK_ON
2153         ) {
2154         p = NULL;
2155         dialtype = -2;
2156         if (!cktapiConvertPhoneNumber(dn_p[k],&p))
2157           return(-1);
2158         makestr(&dn_p2[k], p);
2159         if (p) free(p);
2160         return(0);
2161     } else {
2162 #endif /* CK_TAPI */
2163         makestr(&dn_p2[k], outbuf);
2164 #ifdef CK_TAPI
2165     }
2166 #endif /* CK_TAPI */
2167     dialtype = what;
2168     return(0);
2169 }
2170
2171 static int
2172 ddcvt(s, f, n) char * s; FILE * f; int n; { /* Dial Directory Convert */
2173     char linebuf[1024], *s2;            /* Buffers and pointers */
2174 #ifdef VMS
2175     char * temp = NULL;
2176 #endif /* VMS */
2177     char *info[8];                      /* Pointers to words from entry */
2178     FILE * f2 = NULL;
2179     int x, rc;
2180     rc = -1;
2181
2182     debug(F110,"ddcvt file",s,0);
2183
2184     if (!s || !f)                       /* No filename or file */
2185       return(-1);
2186     if (!*s)
2187
2188     fclose(f);
2189     znewn(s,&s2);                       /* s2 = address of static buffer */
2190     debug(F110,"ddcvt newname",s2,0);
2191
2192 #ifdef VMS
2193     /* In VMS, znewn() returns the same file name with a new version number */
2194     makestr(&temp,s);                   /* Swap - otherwise the new */
2195     s = s2;                             /* version has the older version */
2196     s2 = temp;                          /* number... */
2197     debug(F110,"ddcvt after swap s",s,0);
2198     debug(F110,"ddcvt after swap s2",s2,0);
2199     makestr(&(dialdir[n]),s);           /* New file gets new version number */
2200     debug(F110,"ddcvt after makestr s2",s2,0);
2201     debug(F111,"ddcvt dialdir[n]",dialdir[n],n);
2202 #else
2203     if (zrename(s,s2) < 0) {            /* Not VMS - rename old file */
2204         perror(s2);                     /* to new (wierd) name. */
2205         goto ddexit;
2206     }
2207 #endif /* VMS */
2208     debug(F110,"ddcvt s2 (old)",s2,0);
2209     if ((f = fopen(s2,"r")) == NULL) {  /* Reopen old file with wierd name */
2210         debug(F110,"ddcvt s2 open error",ck_errstr(),0);
2211         dirline = 0;                    /* (or in VMS, old version) */
2212         perror(s2);
2213         goto ddexit;
2214     }
2215     debug(F110,"ddcvt fopen(s2) OK",s2,0);
2216
2217     debug(F110,"ddcvt s (new)",s,0);
2218     if ((f2 = fopen(s,"w")) == NULL) {  /* Create new file with old name */
2219         debug(F110,"ddcvt s open error",ck_errstr(),0);
2220         perror(s);                      /* (or in VMS, new version) */
2221         goto ddexit;
2222     }
2223     debug(F110,"ddcvt fopen(s) OK",s,0);
2224
2225     printf("\nSaving old directory as %s.\nConverting %s...",s2,s);
2226     fprintf(f2,"; %s - Kermit dialing directory\n", s);
2227     fprintf(f2,"%-16s %-20s ; %5s %-6s ; %s\n",
2228                "; Name","Number","Speed","Parity","Comment"
2229                );
2230
2231     while (1) {
2232         linebuf[0] = NUL;               /* Read a line */
2233         if (fgets(linebuf,1023,f) == NULL)
2234           break;
2235         debug(F110,"ddcvt linebuf",linebuf,0);
2236         if (!linebuf[0]) {              /* Empty line */
2237             fprintf(f2,"\n");
2238             continue;
2239         }
2240         x = (int) strlen(linebuf);      /* Strip line terminator, */
2241         while (x-- > 0) {               /* if any. */
2242             if (linebuf[x] <= SP)
2243               linebuf[x] = NUL;
2244             else
2245               break;
2246         }
2247         xwords(linebuf,5,info,1);       /* Parse it the old way */
2248         for (x = 1; x < 6; x++)
2249           if (!info[x]) info[x] = "";
2250         fprintf(f2,"%-16s %-20s ; %5s %-6s %s\n",
2251                info[1],info[2],info[3],info[4],info[5]
2252                );
2253     }
2254     printf(" OK\n\n");
2255     rc = 0;                             /* Success */
2256   ddexit:
2257     if (f) fclose(f);
2258     if (f2) fclose(f2);
2259 #ifdef VMS
2260     if (temp) free(temp);
2261 #endif /* VMS */
2262     return(rc);
2263 }
2264
2265 int                                     /* s = name to look up   */
2266 #ifdef CK_ANSIC                         /* cx = index of command */
2267 ludial(char *s, int cx)                 /* (DIAL, LOOKUP, etc)   */
2268 #else
2269 ludial(s, cx) char *s; int cx;
2270 #endif /* CK_ANSIC */
2271 /* ludial */ {
2272
2273     int dd, n1, n2, n3, i, j, t;        /* Workers */
2274     int olddir, newdir, oldentry, newentry;
2275     int pass = 0;
2276     int oldflg = 0;
2277     int ambiguous = 0;                  /* Flag for lookup was ambiguous */
2278     char *info[7];                      /* Pointers to words from entry */
2279     char *pp;                           /* Pointer to element of array */
2280     FILE * f;
2281     char *line;                         /* File input buffer */
2282
2283 /* #define LUDEBUG */
2284
2285 #ifdef LUDEBUG
2286 int zz = 1;
2287 #endif /* LUDEBUG */
2288
2289     if (!s || ndialdir < 1)             /* Validate arguments */
2290       return(-1);
2291
2292     if ((n1 = (int) strlen(s)) < 1)     /* Length of string to look up */
2293       return(-1);
2294
2295     if (!(line = malloc(1024)))         /* Allocate input buffer */
2296       return(-1);
2297
2298 #ifdef LUDEBUG
2299 if (zz) printf("LUDIAL 1 s[%s], n1=%d\n",s,n1);
2300 #endif /* LUDEBUG */
2301
2302     pass = 0;
2303   lu_again:
2304     f = NULL;                           /* Dial directory file descriptor */
2305     t = dncount = 0;                    /* Dial-number match count */
2306     dd = 0;                             /* Directory counter */
2307     olddir = 0;
2308     newdir = 0;
2309 /*
2310   We need to recognize both old- and new-style directories.
2311   But we can't allow old-style and new-style entries in the same
2312   directory because there is no way to tell for sure the difference between
2313   an old-style entry like this:
2314
2315     foo  5551212  9600
2316
2317   and a new-style literal entry like this:
2318
2319     foo  555 9600
2320
2321   I.e. is the "9600" a speed, or part of the phone number?
2322 */
2323     while (1) {                         /* We make one pass */
2324         if (!f) {                       /* Directory not open */
2325             if (dd >= ndialdir)         /* No directories left? */
2326               break;                    /* Done. */
2327             debug(F111,"ludial dialdir[dd]",dialdir[dd],dd);
2328             if ((f = fopen(dialdir[dd],"r")) == NULL) { /* Open it */
2329                 perror(dialdir[dd]);    /* Can't, print message saying why */
2330                 if (line) {
2331                     free(line);
2332                     line = NULL;
2333                 }
2334                 dd++;                   /* Go on to next one, if any... */
2335                 continue;
2336             }
2337             dirline = 0;                /* Directory file line number */
2338             if (dialdpy && !pass)
2339               printf("Opening: %s...\n",dialdir[dd]);
2340             dd++;
2341             if (!oldflg) olddir = 0;
2342             newdir = 0;
2343         }
2344         oldentry = 0;
2345         newentry = 0;
2346         line[0] = NUL;
2347         if (getnct(line,1023,f,1) < 0) { /* Read a line */
2348             if (f) {                    /* f can be clobbered! */
2349                 fclose(f);              /* Close the file */
2350                 f = NULL;               /* Indicate next one needs opening */
2351                 oldflg = 0;
2352             }
2353             continue;
2354         }
2355         if (!line[0])                   /* Empty line */
2356           continue;
2357 #ifdef LUDEBUG
2358 if (zz) printf("LUDIAL 2 s[%s]\n",s);
2359 #endif /* LUDEBUG */
2360
2361         /* Make a copy and parse it the old way */
2362         /* A copy is needed because xwords() pokes NULs into the string */
2363
2364         if ((pp = malloc((int)strlen(line) + 1))) {
2365             strcpy(pp,line);            /* safe */
2366             xwords(pp,5,info,0);        /* Parse it the old way */
2367
2368 #ifdef LUDEBUG
2369 if (zz) printf("LUDIAL 3 s[%s]\n",s);
2370 #endif /* LUDEBUG */
2371
2372             if (!info[1])
2373               continue;
2374             if (*info[1] == ';') {      /* If full-line comment, */
2375                 newdir = 1;             /* (only new directories have them) */
2376                 continue;               /* keep reading. */
2377             }
2378             if (!info[2])
2379               continue;
2380             if (*info[2] == '+')
2381               newentry = 1;
2382             if (info[4]) {
2383                 if ((*info[4] == '=') ||
2384                     !ckstrcmp(info[4],"none", 4,0) ||
2385                     !ckstrcmp(info[4],"even", 4,0) ||
2386                     !ckstrcmp(info[4],"space",5,0) ||
2387                     !ckstrcmp(info[4],"mark", 4,0) ||
2388                     !ckstrcmp(info[4],"odd",  3,0)
2389                     )
2390                   oldentry = 1;
2391             }
2392         }
2393         if (pp) {
2394             free(pp);
2395             pp = NULL;
2396         }
2397
2398         /* Check consistency */
2399
2400         if ((oldentry || olddir) && (newentry || newdir)) {
2401             printf(
2402 "\nERROR: You seem to have old- and new-format entries mixed in your\n");
2403             printf(
2404 "dialing directory.  You'll have to edit it by hand to convert it to the\n");
2405 #ifndef NOHELP
2406             printf("new format.  Type HELP DIAL for further information.\n\n");
2407 #else
2408             printf("new format.\n\n");
2409 #endif /* NOHELP */
2410             if (line) {
2411                 free(line);
2412                 line = NULL;
2413             }
2414             return(-1);
2415         }
2416         if (!olddir && oldentry) {
2417             int convert = 0;
2418             olddir = 1;
2419             if (dialcvt == 2) {         /* 2 == ASK */
2420                 sprintf(tmpbuf,
2421 "WARNING: Old-style dialing directory detected:\n%s", line);
2422                 convert = uq_ok(tmpbuf,
2423                                 "Shall I convert it for you? ",3,NULL,0);
2424             } else
2425               convert = dialcvt;
2426             if (convert) {
2427                 debug(F111,"ludial calling ddcvt",dialdir[dd-1],dd);
2428                 if (ddcvt(dialdir[dd-1],f,dd-1) < 0) {
2429                     debug(F111,"ludial ddcvt failed",dialdir[dd-1],dd);
2430                     oldflg = 1;
2431                     printf(
2432 "  Sorry, can't convert.");
2433                     printf(
2434 "  Will ignore speed and parity fields, continuing...\n\n");
2435                 } else {
2436                     olddir = newdir = 0;
2437                     debug(F111,"ludial ddcvt ok",dialdir[dd-1],dd);
2438                 }
2439                 dd--;
2440                 f = NULL;
2441                 continue;
2442             } else {
2443                 if (dialcvt == 2)
2444                   printf(
2445 "  OK, will ignore speed and parity fields, continuing...\n\n");
2446                 olddir = 1;
2447             }
2448         }
2449
2450 #ifdef LUDEBUG
2451 if (zz) printf("LUDIAL XX s[%s], n1=%d\n",s,n1);
2452 #endif /* LUDEBUG */
2453
2454         /* Now parse again for real */
2455
2456         if (oldentry)                   /* Parse it the old way */
2457           xwords(line,5,info,0);
2458         else                            /* Parse it the new way */
2459           xwords(line,2,info,1);
2460
2461 #ifdef LUDEBUG
2462 if (zz) printf("LUDIAL YY s[%s], n1=%d\n",s,n1);
2463 if (zz) printf("%s [%s]\n",info[1],info[2]);
2464 #endif /* LUDEBUG */
2465
2466         if (info[1]) {                  /* First word is entry name */
2467             if ((n3 = (int) strlen(info[1])) < 1) /* Its length */
2468               continue;                 /* If no first word, keep reading. */
2469             if (n3 < n1)                /* Search name is longer */
2470               continue;                 /* Can't possibly match */
2471             if (ambiguous && n3 != n1)
2472               continue;
2473
2474 #ifdef LUDEBUG
2475 if (zz) printf("MATCHING: [%s] [%s], n1=%d\n",s,info[1],n1);
2476 #endif /* LUDEBUG */
2477
2478             if (ckstrcmp(s,info[1],n1,0)) /* Caseless string comparison */
2479               continue;
2480
2481 #ifdef LUDEBUG
2482 if (zz) printf("MATCH OK: [%s] [%s], n1=%d\n",s,info[1],n1);
2483 #endif /* LUDEBUG */
2484
2485             if (!info[2])               /* No phone number given */
2486               continue;
2487             if ((n2 = (int) strlen(info[2])) < 1) /* Length of phone number */
2488               continue;                 /* Ignore empty phone numbers */
2489
2490             /* Got one */
2491
2492             if (!(pp = (char *)malloc(n2 + 1))) { /* Allocate storage for it */
2493                 printf("?internal error - ludial malloc 1\n");
2494                 if (line) {
2495                     free(line);
2496                     line = NULL;
2497                 }
2498                 dncount = 0;
2499                 return(-1);
2500             }
2501             strcpy(pp,info[2]);         /* safe */
2502
2503             if (dncount > MAXDNUMS) {
2504                 printf("Warning: %d matches found, %d max\n",
2505                        dncount,
2506                        MAXDNUMS
2507                        );
2508                 dncount = MAXDNUMS;
2509                 break;
2510             }
2511             dn_p[dncount++] = pp;       /* Add pointer to array. */
2512             if (dncount == 1) {         /* First one... */
2513                 if (d_name) free(d_name);
2514                 if (!(d_name = (char *)malloc(n3 + 1))) { /* Save its name */
2515                     printf("?internal error - ludial malloc 2\n");
2516                     if (line) {
2517                         free(line);
2518                         line = NULL;
2519                     }
2520                     dncount = 0;
2521                     return(-1);
2522                 }
2523                 t = n3;                 /* And its length */
2524                 strcpy(d_name,info[1]); /* safe */
2525             } else {                    /* Second or subsequent one */
2526
2527 #ifdef LUDEBUG
2528                 if (zz)
2529                   printf("d_name=[%s],info[1]=%s,t=[%d]\n",d_name,info[1],t);
2530 #endif /* LUDEBUG */
2531
2532                 if ((int) strlen(info[1]) == t) /* Lengths compare */
2533                   if (!ckstrcmp(d_name,info[1],t,0)) /* Caseless compare OK */
2534                     continue;
2535
2536                 /* Name given by user matches entries with different names */
2537
2538                 if (ambiguous)          /* Been here before */
2539                   break;
2540
2541                 ambiguous = 1;          /* Now an exact match is required */
2542                 for (j = 0; j < dncount; j++) { /* Clean out previous list */
2543                     if (dn_p[j]) {
2544                         free(dn_p[j]);
2545                         dn_p[j] = NULL;
2546                     }
2547                 }
2548                 pass++;                 /* Second pass... */
2549                 goto lu_again;          /* Do it all over again. */
2550             }
2551         }
2552     }
2553     if (line) free(line);
2554     if (dncount == 0 && ambiguous) {
2555         printf(" Lookup: \"%s\" - ambiguous%s\n",
2556                s,
2557                cx == XXLOOK ? "" : " - dialing skipped"
2558                );
2559         return(-2);
2560     }
2561     return(dncount);
2562 }
2563
2564 char *
2565 pncvt(s) char *s; {                     /* Phone number conversion */
2566     char *p = NULL;                     /* (just a wrapper for dncvt() */
2567     char *q = NULL;
2568     static char pnbuf[128];
2569     makestr(&p,dn_p[0]);                /* Save these in case they are */
2570     makestr(&q,dn_p2[0]);               /* being used */
2571     makestr(&dn_p[0],s);                /* Copy the argument string to here */
2572     dncvt(0,XXLOOK,1,1);                /* Convert it */
2573     if (!dn_p2[0])                      /* Put result where can return it */
2574       pnbuf[0] = NUL;
2575     else
2576       ckstrncpy(pnbuf,dn_p2[0],127);
2577     makestr(&dn_p[0],p);                /* Restore these */
2578     makestr(&dn_p2[0],q);
2579     makestr(&p,NULL);                   /* Free these */
2580     makestr(&q,NULL);
2581     return((char *)pnbuf);
2582 }
2583
2584 int
2585 dodial(cx) int cx; {                    /* DIAL or REDIAL */
2586     int i = 0, x = 0;                   /* Workers */
2587     int sparity = -1;                   /* For saving global parity value */
2588     int previous = 0;
2589     int len = 0;
2590     int literal = 0;
2591     int flowsave;
2592     int lufound = 0;                    /* Did any lookup succeed? */
2593     int prefix = 1;
2594     int postfix = 1;
2595     int wasalpha = 0;
2596     int xredial = 0;
2597     int braces = 0;
2598
2599     char *p = NULL, *s3 = NULL, * sav = NULL;
2600     int j = 0, t = 0, n = 0;
2601     int xretries, xlcc;
2602
2603     debug(F101,"dodial cx","",cx);
2604     debug(F111,"dodial diallcc",diallcc,diallcc);
2605
2606     xretries = dialrtr;                 /* If retries not set, */
2607     if (diallcc) {                      /* choose default based on */
2608         xlcc = atoi(diallcc);           /* local country code. */
2609         if (xretries < 0) {
2610             switch (xlcc) {
2611               case 1: xretries = 10; break; /* No restrictions in NANP */
2612                 /* Add other country codes here */
2613                 /* that are known to have no restrictions on redialing. */
2614               default: xretries = 1;
2615             }
2616         }
2617     }
2618     if (cx == XXPDIA) {                 /* Shortcut... */
2619         cx = XXDIAL;
2620         partial = 1;
2621         debug(F100,"PDIAL sets partial=1","",0);
2622         postfix = 0;                    /* Do not add postfix */
2623     } else {
2624         partial = 0;
2625         debug(F100,"DIAL sets partial=0","",0);
2626     }
2627     previous = dialsta;                 /* Status of previous call, if any */
2628     if (previous == DIA_PART) {
2629         prefix = 0;                     /* do not add prefix */
2630     }
2631     s = NULL;                           /* Initialize user's dial string */
2632     if (cx == XXRED) {                  /* REDIAL or... */
2633         if ((y = cmcfm()) < 0)
2634           return(y);
2635     } else if (cx == XXANSW) {          /* ANSWER or ... */
2636         if ((y = cmnum("timeout (seconds)","0",10,&x,xxstring)) < 0)
2637           return(y);
2638         dialatmo = x;
2639         if ((y = cmcfm()) < 0)
2640           return(y);
2641     } else {                            /* DIAL or LOOKUP */
2642         if (ndialdir > 0)
2643           s3 = "Number to dial or entry from dial directory";
2644         else
2645           s3 = "Number to dial";
2646         if ((x = cmtxt(s3, dialnum ? dialnum : "",&s,xxstring)) < 0)
2647           return(x);
2648         if (s) {
2649             len = (int) strlen(s);
2650             ckstrncpy(tmpbuf,s,TMPBUFSIZ); /* Save literal copy */
2651 #ifdef COMMENT
2652             if (len > 1) {              /* Strip outer braces if given */
2653                 if (*s == '{') {
2654                     if (s[len-1] == '}') {
2655                         s[len-1] = NUL;
2656                         s++;
2657                         len -= 2;
2658                     }
2659                 }
2660             }
2661 #else
2662             s = brstrip(s);             /* Strip outer braces or quotes */
2663 #endif /* COMMENT */
2664         }
2665     }
2666
2667     if (cx != XXLOOK) {                 /* Not LOOKUP */
2668 #ifdef IKSD
2669         if (inserver) {
2670             printf("Sorry, dialing is disabled.\r\n");
2671             return(success = 0);
2672         }
2673 #endif /* IKSD */
2674 #ifdef CK_TAPI
2675         if (tttapi && !tapipass) {
2676           ;                             /* Skip the modem test if TAPI */
2677         } else
2678 #endif /* CK_TAPI */
2679         if (mdmtyp < 1 && !dialtest) {
2680             if (network
2681 #ifdef TN_COMPORT
2682                  && !istncomport()
2683 #endif /* TN_COMPORT */
2684                  )
2685               printf("Please SET HOST first, and then SET MODEM TYPE\n");
2686             else
2687               printf("Sorry, you must SET MODEM TYPE first\n");
2688             dialsta = DIA_NOMO;
2689             return(success = 0);
2690         }
2691         if (!local && !dialtest) {
2692             printf("Sorry, you must SET %s or SET HOST first\n",
2693 #ifdef OS2
2694                    "PORT"
2695 #else
2696                    "LINE"
2697 #endif /* OS2 */
2698                    );
2699             dialsta = DIA_NOLI;
2700             return(success = 0);
2701         }
2702         if ((!network 
2703 #ifdef TN_COMPORT
2704               || istncomport()
2705 #endif /* TN_COMPORT */
2706               ) && !dialtest &&
2707 #ifdef CK_TAPI
2708              !tttapi &&
2709 #endif /* CK_TAPI */
2710             (speed < 0L)
2711 #ifdef UNIX
2712             && (strcmp(ttname,"/dev/null"))
2713 #else
2714 #ifdef OSK
2715             && (strcmp(ttname,"/nil"))
2716 #endif /* OSK */
2717 #endif /* UNIX */
2718             ) {
2719             printf("\nSorry, you must SET SPEED first\n");
2720             dialsta = DIA_NOSP;
2721             return(success = 0);
2722         }
2723     }
2724     if (cx != XXANSW) {
2725         for (j = 0; j < MAXDNUMS; j++) { /* Initialize dial-number list */
2726             if (!dialnum) {             /* First time dialing */
2727                 dn_p[j] = NULL;         /* initialize all pointers. */
2728                 dn_p2[j] = NULL;
2729             } else if (dn_p[j]) {       /* Not the first time, */
2730                 free(dn_p[j]);          /* free previous, if any, */
2731                 dn_p[j] = NULL;         /* then set to NULL. */
2732                 if (dn_p2[j])
2733                   free(dn_p2[j]);
2734                 dn_p2[j] = NULL;
2735             } else break;               /* Already NULL */
2736         }
2737         if (len == 0)
2738           s = NULL;
2739         if (!s)
2740           s = dialnum;
2741         if (!s) {
2742             if (cx == XXLOOK)
2743               printf("?Lookup what?\n");
2744             else
2745               printf("%s\n", (cx == XXRED) ?
2746                    "?No DIAL command given yet" :
2747                    "?You must specify a number to dial"
2748                    );
2749             return(-9);
2750         }
2751
2752     /* Now we have the "raw" dial or lookup string and s is not NULL */
2753
2754         makestr(&dscopy,s);             /* Put it in a safe place */
2755         s = dscopy;
2756         n = 0;
2757
2758         debug(F111,"dodial",s,ndialdir);
2759
2760         wasalpha = 0;
2761         if (isalpha(*s)) {
2762             wasalpha = 1;
2763             if (ndialdir > 0) {         /* Do we have a dialing directory? */
2764                 n = ludial(s,cx);       /* Look up what the user typed */
2765                 if (n == 0)
2766                   printf(" Lookup: \"%s\" - not found%s\n",
2767                          s,
2768                          cx == XXLOOK ? "" : " - dialing as given\n"
2769                          );
2770             }
2771             debug(F101,"dodial",s,n);
2772             if (n < 0 && cx != XXLOOK) { /* Error out if they wanted to dial */
2773                 if (n == -1)            /* -2 means ludial already gave msg */
2774                   printf(" Lookup: fatal error - dialing skipped\n");
2775                 dialsta = DIA_DIR;
2776                 return(-9);
2777             }
2778             if (n > 0)                  /* A successful lookup */
2779               lufound = 1;
2780         } else if (*s == '=') {         /* If number starts with = sign */
2781             s++;                        /* strip it */
2782             literal = 1;                /* remember this */
2783             while (*s == SP) s++;       /* and then also any leading spaces */
2784         } else if (tmpbuf[0] == '{' && tmpbuf[1] == '{') {
2785             makelist(tmpbuf,dn_p,MAXDNUMS);
2786             makestr(&dscopy,tmpbuf);
2787             s = tmpbuf;
2788             for (n = 0; n < MAXDNUMS; n++) /* (have to count how many) */
2789               if (!dn_p[n]) break;
2790             braces = 1;
2791         }
2792         if (cx == XXLOOK && !wasalpha && !braces) {
2793             /* We've been told to lookup a number or a quoted name */
2794             char *p;
2795             n = 0;
2796             p = literal ? s : pncvt(dscopy);
2797             if (!p) p = "";
2798             if (*p) {
2799                 printf("%s  => %s\n", dscopy, p);
2800                 return(success = 1);
2801             } else {
2802                 printf("?Bad phone number\n");
2803                 return(success = 0);
2804             }
2805         }
2806         /* Save DIAL or successful LOOKUP string for future DIAL or REDIAL */
2807         /* But don't save pieces of partial dial ... */
2808
2809         debug(F101,"DIAL save dialnum partial","",partial);
2810         debug(F101,"DIAL save dialnum previous","",previous);
2811         if ((cx == XXDIAL && partial == 0 && previous != DIA_PART) ||
2812             (cx == XXLOOK && n > 0)) {
2813             makestr(&dialnum,dscopy);
2814             if (!quiet && dscopy && !dialnum)
2815               printf("WARNING - memory allocation failure: redial number\n");
2816         }
2817         if (n > 0) {
2818             if (!quiet && !backgrd && !braces /* && dialdpy */ ) {
2819                 if (!strcmp(d_name,s))
2820                   printf(" Lookup: \"%s\" - exact match\n",s);
2821                 else
2822                   printf(" Lookup: \"%s\" - uniquely matches \"%s\"\n",
2823                          s,
2824                          d_name
2825                          );
2826             }
2827             if ((cx == XXLOOK) ||
2828                 ((n > 1) && !quiet && !backgrd /* && dialdpy */ )) {
2829                 printf(" %d telephone number%sfound for \"%s\"%s\n",
2830                        n,
2831                        (n == 1) ? " " : "s ",
2832                        s,
2833                        (n > 0) ? ":" : "."
2834                        );
2835                 s3 = getdname();
2836             }
2837             for (i = 0; i < n; i++) {   /* Convert */
2838                 dn_x[i] = -1;
2839                 if (dncvt(i,cx,prefix,postfix) < 0) {
2840                     if (cx != XXLOOK) {
2841                         dialsta = DIA_DIR;
2842                         return(-9);
2843                     }
2844                 }
2845             }
2846             if (dialsrt && n > 1) {     /* Sort into optimal order */
2847                 for (i = 0; i < n-1; i++) {
2848                     for (j = i+1; j < n; j++) {
2849                         if (dn_x[j] < dn_x[i]) {
2850                             t = dn_x[j];
2851                             dn_x[j] = dn_x[i];
2852                             dn_x[i] = t;
2853                             p = dn_p[j];
2854                             dn_p[j] = dn_p[i];
2855                             dn_p[i] = p;
2856                             p = dn_p2[j];
2857                             dn_p2[j] = dn_p2[i];
2858                             dn_p2[i] = p;
2859                         }
2860                     }
2861                 }
2862             }
2863             if ((cx == XXLOOK) ||
2864                 ((n > 1) && !quiet && !backgrd /* && dialdpy */ )) {
2865                 int nn = n;
2866 #ifndef NOSPL
2867                 char * p;
2868 #endif /* NOSPL */
2869                 if (cx != XXLOOK)
2870                   if (n > 12) nn = 12;
2871                 for (i = 0; i < nn; i++) {
2872                     printf("%3d. %-12s  %-20s =>  %-20s  (%d)\n",i+1,
2873                            s3, dn_p[i],
2874                            dn_p2[i] ? dn_p2[i] : "(processing failed)",
2875                            dn_x[i]
2876                            );
2877                 }
2878                 if (cx != XXLOOK && n != nn)
2879                   printf("And %d more...\n", n - nn);
2880             }
2881         } else if (n == 0) {            /* Not found in directory */
2882             makestr(&(dn_p[0]),literal ? s : dscopy);
2883             makestr(&d_name,literal ? s : dscopy);
2884             dncount = 1;
2885             n = 1;
2886             if (dncvt(0,cx,prefix,postfix) < 0) { /* In case they typed a */
2887                 dialsta = DIA_DIR;      /* portable-format number ... */
2888                 return(-9);
2889             }
2890         }
2891
2892 #ifndef NONET
2893 #ifdef NETCONN
2894         /* It's not good that the networks directory depends on NOT-NODIAL.. */
2895         if (cx == XXLOOK && dscopy) {   /* Networks here too... */
2896             extern char *nh_p[], *nh_p2[], *n_name;
2897             extern char *nh_px[4][MAXDNUMS+1];
2898             n = -1;
2899             if (nnetdir > 0) {          /* Do we have a network directory? */
2900                 dirline = 0;
2901                 n = lunet(dscopy);      /* Look up what the user typed */
2902             }
2903             if (n > -1) {
2904                 int k;
2905                 if (n > 0)              /* A successful lookup */
2906                   lufound = 1;
2907                 if (cx == XXLOOK && n == 0)
2908                   printf(" Lookup: \"%s\" - not found\n",dscopy);
2909                 else
2910                   printf("%s %d network entr%s found for \"%s\"%s\n",
2911                          cx == XXLOOK ? " Lookup:" : "",
2912                          n,
2913                          (n == 1) ? "y" : "ies",
2914                          dscopy,
2915                          (n > 0) ? ":" : "."
2916                          );
2917
2918                 for (i = 0; i < n; i++) {
2919
2920                     printf("%3d. %-12s => %-9s %s",
2921                            i+1,n_name,nh_p2[i],nh_p[i]);
2922                     for (k = 0; k < 4; k++) {
2923                         if (nh_px[k][i]) {
2924                             printf(" %s",nh_px[k][i]);
2925                         } else
2926                           break;
2927                     }
2928                     printf("\n");
2929                 }
2930             }
2931         }
2932 #endif /* NETCONN */
2933 #endif /* NONET */
2934         if (cx == XXLOOK)
2935           return(success = lufound);
2936     } /* cx != XXANSW */
2937
2938 #ifdef VMS
2939     conres();                   /* So Ctrl-C/Y will work */
2940 #endif /* VMS */
2941 /*
2942   Some modems do not react well to parity.  Also, if we are dialing through a
2943   TCP/IP TELNET modem server, parity can be fatally misinterpreted as TELNET
2944   negotiations.
2945
2946   This should work even if the user interrupts the DIAL command, because the
2947   DIAL module has its own interrupt handler.  BUT... if, for some reason, a
2948   dialing device actually *requires* parity (e.g. CCITT V.25bis says that even
2949   parity should be used), this might prevent successful dialing.  For that
2950   reason, we don't do this for V.25bis modems.
2951 */
2952     sparity = parity;                   /* Save current parity */
2953     if ((dialcapas & CKD_V25) == 0)     /* If not V.25bis...  */
2954       parity = 0;                       /* Set parity to NONE */
2955
2956     flowsave = flow;
2957 /*
2958   These modems use some kind of screwy flow control while in command mode,
2959   and do not present CTS as they should.  So if RTS/CTS is set (or even if
2960   it isn't) disable flow control during dialing.
2961 */
2962 #ifndef MINIDIAL
2963     if (mdmtyp == n_ATT1910 || mdmtyp == n_ATT1900) {
2964         flow = FLO_NONE;                /* This is not enough */
2965 #ifdef CK_TTSETFLOW
2966         ttsetflow(FLO_NONE);            /* Really turn it off */
2967 #endif /* CK_TTSETFLOW */
2968     }
2969 #endif /* MINIDIAL */
2970     if (!network
2971 #ifdef TN_COMPORT
2972         || istncomport()
2973 #endif /* TN_COMPORT */
2974          ) {
2975         int x;
2976         if ((x = ttgmdm()) > -1) {
2977             if (!x && msgflg) {
2978                 printf(
2979 "WARNING - No modem signals detected.  Is your modem turned on?  If not,\n\
2980 use Ctrl-C to interrupt dialing, turn on your modem, then %s.\n",
2981                        cx == XXANSW ?
2982                        "ANSWER again" :
2983                        "REDIAL"
2984                        );
2985             }
2986             if (flow == FLO_RTSC) {
2987                 if (!(x & BM_CTS)) {
2988                     if (msgflg)
2989                       printf(
2990 "WARNING - SET FLOW RTS/CTS is in effect but modem's CTS signal is off.\n\
2991 Disabling flow control temporarily %s...\n",
2992                              cx == XXANSW ?
2993                              "while waiting for call" :
2994                              "during dialing"
2995                              );
2996                     flow = FLO_NONE;
2997                 }
2998             }
2999         }
3000     }
3001     if (cx == XXANSW) {                 /* ANSWER */
3002         success = ckdial("",0,0,1,0);
3003         goto dialfin;
3004     }
3005
3006 /* Edit 192 adds the ability to dial repeatedly. */
3007
3008     i = 0;
3009     dialcount = 0;
3010     do {
3011         if (i > 0) printf("\nDial attempt %d of %d...\n", i+1, xretries);
3012         dialcount = i+1;
3013         success = 0;
3014         /* And the ability to dial alternate numbers. */
3015         /* Loop to dial each in a list of numbers for the same name... */
3016         for (j = 0; j < n && !success; j++) { /* until one answers. */
3017             s = dn_p2[j];               /* Next number in list */
3018             if (dn_x[j] >= dialrstr) {  /* Dial restriction */
3019                 printf("Restricted: %s, skipping...\n",dn_p[j]);
3020                 continue;
3021             }
3022             xredial = (i == 0 && j == 0) ? 0 : 1;
3023             if (!s) s = dn_p[j];
3024
3025 #ifndef NOSPL
3026             sav = s;
3027             p = xdial(s);               /* Apply DIAL macro now */
3028             if (p) s = p;
3029 #endif /* NOSPL */
3030
3031             /* Dial confirmation */
3032             /* NOTE: the uq_xxx() calls allow for a GUI dialog */
3033
3034             if (i == 0 && dialcnf) {
3035                 char msgbuf[128];
3036                 ckmakmsg(msgbuf,128,"Dialing ",s,NULL,NULL);
3037                 x = uq_ok(msgbuf,"Is this number correct? ",3,NULL,0);
3038                 if (!x) {
3039
3040 #ifndef COMMENT
3041                     x = uq_txt(         /* Allow GUI dialog */
3042 #ifdef OS2
3043 " Please enter the correct number,\r\n or press Enter to skip.",
3044 #else
3045 " Please enter the correct number,\r\n or press Return to skip.",
3046 #endif /* OS2 */
3047                               "Corrected phone number: ",
3048                                1,
3049                                NULL,
3050                                atmbuf,
3051                                ATMBL,
3052                                s,
3053                                DEFAULT_UQ_TIMEOUT
3054                                );
3055                     if (x && atmbuf[0]) { /* They gave a new one */
3056                         s = atmbuf;
3057                         makestr(&(dn_p2[j]), s);
3058                     }                   
3059
3060 #else  /* COMMENT */
3061
3062 #ifdef CK_RECALL
3063                     extern int on_recall;
3064 #endif /* CK_RECALL */
3065                     cmsavp(psave,PROMPTL);
3066                     cmsetp(
3067 #ifdef OS2
3068 " Please enter the correct number,\r\n or press Enter to skip: "
3069 #else
3070 " Please enter the correct number,\r\n or press Return to skip: "
3071 #endif /* OS2 */
3072                            );
3073                     cmini(ckxech);
3074                     x = -1;
3075                     if (pflag) prompt(NULL);
3076 #ifdef CK_RECALL
3077                     on_recall = 0;
3078 #endif /* CK_RECALL */
3079                     y = cmdgquo();
3080                     cmdsquo(0);
3081                     while (x < 0) {
3082                         x = cmtxt("Corrected phone number","",&s,NULL);
3083                         cmres();
3084                     }
3085                     if ((int) strlen(s) < 1) {
3086                         cmsetp(psave);
3087                         continue;
3088                     }
3089                     makestr(&(dn_p2[j]), s);
3090                     cmdsquo(y);
3091                     cmsetp(psave);
3092 #endif /* COMMENT */
3093                 }
3094             }
3095             if (dialtest) {             /* Just testing */
3096                 if (i + j == 0)
3097                   printf("\nTESTING...\n");
3098                 if (dialmac)
3099                   printf(" Number: \"%s\" => \"%s\"\n",sav,s);
3100                 else
3101                   printf(" Number: \"%s\"\n",s);
3102                 dialsta = DIA_BUSY;
3103                 success = 0;
3104             } else {
3105                 what |= W_DIALING;
3106                 success = ckdial(s,i,j,partial ? 3 : 0, xredial); /* Dial it */
3107                 what &= ~(W_DIALING);
3108                 if (!success) {
3109                     if (dialsta < 8 ||  /* Break out if unrecoverable error */
3110                         dialsta  == DIA_INTR ||
3111                         dialsta  == DIA_ERR  ||
3112                         previous == DIA_PART
3113                         )
3114                       break;
3115                 }
3116             }
3117         }
3118         if (success)                    /* Succeeded, leave the outer loop */
3119           break;
3120         if (dialsta < 8 ||              /* Break out if unrecoverable error */
3121             dialsta == DIA_INTR ||      /* Interrupted */
3122             dialsta == DIA_NODT ||      /* No dialtone */
3123             dialsta == DIA_NOAC ||      /* Access forbidden */
3124             dialsta == DIA_BLCK ||      /* Blacklisted */
3125             dialsta == DIA_DIR  ||      /* Dialing directory error */
3126             dialsta == DIA_ERR  ||      /* Modem command error */
3127             previous == DIA_PART)
3128           break;
3129         if (++i >= xretries)            /* Break out if too many tries */
3130           break;
3131         if (!backgrd && !quiet) {
3132             if (dialint > 5)
3133               printf(
3134 "\nWill redial in %d second%s- press any key to redial immediately.\n",
3135                      dialint,
3136                      dialint == 1 ? " " : "s "
3137                      );
3138             printf("Ctrl-C to cancel...\n");
3139         }
3140         x = dialint;                    /* Redial interval */
3141         while (x-- > 0) {
3142             if ((y = conchk()) > 0) {   /* Did they type something? */
3143                 while (y--) coninc(0);  /* Yes, absorb it */
3144                 break;                  /* And wake up */
3145             }
3146             sleep(1);                   /* No interrupt, sleep a sec */
3147         }
3148     } while (!success);
3149
3150   dialfin:
3151
3152     if (cx != XXLOOK) {
3153         if (!success)
3154           bleep((short) BP_FAIL);
3155         else if (!quiet)
3156           bleep((short) BP_NOTE);
3157 #ifdef OS2
3158         setint();                       /* Fix OS/2 interrupts */
3159 #endif /* OS2 */
3160         if (sparity > -1)
3161           parity = sparity;             /* Restore parity if we saved it */
3162         flow = flowsave;
3163 #ifdef OS2
3164         ttres();                        /* Restore DIAL device */
3165 #endif /* OS2 */
3166 #ifdef VMS
3167         concb((char)escape);            /* Restore console */
3168 #endif /* VMS */
3169 #ifdef OS2
3170         {                               /* Set session title */
3171             char * p, name[72];         /* in window list. */
3172             char * q;
3173             if (cx == XXANSW) {
3174                 q = "Incoming call";
3175             } else {
3176                 if (d_name)
3177                   q = d_name;
3178                 else if (dialnum)
3179                   q = dialnum;
3180                 else if (ttname[0])
3181                   q = ttname;
3182                 else q = "";
3183             }
3184             p = name;
3185             if (success) {
3186                 strncpy(name,q,48);
3187                 while (*p) {            /* Uppercase it for emphasis. */
3188                     if (islower(*p))
3189                       *p = toupper(*p);
3190                     p++;
3191                 }
3192             } else
3193               name[0] = NUL ;
3194             os2settitle((char *) name, TRUE);
3195         }
3196 #endif /* OS2 */
3197     }
3198     if (cx != XXLOOK) {
3199         if (success) {
3200             if (reliable == SET_AUTO) { /* It's not a reliable connection. */
3201                 reliable = SET_OFF;
3202                 debug(F101,"dodial reliable","",reliable);
3203             }
3204         } else {
3205 #ifndef NOHINTS
3206             extern int hints;
3207             if (hints && !quiet && dialsta != 9) { /* 9 == User interrupted */
3208                 extern int dialmhu, dialhng, dialdpy;
3209                 extern char * dialmsg[];
3210                 printf("\n*************************\n");
3211                 printf("DIAL-class command failed.\n");
3212                 printf("Modem type:  %s\n", gmdmtyp());
3213                 printf("Device:      %s\n", ttname);
3214                 printf("Speed:       %ld\n", speed);
3215                 printf("Dial status: %d",dialsta);
3216                 if (dialsta < 35 && dialmsg[dialsta])
3217                   printf(" [%s]",dialmsg[dialsta]);
3218                 printf("\n");
3219                 if (dialsta == DIA_TIMO ||
3220                     dialsta == DIA_NRDY ||
3221                    (dialsta > 13 && dialsta != DIA_BUSY && dialsta != DIA_NOAN)
3222                     ) {
3223                     switch (dialsta) {
3224                       case DIA_TIMO:
3225                         printf(
3226 " . SET DIAL TIMEOUT to a greater value and try again.\n"
3227                                );
3228                         break;
3229                       case DIA_NRSP:
3230                       case DIA_NRDY:
3231                       case DIA_NOIN:
3232                         printf(
3233 " . Is the modem turned on?\n"
3234                                );
3235                         printf(
3236 " . Are you using the right communication port?\n"
3237                                );
3238                         break;
3239                       case DIA_NODT:
3240                         printf(
3241 " . Is the modem connected to the telephone line?\n"
3242                                );
3243                     }
3244                     if (mdmtyp == n_GENERIC) {
3245                         printf(
3246 " . Please choose a specific modem type with SET MODEM TYPE and try again.\n"
3247                                );
3248                         printf(
3249 "    SET MODEM TYPE ? to see the list of known modem types.\n"
3250                                );
3251                     } else {
3252                         printf(
3253 " . Are you sure you have chosen the appropriate modem type?\n"
3254                                );
3255                     }
3256                     if (speed > 19200L) {
3257                         printf(
3258 " . Maybe the interface speed (%ld) is too fast:\n", speed
3259                                );
3260                         printf(
3261 "    SET SPEED to a lower speed and try again.\n"
3262                                );
3263                         printf(
3264 "    SET SPEED ? to see the list of valid speeds.\n"
3265                                );
3266                     }
3267                     if (dialhng) {
3268                         if (dialmhu)
3269                           printf(
3270 " . SET MODEM HANGUP-METHOD RS232 and try again.\n"
3271                                  );
3272                         else
3273                           printf(
3274 " . SET MODEM HANGUP-METHOD MODEM-COMMAND and try again.\n"
3275                                  );
3276                         printf(
3277 " . If that doesn't work, try again with SET DIAL HANGUP OFF.\n"
3278                                );
3279                     } else {
3280                         printf(
3281 " . Give a HANGUP or SET DIAL HANGUP ON command and try again.\n"
3282                                );
3283                     }
3284                     if (!dialdpy)
3285                       printf(
3286 " . Use SET DIAL DISPLAY ON to watch the dialog between Kermit and modem.\n"
3287                              );
3288                 }
3289 #ifndef NOSHOW
3290                 printf(
3291 " . SHOW COMMUNICATIONS, SHOW MODEM, SHOW DIAL to see current settings.\n"
3292                        );
3293 #endif /* NOSHOW */
3294
3295 #ifndef NOHELP
3296                 printf(
3297 " . HELP SET MODEM, HELP SET DIAL, and HELP DIAL for more information.\n"
3298                        );
3299 #endif /* NOHELP */
3300                 printf("(Use SET HINTS OFF to suppress future hints.)\n");
3301                 printf("*************************\n\n");
3302             }
3303 #endif /* NOHINTS */
3304         }
3305     }
3306     return(success);
3307 }
3308 #endif /* NODIAL */
3309
3310 /*  D O T Y P E  --  Type (display) a file with various options...  */
3311
3312 #ifdef BIGBUFOK
3313 #define TYPBUFL 16384
3314 #else
3315 #define TYPBUFL 256
3316 #endif /* BIGBUFOK */
3317
3318 int typ_lines = 0;                      /* \v(ty_ln) */
3319 int typ_mtchs = 0;                      /* \v(ty_lm) */
3320 static int typ_int = 0;                 /* Flag if TYPE interrupted */
3321
3322 #ifdef UNICODE
3323 extern int fcharset, fileorder, byteorder, ucsorder;
3324 #define TYPXBUFL TYPBUFL+TYPBUFL+TYPBUFL+4
3325 static char * mp = NULL;
3326 static char * mbuf = NULL;
3327 static long xn = 0L;
3328
3329 static int
3330 #ifdef CK_ANSIC
3331 storechar(char c)
3332 #else
3333 storechar(c) char c;
3334 #endif /* CK_ANSIC */
3335 {
3336     if (!mp) return(-1);
3337     if (++xn > TYPXBUFL)
3338       return(-1);
3339     debug(F111,"storechar xn",ckitoa((int)c),xn);
3340     *mp++ = c;
3341     return(0);
3342 }
3343 #endif /* UNICODE */
3344
3345 static FILE * ofp = NULL;               /* For /OUTPUT: file */
3346
3347 static int
3348 typeline(buf,len,outcs,ofp) char * buf; int len, outcs; FILE * ofp; {
3349     register int i;
3350
3351     debug(F011,"typeline buf",buf,len);
3352     /* debug(F101,"typeline outcs","",outcs); */
3353
3354 #ifdef OS2
3355 #ifndef NOLOCAL
3356 #ifdef UNICODE
3357     /* In K95 only, the buffer is guaranteed to be in UCS-2 if outcs >= 0. */
3358     /* Len is its length in bytes.  There is no line terminator. */
3359     /* outcs is the file character-set number (FC_xxx) of the target set */
3360     /* that was requested by the user. */
3361     if (!inserver && !k95stdout) {
3362         extern int wherex[], wherey[];
3363         extern unsigned char colorcmd;
3364
3365         VscrnWrtUCS2StrAtt( VCMD, (unsigned short *)buf, len/2,
3366                            wherey[VCMD], wherex[VCMD], &colorcmd);
3367         printf("\r\n");
3368         return(0);
3369     }
3370 #endif /* UNICODE */
3371 #endif /* NOLOCAL */
3372 #endif /* OS2 */
3373
3374 /* In Unix, VMS, etc, the line has already been converted to the desired  */
3375 /* character-set, if one was given.  OR... on all platforms, including in */
3376 /* K95, we don't know the character set.  In either case we dump the line */
3377 /* byte by byte in case it contains NULs (printf() would truncate). */
3378
3379 #ifdef COMMENT
3380     for (i = 0; i < len; i++)
3381       putchar(buf[i]);
3382 #else
3383     for (i = 0; i < len; i++) {
3384         if (ofp == stdout) {
3385             putchar(buf[i]);
3386         } else {
3387             putc(buf[i],ofp);
3388         }
3389     }
3390 #endif /* COMMENT */
3391
3392 #ifdef IKSD
3393     if (inserver) {
3394 #ifdef UNICODE
3395         if (outcs == FC_UCS2) {
3396             if (ofp == stdout) {
3397                 putchar(NUL);
3398             } else {
3399                 putc(NUL,ofp);
3400             }
3401         }
3402 #endif /* UNICODE */
3403         if (ofp == stdout) {
3404             putchar('\r');
3405         } else {
3406             putc('\r',ofp);
3407         }
3408     }
3409 #endif /* IKSD */
3410 #ifdef UNICODE
3411     if (outcs == FC_UCS2) {
3412         if (ofp == stdout) {
3413             putchar(NUL);
3414         } else {
3415             putc(NUL,ofp);
3416         }
3417     }
3418 #endif /* UNICODE */
3419     if (ofp == stdout) {
3420         putchar('\n');
3421     } else {
3422         putc('\n',ofp);
3423     }
3424     fflush(stdout);
3425     return(0);
3426 }
3427
3428 static int                              /* Get translated line */
3429 typegetline(incs, outcs, buf, n) int incs, outcs, n; char * buf; {
3430     int x = 0, c0, c1, len = 0, count = 0, eof = 0, xlate = 0;
3431 #ifdef UNICODE
3432     int xxn = -1;
3433     int yyn = -9;
3434     xn = 0L;
3435
3436 #ifdef DEBUG
3437     if (deblog && typ_lines == 0) {
3438         debug(F101,"typegetline incs","",incs);
3439         debug(F101,"typegetline outcs","",outcs);
3440         debug(F101,"typegetline feol","",feol);
3441         debug(F101,"typegetline byteorder","",byteorder);
3442         debug(F101,"typegetline ucsorder ","",ucsorder);
3443         debug(F111,"typegetline fileorder","1",fileorder);
3444     }
3445 #endif /* DEBUG */
3446
3447     if (incs < 0)                       /* Shouldn't happen */
3448       return(-2);
3449
3450     if (outcs == -1)                    /* Can happen */
3451       outcs = incs;
3452
3453     if (incs != outcs || incs == FC_UCS2) { /* See if we should translate */
3454         xlate = 1;
3455         if (!mbuf) {                    /* Allocate buffer if not allocated */
3456             mbuf = (char *)malloc(TYPXBUFL+1); /* yet */
3457             if (!mbuf) {
3458                 printf("WARNING: Translation buffer allocation failure.\n");
3459                 printf("Translation will be skipped...\n");
3460                 xlate = 0;
3461             }
3462         }
3463     }
3464     if (xlate) {                        /* Translating... */
3465         mp = mbuf;                      /* Reset working buffer pointer */
3466 /*
3467   Here we call xgnbyte() in a loop, having it return UCS-2 bytes.  In K95, we
3468   use UCS-2 directly.  Elsewhere, we feed the UCS-2 bytes into xpnbyte() to
3469   convert them to the desired target character set.  But since we are using
3470   UCS-2, we have several sources for confusion: (1) xgnbyte() might return in
3471   LE or BE byte order, with no explicit indication of what the order is; but
3472   (2) xpnbyte() wants BE; but (3) Windows wants LE.
3473 */
3474         while (1) {
3475             if (typ_int)                /* Quit if interrupted */
3476               return(0);
3477             c0 = xgnbyte(FC_UCS2,incs,NULL); /* Convert to UCS-2 */
3478             debug(F000,"typegetline c0","",c0);
3479             if (c0 < 0) {               /* EOF */
3480                 eof++;
3481                 break;
3482             }
3483             c1 = xgnbyte(FC_UCS2,incs,NULL); /* Convert to UCS-2 */
3484             debug(F000,"typegetline c1","",c1);
3485             if (c1 < 0) {               /* EOF */
3486                 eof++;
3487                 break;
3488             }
3489 #ifdef DEBUG
3490             if (deblog && typ_lines == 0) {
3491                 if (count == 0) /* Check fileorder after BOM */
3492                   debug(F111,"typegetline fileorder","2",fileorder);
3493             }
3494 #endif /* DEBUG */
3495
3496 #ifdef COMMENT
3497 /* Now we have the two UCS-2 bytes.  Which order are they in? */
3498
3499             if (fileorder > 0) {        /* Little Endian */
3500                 int t;                  /* So swap them */
3501                 debug(F100,"typegetline swapping","",0);
3502                 t = c1;
3503                 c1 = c0;
3504                 c0 = t;
3505             }
3506 #endif /* COMMENT */
3507             if (c0 == 0 && c1 == 0x0D)  /* Now see if we have EOL */
3508               yyn = xn;
3509
3510             if (c0 == 0 && c1 == 0x0A)  /* Now see if we have EOL */
3511               xxn = xn;
3512
3513             count++;                    /* Count byte */
3514
3515 /* Give the two bytes to xpnbyte() in BE order */
3516
3517             if ((x = xpnbyte(c0,TC_UCS2,outcs,storechar)) < 0) return(-1);
3518             if ((x = xpnbyte(c1,TC_UCS2,outcs,storechar)) < 0) return(-1);
3519
3520             if (xxn > -1) {             /* Have end of line? */
3521                 xn = xxn;
3522                 if (yyn == xxn - 2)     /* Adjust for CRLF */
3523                   xn = yyn;
3524                 break;                  /* And break out of loop. */
3525             }
3526         }
3527         mbuf[xn] = NUL;
3528         if (xn > n)                     /* Can truncate here... */
3529           xn = n;
3530         memcpy(buf,mbuf,xn);
3531         debug(F011,"typegetline xlate",buf,xn);
3532         return((eof && (xn == 0)) ? -1 : xn);
3533     }
3534 #endif /* UNICODE */
3535 #ifdef COMMENT
3536     /* We can't use this because, stupidly, zsinl() doesn't return a length. */
3537     /* It could be changed but then we'd have to change all ck?fio.c modules */
3538     x = zsinl(ZIFILE,buf,n);
3539 #else
3540     /* So instead, we copy zsinl() to here... */
3541     /* But note: This does not necessarily handle UCS-2 alignment properly;  */
3542     /* that's what the code in the first section of this routine is for. */
3543     /* But it does tolerate files that contain NULs. */
3544     {
3545         int a;
3546         char *s;
3547
3548         s = buf;
3549         a = -1;                         /* Current character, none yet. */
3550         debug(F101,"typegetline zsinl simulation","",n);
3551         while (n--) {                   /* Up to given length */
3552 #ifdef COMMENT
3553             int old = 0;
3554             if (feol)                   /* Previous character */
3555               old = a;
3556 #endif /* COMMENT */
3557             if (zchin(ZIFILE,&a) < 0) { /* Read a character from the file */
3558                 debug(F101,"typegetline zchin fail","",count);
3559                 if (count == 0)
3560                   x = -1;               /* EOF or other error */
3561                 break;
3562             } else
3563               count++;
3564             if (feol) {                 /* Single-character line terminator */
3565                 if (a == feol)
3566                   break;
3567             } else {                    /* CRLF line terminator */
3568 #ifdef COMMENT
3569 /* Debug log shows that in Windows, <CR><LF> is returned as <LF>. */
3570 /* Apparently we're not reading the file in binary mode. */
3571
3572                 if (a == '\015')        /* CR, get next character */
3573                   continue;
3574                 if (old == '\015') {    /* Previous character was CR */
3575                     if (a == '\012') {  /* This one is LF, so we have a line */
3576                         break;
3577                     } else {            /* Not LF, deposit CR */
3578                         *s++ = '\015';
3579                         n--;
3580                         len++;
3581                     }
3582                 }
3583 #else
3584                 if (a == LF) {
3585                     if (s[len] == CR) { /* This probably won't happen */
3586                         s[len] = NUL;
3587                         s--;
3588                         len--;
3589                     }
3590                     break;
3591                 }
3592 #endif /* COMMENT */
3593             }
3594             *s = a;                     /* Deposit character */
3595             s++;
3596             len++;
3597         }
3598         *s = '\0';                      /* Terminate the string */
3599     }
3600 #endif /* COMMENT */
3601     return(x < 0 ? -1 : len);
3602 }
3603
3604
3605 #ifndef MAC
3606 SIGTYP
3607 #ifdef CK_ANSIC
3608 tytrap(int foo)                         /* TYPE interrupt trap */
3609 #else
3610 tytrap(foo) int foo;
3611 #endif /* CK_ANSIC */
3612 /* tytrap */ {
3613 #ifdef __EMX__
3614     signal(SIGINT, SIG_ACK);
3615 #endif
3616     debug(F100,"type tytrap SIGINT","",0);
3617     typ_int = 1;                        /* (Need arg for ANSI C) */
3618     SIGRETURN;
3619 }
3620 #endif /* MAC */
3621
3622 int
3623 dotype(file, paging, first, head, pat, width, prefix, incs, outcs, outfile, z)
3624     char * file, * pat, * prefix; int paging, first, head, width, incs, outcs;
3625     char * outfile; int z;
3626 /* dotype */ {
3627     extern long ffc;
3628     char buf[TYPBUFL+2];
3629     char * s = NULL;
3630     int rc = 1, lines = 0, ucs2 = 0;
3631     char ** tail = NULL;
3632     int * tlen = NULL;
3633     int tailing = 0, counting = 0;
3634     int x, c, n, i, j, k = 0;
3635     int number = 0, save, len, pfxlen = 0, evalpfx = 1;
3636 #ifdef UNICODE
3637     int ucsbom_sav;
3638     extern int ucsbom;
3639 #endif /* UNICODE */
3640 #ifdef NT
3641     int gui = 0;
3642 #endif /* NT */
3643
3644 #ifndef MAC
3645 #ifdef OS2
3646 #ifdef NT
3647     SIGTYP (* oldsig)(int);             /* For saving old interrupt trap. */
3648 #else /* NT */
3649     SIGTYP (* volatile oldsig)(int);
3650 #endif /* NT */
3651 #else /* OS2 */
3652     SIGTYP (* oldsig)();
3653 #endif /* OS2 */
3654 #endif /* MAC */
3655
3656 #ifdef KUI
3657     if (outfile == (char *)1) {
3658         gui = 1;
3659         outfile = "";
3660     }
3661 #endif /* KUI */
3662
3663     if (!file) file = "";
3664     if (!*file) return(-2);
3665
3666     if (ofp != stdout) {                /* In case of previous interruption */
3667         if (ofp) fclose(ofp);
3668         ofp = stdout;
3669     }
3670     if (!outfile) outfile = "";
3671     if (outfile[0]) {
3672         ofp = fopen(outfile,"w");       /* Open output file */
3673         if (!ofp) {
3674             printf("?Can't open output file %s: %s\n",outfile,ck_errstr());
3675             ofp = stdout;
3676             return(-9);
3677         }
3678     }
3679     number = z;
3680     if (number && prefix) prefix = NULL;
3681
3682 #ifdef UNICODE
3683     ucsbom_sav = ucsbom;                /* We are not creating a file */
3684     ucsbom = 0;                         /* Do not use BOM bytes */
3685 #endif /* UNICODE */
3686
3687     typ_int = 0;
3688
3689     save = binary;                      /* Save file type */
3690
3691     debug(F101,"dotype incs","",incs);
3692     debug(F101,"dotype outcs","",outcs);
3693
3694 #ifdef UNICODE
3695     debug(F111,"dotype fileorder","A",fileorder);
3696 #ifdef OS2
3697     if (!inserver && !k95stdout)
3698       outcs = FC_UCS2;
3699 #endif /* OS2 */
3700
3701     if (outcs == FC_UCS2)               /* Output is UCS-2? */
3702       ucs2 = 1;
3703     if (fileorder < 0)
3704       fileorder = ucsorder;
3705     debug(F111,"dotype fileorder","B",fileorder);
3706 #endif /* UNICODE */
3707
3708 #ifdef CK_TTGWSIZ
3709 #ifdef OS2
3710     ttgcwsz();
3711 #else /* OS2 */
3712     /* Check whether window size changed */
3713     if (ttgwsiz() > 0) {
3714         if (tt_rows > 0 && tt_cols > 0) {
3715             cmd_rows = tt_rows;
3716             cmd_cols = tt_cols;
3717             debug(F101,"dotype cmd_rows","",cmd_rows);
3718             debug(F101,"dotype cmd_cols","",cmd_cols);
3719         }
3720     }
3721 #endif /* OS2 */
3722 #endif /* CK_TTGWSIZ */
3723
3724     if (prefix)
3725       pfxlen = strlen(prefix);
3726
3727     if (paging < 0) {                   /* Count only, don't print */
3728         counting = 1;
3729         prefix = NULL;
3730         width = 0;
3731         paging = 0;
3732     }
3733     if (ucs2)                           /* Crude... */
3734       width *= 2;
3735
3736 #ifdef OS2
3737     if (*file) {
3738         ckstrncpy(buf, file, TYPBUFL);  /* Change / to \. */
3739         p = buf;
3740         while (*p) {
3741             if (*p == '/') *p = '\\';
3742             p++;
3743         }
3744         file = buf;
3745     } else {
3746         rc = 0;
3747         goto xdotype;
3748     }
3749 #endif /* OS2 */
3750
3751     if (zchki(file) == -2) {            /* It's a directory */
3752         debug(F111,"dotype zchki failure",file,-2);
3753         if (xcmdsrc == 0) {
3754             printf("?Not a regular file: \"%s\"\n",file);
3755             rc = -9;
3756         } else
3757           rc = 0;
3758         goto xdotype;
3759     }
3760     if (!zopeni(ZIFILE, file)) {        /* Not a directory, open it */
3761         debug(F111,"dotype zopeni failure",file,0);
3762         if (xcmdsrc == 0) {
3763             printf("?Can't open file: \"%s\"\n",file);
3764             rc = -9;
3765         } else
3766           rc = 0;
3767         goto xdotype;
3768     }
3769
3770 #ifndef AMIGA
3771 #ifndef MAC
3772     errno = 0;
3773     oldsig = signal(SIGINT, tytrap);    /* Save current interrupt trap. */
3774     debug(F111,"type SIGINT trap set",ckitoa(errno),oldsig);
3775 #endif /* MAC */
3776 #endif /* AMIGA */
3777
3778     if (paging > -1)                    /* More-prompting */
3779       xaskmore = paging;
3780
3781     binary = 0;
3782
3783     if (head < 0) {                     /* "tail" was requested */
3784         tailing = 1;                    /* Set flag */
3785         head = 0 - head;                /* Get absolute number of lines */
3786         if (!counting) {
3787             tail = (char **) malloc(head * sizeof(char *)); /* Allocate list */
3788             if (!tail) {
3789                 printf("?Memory allocation failure\n");
3790                 goto xdotype;
3791
3792             }
3793             tlen = (int *) malloc(head * sizeof(int));
3794             if (!tlen) {
3795                 printf("?Memory allocation failure\n");
3796                 goto xdotype;
3797
3798             }
3799             for (i = 0; i < head; i++) { /* Initialize each pointer in list. */
3800                 tail[i] = NULL;
3801                 tlen[i] = 0;
3802             }
3803         }
3804     }
3805     typ_lines = 0;
3806     typ_mtchs = 0;
3807
3808 #ifdef UNICODE
3809     if (outcs > -1 && (incs != outcs || incs == FC_UCS2)) { /* Translating? */
3810         ffc = 0L;
3811         initxlate(incs,outcs);          /* Set up translation functions */
3812     } else
3813 #endif /* UNICODE */
3814       outcs = -1;                       /* Means we don't know the charset */
3815
3816     debug(F101,"dotype ffc","",ffc);
3817     debug(F101,"dotype outcs 2","",outcs);
3818 #ifdef UNICODE
3819     debug(F111,"dotype fileorder","C",fileorder);
3820 #endif /* UNICODE */
3821
3822     /* Allow the buffer to contain NULs */
3823
3824     for (n = first;
3825          (len = typegetline(incs,outcs,buf,TYPBUFL)) > -1;
3826          lines++
3827          ) {
3828         debug(F011,"dotype line",buf,len);
3829 #ifndef MAC
3830         if (typ_int) {                  /* Interrupted? */
3831             typ_int = 0;
3832             debug(F101,"type interrupted line","",lines);
3833             printf("^C...\n");          /* Print message */
3834             if (ofp != stdout) {        /* Close any output file */
3835                 if (ofp) fclose(ofp);
3836                 ofp = stdout;
3837             }
3838             goto xxdotype;
3839         }
3840 #endif /* MAC */
3841         typ_lines++;                    /* For \v(ty_ln) */
3842         if (pat)                        /* Matching? */
3843           if (!ckmatch(pat,buf,1,1+4))  /* Line matches pattern? */
3844             continue;                   /* No, skip it */
3845         typ_mtchs++;
3846
3847         if (head > 0 && !tailing && lines == head) /* Handle /HEAD:n */
3848           break;
3849
3850         buf[TYPBUFL+1] = NUL;           /* Just in case... */
3851         if (prefix) {                   /* Add specified prefix to each line */
3852             char pbuf[64];
3853             char * pp;
3854             pp = prefix;
3855 #ifndef NOSPL
3856             if (evalpfx) {              /* Prefix is a variable? */
3857                 int n = 63;             /* Maybe - evaluate it and see */
3858                 char * p = pbuf;
3859                 zzstring(prefix,&p,&n); /* If there is no change */
3860                 if (!strcmp(prefix,pbuf)) { /* it's not a variable */
3861                     evalpfx = 0;        /* So don't do this again. */
3862                 } else {                /* It was a variable */
3863                     pp = pbuf;          /* So substitute its value */
3864                     pfxlen = 63 - n;    /* and get its new length */
3865                 }
3866             }
3867 #endif /* NOSPL */
3868             if (len + pfxlen + 2 < TYPBUFL) {
3869                 /* Shift right to make room for prefix */
3870                 memcpy((char *)line+pfxlen,(char *)buf,len);
3871                 lset((char *)line,pp,pfxlen,SP);
3872                 debug(F110,"dotype prefix",line,pfxlen);
3873                 len += pfxlen;
3874                 memcpy((char *)buf,(char *)line,len);
3875             }
3876         } else if (number) {            /* Line numbers */
3877             int x;
3878             sprintf(line,"%4d. ",typ_lines);
3879             x = strlen(line);
3880             len += x;
3881             if (len < LINBUFSIZ) {
3882                 memcpy((char *)&line[x],(char *)buf,len);
3883                 memcpy((char *)buf,(char *)line,len);
3884             }
3885         }
3886         if (width > 0 && width <= TYPBUFL) { /* Truncate at given width. */
3887             char * obuf = line;         /* But to do that first we must */
3888             int i,k,z;                  /* expand tabs; assume every 8 cols. */
3889             line[0] = NUL;
3890             for (i = 0, k = 0; i < width; k++) { /* Character loop... */
3891                 if (!buf[k])            /* No more chars in this line, done. */
3892                   break;
3893                 if (buf[k] != '\t') {   /* If it's not a tab */
3894                     if (i >= LINBUFSIZ) /* Check for overflow */
3895                       break;
3896                     obuf[i++] = buf[k]; /* and then deposit it. */
3897                     obuf[i] = NUL;      /* Keep it null-terminated */
3898                     continue;
3899                 }
3900                 z = 8 - (i % 8);        /* It's a tab, expand it. */
3901                 if (z == 0) z = 8;
3902                 for (j = 0; j < z && i < LINBUFSIZ; j++) {
3903 #ifdef UNICODE
3904                     if (ucs2 && !ucsorder)
3905                       obuf[i++] = NUL;
3906 #endif /* UNICODE */
3907                     obuf[i++] = ' ';
3908 #ifdef UNICODE
3909                     if (ucs2 && ucsorder)
3910                       obuf[i++] = NUL;
3911 #endif /* UNICODE */
3912                 }
3913                 obuf[i++] = NUL;
3914                 obuf[i] = NUL;
3915             }
3916             obuf[width] = NUL;          /* Now truncate at given width. */
3917 #ifdef COMMENT
3918             /* This doesn't work for UCS-2 because it contains NULs */
3919             ckstrncpy(buf,obuf,TYPBUFL); /* and copy it back (again?) */
3920 #else
3921             memcpy((char *)buf,(char *)obuf,i); /* Copy it back */
3922 #endif /* COMMENT */
3923             len = (i > width) ? width : i; /* Spare us another strlen()... */
3924         }
3925         if (tailing) {                  /* If /TAIL:n... */
3926             k = lines % head;           /* save this line in circular buffer */
3927             if (!counting) {
3928                 if (tail[k]) free(tail[k]);
3929                 tail[k] = malloc(len+2);
3930                 if (!tail[k]) {
3931                     printf("?Memory allocation failure\n");
3932                     goto xdotype;
3933                 }
3934                 memcpy(tail[k],buf,len);
3935                 tlen[k] = len;
3936                 continue;
3937             }
3938         }
3939         if (counting)                   /* If only counting */
3940           continue;                     /* we're done with this line */
3941
3942         if (paging) {                   /* Displaying this line... */
3943             int u;
3944             u = len;                    /* Length in BYTES */
3945             if (ucs2)                   /* If outputting in UCS-2 */
3946               u /= 2;                   /* convert length to CHARACTERS */
3947             x = (u / cmd_cols) + 1;     /* Crudely allow for wrap */
3948             if (cmd_rows > 0 && cmd_cols > 0)
3949               n += x;                   /* This assumes terminal will wrap */
3950         }
3951 #ifdef KUI
3952         if ( gui ) {
3953             int i;
3954             unsigned short * uch = (unsigned short *)buf;
3955             for ( i=0; i<len/2; i++)
3956                 gui_text_popup_append(uch[i]);
3957                         gui_text_popup_append(CR);
3958                         gui_text_popup_append(LF);
3959         } 
3960         else
3961 #endif /* KUI */
3962         typeline(buf,len,outcs,ofp);    /* Print line, length based */
3963 #ifdef CK_TTGWSIZ
3964         debug(F101,"dotype n","",n);
3965         if (paging > 0 && ofp == stdout) { /* Pause at end of screen */
3966             if (cmd_rows > 0 && cmd_cols > 0) {
3967                 if (n > cmd_rows - 3) {
3968                     if (!askmore())
3969                       goto xdotype;
3970                     else
3971                       n = 0;
3972                 }
3973             }
3974         }
3975 #endif /* CK_TTGWSIZ */
3976     }
3977
3978   xdotype:
3979     if (counting) {
3980         fprintf(ofp,
3981                 "%s: %d line%s\n",file,typ_lines,typ_lines == 1 ? "" : "s");
3982         if (pat)
3983           fprintf(ofp,
3984                   "%s: %d match%s\n",pat,typ_mtchs,typ_mtchs == 1 ? "" : "es");
3985         goto xxdotype;
3986     }
3987     if (tailing && tail) {              /* Typing tail of file? */
3988         if (lines < head) {             /* Yes, show the lines we saved */
3989             k = 0;                      /* Show all lines */
3990         } else {                        /* More lines than tail number */
3991             lines = k;                  /* Last line to show */
3992             k++;                        /* First line to show */
3993             if (k >= head)
3994               k = 0;
3995         }
3996         n = first;                      /* Output line counter */
3997         for (i = k ;; i++) {            /* Loop thru circular buffer */
3998 #ifndef MAC
3999             if (typ_int) {              /* Interrupted? */
4000                 printf("^C...\n");      /* Print message */
4001                 goto xxdotype;
4002             }
4003 #endif /* MAC */
4004             j = i % head;               /* Index of this line */
4005             s = tail[j];                /* Point to line to display */
4006             if (!s)                     /* (shouldn't happen...) */
4007               break;
4008             if (paging) {               /* Crudely allow for line wrap */
4009                 x = tlen[j];
4010                 if (ucs2) x /= 2;
4011                 x = x / cmd_cols + 1;
4012                 if (cmd_rows > 0 && cmd_cols > 0)
4013                   n += x;
4014             }
4015             typeline(s,tlen[j],outcs,ofp); /* Display this line */
4016             if (paging && ofp == stdout) { /* Pause at end of screen */
4017                 if (cmd_rows > 0 && cmd_cols > 0) {
4018                     if (n > cmd_rows - 3) {
4019                         if (!askmore())
4020                           break;
4021                         else
4022                           n = 0;
4023                     }
4024                 }
4025             }
4026             tail[j] = NULL;
4027             free(s);                    /* Free the line */
4028             if (i % head == lines)      /* When to stop */
4029               break;
4030         }
4031         free((char *)tail);             /* Free the list */
4032         tail = NULL;
4033         if (tlen) free((char *)tlen);
4034         tlen = NULL;
4035     }
4036
4037 /* Come here when finished or on SIGINT */
4038
4039   xxdotype:
4040 #ifndef AMIGA
4041 #ifndef MAC
4042     signal(SIGINT,oldsig);              /* Put old signal action back. */
4043 #endif /* MAC */
4044 #endif /* AMIGA */
4045     if (tailing && tail) {
4046         for (i = 0; i < head; i++) {    /* Free each line. */
4047             if (tail[i])
4048               free(tail[i]);
4049         }
4050         free((char *)tail);             /* Free list pointer */
4051         if (tlen)
4052           free((char *)tlen);
4053     }
4054     x = zclose(ZIFILE);                 /* Done, close the input file */
4055     if (ofp != stdout) {                /* Close any output file */
4056         if (ofp) fclose(ofp);
4057         ofp = stdout;
4058     }
4059     binary = save;                      /* Restore text/binary mode */
4060 #ifdef UNICODE
4061     ucsbom = ucsbom_sav;                /* Restore BOM usage */
4062 #endif /* UNICODE */
4063
4064 #ifdef KUI
4065     if ( gui )
4066         gui_text_popup_wait(-1);        /* Wait for user to close the dialog */
4067 #endif /* KUI */
4068     return(rc);
4069 }
4070
4071 /* GREP command */
4072
4073 #define GREP_CASE  0                    /* /CASE */
4074 #define GREP_COUN  1                    /* /COUNT */
4075 #define GREP_DOTF  2                    /* /DOTFILES */
4076 #define GREP_NAME  3                    /* /NAMEONLY */
4077 #define GREP_NOBK  4                    /* /NOBACKUP */
4078 #define GREP_NODO  5                    /* /NODOTFILES */
4079 #define GREP_NOLI  6                    /* /NOLIST */
4080 #define GREP_NOMA  7                    /* /INVERT = /NOMATCH */
4081 #define GREP_NOPA  8                    /* /NOPAGE */
4082 #define GREP_NUMS  9                    /* /LINENUMBERS */
4083 #define GREP_PAGE 10                    /* /PAGE */
4084 #define GREP_RECU 11                    /* /RECURSIVE */
4085 #define GREP_TYPE 12                    /* /TYPE: */
4086 #define GREP_OUTP 13                    /* /OUTPUTFILE: */
4087
4088 static struct keytab greptab[] = {
4089     { "/count",        GREP_COUN, CM_ARG },
4090     { "/dotfiles",     GREP_DOTF, 0 },
4091     { "/linenumbers",  GREP_NUMS, 0 },
4092     { "/nameonly",     GREP_NAME, 0 },
4093     { "/nobackupfiles",GREP_NOBK, 0 },
4094     { "/nocase",       GREP_CASE, 0 },
4095     { "/nodotfiles",   GREP_NODO, 0 },
4096     { "/nolist",       GREP_NOLI, 0 },
4097     { "/nomatch",      GREP_NOMA, 0 },
4098     { "/nopage",       GREP_NOPA, 0 },
4099     { "/output",       GREP_OUTP, CM_ARG },
4100     { "/page",         GREP_PAGE, 0 },
4101     { "/quiet",        GREP_NOLI, CM_INV },
4102 #ifdef RECURSIVE
4103     { "/recursive",    GREP_RECU, 0 },
4104 #endif /* RECURSIVE */
4105     { "/type",         GREP_TYPE, CM_ARG },
4106     { "", 0, 0 }
4107 };
4108 static int ngreptab =  sizeof(greptab)/sizeof(struct keytab)-1;
4109
4110 int
4111 dogrep() {
4112     int match, x, y, fc, getval, mc = 0, count = 0, bigcount = 0;
4113     int fline = 0, sline = 0, wild = 0, len = 0;
4114     int xmode = -1, scan = 0;
4115     char c, name[CKMAXPATH+1], outfile[CKMAXPATH+1], *p, *s, *cv = NULL;
4116     FILE * fp = NULL;
4117
4118     int                                 /* Switch values and defaults */
4119       gr_coun = 0,
4120       gr_name = 0,
4121       gr_nobk = 0,
4122       gr_case = 1,
4123       gr_noli = 0,
4124       gr_noma = 0,
4125       gr_nums = 0,
4126       gr_page = xaskmore;
4127
4128     struct FDB sw, fl;
4129
4130     g_matchdot = matchdot;              /* Save global matchdot setting */
4131     outfile[0] = NUL;
4132
4133     if (ofp != stdout) {                /* In case of previous interruption */
4134         if (ofp) fclose(ofp);
4135         ofp = stdout;
4136     }
4137     cmfdbi(&sw,                         /* First FDB - command switches */
4138            _CMKEY,                      /* fcode */
4139            "String or pattern to search for, or switch",
4140            "",                          /* default */
4141            "",                          /* addtl string data */
4142            ngreptab,                    /* addtl numeric data 1: tbl size */
4143            4,                           /* addtl numeric data 2: 4 = cmswi */
4144            xxstring,                    /* Processing function */
4145            greptab,                     /* Keyword table */
4146            &fl                          /* Pointer to next FDB */
4147            );
4148     cmfdbi(&fl,                         /* Anything that doesn't match */
4149            _CMFLD,                      /* fcode */
4150            "",                          /* hlpmsg */
4151            "",                          /* default */
4152            "",                          /* addtl string data */
4153            0,                           /* addtl numeric data 1 */
4154            0,                           /* addtl numeric data 2 */
4155            xxstring,                    /* xxstring */
4156            NULL,
4157            NULL
4158            );
4159     while (1) {                         /* Parse 0 or more switches */
4160         x = cmfdb(&sw);                 /* Parse something */
4161         if (x < 0)
4162           return(x);
4163         if (cmresult.fcode != _CMKEY)   /* Break out if not a switch */
4164           break;
4165         c = cmgbrk();
4166         if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
4167             printf("?This switch does not take an argument\n");
4168             return(-9);
4169         }
4170         if ((cmresult.nresult != GREP_COUN) && !getval &&
4171             (cmgkwflgs() & CM_ARG)) {
4172             printf("?This switch requires an argument\n");
4173             return(-9);
4174         }
4175         switch (cmresult.nresult) {
4176           case GREP_COUN: {
4177               gr_coun++;
4178               if (getval) {
4179                   if ((x = cmfld("Variable for result","",&s,NULL)) < 0)
4180                     return(x);
4181                   makestr(&cv,s);
4182               }
4183               break;
4184           }
4185           case GREP_CASE: gr_case=0; break;
4186           case GREP_NAME: gr_name++; gr_noli=0; break;
4187           case GREP_NOBK: gr_nobk++; break;
4188           case GREP_NOLI: gr_noli++; gr_name=0; gr_nums=0; break;
4189           case GREP_NOMA: gr_noma++; break;
4190           case GREP_NOPA: gr_page=0; break;
4191           case GREP_NUMS: gr_nums++; gr_noli=0; break;
4192           case GREP_PAGE: gr_page++; gr_noli=0; break;
4193           case GREP_NODO:
4194             matchdot = 0;
4195             break;
4196           case GREP_DOTF:
4197             matchdot = 1;
4198             break;
4199 #ifdef RECURSIVE
4200           case GREP_RECU:
4201             recursive = 1;
4202             break;
4203 #endif /* RECURSIVE */
4204           case GREP_TYPE: {
4205               extern struct keytab txtbin[];
4206               if ((x = cmkey(txtbin,3,"","",xxstring)) < 0)
4207                 return(x);
4208               if (x == 2) {             /* ALL */
4209                   xmode = -1;
4210               } else {                  /* TEXT or BINARY only */
4211                   xmode = x;
4212                   scan = 1;
4213               }
4214               break;
4215           }
4216           case GREP_OUTP:               /* Send output to file */
4217             if ((x = cmofi("File for GREP'd lines","",&s,xxstring)) < 0)
4218               return(x);
4219             ckstrncpy(outfile,s,CKMAXPATH);
4220             break;
4221         }
4222     }
4223     if (outfile[0]) {
4224         ofp = fopen(outfile,"w");       /* Open output file */
4225         if (!ofp) {
4226             printf("?Can't open output file %s: %s\n",outfile,ck_errstr());
4227             ofp = stdout;
4228             return(-9);
4229         }
4230         gr_page = 0;
4231     }
4232     s = cmresult.sresult;
4233     s = brstrip(s);                     /* Strip braces from pattern */
4234     if (!*s) {
4235         printf("?Pattern required\n");
4236         return(-9);
4237     }
4238     ckstrncpy(tmpbuf,s,TMPBUFSIZ);      /* Save pattern */
4239     if ((x = cmifi("File(s) to search","",&s,&wild,xxstring)) < 0) {
4240         if (x == -3) {
4241             printf("?File specification required\n");
4242             x = -9;
4243         }
4244         return(x);
4245     }
4246     s = brstrip(s);                     /* Strip braces from filename */
4247 #ifndef ZXREWIND
4248     ckstrncpy(line,s,LINBUFSIZ);
4249 #endif /* ZXREWIND */
4250     if ((y = cmcfm()) < 0)
4251       return(y);
4252
4253     if (gr_page > -1)
4254       xaskmore = gr_page;               /* Paging... */
4255
4256     p = tmpbuf;                         /* Point to pattern */
4257 #ifdef COMMENT
4258 /* Now this is done in ckmatch */
4259     if (*p == '^') {                    /* '^' anchors pattern to beginning */
4260         p++;
4261     } else if (*p != '*') {             /* Otherwise prepend implied '*' */
4262         tmpbuf[0] = '*';
4263         p = tmpbuf;
4264     }
4265     x = strlen(p);                      /* Get length of result */
4266     if (x > 0 && x < TMPBUFSIZ) {       /* '$' at end anchors pattern to end */
4267         if (p[x-1] == '$') {
4268             p[x-1] = NUL;
4269         } else if (p[x-1] != '*') {
4270             p[x] = '*';
4271             p[x+1] = NUL;
4272         }
4273     }
4274 #endif /* COMMENT */
4275     debug(F111,"grep pat",p,x);
4276
4277 #ifdef ZXREWIND
4278     fc = zxrewind();                    /* Rewind the file list */
4279 #else
4280     {
4281         int flags = ZX_FILONLY;         /* Expand file list */
4282         if (matchdot)  flags |= ZX_MATCHDOT;
4283         if (recursive) flags |= ZX_RECURSE;
4284         fc = nzxpand(line,flags);
4285     }
4286 #endif /* ZXREWIND */
4287 #ifdef UNIX
4288     sh_sort(mtchs,NULL,fc,0,0,filecase);
4289 #endif /* UNIX */
4290
4291     debug(F101,"grep cmd_rows","",cmd_rows);
4292     debug(F101,"grep cmd_cols","",cmd_cols);
4293
4294     while (1) {                         /* Loop for each file */
4295         znext(name);                    /* Get next file */
4296         if (!name[0])                   /* No more, done */
4297           break;
4298         if (gr_nobk)                    /* Skipping backup files? */
4299           if (ckmatch("*.~[1-9]*~",name,1,1)) /* Backup file? */
4300             continue;                   /* Yes, skip */
4301         if (scan) {                     /* /TYPE: given? */
4302             switch (scanfile(name,&y,nscanfile)) { /* Yes, scan the file */
4303               case FT_BIN:
4304                 if (xmode != 1)
4305                   continue;
4306                 break;
4307               case FT_TEXT:
4308               case FT_7BIT:
4309               case FT_8BIT:
4310 #ifdef UNICODE
4311               case FT_UTF8:
4312               case FT_UCS2:
4313 #endif /* UNICODE */
4314                 if (xmode != 0)
4315                   continue;
4316             }
4317         }
4318         fp = fopen(name,"r");           /* Open */
4319         if (!fp)                        /* Can't */
4320           continue;                     /* Skip */
4321         count = 0;                      /* Match count, this file */
4322         fline = 0;                      /* Line count, this file */
4323         while (1) {                     /* Loop for each line */
4324             if (fgets(line,LINBUFSIZ,fp) == NULL) { /* Get next line */
4325                 fclose(fp);
4326                 fp = NULL;
4327                 debug(F100,"GREP EOF","",0);
4328                 break;
4329             }
4330             fline++;                    /* Count this line */
4331             line[LINBUFSIZ] = NUL;      /* Make sure it's terminated */
4332             debug(F111,"GREP",line,fline);
4333             len = (int)strlen(line);    /* Get length */
4334             while (len > 0 && (line[len-1] == '\n' || line[len-1] == '\r'))
4335               line[--len] = NUL;        /* Chop off terminators */
4336             match = ckmatch(p,line,gr_case,1+4); /* Match against pattern */
4337             if (gr_noma)                /* Invert match sense if requested */
4338               match = !match;
4339             if (match) {                /* Have a matching line */
4340                 mc++;                   /* Total match count */
4341                 count++;                /* Match count this file */
4342                 if (gr_name) {          /* Don't care how many lines match */
4343                     fclose(fp);         /* Close the file */
4344                     fp = NULL;          /* and quit the line-reading loop. */
4345                     break;
4346                 }
4347                 if (gr_coun || gr_noli) /* Not listing each line */
4348                   continue;             /* so don't print anything now. */
4349                 if (wild) {             /* If searching multiple files */
4350                     fprintf(ofp,"%s:",name); /* print filename. */
4351                     len += (int)strlen(name) + 1;
4352                 }
4353                 if (gr_nums) {          /* If line numbers wanted */
4354                     char nbuf[32];
4355                     len += ckmakmsg(nbuf,32,ckitoa(fline),":",NULL,NULL);
4356                     fprintf(ofp,"%s",nbuf);
4357                 }
4358                 if (cmd_rows > 0 && cmd_cols > 0)
4359                   sline += (len / cmd_cols) + 1;
4360                 fprintf(ofp,"%s\n",line); /* Print the line. */
4361                 if (sline > cmd_rows - 3) {
4362                     if (!askmore()) goto xgrep; else sline = 0;
4363                 }
4364             }
4365         }
4366         if (!gr_noli) {                 /* If not not listing... */
4367             x = 0;
4368             if (gr_coun) {              /* Show match count only */
4369                 fprintf(ofp,"%s:%d\n",name,count);
4370                 x++;
4371             } else if (gr_name && count > 0) { /* Show name only */
4372                 fprintf(ofp,"%s\n",name);
4373                 x++;
4374             }
4375             if (x > 0) {
4376                 if (++sline > cmd_rows - 3) {
4377                     if (!askmore()) goto xgrep; else sline = 0;
4378                 }
4379             }
4380         }
4381         bigcount += count;              /* Overall count */
4382     }
4383   xgrep:
4384 #ifndef NOSPL
4385     if (gr_coun && cv) {                /* /COUNT:blah */
4386         addmac(cv,ckitoa(bigcount));    /* set the variable */
4387         makestr(&cv,NULL);              /* free this */
4388     }
4389 #endif /* NOSPL */
4390     if (fp) fclose(fp);                 /* close input file if still open */
4391     if (ofp != stdout) {                /* Close any output file */
4392         if (ofp) fclose(ofp);
4393         ofp = stdout;
4394     }
4395     return(success = mc ? 1 : 0);
4396 }
4397
4398 /* System-independent directory */
4399
4400 static char ** dirlist = NULL;
4401 static int ndirlist = 0;
4402
4403 static VOID
4404 freedirlist() {
4405     if (dirlist) {
4406         int i;
4407         for (i = 0; i < ndirlist; i++) {
4408             if (dirlist[i])
4409               free(dirlist[i]);
4410         }
4411         free((char *)dirlist);
4412         dirlist = NULL;
4413     }
4414     ndirlist = 0;
4415 }
4416
4417 static struct keytab dirswtab[] = {     /* DIRECTORY command switches */
4418     { "/after",       DIR_AFT, CM_ARG },
4419     { "/all",         DIR_ALL, 0 },
4420 #ifndef NOSPL
4421     { "/array",       DIR_ARR, CM_ARG },
4422 #endif /* NOSPL */
4423     { "/ascending",   DIR_ASC, 0 },
4424     { "/backup",      DIR_BUP, 0 },
4425     { "/before",      DIR_BEF, CM_ARG },
4426     { "/brief",       DIR_BRF, 0 },
4427     { "/descending",  DIR_DSC, CM_INV },
4428     { "/directories", DIR_DIR, 0 },
4429     { "/dotfiles",    DIR_DOT, 0 },
4430     { "/englishdate", DIR_DAT, 0 },
4431     { "/except",      DIR_EXC, CM_ARG },
4432     { "/files",       DIR_FIL, 0 },
4433     { "/heading",     DIR_HDG, 0 },
4434     { "/isodate",     DIR_ISO, 0 },
4435     { "/larger-than", DIR_LAR, CM_ARG },
4436 #ifdef CKSYMLINK
4437     { "/followlinks", DIR_LNK, 0 },
4438 #endif /* CKSYMLINK */
4439     { "/message",     DIR_MSG, CM_ARG },
4440     { "/nobackupfiles",DIR_NOB, 0 },
4441     { "/nodotfiles",  DIR_NOD, 0 },
4442 #ifdef CKSYMLINK
4443     { "/nofollowlinks",DIR_NLK, 0 },
4444 #endif /* CKSYMLINK */
4445     { "/noheading",   DIR_NOH, 0 },
4446     { "/nomessage",   DIR_NOM, 0 },
4447 #ifdef CK_TTGWSIZ
4448     { "/nopage",      DIR_NOP, 0 },
4449 #endif /* CK_TTGWSIZ */
4450 #ifdef RECURSIVE
4451     { "/norecursive", DIR_NOR, 0 },
4452 #else
4453 #ifdef VMS
4454     { "/norecursive", DIR_NOR, 0 },
4455 #else
4456 #ifdef datageneral
4457     { "/norecursive", DIR_NOR, 0 },
4458 #endif /* datageneral */
4459 #endif /* VMS */
4460 #endif /* RECURSIVE */
4461     { "/nosort",      DIR_NOS, 0 },
4462     { "/not-after",   DIR_NAF, CM_ARG },
4463     { "/not-before",  DIR_NBF, CM_ARG },
4464     { "/not-since",   DIR_NAF, CM_INV|CM_ARG },
4465     { "/noxfermode",  DIR_NOT, 0 },
4466     { "/output",      DIR_OUT, CM_ARG },
4467 #ifdef CK_TTGWSIZ
4468     { "/page",        DIR_PAG, 0 },
4469 #endif /* CK_TTGWSIZ */
4470 #ifdef RECURSIVE
4471     { "/recursive",   DIR_REC, 0 },
4472 #else
4473 #ifdef VMS
4474     { "/recursive",   DIR_REC, 0 },
4475 #else
4476 #ifdef datageneral
4477     { "/recursive",   DIR_REC, 0 },
4478 #endif /* datageneral */
4479 #endif /* VMS */
4480 #endif /* RECURSIVE */
4481     { "/reverse",     DIR_DSC, 0 },
4482     { "/since",       DIR_AFT, CM_ARG|CM_INV },
4483     { "/smaller-than",DIR_SMA, CM_ARG },
4484     { "/sort",        DIR_SRT, CM_ARG },
4485     { "/summary",     DIR_SUM, 0 },
4486     { "/type",        DIR_BIN, CM_ARG },
4487     { "/xfermode",    DIR_TYP, 0 },
4488     { "/verbose",     DIR_VRB, 0 },
4489     { "",0,0 }
4490 };
4491 static int ndirswtab = (sizeof(dirswtab) / sizeof(struct keytab)) - 1;
4492
4493 static struct keytab dirsort[] = {      /* DIRECTORY /SORT: options */
4494     { "date",         DIRS_DT, 0 },
4495     { "name",         DIRS_NM, 0 },
4496     { "size",         DIRS_SZ, 0 }
4497 };
4498 static int ndirsort = (sizeof(dirsort) / sizeof(struct keytab));
4499
4500 static int dir_date = -1;               /* Option defaults (-1 means none) */
4501 static int dir_page = -1;
4502 static int dir_verb =  1;
4503 static int dir_msg  = -1;
4504 #ifdef VMS
4505 static int dir_sort = -1;               /* Names are already sorted in VMS */
4506 static int dir_rvrs = -1;
4507 #else
4508 static int dir_sort =  1;               /* Sort by default */
4509 static int dir_rvrs =  0;               /* Not in reverse */
4510 #endif /* VMS */
4511 static int dir_skey = DIRS_NM;          /* By name */
4512 #ifdef RECURSIVE
4513 static int dir_recu = -1;
4514 #endif /* RECURSIVE */
4515 static int dir_mode = -1;
4516 static int dir_show = -1;               /* Show all files by default */
4517 int dir_dots =  -1;                     /* Except dot files */
4518 int dir_back =  1;
4519 int dir_head =  0;
4520 static char * dirmsg = NULL;
4521 static int dirmsglen = 0;
4522
4523 #ifndef NOSHOW
4524 VOID
4525 showdiropts() {
4526     int x = 0;
4527     extern int optlines;
4528     prtopt(&optlines,"DIRECTORY");
4529     if (dir_show > 0) {
4530         prtopt(&optlines,(dir_show == 1) ? "/FILES" :
4531                ((dir_show == 2) ? "/DIRECTORIES" : "/ALL"));
4532         x++;
4533     } else {
4534         prtopt(&optlines,"/ALL");
4535         x++;
4536     }
4537     if (dir_verb > -1) {
4538         prtopt(&optlines,dir_verb ? "/VERBOSE" : "/BRIEF");
4539         x++;
4540     }
4541     if (dir_page > -1) {
4542         prtopt(&optlines,dir_page ? "/PAGE" : "/NOPAGE");
4543         x++;
4544     }
4545     if (dir_date > -1) {
4546         prtopt(&optlines,dir_date ? "/ENGLISHDATE" : "/ISODATE");
4547         x++;
4548     }
4549     if (dir_dots > -1) {
4550         prtopt(&optlines,dir_dots ? "/DOTFILES" : "/NODOTFILES");
4551         x++;
4552     }
4553     if (dir_back > -1) {
4554         prtopt(&optlines,dir_back ? "/BACKUP" : "/NOBACKUP");
4555         x++;
4556     }
4557     if (dir_head > -1) {
4558         prtopt(&optlines,dir_head ? "/HEADING" : "/NOHEADING");
4559         x++;
4560     }
4561 #ifdef RECURSIVE
4562     if (dir_recu > -1) {
4563         prtopt(&optlines,dir_recu ? "/RECURSIVE" : "/NORECURSIVE");
4564         x++;
4565     }
4566 #endif /* RECURSIVE */
4567     if (dir_mode > -1) {
4568         prtopt(&optlines,dir_mode ? "/XFERMODE" : "/NOXFERMODE");
4569         x++;
4570     }
4571     if (dir_sort == 0) {
4572         x++;
4573         prtopt(&optlines,"/NOSORT ");
4574     } else if (dir_sort > 0) {
4575         x++;
4576         if (dir_skey == DIRS_NM) s = "/SORT:NAME";
4577         else if (dir_skey == DIRS_SZ) s = "/SORT:SIZE";
4578         else if (dir_skey == DIRS_DT) s = "/SORT:DATE";
4579         prtopt(&optlines,s);
4580     }
4581     if (dir_rvrs > -1) {
4582         prtopt(&optlines,dir_rvrs ? "/REVERSE" : "/ASCENDING");
4583         x++;
4584     }
4585     if (dir_msg > -1) {
4586         if (dir_msg == 0) {
4587             prtopt(&optlines,"/NOMESSAGE");
4588         } else {
4589             ckmakmsg(tmpbuf,TMPBUFSIZ,"/MESSAGE:{",dirmsg,"}",NULL);
4590             prtopt(&optlines,tmpbuf);
4591         }
4592         x++;
4593     }
4594     if (!x) prtopt(&optlines,"(no options set)");
4595     prtopt(&optlines,"");
4596 }
4597 #endif /* NOSHOW */
4598
4599 int
4600 setdiropts() {                          /* Set DIRECTORY option defaults */
4601     int xb = -1, xv = -1, xp = -1, xd = -1, xh = -1, xf = -1;
4602     int xk = -1, xr = -1, xs = -1, xx = -1, xm = -1, xa = -1, xg = -1;
4603     int getval;
4604     char c;
4605     while (1) {
4606         if ((y = cmswi(dirswtab,ndirswtab,"Switch","",xxstring)) < 0) {
4607             if (y == -3)
4608               break;
4609             else
4610               return(y);
4611         }
4612         c = cmgbrk();
4613         if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
4614             printf("?This switch does not take an argument\n");
4615             return(-9);
4616         }
4617         if (!getval && (cmgkwflgs() & CM_ARG)) {
4618             printf("?This switch requires an argument\n");
4619             return(-9);
4620         }
4621         switch (y) {
4622           case DIR_BRF: xv = 0; break;
4623           case DIR_VRB: xv = 1; break;
4624           case DIR_PAG: xp = 1; break;
4625           case DIR_NOP: xp = 0; break;
4626           case DIR_ISO: xd = 0; break;
4627           case DIR_DAT: xd = 1; break;
4628           case DIR_HDG: xh = 1; break;
4629           case DIR_NOH: xh = 0; break;
4630           case DIR_DOT: xf = 1; break;
4631           case DIR_NOD: xf = 0; break;
4632           case DIR_ALL: xa = 3; break;
4633           case DIR_DIR: xa = 2; break;
4634           case DIR_FIL: xa = 1; break;
4635           case DIR_SRT:
4636             x = DIRS_NM;
4637             if (getval)
4638               if ((x = cmkey(dirsort,ndirsort,"Sort key","name",xxstring)) < 0)
4639                 return(x);
4640             xk = x;
4641             xs = 1;
4642             break;
4643           case DIR_NOS: xs = 0; break;
4644           case DIR_ASC: xx = 0; break;
4645           case DIR_DSC: xx = 1; break;
4646           case DIR_REC: xr = 1; break;
4647           case DIR_NOR: xr = 0; break;
4648           case DIR_TYP: xm = 1; break;
4649           case DIR_NOT: xm = 0; break;
4650           case DIR_BUP: xb = 1; break;
4651           case DIR_NOB: xb = 0; break;
4652           case DIR_NOM: xg = 0; break;
4653           case DIR_MSG:
4654             if (getval)
4655               if ((x = cmfld("Message to append to each line",
4656                              "",
4657                              &s,
4658                              xxstring
4659                              )) < 0)
4660                 return(x);
4661             xg = 1;
4662             ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
4663             break;
4664           default:
4665             printf("?This option can not be set\n");
4666             return(-9);
4667         }
4668     }
4669     if ((x = cmcfm()) < 0)              /* Get confirmation */
4670       return(x);
4671     if (xv > -1) dir_verb = xv;         /* Confirmed, save defaults */
4672     if (xp > -1) dir_page = xp;
4673     if (xd > -1) dir_date = xd;
4674     if (xh > -1) dir_head = xh;
4675     if (xs > -1) dir_sort = xs;
4676     if (xk > -1) dir_skey = xk;
4677     if (xx > -1) dir_rvrs = xx;
4678     if (xf > -1) dir_dots = xf;
4679     if (xa > -1) dir_show = xa;
4680     if (xm > -1) dir_mode = xm;
4681     if (xb > -1) dir_back = xb;
4682 #ifdef RECURSIVE
4683     if (xr > -1) dir_recu = xr;
4684 #endif /* RECURSIVE */
4685     if (xg > -1) dir_msg  = xg;
4686     if (xg > 0)
4687       makestr(&dirmsg,tmpbuf);
4688     return(success = 1);
4689 }
4690
4691 int
4692 domydir() {                             /* Internal DIRECTORY command */
4693     extern char *months[];
4694 #ifdef VMS
4695     _PROTOTYP( char * zrelname, (char *,char *) );
4696     char * cdp = NULL;
4697 #endif /* VMS */
4698
4699     char name[CKMAXPATH+1], outfile[CKMAXPATH+1], *p = NULL, c = NUL;
4700     char linebuf[CKMAXPATH+256];
4701     char * mstr = NULL, * dstr = NULL, * s2 = NULL;
4702     long len = 0, ndirs = 0, nfiles = 0, nbytes = 0, nmatches = 0;
4703     int verbose = 0, wild = 0, page = 0, n = 0, engdate = 0, summary = 0;
4704     int heading = 0, xsort = 0, reverse = 0, sortby = 0, msg = 0;
4705     int k, i = 0, x = 0, nx = 0, skey = 0, dlen = 0, itsadir = 0;
4706     int show = 3, xfermod = 0, backup = 1, rc = 0, getval = 0;
4707     int fs = 0;
4708     int multiple = 0;
4709     int cmifn1 = 1, cmifn2 = 0;
4710     long minsize = -1L, maxsize = -1L;
4711     struct FDB sw, fi, fl;
4712     char dbuf[32], xbuf[32];
4713
4714 #ifndef NOSPL
4715     char array = NUL;
4716     char ** ap = NULL;
4717 #endif /* NOSPL */
4718     char
4719       * dir_aft = NULL,
4720       * dir_bef = NULL,
4721       * dir_naf = NULL,
4722       * dir_nbf = NULL,
4723       * dir_exc = NULL;
4724     char * xlist[16];
4725
4726     g_matchdot = matchdot;              /* Save global matchdot setting */
4727     nolinks = 2;                        /* (it should already be 2) */
4728     outfile[0] = NUL;                   /* No output file yet */
4729
4730     if (ofp != stdout) {                /* In case of previous interruption */
4731         if (ofp) fclose(ofp);
4732         ofp = stdout;
4733     }
4734     for (i = 0; i < 16; i++) xlist[i] = NULL;
4735
4736     name[0] = NUL;
4737     freedirlist();                      /* In case not freed last time */
4738     page      = dir_page > -1 ? dir_page : xaskmore; /* Set option defaults */
4739     engdate   = dir_date > -1 ? dir_date : 0;
4740     verbose   = dir_verb > -1 ? dir_verb : 1;
4741     heading   = dir_head > -1 ? dir_head : 0;
4742     xsort     = dir_sort > -1 ? dir_sort : 0;
4743     sortby    = dir_skey > -1 ? dir_skey : 0;
4744     reverse   = dir_rvrs > -1 ? dir_rvrs : 0;
4745     msg       = dir_msg  > -1 ? dir_msg  : 0;
4746 #ifdef UNIXOROSK
4747     if (dir_dots > -1) matchdot = dir_dots;
4748 #endif /* UNIXOROSK */
4749     xfermod   = dir_mode > -1 ? dir_mode : 0;
4750     backup    = dir_back > -1 ? dir_back : 1;
4751 #ifdef RECURSIVE
4752     recursive = dir_recu > -1 ? dir_recu : 0;
4753 #endif /* RECURSIVE */
4754     show      = dir_show > -1 ? dir_show : 3;
4755
4756 #ifdef CK_TTGWSIZ
4757 #ifdef OS2
4758     ttgcwsz();                          /* Screen length for more-prompting */
4759 #else /* OS2 */
4760     /* Check whether window size changed */
4761     if (ttgwsiz() > 0) {
4762         if (tt_rows > 0 && tt_cols > 0) {
4763             cmd_rows = tt_rows;
4764             cmd_cols = tt_cols;
4765         }
4766     }
4767 #endif /* OS2 */
4768 #endif /* CK_TTGWSIZ */
4769
4770     diractive = 1;
4771     cmifn1 = nolinks | 1;               /* 1 = files or directories */
4772     cmifn2 = 0;                         /* 0 = not directories only */
4773
4774   again:
4775
4776     cmfdbi(&sw,                         /* First FDB - command switches */
4777            _CMKEY,                      /* fcode */
4778            "Enter or Return to confirm the command, or\n\
4779  file specification, or switch",
4780            "",                          /* default */
4781            "",                          /* addtl string data */
4782            ndirswtab,                   /* addtl numeric data 1: tbl size */
4783            4,                           /* addtl numeric data 2: 4 = cmswi */
4784            xxstring,                    /* Processing function */
4785            dirswtab,                    /* Keyword table */
4786            &fi                          /* Pointer to next FDB */
4787            );
4788     cmfdbi(&fi,                         /* 2nd FDB - filespec to match */
4789            _CMIFI,                      /* fcode */
4790            "File specification",        /* hlpmsg */
4791 #ifdef datageneral
4792            "+",                         /* Default filespec is wildcard */
4793 #else                                   /* that matches all files... */
4794 #ifdef VMS
4795            "*.*",
4796 #else
4797            "*",
4798 #endif /* VMS */
4799 #endif /* datageneral */
4800            "",                          /* addtl string data */
4801            cmifn1,
4802            cmifn2,                      /* 1 = only dirs; 0 files or dirs */
4803            xxstring,
4804            NULL,
4805            &fl
4806            );
4807     cmfdbi(&fl,                         /* Anything that doesn't match */
4808            _CMFLD,                      /* fcode */
4809            "",                          /* hlpmsg */
4810            "",                          /* default */
4811            "",                          /* addtl string data */
4812            0,                           /* addtl numeric data 1 */
4813            0,                           /* addtl numeric data 2 */
4814            xxstring,
4815            NULL,
4816            NULL
4817            );
4818     while (1) {                         /* Parse 0 or more switches */
4819         x = cmfdb(&sw);                 /* Parse something */
4820         debug(F101,"domydir cmfdb","",x);
4821         if (x < 0)
4822           return(x);
4823         if (cmresult.fcode != _CMKEY)   /* Break out if not a switch */
4824           break;
4825         c = cmgbrk();
4826         if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
4827             printf("?This switch does not take an argument\n");
4828             return(-9);
4829         }
4830         if (!getval && (cmgkwflgs() & CM_ARG)) {
4831             printf("?This switch requires an argument\n");
4832             return(-9);
4833         }
4834         switch (k = cmresult.nresult) {
4835           case DIR_BRF: verbose = 0; break;
4836           case DIR_VRB: verbose = 1; break;
4837 #ifdef CK_TTGWSIZ
4838           case DIR_PAG: page = 1;    break;
4839           case DIR_NOP: page = 0;    break;
4840 #endif /* CK_TTGWSIZ */
4841           case DIR_ISO: engdate = 0; break;
4842           case DIR_DAT: engdate = 1; break;
4843           case DIR_HDG: heading = 1; break;
4844           case DIR_NOH: heading = 0; break;
4845 #ifdef UNIXOROSK
4846           case DIR_DOT: matchdot = 1; break;
4847           case DIR_NOD: matchdot = 0; break;
4848 #endif /* UNIXOROSK */
4849           case DIR_ALL:
4850             show = 3;
4851             cmifn1 |= 1;
4852             cmifn2 = 0;
4853             goto again;
4854           case DIR_DIR:
4855             show = 2;
4856             cmifn1 |= 1;
4857             cmifn2 = 1;
4858             goto again;
4859           case DIR_FIL:
4860             show = 1;
4861             cmifn1 &= ~(1);
4862             cmifn2 = 0;
4863             goto again;
4864           case DIR_SRT:
4865             x = DIRS_NM;
4866             if (c == ':' || c == '=')
4867               if ((x = cmkey(dirsort,ndirsort,"Sort key","name",xxstring)) < 0)
4868                 return(x);
4869             xsort = 1;
4870             sortby = x;
4871             break;
4872
4873           case DIR_BUP: backup  = 1; fs++;   break;
4874           case DIR_NOB: backup  = 0; fs++;   break;
4875
4876           case DIR_NOS: xsort = 0;     break;
4877           case DIR_ASC: reverse = 0;   break;
4878           case DIR_DSC: reverse = 1;   break;
4879 #ifdef RECURSIVE
4880           case DIR_REC: recursive = 1; diractive = 1; break;
4881           case DIR_NOR: recursive = 0; diractive = 0; break;
4882 #endif /* RECURSIVE */
4883           case DIR_TYP: xfermod = 1;   break;
4884           case DIR_NOT: xfermod = 0;   break;
4885
4886 #ifdef CKSYMLINK
4887           case DIR_LNK:                 /* Follow links */
4888             nolinks = 0;
4889             cmifn1 &= ~(2);
4890             goto again;
4891           case DIR_NLK:                 /* Don't follow links */
4892             nolinks = 2;
4893             cmifn1 &= ~(2);
4894             goto again;
4895 #endif /* CKSYMLINK */
4896
4897           case DIR_NOM: msg     = 0;   break;
4898           case DIR_MSG:
4899             if (c == ':' || c == '=')
4900               if ((x = cmfld("Message to append to each line",
4901                              "",
4902                              &s,
4903                              xxstring
4904                              )) < 0)
4905                 return(x);
4906             msg = 1;
4907             ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
4908             break;
4909
4910           case DIR_SMA:
4911           case DIR_LAR:
4912             if (!getval) break;
4913             if ((x = cmnum("File size in bytes","0",10,&y,xxstring)) < 0)
4914               return(x);
4915             fs++;
4916             show = 1;
4917             switch (cmresult.nresult) {
4918               case DIR_SMA: minsize = y; break;
4919               case DIR_LAR: maxsize = y; break;
4920             }
4921             break;
4922
4923 #ifndef NOSPL
4924           case DIR_ARR:
4925             if (c != ':' && c != '=') {
4926                 printf("?Array name required\n");
4927                 return(-9);
4928             }
4929             if ((x = cmfld("Array name (a single letter will do)",
4930                            "",
4931                            &s,
4932                            NULL
4933                            )) < 0) {
4934                 if (x == -3) {
4935                     printf("?Array name required\n");
4936                     return(-9);
4937                 } else
4938                   return(x);
4939             }
4940             if (!*s) {
4941                 printf("?Array name required\n");
4942                 return(-9);
4943             }
4944             s2 = s;
4945             if (*s == CMDQ) s++;
4946             if (*s == '&') s++;
4947             if (!isalpha(*s)) {
4948                 printf("?Bad array name - \"%s\"\n",s2);
4949                 return(-9);
4950             }
4951             array = *s++;
4952             if (isupper(array)) array = tolower(array);
4953             if (*s && (*s != '[' || *(s+1) != ']')) {
4954                 printf("?Bad array name - \"%s\"\n",s2);
4955                 return(-9);
4956             }
4957             break;
4958 #endif /* NOSPL */
4959           case DIR_AFT:
4960           case DIR_BEF:
4961           case DIR_NAF:
4962           case DIR_NBF:
4963             if (!getval) break;
4964             if ((x = cmdate("File-time","",&s,0,xxstring)) < 0) {
4965                 if (x == -3) {
4966                     printf("?Date-time required\n");
4967                     rc = -9;
4968                 } else
4969                   rc = x;
4970                 goto xdomydir;
4971             }
4972             fs++;
4973             switch (k) {
4974               case DIR_AFT: makestr(&dir_aft,s); break;
4975               case DIR_BEF: makestr(&dir_bef,s); break;
4976               case DIR_NAF: makestr(&dir_naf,s); break;
4977               case DIR_NBF: makestr(&dir_nbf,s); break;
4978             }
4979             break;
4980           case DIR_EXC:
4981             if (!getval) break;
4982             if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
4983                 if (x == -3) {
4984                     printf("?Pattern required\n");
4985                     rc = -9;
4986                 } else
4987                   rc = x;
4988                 goto xdomydir;
4989             }
4990             fs++;
4991             makestr(&dir_exc,s);
4992             break;
4993
4994           case DIR_SUM:
4995             summary = 1; break;
4996
4997           case DIR_BIN: {
4998               extern struct keytab txtbin[];
4999               extern int xfiletype;
5000               if (!getval) break;
5001               if ((x = cmkey(txtbin,3,"","all",xxstring)) < 0) {
5002                   rc = x;
5003                   goto xdomydir;
5004               }
5005               if (x == 2) {
5006                   xfiletype = -1;
5007               } else {
5008                   xfiletype = x;
5009                   fs = 1;
5010               }
5011               break;
5012           }
5013           case DIR_OUT:
5014             if ((x = cmofi("File for directory listing","",&s,xxstring)) < 0)
5015               return(x);
5016             ckstrncpy(outfile,s,CKMAXPATH+1);
5017             break;
5018
5019           default:
5020             printf("?Sorry, not implemented yet - \"%s\"\n", atmbuf);
5021             goto xdomydir;
5022         }
5023     }
5024     ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Safe copy of filespec */
5025
5026 /* ^^^ START MULTIPLE */
5027     
5028     while (1) {
5029         x = cmfld("Another filespec or Enter","",&s,xxstring);
5030         if (x == -3)
5031           break;
5032         if (x < 0)
5033           return(x);
5034         ckstrncat(line,",",LINBUFSIZ);
5035         ckstrncat(line,s,LINBUFSIZ);
5036         multiple++;
5037     }
5038     ckmakmsg(tmpbuf,TMPBUFSIZ,"{",line,"}",NULL);
5039     ckstrncpy(line,tmpbuf,LINBUFSIZ);
5040     cmresult.nresult = 1;
5041     cmresult.fcode = _CMIFI;
5042
5043 /* ^^^ END MULTIPLE */
5044
5045     s = line;
5046
5047     if ((x = cmcfm()) < 0)              /* Get confirmation */
5048       return(x);
5049     if (cmresult.fcode != _CMIFI) {     /* Nothing matched */
5050         char * m;
5051         if (*s == '/')
5052 #ifdef UNIXOROSK
5053           m = "does not match switch or name of accessible file";
5054 #else
5055 #ifdef OS2
5056           m = "does not match switch or name of accessible file";
5057 #else
5058           m = "no switches match";
5059 #endif /* OS2 */
5060 #endif /* UNIXOROSX */
5061         else
5062           m = "not found or not accessible";
5063         printf("\"%s\" - %s\n",s,m);
5064         rc = -9;
5065         goto xdomydir;
5066     }
5067     wild = cmresult.nresult;            /* Wildcard was given? */
5068     debug(F111,"domydir cmifi2",s,wild);
5069
5070     if (outfile[0]) {
5071         ofp = fopen(outfile,"w");       /* Open output file */
5072         if (!ofp) {
5073             printf("?Can't open output file %s: %s\n",outfile,ck_errstr());
5074             ofp = stdout;
5075             return(-9);
5076         }
5077         page = 0;
5078     }
5079
5080 #ifdef OS2
5081     if (!wild) {
5082         if (zchki(s) == -2) {           /* Found a directory */
5083             p = s + (int)strlen(s) - 1; /* Yes */
5084             if (*p == '\\' || *p == '/')
5085               strcat(s, "*");
5086             else if (*p == ':')
5087               strcat(s, "./*");
5088             else
5089               strcat(s, "/*");
5090             wild = 1;                   /* Now it's wild */
5091         }
5092     }
5093 #else
5094     if (!wild) if (isdir(s)) {          /* Is it a directory? */
5095         p = s + (int)strlen(s) - 1;     /* Yes */
5096 #ifdef VMS
5097         {
5098             /* Convert from FOO.DIR;1 to [x.FOO] if necessary */
5099             char buf[CKMAXPATH+1];
5100             debug(F000,"domydir directory 0",s,*p);
5101             if (cvtdir(s,buf,CKMAXPATH) > 0)
5102               ckstrncpy(line,buf,LINBUFSIZ);
5103         }
5104 #endif /* VMS */
5105         debug(F000,"domydir directory 1",s,*p);
5106 #ifdef VMS
5107         if (*p == ']' || *p == '>' || *p == ':')
5108           strcat(s, "*.*");
5109 #else
5110 #ifdef datageneral
5111         if (*p == ':')
5112           strcat(s, "+");
5113         else
5114           strcat(s, ":+");
5115 #else
5116 #ifdef STRATUS
5117         if (*p == '>')
5118           strcat(s, "*");
5119         else
5120           strcat(s, ">*");
5121 #endif /* STRATUS */
5122 #endif /* datageneral */
5123 #endif /* VMS */
5124         wild = 1;                       /* Now it's wild */
5125         debug(F000,"domydir directory 2",s,*p);
5126     }
5127 #endif /* OS2 */
5128
5129 #ifdef ZXREWIND
5130 /* cmifi() already called nzxpand so we can just re-use the same list. */
5131     if (!multiple) {
5132         x = zxrewind();                 /* Rewind the list */
5133         debug(F111,"domydir zxrewind",s,x);
5134     } else {
5135 #endif /* ZXREWIND */
5136         nzxopts = (show == ZX_DIRONLY) ? ZX_DIRONLY :
5137           (show == ZX_FILONLY ? ZX_FILONLY : 0);
5138         if (matchdot)  nzxopts |= ZX_MATCHDOT;
5139         if (recursive) nzxopts |= ZX_RECURSE;
5140         x = nzxpand(s,nzxopts);             /* Expand file list */
5141         debug(F111,"domydir nzxpand",s,x);
5142 #ifdef ZXREWIND
5143     }
5144 #endif /* ZXREWIND */
5145
5146 #ifndef NOSPL
5147     if (array) {
5148         int n, xx;
5149         n = (x < 0) ? 0 : x;
5150         if ((xx = dclarray(array,n)) < 0) {
5151             printf("?Array declaration failure\n");
5152             rc = -9;
5153             goto xdomydir;
5154         }
5155         array = xx;
5156         ap = a_ptr[array];
5157         if (n < 1) {
5158             rc = 0;
5159             goto xdomydir;
5160         }
5161     } else
5162 #endif /* NOSPL */
5163       if (x < 1) {
5164 #ifdef CKROOT
5165           extern int ckrooterr;
5166           if (ckrooterr)
5167             printf("?Off limits: %s\n",s);
5168           else
5169 #endif /* CKROOT */
5170             if (x == 0 && isdir(s))
5171               printf("?Empty directory - \"%s\"\n", s);
5172             else
5173               printf("?%s %s match - \"%s\"\n",
5174                      (x == 0) ? "No" : "Too many",
5175                      (show == 2) ? "directories" : "files",
5176                      s
5177                      );
5178           rc = -9;
5179           goto xdomydir;
5180     }
5181     nx = x;                             /* Remember how many files */
5182
5183     if (msg) {
5184         makestr(&dirmsg,tmpbuf);
5185         dirmsglen = strlen(tmpbuf);
5186     }
5187
5188 #ifdef VMS
5189     cdp = zgtdir();                     /* Get current directory */
5190     debug(F110,"domydir VMS zgtdir",cdp,0);
5191 #endif /* VMS */
5192
5193     if (xsort && verbose) {             /* If sorting, allocate space */
5194         if (!(dirlist = (char **) malloc((x + 1) * sizeof(char **)))) {
5195             if (!quiet) {
5196                 printf("* Warning: Failure to allocate memory for sorting.\n");
5197                 printf("* Will proceed without sorting...\n");
5198             }
5199             xsort = 0;
5200         }
5201         debug(F101,"domydir sort malloc","",xsort);
5202     }
5203
5204     /* Display the listing */
5205
5206 #ifndef NOSPL
5207     if (array)                          /* Storing instead of printing */
5208       heading = 0;
5209 #endif /* NOSPL */
5210
5211     if (heading) {                      /* If /HEADING print heading */
5212         zfnqfp(s,TMPBUFSIZ,tmpbuf);
5213         fprintf(ofp,"\nDirectory of %s\n\n",tmpbuf);
5214         n += 3;
5215     }
5216     if (page > -1)                      /* Paging */
5217       xaskmore = page;
5218
5219     if (!verbose) {                     /* /BRIEF */
5220         if (outfile[0]) {               /* To file  */
5221             int k = 0;
5222             znext(name);
5223             while (name[0]) {           /* One line per file */
5224                 k++;
5225                 if (fs) if (fileselect(name,
5226                                        dir_aft,dir_bef,dir_naf,dir_nbf,
5227                                        minsize,maxsize,!backup,16,xlist) < 1) {
5228                     znext(name);
5229                     continue;
5230                 }
5231                 fprintf(ofp,"%s\n",name);
5232                 znext(name);
5233             }
5234             if (heading)
5235               fprintf(ofp,"Files: %d\n\n",k);
5236             rc = 1;
5237             goto xdomydir;
5238         } else {
5239             rc = filhelp(x,"","",n,0);
5240             if (rc < 0)
5241               goto xdomydir;
5242             if (heading && rc > 0)
5243               fprintf(ofp,"Files: %d\n\n",x); /* (Might scroll a line or 2) */
5244             rc = 1;
5245             goto xdomydir;
5246         }
5247     }
5248     ndirs = nfiles = nbytes = 0L;       /* Initialize counters */
5249
5250     if (dir_exc)                        /* Have exception list? */
5251       makelist(dir_exc,xlist,16);       /* Yes, convert to array */
5252
5253     diractive = 1;
5254     znext(name);                        /* Get next file */
5255     while (name[0]) {                   /* Loop for each file */
5256         if (fs) if (fileselect(name,
5257                        dir_aft,dir_bef,dir_naf,dir_nbf,
5258                        minsize,maxsize,!backup,16,xlist) < 1) {
5259             znext(name);
5260             continue;
5261         }
5262         len = zgetfs(name);             /* Get file length */
5263         debug(F111,"domydir zgetfs",name,len);
5264 #ifdef VMSORUNIX
5265         itsadir = zgfs_dir;             /* See if it's a directory */
5266 #else
5267         itsadir = (len == -2 || isdir(name));
5268 #endif /* VMSOUNIX */
5269         debug(F111,"domydir itsadir",name,itsadir);
5270         if ((itsadir && (show == 1)) || (!itsadir && (show == 2))) {
5271             znext(name);
5272             continue;
5273         }
5274         /* Get here when we know we have selected this file */
5275
5276         nmatches ++;
5277         if (itsadir) {                  /* Accumulate totals for summary */
5278             ndirs++;
5279         } else {
5280             nfiles++;
5281             nbytes += len;
5282         }
5283         if (summary) {                  /* Summary only, no detail */
5284             znext(name);
5285             continue;
5286         }
5287 #ifndef NOSPL
5288         if (array) {
5289             debug(F111,"domydir array",name,nfiles);
5290             if (ap)
5291               makestr(&(ap[nmatches]),name);
5292             znext(name);
5293             continue;
5294         }
5295 #endif /* NOSPL */
5296
5297 /*
5298   NOTE: The sprintf's in this routine should be safe.  They involve
5299   permission strings, date/time strings, and filenames, all of which have
5300   known maximum lengths; none of these items is input from users.  The
5301   destination buffers are large enough to hold maximum sizes for any and
5302   all items.
5303 */
5304         dstr = zfcdat(name);            /* Get modification date/time */
5305         debug(F111,"domydir zcfdat",dstr,0);
5306         if (!dstr) dstr = "";
5307         {
5308 /*
5309   Note that zfcdat() always returns "" or yyyymmdd hh:mm:ss, so any warnings
5310   about possible out-of-bounds dstr[] array refs do not apply.  This block of
5311   code is to stifle the warnings and also allows for any out-of-spec
5312   zfcdat() implementations.
5313 */
5314             int x;
5315             char * p = "00000000 00:00:00";
5316             x = ckstrncpy(xbuf,dstr,32);
5317             if (x < 17) ckstrncpy(&xbuf[x],p+x,32-x);
5318             dstr = xbuf;
5319         }
5320         if (engdate) {                  /* English date requested? */
5321             short month, day, year, hour, minute, seconds;
5322             month = (dstr[4]-48)*10 + (dstr[5]-48);
5323             mstr  = (month > 0 && month <= 12) ? months[month-1] : "xxx";
5324             day   = (dstr[6]-48)*10 + (dstr[7]-48);
5325             year  = (((dstr[0]-48)*10 +
5326                       (dstr[1]-48))*10 +
5327                       (dstr[2]-48))*10 +
5328                       (dstr[3]-48);
5329             hour  = (dstr[9]-48)*10 + (dstr[10]-48);
5330             minute = (dstr[12]-48)*10 + (dstr[13]-48);
5331             seconds = (dstr[15]-48)*10 + (dstr[16]-48);
5332             sprintf(dbuf,               /* SAFE */
5333                     "%2d-%s-%4d %02d:%02d:%02d",
5334                     day,mstr,year,hour,minute,seconds
5335                     );
5336             dstr = dbuf;
5337         } else {                        /* ISO date */
5338             dbuf[0] = dstr[0];          /* yyyy */
5339             dbuf[1] = dstr[1];
5340             dbuf[2] = dstr[2];
5341             dbuf[3] = dstr[3];
5342             dbuf[4] = '-';
5343             dbuf[5] = dstr[4];          /* mm (numeric) */
5344             dbuf[6] = dstr[5];
5345             dbuf[7] = '-';
5346             dbuf[8] = dstr[6];          /* dd */
5347             dbuf[9] = dstr[7];
5348             strcpy(dbuf+10,dstr+8);     /* hh:mm:ss */
5349             dstr = dbuf;
5350         }
5351         dlen = strlen(dbuf);            /* Length of date */
5352         name[CKMAXPATH] = NUL;
5353 #ifdef CK_PERMS
5354 #ifdef VMSORUNIX
5355         p = ziperm(name);               /* Get permissions */
5356         debug(F110,"ziperm perms",p,0);
5357 #else
5358         p = zgperm(name);
5359         debug(F110,"zgperm perms",p,0);
5360 #endif /* VMSORUNIX */
5361 #else
5362         p = NULL;
5363         debug(F110,"NULL perms",p,0);
5364 #endif /* CK_PERMS */
5365
5366 #ifdef VMS
5367         /* Get relative name to save space -- VMS fullnames are long... */
5368         ckstrncpy(name,zrelname(name,cdp),CKMAXPATH);
5369 #endif /* VMS */
5370
5371         if (itsadir && len < 0) {       /* Directory */
5372 #ifdef VMS
5373             sprintf(linebuf,"%-22s%-10s  %s  %s",p,"<DIR>",dstr,name);
5374 #else
5375             if (p)
5376               sprintf(linebuf,"%10s%-10s  %s  %s",p,"<DIR>",dstr,name);
5377             else
5378               sprintf(linebuf,"%-10s  %s  %s", "<DIR>", dstr, name);
5379 #endif /* VMS */
5380         } else {                        /* Regular file */
5381 #ifdef VMS
5382             sprintf(linebuf,"%-22s%10ld  %s  %s", p, len, dstr, name);
5383 #else
5384             if (p)
5385               sprintf(linebuf,"%10s%10ld  %s  %s", p, len, dstr, name);
5386             else
5387               sprintf(linebuf,"%10ld  %s  %s", len, dstr, name);
5388 #endif /* VMS */
5389         }
5390 #ifdef UNIX
5391 #ifdef CKSYMLINK
5392         if (zgfs_link) {
5393             int n, m;
5394             extern char linkname[];
5395             n = strlen(linebuf);
5396             m = strlen(linkname) + n;
5397             if (m < CKMAXPATH + 58)
5398               strcpy(linebuf+n, " -> "); /* safe (checked) */
5399             if (m + 4 < CKMAXPATH - 58)
5400               strcpy(linebuf+n+4, linkname); /* safe (checked) */
5401         } else
5402 #endif /* CKSYMLINK */
5403 #endif /* UNIX */
5404         if (xfermod) {                  /* Show transfer mode */
5405             int i, x, y;
5406             char * s = "";
5407             y = -1;
5408             x = scanfile(name,&y,nscanfile);
5409             switch (x) {
5410               case FT_TEXT: s = " (T)"; break;
5411               case FT_7BIT: s = " (T)(7BIT)"; break;
5412               case FT_8BIT: s = " (T)(8BIT)"; break;
5413 #ifdef UNICODE
5414               case FT_UTF8: s = " (T)(UTF8)"; break;
5415               case FT_UCS2:
5416                 s = y ? " (T)(UCS2LE)" : " (T)(UCS2BE)";
5417                 break;
5418 #endif /* UNICODE */
5419               case FT_BIN:  s = " (B)"; break;
5420             }
5421             if (!*s) {
5422                 s = binary ? " (B)" : " (T)";
5423             }
5424             if (*s) {
5425                 int n;
5426                 n = strlen(linebuf);
5427                 if (n + 4 < CKMAXPATH - 58)
5428                   strcpy(linebuf+n, s); /* safe (checked) */
5429             }
5430         }
5431         if (msg && dirmsg) {
5432             int n;
5433             n = strlen(linebuf);
5434             if (n + dirmsglen + 2 < CKMAXPATH)
5435               sprintf((char *)(linebuf+n)," %s", dirmsg); /* SAFE */
5436         }
5437         if (xsort) {                    /* Sorting - save line */
5438             i = strlen(linebuf);
5439             if ((ndirlist >= nx) ||
5440                 !(dirlist[ndirlist] = (char *)malloc(i+1))) {
5441                 printf("?Memory allocation error - try /NOSORT\n");
5442                 rc = -9;
5443                 goto xdomydir;
5444             }
5445             strcpy(dirlist[ndirlist],linebuf); /* safe */
5446             ndirlist++;
5447         }
5448         znext(name);                    /* Peek ahead to next file */
5449
5450         if (!xsort) {
5451             fprintf(ofp,"%s\n",linebuf);
5452             if (page && (name[0] || heading)) { /* If /PAGE */
5453                 if (cmd_cols > 0) {
5454                     int x = strlen(linebuf);
5455                     int y;
5456                     y = (x % cmd_cols) ? 1 : 0;
5457                     n += x / cmd_cols + y;
5458                 } else {
5459                     n++;
5460                 }
5461 #ifdef CK_TTGWSIZ
5462                 if (n > (cmd_rows - 3)) { /* Do more-prompting */
5463                     if (!askmore()) {
5464                         rc = 0;
5465                         goto xdomydir;
5466                     } else
5467                       n = 0;
5468                 }
5469 #endif /* CK_TTGWSIZ */
5470             }
5471         }
5472     }
5473 #ifndef NOSPL
5474     if (array) {
5475         if (ap)
5476           makestr(&(ap[0]),ckitoa(nmatches));
5477         rc = 1;
5478         goto xdomydir;
5479     }
5480 #endif /* NOSPL */
5481     if (xsort) {
5482         skey = 0;
5483 #ifdef VMS
5484         switch (sortby) {
5485           case DIRS_NM: skey = dlen + 35; break;
5486           case DIRS_DT: skey = 33; break;
5487           case DIRS_SZ: skey = 21;
5488         }
5489 #else
5490         if (p) {
5491             switch (sortby) {
5492               case DIRS_NM: skey = dlen + 24; break;
5493               case DIRS_DT: skey = 22; break;
5494               case DIRS_SZ: skey = 10;
5495             }
5496         } else {
5497             switch (sortby) {
5498               case DIRS_NM: skey = dlen + 14; break;
5499               case DIRS_DT: skey = 12; break;
5500               case DIRS_SZ: skey = 0;
5501             }
5502         }
5503 #endif /* VMS */
5504         sh_sort(dirlist,NULL,ndirlist,skey,reverse,filecase);
5505         for (i = 0; i < ndirlist; i++) {
5506             fprintf(ofp,"%s\n",dirlist[i]);
5507             if (page && (i < ndirlist -1 || heading)) { /* If /PAGE */
5508                 if (cmd_cols > 0) {
5509                     int x = strlen(dirlist[i]);
5510                     int y;
5511                     y = (x % cmd_cols) ? 1 : 0;
5512                     n += ((int)strlen(dirlist[i]) / cmd_cols) + y;
5513                 } else {
5514                     n++;
5515                 }
5516 #ifdef CK_TTGWSIZ
5517                 if (n > (cmd_rows - 3)) { /* Do more-prompting */
5518                     if (!askmore()) {
5519                         rc = 0;
5520                         goto xdomydir;
5521                     } else
5522                       n = 0;
5523                 }
5524 #endif /* CK_TTGWSIZ */
5525             }
5526         }
5527     }
5528
5529     if (heading || summary) {
5530 #ifdef CKFLOAT
5531         CKFLOAT gm;
5532 #endif /* CKFLOAT */
5533         fprintf(ofp,"\n%ld director%s, %ld file%s, %ld byte%s",
5534                ndirs,
5535                (ndirs == 1) ? "y" : "ies",
5536                nfiles,
5537                (nfiles == 1) ? "" : "s",
5538                nbytes,
5539                (nbytes == 1) ? "" : "s"
5540                );
5541 #ifdef CKFLOAT
5542         gm = ((CKFLOAT) nbytes ) / 1000000.0;
5543         if (gm > 1000.0)
5544           fprintf(ofp," (%0.2fGB)",(gm / 1000.0));
5545         else if (gm >= 0.01)
5546           fprintf(ofp," (%0.2fMB)",gm);
5547 #endif /* CKFLOAD */
5548         fprintf(ofp,"\n\n");
5549     }
5550   xdomydir:
5551     if (g_matchdot > -1) {
5552         matchdot = g_matchdot;          /* Restore these... */
5553         g_matchdot = -1;
5554     }
5555     freedirlist();
5556     if (ofp != stdout) {                /* Close any output file */
5557         if (ofp) fclose(ofp);
5558         ofp = stdout;
5559     }
5560     if (rc > 0)
5561       success = 1;
5562     return(rc);
5563 }
5564
5565 int
5566 dodir(cx) int cx; {                     /* Do the DIRECTORY command */
5567     char *dc , *msg;
5568
5569 #ifdef OS2
5570     return(domydir());
5571 #else /* OS2 */
5572     if (nopush
5573 #ifdef DOMYDIR                          /* Builds that domydir() by default */
5574         || (cx == XXDIR || cx == XXLDIR)
5575 #endif /* DOMYDIR */
5576         )
5577       return(domydir());                /* Built-in directory command */
5578
5579     /* Use the system's directory command. */
5580
5581     msg = (cx == XXLS) ?
5582       "Arguments for ls" :
5583         "Directory and/or file specification";
5584     if ((x = cmtxt(msg,"",&s,xxstring)) < 0)
5585       return(x);
5586
5587     ckstrncpy(tmpbuf,s,TMPBUFSIZ);      /* Copy the filespec */
5588     s = tmpbuf;
5589
5590     if ((y = cmcfm()) < 0) return(y);
5591
5592     lp = line;
5593     if (!(dc = getenv("CK_DIR")))
5594       dc = DIRCMD;
5595     ckmakmsg(lp,LINBUFSIZ,dc," ",s,NULL);
5596     debug(F110,"DIR",line,0);
5597 #ifdef VMS
5598     conres();
5599 #endif /* VMS */
5600     x = zshcmd(line);
5601 #ifdef VMS
5602     concb((char)escape);
5603 #endif /* VMS */
5604     return(success = (x < 1) ? 0 : 1);
5605 #endif /* OS2 */
5606 }
5607
5608 #ifndef NOSERVER
5609 #ifndef NOFRILLS
5610 /* Do the ENABLE and DISABLE commands */
5611
5612 int
5613 doenable(y,x) int y, x; {
5614 #ifdef CK_LOGIN
5615     if (isguest)                        /* IKSD: Don't let guests */
5616       return(0);                        /* enable anything that's disabled */
5617 #endif /* CK_LOGIN */
5618     switch (x) {
5619       case EN_ALL:
5620         en_cwd = en_cpy = en_del = en_dir = en_fin = en_get = y;
5621         en_ren = en_sen = en_set = en_spa = en_typ = en_ret = y;
5622         if (!inserver)
5623           en_who = en_mai = en_pri = y;
5624         en_mkd = en_rmd = y;
5625         en_xit = y;
5626 #ifndef datageneral
5627         en_bye = y;
5628 #endif /* datageneral */
5629 #ifndef NOPUSH
5630         if (!nopush && !inserver)
5631           en_hos = y;
5632 #endif /* NOPUSH */
5633 #ifndef NOSPL
5634         en_asg = en_que = y;
5635 #endif /* NOSPL */
5636         break;
5637
5638       case EN_BYE:
5639 #ifndef datageneral
5640 /*
5641   In Data General AOS/VS Kermit can't log out its superior process.
5642 */
5643         en_bye = y;
5644 #endif /* datageneral */
5645         break;
5646       case EN_CPY:
5647         en_cpy = y;
5648         break;
5649       case EN_CWD:
5650         en_cwd = y;
5651 #ifdef IKSD
5652         if (inserver && y == 0) {
5653             fnrpath = PATH_OFF;
5654             fnspath = PATH_OFF;
5655         }
5656 #endif /* IKSD */
5657         break;
5658       case EN_DEL:                      /* Deleting of files */
5659         en_del = y;
5660         break;
5661       case EN_DIR:
5662         en_dir = y;
5663         break;
5664       case EN_FIN:
5665         en_fin = y;
5666         break;
5667       case EN_GET:
5668         en_get = y;
5669         break;
5670 #ifndef NOPUSH
5671       case EN_HOS:
5672         if (!nopush)
5673          en_hos = y;
5674         break;
5675 #endif /* NOPUSH */
5676       case EN_REN:
5677         en_ren = y;
5678         break;
5679       case EN_SEN:
5680         en_sen = y;
5681         break;
5682       case EN_SET:
5683         en_set = y;
5684         break;
5685       case EN_SPA:
5686         en_spa = y;
5687         break;
5688       case EN_TYP:
5689         en_typ = y;
5690         break;
5691       case EN_WHO:
5692         en_who = y;
5693         break;
5694 #ifndef NOSPL
5695       case EN_ASG:
5696         en_asg = y;
5697         break;
5698       case EN_QUE:
5699         en_que = y;
5700         break;
5701 #endif /* NOSPL */
5702       case EN_RET:
5703         en_del = y;
5704         break;
5705       case EN_MAI:
5706 #ifdef CK_LOGIN
5707         if (isguest && y) {
5708             printf("?Sorry, not valid for guests\n");
5709             return(-9);
5710         }
5711 #endif /* CK_LOGIN */
5712         en_mai = y;
5713         break;
5714       case EN_PRI:
5715 #ifdef CK_LOGIN
5716         if (isguest && y) {
5717             printf("?Sorry, not valid for guests\n");
5718             return(-9);
5719         }
5720 #endif /* CK_LOGIN */
5721         en_pri = y;
5722         break;
5723       case EN_MKD:
5724         en_mkd = y;
5725         break;
5726       case EN_RMD:
5727         en_rmd = y;
5728         break;
5729       case EN_XIT:
5730         en_xit = y;
5731         break;
5732       case EN_ENA:
5733         if (((y & 1) && !(en_ena & 1)) ||
5734             ((y & 2) && !(en_ena & 2))) {
5735             printf("?Sorry, DISABLE ENABLE can not be undone\n");
5736             return(-9);
5737         } else {
5738             en_ena = y;
5739             break;
5740         }
5741       default:
5742         return(-2);
5743     }
5744     return(1);
5745 }
5746 #endif /* NOFRILLS */
5747 #endif /* NOSERVER */
5748
5749 #ifndef NOFRILLS
5750
5751 static int del_lis = 0;
5752 static int del_dot = 0;
5753 static int del_hdg = 0;
5754 static int del_pag = -1;
5755 static int del_ask = 0;
5756
5757 #ifndef NOSHOW
5758 VOID
5759 showdelopts() {
5760     int x = 0;
5761     extern int optlines;
5762     prtopt(&optlines,"");
5763     prtopt(&optlines,"DELETE");
5764     if (del_ask > -1) {
5765         prtopt(&optlines, del_ask ? "/ASK" : "/NOASK");
5766         x++;
5767     }
5768 #ifdef UNIXOROSK
5769     if (del_dot > -1) {
5770         prtopt(&optlines, del_dot ? "/DOTFILES" : "/NODOTFILES");
5771         x++;
5772     }
5773 #endif /* UNIXOROSK */
5774     if (del_lis > -1) {
5775         prtopt(&optlines, del_lis ? "/LIST" : "/NOLIST");
5776         x++;
5777     }
5778     if (del_hdg > -1) {
5779         prtopt(&optlines, del_hdg ? "/HEADING" : "/NOHEADING");
5780         x++;
5781     }
5782 #ifndef CK_TTGWSIZ
5783     if (del_pag > -1) {
5784         prtopt(&optlines, del_pag ? "/PAGE" : "/NOPAGE");
5785         x++;
5786     }
5787 #endif /* CK_TTGWSIZ */
5788     if (!x) prtopt(&optlines,"(no options set)");
5789     prtopt(&optlines,"");
5790 }
5791 #endif /* NOSHOW */
5792
5793
5794 int
5795 setdelopts() {
5796     int x_lis = -1, x_pag = -1, x_dot = -1, x_hdg = -1, x_ask = -1;
5797     int getval = 0;
5798     char c;
5799     while (1) {
5800         if ((y = cmswi(deltab,ndeltab,"Switch","",xxstring)) < 0) {
5801             if (y == -3)
5802               break;
5803             else
5804               return(y);
5805         }
5806         c = cmgbrk();
5807         if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
5808             printf("?This switch does not take an argument\n");
5809             return(-9);
5810         }
5811         if (!getval && (cmgkwflgs() & CM_ARG)) {
5812             printf("?This switch requires an argument\n");
5813             return(-9);
5814         }
5815         switch (y) {
5816           case DEL_DOT:
5817             x_dot = 1;
5818             break;
5819           case DEL_NOD:
5820             x_dot = 0;
5821             break;
5822           case DEL_HDG:
5823             x_hdg = 1;
5824             break;
5825           case DEL_LIS:
5826             x_lis = 1;
5827             break;
5828           case DEL_NOL:
5829             x_lis = 0;
5830             break;
5831 #ifndef CK_TTGWSIZ
5832           case DEL_PAG:
5833             x_pag = 1;
5834             break;
5835           case DEL_NOP:
5836             x_pag = 0;
5837             break;
5838 #endif /* CK_TTGWSIZ */
5839           case DEL_QUI:
5840             x_lis = 0;
5841             break;
5842           case DEL_VRB:
5843             x_lis = 1;
5844             break;
5845           case DEL_ASK:
5846             x_ask = 1;
5847             break;
5848           case DEL_NAS:
5849             x_ask = 0;
5850             break;
5851           default:
5852             printf("?Sorry, this option can not be set\n");
5853             return(-9);
5854         }
5855     }
5856     if ((x = cmcfm()) < 0)              /* Get confirmation */
5857       return(x);
5858     if (x_pag > -1) del_pag = x_pag;
5859     if (x_dot > -1) del_dot = x_dot;
5860     if (x_hdg > -1) del_hdg = x_hdg;
5861     if (x_lis > -1) del_lis = x_lis;
5862     if (x_ask > -1) del_ask = x_ask;
5863     return(success = 1);
5864 }
5865
5866 #ifdef OS2
5867 static char ** xmtchs = NULL;
5868 static int xmtchn = 0;
5869 #endif /* OS2 */
5870
5871 int
5872 dodel() {                               /* DELETE */
5873     int i, j, k, x;
5874     int fs = 0;                         /* Need to call fileselect() */
5875     int len = 0;
5876     int bad = 0;
5877     int getval = 0, asking = 0;
5878     int simulate = 0, rc = 0;
5879     long minsize = -1L, maxsize = -1L;
5880     int havename = 0, confirmed = 0;
5881     int qflag = 0;
5882     int summary = 0;
5883     int deldirs = 0;
5884     int deltree = 0;
5885     int itsadir = 0;
5886     int argisdir = 0;
5887     int xmode = -1, scan = 0, skip = 0;
5888 #ifdef COMMENT
5889     int pass = 0;
5890 #endif /* COMMENT */
5891     char c;
5892     char * deldef = "";
5893     char safebuf[CKMAXPATH+1];
5894     struct FDB sw, fi, fl;
5895     char
5896       * del_aft = NULL,
5897       * del_bef = NULL,
5898       * del_naf = NULL,
5899       * del_nbf = NULL,
5900       * del_exc = NULL;
5901     int
5902       x_lis = 0,
5903       /* x_dot = -1, */
5904       x_hdg = 0;
5905
5906     char * dxlist[8];
5907
5908     for (i = 0; i < 8; i++) dxlist[i] = NULL;
5909
5910     g_matchdot = matchdot;
5911
5912     if (del_lis > -1) x_lis    = del_lis;
5913     if (del_dot > -1) matchdot = del_dot;
5914     if (del_hdg > -1) x_hdg    = del_hdg;
5915     if (del_pag > -1) xaskmore = del_pag;
5916     if (del_ask > -1) asking   = del_ask;
5917
5918     diractive = 1;
5919     nolinks = 2;                        /* By default don't follow links */
5920
5921     cmfdbi(&sw,                         /* First FDB - command switches */
5922            _CMKEY,                      /* fcode */
5923            "File specification;\n or switch",
5924            "",                          /* default */
5925            "",                          /* addtl string data */
5926            ndeltab,                     /* addtl numeric data 1: tbl size */
5927            4,                           /* addtl numeric data 2: 4 = cmswi */
5928            xxstring,                    /* Processing function */
5929            deltab,                      /* Keyword table */
5930            &fi                          /* Pointer to next FDB */
5931            );
5932     cmfdbi(&fl,                         /* Anything that doesn't match */
5933            _CMFLD,                      /* fcode */
5934            "",                          /* hlpmsg */
5935            "",                          /* default */
5936            "",                          /* addtl string data */
5937            0,                           /* addtl numeric data 1 */
5938            0,                           /* addtl numeric data 2 */
5939            xxstring,
5940            NULL,
5941            NULL
5942            );
5943   again:
5944     cmfdbi(&fi,                         /* 2nd FDB - file to delete */
5945            _CMIFI,                      /* fcode */
5946            "File(s) to delete",         /* hlpmsg */
5947            deldef,                      /* default */
5948            "",                          /* addtl string data */
5949            nolinks | deldirs,           /* 0 = files, 1 = files or dirs */
5950            0,                           /* 1 = dirs only */
5951            xxstring,
5952            NULL,
5953            &fl
5954            );
5955     while (!havename && !confirmed) {
5956         x = cmfdb(&sw);                 /* Parse something */
5957         if (x < 0) {                    /* Error */
5958             if (x == -3)
5959               break;
5960             if (x == -2 || x == -9)
5961               printf("?Does not match switch or filename: \"%s\"\n",atmbuf);
5962             return(x);
5963         }
5964         if (cmresult.fcode != _CMKEY)   /* Break out if not a switch */
5965           break;
5966         c = cmgbrk();                   /* Get break character */
5967         if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
5968             printf("?This switch does not take an argument\n");
5969             rc = -9;
5970             goto xdelete;
5971         }
5972         if (!getval && (cmgkwflgs() & CM_ARG)) {
5973             printf("?This switch requires an argument\n");
5974             rc = -9;
5975             goto xdelete;
5976         }
5977         switch (k = cmresult.nresult) {
5978           case DEL_AFT:
5979           case DEL_BEF:
5980           case DEL_NAF:
5981           case DEL_NBF:
5982             if (!getval) break;
5983             if ((x = cmdate("File-time","",&s,0,xxstring)) < 0) {
5984                 if (x == -3) {
5985                     printf("?Date-time required\n");
5986                     x = -9;
5987                 } else
5988                   rc = x;
5989                 goto xdelete;
5990             }
5991             fs++;
5992             deltree = 0;
5993             switch (k) {
5994               case DEL_AFT: makestr(&del_aft,s); break;
5995               case DEL_BEF: makestr(&del_bef,s); break;
5996               case DEL_NAF: makestr(&del_naf,s); break;
5997               case DEL_NBF: makestr(&del_nbf,s); break;
5998             }
5999             break;
6000           case DEL_DOT:
6001             matchdot = 1;
6002             break;
6003           case DEL_NOD:
6004             matchdot = 0;
6005             break;
6006           case DEL_ALL:
6007             fs = 0;
6008 #ifdef VMS
6009             deldef = "*.*";             /* UNIX, Windows, OS/2 */
6010 #else
6011 #ifdef datageneral
6012             deldef = "+";               /* AOS/VS */
6013 #else
6014             deldef = "*";               /* UNIX, Windows, OS/2, VMS... */
6015 #endif /* datageneral */
6016 #endif /* VMS */
6017             deltree = 1;
6018             nolinks = 2;
6019             matchdot = 1;
6020             recursive = 1;              /* Fall through purposely... */
6021           case DEL_DIR:
6022             deldirs = 1;
6023             goto again;
6024           case DEL_EXC:
6025             if (!getval) break;
6026             if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
6027                 if (x == -3) {
6028                     printf("?Pattern required\n");
6029                     x = -9;
6030                 } else
6031                   rc = x;
6032                 goto xdelete;
6033             }
6034             fs++;
6035             deltree = 0;
6036             makestr(&del_exc,s);
6037             break;
6038           case DEL_HDG:
6039             x_hdg = 1;
6040             break;
6041 #ifdef RECURSIVE
6042           case DEL_REC:
6043             recursive = 1;
6044             break;
6045 #endif /* RECURSIVE */
6046           case DEL_LIS:
6047             x_lis = 1;
6048             break;
6049           case DEL_SUM:
6050             summary = 1;
6051             x_lis = 0;
6052             x_hdg = 1;
6053             break;
6054           case DEL_NOL:
6055             x_lis = 0;
6056             break;
6057 #ifndef CK_TTGWSIZ
6058           case DEL_PAG:
6059             xaskmore = 1;
6060             break;
6061           case DEL_NOP:
6062             xaskmore = 0;
6063             break;
6064 #endif /* CK_TTGWSIZ */
6065           case DEL_QUI:
6066             qflag = 1;
6067             x_lis = 0;
6068             break;
6069           case DEL_VRB:
6070             x_lis = 1;
6071             break;
6072
6073           case DEL_SMA:
6074           case DEL_LAR:
6075             if (!getval) break;
6076             if ((x = cmnum("File size in bytes","0",10,&y,xxstring)) < 0)
6077               return(x);
6078             fs++;
6079             deltree = 0;
6080             switch (cmresult.nresult) {
6081               case DEL_SMA: minsize = y; break;
6082               case DEL_LAR: maxsize = y; break;
6083             }
6084             break;
6085
6086           case DEL_SIM:
6087             simulate = 1;
6088             x_lis = 1;
6089             break;
6090           case DEL_ASK:
6091             asking = 1;
6092             break;
6093           case DEL_NAS:
6094             asking = 0;
6095             break;
6096           case DEL_TYP: {
6097               extern struct keytab txtbin[];
6098               if (!getval) break;
6099               if ((x = cmkey(txtbin,3,"","",xxstring)) < 0)
6100                 return(x);
6101               if (x == 2) {             /* ALL */
6102                   xmode = -1;
6103               } else {                  /* TEXT or BINARY only */
6104                   xmode = x;
6105                   scan = 1;
6106               }
6107               break;
6108           }
6109           default:
6110             printf("?Not implemented yet - \"%s\"\n",atmbuf);
6111             return(-9);
6112         }
6113     }
6114     if (qflag && (cmresult.fcode == _CMFLD)) {
6115         if ((x = cmcfm()) < 0)
6116           return(x);
6117         else
6118           return(success = 0);
6119     }
6120     if (cmresult.fcode != _CMIFI) {
6121         if (*atmbuf) {
6122             int x;
6123             if (iswild(atmbuf) && nzxpand(atmbuf,nzxopts) == 0)
6124               printf("?No files match: %s\n",atmbuf);
6125             else if ((x = zchki(atmbuf)) == -1)
6126               printf("?File not found: %s\n",atmbuf);
6127             else if (x == -2)
6128               printf("?Not a regular file: %s\n",atmbuf);
6129             else
6130               /* printf("?Not a deletable file: %s\n",atmbuf); */
6131               goto tryanyway;
6132         } else {
6133             printf("?A file specification is required\n");
6134         }
6135         return(-9);
6136     }
6137   tryanyway:
6138     ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ); /* Safe copy of filespec */
6139     if (deldirs) {
6140         ckstrncpy(safebuf,cmresult.sresult,CKMAXPATH);
6141 #ifdef VMSORUNIX
6142         len = zgetfs(tmpbuf);           /* Is it a directory name? */
6143         argisdir = zgfs_dir;            /* Then because of how zxpand() */
6144         if (argisdir && zgfs_link)      /* works, we have to add it to */
6145           argisdir = 0;                 /* the list. */
6146         if (itsadir)
6147           len = -2;
6148 #else
6149         len = zchki(tmpbuf);
6150         if (len < 0)
6151           argisdir = isdir(tmpbuf);
6152 #endif /* VMSORUNIX */
6153     }
6154     debug(F110,"DELETE file",tmpbuf,0);
6155     if ((x = cmcfm()) < 0)
6156       return(x);
6157
6158 #ifdef IKSD
6159 #ifdef CK_LOGIN
6160     if (inserver && isguest) {
6161         printf("?Sorry, DELETE unavailable to guests\n");
6162         return(-9);
6163     }
6164 #endif /* CK_LOGIN */
6165 #endif /* IKSD */
6166
6167 #ifndef OS2ORUNIX
6168     if (simulate) {
6169         printf("?Sorry, /SIMULATE not implemented on this platform\n");
6170         return(-9);
6171     }
6172 #endif /* OS2ORUNIX */
6173
6174 #ifdef COMMENT
6175     /* (not needed) */
6176     if (!iswild(tmpbuf)) {
6177         char *m;
6178         errno = 0;
6179         x = zchki(tmpbuf);
6180         if (x < 0) {
6181             switch (x) {
6182               case -2: m = "Not a regular file"; break;
6183               case -1: m = "File not found or not accessible"; break;
6184               default: m = errno ? ck_errstr() : "Can't delete";
6185             }
6186             printf("?%s: \"%s\"\n",m,tmpbuf);
6187             return(-9);
6188         }
6189     }
6190 #endif /* COMMENT */
6191
6192     makelist(del_exc,dxlist,8);
6193
6194 /* tmpbuf[] has the name - now do any needed conversions on it */
6195
6196 #ifdef OS2
6197     {   /* Lower level functions change / to \, not good for CMD.EXE. */
6198         char *p = tmpbuf;
6199         while (*p) {                    /* Change them back to \ */
6200             if (*p == '/') *p = '\\';
6201             p++;
6202         }
6203     }
6204 #endif /* OS2 */
6205
6206 #ifdef VMS
6207     if (iswild(tmpbuf)) {
6208 #ifdef COMMENT
6209         /* Does not handle '.' as version separator */
6210         char *p = tmpbuf;
6211         x = 0;
6212         while (*p) {
6213             if (*p == ';') {
6214                 x = 1;
6215                 break;
6216             } else
6217               p++;
6218         }
6219         if (!x) ckstrncat(tmpbuf,";*",TMPBUFSIZ);
6220 #else
6221         j = 0; x = 0;                   /* for end_dot and number of dots */
6222         i = strlen(tmpbuf);
6223         if (tmpbuf[i] == ';') {
6224             ckstrncat(tmpbuf,"0",TMPBUFSIZ);
6225         } else {
6226             if (tmpbuf[i--] == '.')
6227               j++;
6228             for (; i >= 0; i--) {
6229                 if (tmpbuf[i] == ';' || tmpbuf[i] == ':' ||
6230                     tmpbuf[i] == ']' || tmpbuf[i] == '>')
6231                   break;
6232                 else if (tmpbuf[i] == '.')
6233                   x++;
6234             }
6235             if (tmpbuf[i] != ';') {     /* dot may have been used */
6236                 if (j) {                /* last char is dot */
6237                   if (x)                /* second is version separator */
6238                     ckstrncat(tmpbuf,"0",TMPBUFSIZ);
6239                   else                  /* 'foo.' */
6240                     ckstrncat(tmpbuf,";0",TMPBUFSIZ);
6241                 } else if (x == 1)      /* lacking a version separator */
6242                   ckstrncat(tmpbuf,";0",TMPBUFSIZ);
6243                 else if (x == 0)        /* x == 2 has a version */
6244                   ckstrncat(tmpbuf,".*;0",TMPBUFSIZ);
6245             }
6246         }
6247 #endif /* COMMENT */
6248     }
6249 #endif /* VMS */
6250
6251     debug(F110,"dodel tmpbuf",tmpbuf,0); /* Filename */
6252
6253 #ifndef OS2ORUNIX                       /* No built-in DELETE code... */
6254     /* Construct system command. */
6255     ckmakmsg(line,LINBUFSIZ,DELCMD," ",tmpbuf,NULL);
6256 #else
6257 #ifdef VMS
6258     if (asking) {                       /* Maybe overwrite in VMS */
6259         if (x_lis)                      /* if options are needed... */
6260           ckmakmsg(line,LINBUFSIZ,DELCMD," /confirm/log ",tmpbuf,NULL);
6261         else
6262           ckmakmsg(line,LINBUFSIZ,DELCMD," /confirm ",tmpbuf,NULL);
6263     } else if (x_lis)
6264       ckmakmsg(line,LINBUFSIZ,DELCMD," /log ",tmpbuf,NULL);
6265     conres();
6266 #endif /* VMS */
6267
6268     debug(F110,"dodel line",line,0);
6269 #endif /* OS2ORUNIX */
6270
6271 #ifdef MAC
6272     success = (zdelet(tmpbuf) == 0);
6273
6274 #else  /* !MAC ... */
6275
6276 #ifdef OS2ORUNIX
6277     {
6278         int filespace = 0;
6279         int count = 0;
6280         int lines = 0;
6281         int n = 0;
6282
6283         s = tmpbuf;
6284
6285 #ifdef CK_TTGWSIZ
6286 #ifdef OS2
6287         ttgcwsz();
6288 #else /* OS2 */
6289         /* Check whether window size changed */
6290         if (ttgwsiz() > 0) {
6291             if (tt_rows > 0 && tt_cols > 0) {
6292                 cmd_rows = tt_rows;
6293                 cmd_cols = tt_cols;
6294             }
6295         }
6296 #endif /* OS2 */
6297 #endif /* CK_TTGWSIZ */
6298
6299         if (x_hdg > 0 && !summary) {
6300             printf("Deleting %s...%s\n", s, simulate ? " (SIMULATION)" : "");
6301             n += 2;
6302         }
6303 #ifdef ZXREWIND
6304         z = zxrewind();                 /* Rewind file list */
6305 #else
6306         if (!deldirs)
6307           nzxopts = ZX_FILONLY;
6308         if (recursive) nzxopts |= ZX_RECURSE;
6309         if (matchdot)  nzxopts |= ZX_MATCHDOT;
6310         errno = 0;
6311         z = nzxpand(s,nzxopts);         /* Expand file list */
6312 #endif /* ZXREWIND */
6313         debug(F111,"dodel",s,z);
6314
6315         /* If deleting directories, sort in reverse order */
6316         /* so we delete the files first, then the directory. */
6317
6318 #ifdef OS2
6319         /* In K95, we have no mtchs array, nor any control over */
6320         /* the order in which znext() returns filenames, so we  */
6321         /* must copy the array and sort it. */
6322         {
6323             int i;
6324             if (xmtchs) {               /* Free previous list in case */
6325                 debug(F101,"dodel freeing previous list","",xmtchn);
6326                 for (i = 0; i < xmtchn; i++) /* it wasn't freed last time. */
6327                   if (xmtchs[i])
6328                     free(xmtchs[i]);
6329                 free(xmtchs);
6330             }
6331             xmtchn = 0;
6332             xmtchs = (char **)malloc(z * (sizeof(char **))); /* Make new one */
6333             if (!xmtchs) {
6334                 printf("?Memory allocation failure\n");
6335                 return(-9);
6336             }
6337             for (i = 0; i < z; i++) {
6338                 xmtchs[i] = NULL;
6339                 znext(tmpbuf);
6340                 if (!*tmpbuf)
6341                   break;
6342                 makestr(&(xmtchs[i]),tmpbuf);
6343                 if (!xmtchs[i]) {
6344                     printf("?Memory allocation failure\n");
6345                     xmtchn = i - 1;
6346                     rc = -9;
6347                     goto xdelete;
6348                 }
6349                 /* debug(F111,"dodel add",xmtchs[i],i); */
6350             }
6351             xmtchn = i;
6352             debug(F101,"dodel xmtchn","",xmtchn);
6353             sh_sort(xmtchs,NULL,z,0,deldirs,0);
6354         }
6355 #else
6356 #ifdef UNIX
6357         sh_sort(mtchs,NULL,z,0,deldirs,filecase);
6358 #endif /* UNIX */
6359 #endif /* OS2 */
6360
6361         if (z > 0) {
6362             int i;
6363 #ifdef OS2
6364             int ix = 0;
6365 #endif /* OS2 */
6366             success = 1;
6367             if (x_hdg > 0)
6368               printf("\n");
6369
6370             while (
6371 #ifdef OS2
6372                    ix < xmtchn
6373 #else
6374                    1
6375 #endif /* OS2 */
6376                    ) {                  /* Loop for all files */
6377 #ifdef OS2
6378                 ckstrncpy(tmpbuf,xmtchs[ix++],TMPBUFSIZ);
6379 #else
6380                 znext(tmpbuf);          /* Get next file */
6381 #endif /* OS2 */
6382                 if (!*tmpbuf) {         /* No more */
6383                     if (deldirs && recursive && argisdir) {
6384                         ckstrncpy(tmpbuf,safebuf,TMPBUFSIZ);
6385                         argisdir = 0;   /* (only do this once) */
6386                     } else
6387                       break;
6388                 }
6389                 skip = 0;
6390                 if (!deltree) {
6391                     if (fs)
6392                       if (fileselect(tmpbuf,
6393                                      del_aft,del_bef,del_naf,del_nbf,
6394                                      minsize,maxsize,0,8,dxlist) < 1) {
6395                           skip++;
6396                       }
6397                 }
6398                 if (!skip && scan && itsadir) {
6399                     skip++;
6400                 }
6401                 if (!skip && scan) {
6402                       switch (scanfile(tmpbuf,&y,nscanfile)) {
6403                       case FT_BIN:
6404                         if (xmode != 1)
6405                           skip++;
6406                         break;
6407                       case FT_TEXT:
6408                       case FT_7BIT:
6409                       case FT_8BIT:
6410 #ifdef UNICODE
6411                       case FT_UTF8:
6412                       case FT_UCS2:
6413 #endif /* UNICODE */
6414                         if (xmode != 0)
6415                           skip++;
6416                     }
6417                 }
6418                 if (!skip && asking) {
6419                     int x;
6420                     ckmakmsg(line,LINBUFSIZ," Delete ",tmpbuf,"? ",NULL);
6421                     x = getyesno(line,3);
6422                     switch (x) {
6423                       case 0: continue;           /* no */
6424                       case 1: break;              /* yes */
6425                       case 2: goto xdelete;       /* quit */
6426                       case 3: asking = 0; break;  /* go */
6427                     }
6428                 }
6429 #ifdef VMSORUNIX
6430                 len = zgetfs(tmpbuf);   /* Get length and accessibility */
6431                 itsadir = zgfs_dir;
6432                 if (itsadir && zgfs_link) { /* Treat links to directories */
6433                     itsadir = 0;        /* as regular files */
6434                     if (scan)           /* But not if /TYPE: was given */
6435                       skip++;
6436                 }
6437                 if (itsadir)            /* (emulate non-Unix code) */
6438                   len = -2;
6439 #else
6440                 len = zchki(tmpbuf);    /* Get accessibility */
6441                 if (len < 0)            /* See if it's a directory */
6442                   itsadir = isdir(tmpbuf);
6443 #endif /* VMSORUNIX */
6444
6445                 if (skip) {
6446 #ifdef COMMENT                          /* Too verbose */
6447                     if (x_lis > 0) {
6448                         lines++;
6449                         printf(" %s (SKIPPED)\n",tmpbuf);
6450 #ifdef CK_TTGWSIZ
6451                         if (++n > cmd_rows - 3)
6452                           if (!askmore()) goto xdelete; else n = 0;
6453 #endif /* CK_TTGWSIZ */
6454                     }
6455 #endif /* COMMENT */
6456                     continue;
6457                 }
6458
6459                 debug(F111,"DELETE len",tmpbuf,len);
6460                 if (simulate) {
6461                     filespace += len;
6462                     count++;
6463                     if (x_lis > 0) {
6464                         lines++;
6465                         printf(" %s (SELECTED)\n",tmpbuf);
6466                         if (++n > cmd_rows - 3) {
6467                             int xx;
6468                             xx = askmore();
6469                             if (!xx) goto xdelete; else n = 0;
6470                         }
6471                     }
6472                 } else if (len >= 0 || !itsadir) { /* Regular file */
6473                     zdelet(tmpbuf);                /* or symlink, etc... */
6474                     if (zchki(tmpbuf) < 0) {
6475                         filespace += len;
6476                         count++;
6477                         if (x_lis > 0) {
6478                             lines++;
6479                             printf(" %s (OK)\n",tmpbuf);
6480                             if (++n > cmd_rows - 3)
6481                               if (!askmore()) goto xdelete; else n = 0;
6482                         }
6483                     } else {
6484                         bad++;
6485                         success = 0;
6486                         if (x_lis > 0) {
6487                             lines++;
6488                             printf(" %s (FAILED: %s)\n",tmpbuf,ck_errstr());
6489                             if (++n > cmd_rows - 3)
6490                               if (!askmore()) goto xdelete; else n = 0;
6491                         }
6492                     }
6493                 } else if (/* pass > 0 && */ deldirs && itsadir) {
6494                     /* It's a directory */
6495                     if (zrmdir(tmpbuf) > -1) { /* Only works if empty */
6496                         count++;
6497                         if (x_lis > 0) {
6498                             lines++;
6499                             printf(" %s (OK)\n",tmpbuf);
6500                             if (++n > cmd_rows - 3)
6501                               if (!askmore()) goto xdelete; else n = 0;
6502                         }
6503                     } else {
6504                         success = 0;
6505                         if (x_lis > 0) {
6506                             lines++;
6507                             printf(" %s (FAILED: %s)\n",
6508                                    tmpbuf,
6509                                    ck_errstr());
6510                             if (++n > cmd_rows - 3)
6511                               if (!askmore()) goto xdelete; else n = 0;
6512                         }
6513                     }
6514                 } else if (x_lis > 0) {
6515                     lines++;
6516                     if (isdir(tmpbuf))
6517                       printf(" %s (FAILED: directory)\n",tmpbuf);
6518                     else
6519                       printf(" %s (FAILED: not a regular file)\n",tmpbuf);
6520                     if (++n > cmd_rows - 3)
6521                       if (!askmore()) goto xdelete; else n = 0;
6522                 }
6523             }
6524             if (x_hdg > 0) {
6525                 if (lines > 0)
6526                   printf("\n");
6527                 if (++n > cmd_rows - 3)
6528                   if (!askmore()) goto xdelete; else n = 0;
6529                 printf("%d file%s %sdeleted, %d byte%s %sfreed%s\n",
6530                        count,
6531                        count != 1 ? "s" : "",
6532                        simulate ? "would be " : "",
6533                        filespace,
6534                        filespace != 1 ? "s" : "",
6535                        simulate ? "would be " : "",
6536                        simulate ? " (maybe)" : ""
6537                        );
6538             }
6539             if (!x_lis && !success && !quiet) {
6540                 printf("?DELETE failed for %d file%s \
6541 (use DELETE /LIST to see details)\n",
6542                        bad, bad == 1 ? "" : "s"
6543                        );
6544             }
6545         } else if (x_lis > 0) {
6546             if (errno)
6547               printf("?%s: %s\n",ck_errstr(), tmpbuf);
6548             else
6549               printf("?Can't delete: %s\n",tmpbuf);
6550         }
6551     }
6552 #else /* OS2ORUNIX */
6553 #ifndef VMS                             /* Others - let the system do it. */
6554     xsystem(line);
6555     x = nzxpand(tmpbuf,nzxopts);
6556     success = (x > 0) ? 0 : 1;
6557     if (x_hdg > 0)
6558       printf("%s - %sdeleted\n", tmpbuf, success ? "" : "not ");
6559 #else
6560     if (asking)
6561       printf("\n");
6562     x = xsystem(line);                  /* zshcmd returns 1 for success */
6563     success = (x > 0) ? 1 : 0;
6564     if (x_hdg > 0 && !asking)
6565       printf("%s - %sdeleted\n", tmpbuf, success ? "" : "not ");
6566     concb((char)escape);
6567 #endif /* VMS */
6568 #endif /* OS2ORUNIX */
6569 #endif /* MAC */
6570   xdelete:
6571     if (g_matchdot > -1) {
6572         matchdot = g_matchdot;          /* Restore these... */
6573         g_matchdot = -1;
6574     }
6575 #ifdef OS2
6576     if (xmtchs) {
6577         int i;
6578         debug(F101,"dodel freeing list","",xmtchn);
6579         for (i = 0; i < xmtchn; i++)
6580           if (xmtchs[i]) free(xmtchs[i]);
6581         free(xmtchs);
6582         xmtchs = NULL;
6583         xmtchn = 0;
6584     }
6585 #endif /* OS2 */
6586     debug(F101,"dodel result","",rc);
6587     return((rc < 0) ? rc : success);
6588 }
6589 #endif /* NOFRILLS */
6590
6591 #ifndef NOSPL                           /* The ELSE command */
6592 _PROTOTYP( VOID pushqcmd, (char *) );
6593
6594 int
6595 doelse() {
6596     if (!ifcmd[cmdlvl]) {
6597         printf("?ELSE doesn't follow IF\n");
6598         return(-2);
6599     }
6600 #ifdef COMMENT
6601 /*
6602   Wrong.  This prevents IF..ELSE IF...ELSE IF...ELSE IF...ELSE...
6603   from working.
6604 */
6605     ifcmd[cmdlvl] = 0;
6606 #endif /* COMMENT */
6607     if (!iftest[cmdlvl]) {              /* If IF was false do ELSE part */
6608         if (maclvl > -1 || tlevel > -1) { /* In macro or command file */
6609             debug(F100,"doelse pushing","",0);
6610 #ifdef COMMENT
6611             pushcmd(NULL);              /* save rest of command. */
6612 #else
6613             /* This fixes certain obscure problems */
6614             /* but breaks many other constructions that must work. */
6615             pushqcmd(NULL);
6616 #endif /* COMMENT */
6617         } else {                        /* If interactive, */
6618             cmini(ckxech);              /* just start a new command */
6619             printf("\n");               /* (like in MS-DOS Kermit) */
6620             if (pflag) prompt(xxstring);
6621         }
6622     } else {                            /* Condition is false */
6623         if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
6624           return(y);                    /* Gobble up rest of line */
6625     }
6626     return(0);
6627 }
6628 #endif /* NOSPL */
6629
6630 #ifndef NOSPL
6631 int
6632 doswitch() {
6633     char *lp, *ap;                      /* Macro argument pointer */
6634     int len = 0, x, y, pp = 0;
6635     char brbuf[3];
6636
6637     /* Get variable name */
6638
6639     tmpbuf[0] = NUL;
6640     brbuf[0] = '{';
6641     brbuf[1] = '}';
6642     brbuf[2] = NUL;
6643
6644     y = cmfld("Variable name","",&s,xxstring);
6645     debug(F111,"doswitch cmfld",s,y);
6646     if (y < 0) {
6647         if (y == -3)                    /* Because brstrip() writes */
6648           s = brbuf;                    /* into its argument. */
6649         else
6650           return(y);
6651     }
6652     debug(F110,"doswitch A",s,0);
6653     if (!strcmp(s,"(")) {
6654         pp++;
6655         if ((y = cmfld("Variable name","",&s,xxstring)) < 0) {
6656             if (y == -3)
6657               s = brbuf;
6658             else
6659               return(y);
6660             debug(F110,"doswitch B",s,0);
6661         }
6662     }
6663     len = ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
6664     if (tmpbuf[0] == CMDQ) {
6665         if (chkvar(s) < 1) {
6666             printf("?Variable name required\n");
6667             return(-9);
6668         }
6669     }
6670     if (pp > 0) {                       /* If open paren given parse closing */
6671         if ((y = cmfld("Closing parenthesis","",&s,NULL)) < 0)
6672           return(y);
6673         if (strcmp(atmbuf,")")) {
6674             printf("?Closing parenthesis required\n");
6675             return(-9);
6676         }
6677     }
6678     lp = line;
6679     x = ckstrncpy(lp,"_switx ",LINBUFSIZ); /* _switx + space */
6680     lp += x;
6681     ap = lp;
6682     debug(F010,"SWITCH a",line,0);
6683
6684 #ifdef COMMENT
6685     x = ckmakmsg(lp,LINBUFSIZ-x,tmpbuf," ",NULL,NULL); /* variable name + SP */
6686 #else
6687     {                                   /* variable name + SP */
6688         char * p = tmpbuf;
6689         if (len > 0) {
6690             if (tmpbuf[0] == '(' && tmpbuf[len-1] == ')') {
6691                 tmpbuf[len-1] = NUL;
6692                 p++;
6693             }
6694         }
6695         x = ckmakmsg(lp,LINBUFSIZ-x,"{",brstrip(p),"}"," ");
6696     }
6697 #endif /* COMMENT */
6698     debug(F010,"SWITCH b",line,0);
6699     lp += x;
6700
6701     /* Get body */
6702
6703     if ((y = cmtxt("series of cases","",&s,NULL)) < 0) return(y);
6704     if ((y = (int)strlen(s)) < 1) return(-2);
6705     if (s[0] != '{' && s[y-1] != '}') { /* Supply braces if missing */
6706         ckmakmsg(tmpbuf,TMPBUFSIZ,"{ ",s," }",NULL);
6707         s = tmpbuf;
6708     }
6709     if (litcmd(&s,&lp,(LINBUFSIZ - (lp - (char *)line) - 2)) < 0) {
6710         printf("?Unbalanced braces\n");
6711         return(0);
6712     }
6713     debug(F010,"SWITCH c",line,0);
6714
6715     x = mlook(mactab,"_switx",nmac);    /* Look up SWITCH macro definition */
6716     if (x < 0) {                        /* Not there? */
6717         addmmac("_switx",sw_def);       /* Put it back. */
6718         if ((x = mlook(mactab,"_switx",nmac)) < 0) { /* Look it up again. */
6719             printf("?SWITCH macro definition gone!\n"); /* Shouldn't happen. */
6720             return(success = 0);
6721         }
6722     }
6723     debug(F010,"SWITCH command",line,0); /* Execute the SWITCH macro. */
6724     success = dodo(x,ap,cmdstk[cmdlvl].ccflgs | CF_IMAC);
6725     debug(F101,"SWITCH status","",success);
6726     return(success);
6727 }
6728
6729 int
6730 dofor() {                               /* The FOR command. */
6731     int i, fx, fy, fz;                  /* loop variables */
6732     char *ap, *di;                      /* macro argument pointer */
6733     int pp = 0;                         /* Paren level */
6734     int mustquote = 0;
6735
6736     for (i = 0; i < 2; i++) {
6737         if ((y = cmfld("Variable name","",&s,NULL)) < 0) {
6738             if (y == -3) {
6739                 printf("?Variable name required\n");
6740                 return(-9);
6741             } else
6742               return(y);
6743         }
6744         if (strcmp(s,"("))
6745           break;
6746         pp++;
6747     }
6748 #ifdef COMMENT
6749     if ((y = parsevar(s,&x,&z)) < 0)    /* Check variable. */
6750       return(y);
6751 #else
6752     if (*s == CMDQ)                     /* If loop variable starts with */
6753       mustquote++;                      /* backslash, mustquote is > 0. */
6754 #endif /* COMMENT */
6755
6756     lp = line;                          /* Build a copy of the command */
6757     ckstrncpy(lp,"_forx ",LINBUFSIZ);
6758     lp += (int)strlen(line);            /* "_for" macro. */
6759     ap = lp;                            /* Save pointer to macro args. */
6760
6761     if (*s == CMDQ) s++;                /* Skip past backslash if any. */
6762     while ((*lp++ = *s++)) ;            /* copy it */
6763     lp--; *lp++ = SP;                   /* add a space */
6764
6765     if ((y = cmnum("initial value","",10,&fx,xxstring)) < 0) {
6766         if (y == -3) return(-2);
6767         else return(y);
6768     }
6769     debug(F101,"dofor fx","",fx);
6770     s = atmbuf;                         /* Copy the atom buffer */
6771
6772     if ((int)strlen(s) < 1) goto badfor;
6773 /*
6774   In edit 192, we change the loop variables to be evaluated at loop entry,
6775   not each time through the loop.  This was required in order to allow
6776   \v(argc) to be used as a loop variable, or in a loop-variable expression.
6777   Thus, we can't have FOR loops that modify their own exit conditions by
6778   changing the final value or the increment.  The problem with \v(argc) was
6779   that it is on the macro stack; after entry into the _forx macro, it is at
6780   the wrong place.
6781 */
6782     sprintf(tmpbuf,"%d",fx);            /* (SAFE) Substitute actual value */
6783     s = tmpbuf;
6784     while ((*lp++ = *s++)) ;            /* (what they actually typed) */
6785     lp--; *lp++ = SP;
6786 #ifdef DEBUG
6787     *lp = NUL;
6788     debug(F110,"FOR A",line,0);
6789 #endif /* DEBUG */
6790
6791     if ((y = cmnum("final value","",10,&fy,xxstring)) < 0) {
6792         if (y == -3) return(-2);
6793         else return(y);
6794     }
6795     debug(F101,"dofor fy","",fy);
6796     s = atmbuf;                         /* Same deal */
6797     if ((int)strlen(s) < 1)
6798       goto badfor;
6799
6800     sprintf(tmpbuf,"%d",fy);            /* SAFE */
6801     s = tmpbuf;
6802     while ((*lp++ = *s++)) ;
6803     lp--;
6804     *lp++ = SP;
6805 #ifdef DEBUG
6806     *lp = NUL;
6807     debug(F110,"FOR B",line,0);
6808 #endif /* DEBUG */
6809
6810     x_ifnum = 1;                        /* Increment or parenthesis */
6811     di = (fx < fy) ? "1" : "-1";        /* Default increment */
6812     if ((y = cmnum("increment",di,10,&fz,xxstring)) < 0) {
6813         debug(F111,"dofor increment",atmbuf,y);
6814         x_ifnum = 0;
6815         if (y == -3) {                  /* Premature termination */
6816             return(-2);
6817         } else if (y == -2) {           /* Maybe closing paren */
6818             if (!strcmp(atmbuf,")")) {
6819                 pp--;                   /* Count it */
6820                 s = di;                 /* supply default interval */
6821                 fz = atoi(s);
6822             } else                      /* Not closing paren, invalid */
6823               return(y);
6824         } else                          /* Other error */
6825           return(y);
6826     } else {                            /* Number */
6827         x_ifnum = 0;
6828         debug(F101,"dofor fz","",fz);
6829         s = atmbuf;                     /* Use it */
6830     }
6831     if ((int)strlen(s) < 1)
6832       goto badfor;
6833
6834     sprintf(tmpbuf,"%d",fz);            /* (SAFE) Same deal */
6835     s = tmpbuf;
6836     while ((*lp++ = *s++)) ;
6837     lp--; *lp++ = SP;
6838
6839 #ifdef DEBUG
6840     *lp = NUL;
6841     debug(F110,"FOR C",line,0);
6842 #endif /* DEBUG */
6843
6844     /* Insert the appropriate comparison operator */
6845     if (fz < 0)
6846       *lp++ = '<';
6847     else
6848       *lp++ = '>';
6849     *lp++ = SP;
6850
6851 #ifdef DEBUG
6852     *lp = NUL;
6853     debug(F110,"FOR D",line,0);
6854 #endif /* DEBUG */
6855
6856     if (pp > 0) {                       /* If open paren given parse closing */
6857         if ((y = cmfld("Closing parenthesis","",&s,NULL)) < 0)
6858           return(y);
6859         if (strcmp(atmbuf,")")) {
6860             printf("?Closing parenthesis required\n");
6861             return(-9);
6862         }
6863     }
6864     if ((y = cmtxt("Command to execute","",&s,NULL)) < 0) return(y);
6865     if ((y = (int)strlen(s)) < 1) return(-2);
6866     if (s[0] != '{' && s[y-1] != '}') { /* Supply braces if missing */
6867         ckmakmsg(tmpbuf,TMPBUFSIZ,"{ ",s," }",NULL);
6868         s = tmpbuf;
6869     }
6870     if (litcmd(&s,&lp,(LINBUFSIZ - (lp - (char *)line) - 2)) < 0) {
6871         printf("?Unbalanced braces\n");
6872         return(0);
6873     }
6874 #ifdef DEBUG
6875     *lp = NUL;
6876     debug(F110,"FOR E",line,0);
6877 #endif /* DEBUG */
6878
6879 #ifdef COMMENT
6880 /* Too strict */
6881     if (fz == 0) {
6882         printf("?Zero increment not allowed\n");
6883         return(0);
6884     }
6885 #endif /* COMMENT */
6886 /*
6887   In version 8.0 we decided to allow macro names anyplace a numeric-valed
6888   variable could appear.  But this caused trouble for the FOR loops because
6889   the quoting in for_def[] assumed a \%i-style loop variable.  We account
6890   for this here in the if (mustquote)...else logic by invoking separate
6891   FOR macro definitions in the two cases.
6892 */
6893     if (mustquote) {                    /* \%i-style loop variable */
6894         x = mlook(mactab,"_forx",nmac); /* Look up FOR macro definition */
6895         if (x < 0) {                    /* Not there? */
6896             addmmac("_forx",for_def);   /* Put it back. */
6897             if ((x = mlook(mactab,"_forx",nmac)) < 0) { /* Look it up again. */
6898                 printf("?FOR macro definition gone!\n");
6899                 return(success = 0);
6900             }
6901         }
6902     } else {                            /* Loop variable is a macro */
6903         x = mlook(mactab,"_forz",nmac);
6904         if (x < 0) {
6905             addmmac("_forz",foz_def);
6906             if ((x = mlook(mactab,"_forz",nmac)) < 0) {
6907                 printf("?FOR macro definition gone!\n");
6908                 return(success = 0);
6909             }
6910         }
6911     }
6912     debug(F010,"FOR command",line,0);   /* Execute the FOR macro. */
6913     return(success = dodo(x,ap,cmdstk[cmdlvl].ccflgs | CF_IMAC));
6914
6915 badfor:
6916     printf("?Incomplete FOR command\n");
6917     return(-2);
6918 }
6919 #endif /* NOSPL */
6920
6921 #ifndef NOFRILLS
6922 /* Do the BUG command */
6923
6924 int
6925 dobug() {
6926     int n;
6927     char * s = "";
6928     extern char * k_info_dir;
6929
6930     if (k_info_dir)
6931       s = k_info_dir;
6932
6933 #ifdef COMMENT
6934     printf("\n%s,%s\n Numeric: %ld",versio,ckxsys,vernum);
6935 #endif /* COMMENT */
6936     printf(
6937 "\nBefore requesting technical support from Columbia U., please consult:\n\n"
6938            );
6939     n = 7;
6940 #ifdef OS2
6941     printf(" . Your \"Kermit 95\" user manual (use the MANUAL command).\n");
6942     printf(" . The technical reference manual, \"Using C-Kermit\".\n");
6943     n += 2;
6944 #else
6945     printf(" . The book \"Using C-Kermit\" (type HELP for more info).\n");
6946     n += 1;
6947 #endif /* OS2 */
6948
6949     printf(" . Your own organization's support staff, if any.\n");
6950     printf(
6951 " . The comp.protocols.kermit.misc newsgroup.\n");
6952     printf(
6953 " . The Kermit support website, http://www.columbia.edu/kermit/support.html \n"
6954            );
6955     printf(
6956
6957 " . The Kermit FAQ, http://www.columbia.edu/kermit/newfaq.html \n");
6958 #ifdef OS2
6959     printf(
6960 " . The Kermit 95 FAQ, http://www.columbia.edu/kermit/k95faq.html \n");
6961     n++;
6962 #endif /* OS2 */
6963
6964     printf(
6965 " . The C-Kermit FAQ, http://www.columbia.edu/kermit/ckfaq.html \n");
6966     n += 4;
6967     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
6968     printf("\n\
6969 If you still need help or have a bug to report after consulting these sources,"
6970            );
6971     printf("\nsend e-mail to:\n\n");
6972     n += 2;
6973     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
6974     printf("  mailto:kermit-support@columbia.edu\n\n");
6975     n += 1;
6976     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
6977     printf("Or contact us by post:\n\n");
6978     printf(
6979 "  Kermit, Columbia University, 612 W 115 Street, New York NY  10025, USA\n\n"
6980            );
6981     n += 1;
6982     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
6983     printf("Or by fax at +1 (212) 662-6442.\n\n");
6984     n += 1;
6985     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
6986 #ifdef COMMENT
6987     printf("Telephone support is available too:\n\n");
6988     n += 1;
6989     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
6990     printf(
6991     "  +1 (212) 854-5126, from anywhere, $25.00 USD per call, MC/Visa\n\n");
6992     n += 1;
6993     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
6994 #endif /* COMMENT */
6995 #ifndef NOSHOW
6996 #ifndef NOFRILLS
6997     printf(
6998 "Before reporting problems, please use the SHOW FEATURES command\n");
6999     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
7000     printf(
7001 "to get detailed program version and configuration information.\n\n");
7002 #endif /* NOFRILLS */
7003 #endif /* NOSHOW */
7004     return(1);
7005 }
7006 #endif /* NOFRILLS */
7007
7008 #ifndef NOSPL
7009
7010 /*  T O D 2 S E C  --  Convert time of day as hh:mm:ss to secs since midnite */
7011 /*
7012   Call with a string hh:mm or hh:mm:ss.
7013   Returns a 0 to 86400 on success, or a negative number on failure.
7014 */
7015 long
7016 tod2sec(t) char * t; {
7017     long t2;
7018     long hh = 0L, mm = 0L, ss = 0L;
7019
7020     if (!t) t = "";
7021     if (!*t)
7022       return(-3L);
7023     debug(F110,"tod2sec",t,0);
7024
7025     if (isdigit(*t))                    /* Get hours from argument */
7026       hh = *t++ - '0';
7027     else
7028       return(-1L);
7029     if (isdigit(*t))
7030       hh = hh * 10 + *t++ - '0';
7031 #ifdef COMMENT
7032     if (hh > 24L)
7033       return(-1L);
7034 #endif /* COMMENT */
7035     if (*t == ':')
7036       t++;
7037     else if (!*t)
7038       goto xtod2sec;
7039     else
7040       return(-1L);
7041
7042     if (isdigit(*t))                    /* Minutes */
7043       mm = *t++ - '0';
7044     else
7045       return(-1L);
7046     if (isdigit(*t))
7047       mm = mm * 10 + *t++ - '0';
7048     if (mm > 60L)
7049       return(-1L);
7050     if (*t == ':')
7051       t++;
7052     else if (!*t)
7053       goto xtod2sec;
7054     else
7055       return(-1L);
7056
7057     if (isdigit(*t))                    /* Seconds */
7058       ss = *t++ - '0';
7059     else
7060       return(-1L);
7061     if (isdigit(*t))
7062       ss = ss * 10 + *t++ - '0';
7063     if (ss > 60L)
7064       return(-1L);
7065
7066     if (*t > 32)                        /* No trailing junk allowed */
7067       return(-1L);
7068
7069   xtod2sec:
7070
7071     t2 = hh * 3600L + mm * 60L + ss;    /* Seconds since midnight from arg */
7072     debug(F101,"tod2sec t2","",t2);
7073
7074     return(t2);
7075 }
7076
7077 int waitinterval = 1;
7078
7079 #ifdef OLDWAIT
7080 #undef OLDWAIT
7081 #endif /* OLDWAIT */
7082
7083 int kbchar = NUL;
7084
7085 int
7086 dopaus(cx) int cx; {
7087     long zz;
7088     extern int sleepcan;
7089
7090 #ifdef OLDWAIT
7091     zz = -1L;
7092     x_ifnum = 1;                        /* Turn off internal complaints */
7093     if (cx == XXWAI)
7094       y = cmnum("seconds to wait, or time of day hh:mm:ss","1",10,&x,xxstring);
7095     else if (cx == XXPAU)
7096       y = cmnum("seconds to pause, or time of day hh:mm:ss",
7097                 "1",10,&x,xxstring);
7098     else
7099       y = cmnum("milliseconds to sleep, or time of day hh:mm:ss",
7100                 "100",10,&x,xxstring);
7101     x_ifnum = 0;
7102     if (y < 0) {
7103         if (y == -2) {                  /* Invalid number or expression */
7104             char *p = tmpbuf;           /* Retrieve string from atmbuf */
7105             int n = TMPBUFSIZ;
7106             *p = NUL;
7107             zzstring(atmbuf,&p,&n);     /* Evaluate in case it's a variable */
7108             zz = tod2sec(tmpbuf);       /* Convert to secs since midnight */
7109             if (zz < 0L) {
7110                 printf("?Number, expression, or time of day required\n");
7111                 return(-9);
7112             } else {
7113                 char now[32];           /* Current time */
7114                 char *p;
7115                 long tnow;
7116                 p = now;
7117                 ztime(&p);
7118                 tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
7119                 if (zz < tnow)          /* User's time before now */
7120                   zz += 86400L;         /* So make it tomorrow */
7121                 zz -= tnow;             /* Seconds from now. */
7122             }
7123         } else
7124           return(y);
7125     }
7126     if (x < 0) x = 0;
7127     switch (cx) {
7128       case XXPAU:                       /* PAUSE */
7129       case XXMSL:                       /* MSLEEP */
7130         if ((y = cmcfm()) < 0) return(y);
7131         break;
7132       case XXWAI:                       /* WAIT */
7133         z = 0;                          /* Modem signal mask */
7134         while (1) {                     /* Read zero or more signal names */
7135             y = cmkey(mstab,nms,"modem signal","",xxstring);
7136             if (y == -3) break;         /* -3 means they typed CR */
7137             if (y < 0) return(y);       /* Other negatives are errors */
7138             z |= y;                     /* OR the bit into the signal mask */
7139         }
7140         if ((y = cmcfm()) < 0) return(y);
7141         break;
7142
7143       default:                          /* Shouldn't happen */
7144         return(-2);
7145     }
7146
7147 /* Command is entered, now do it. */
7148
7149     if (zz > -1L) {                     /* Time of day given? */
7150         x = zz;
7151         if (zz != (long) x) {
7152             printf(
7153 "Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n"
7154                    );
7155             return(-9);
7156         }
7157     }
7158     if (cx == XXMSL) {                  /* Millisecond sleep */
7159         msleep(zz < 0 ? x : x * 1000);
7160         return(success = 1);
7161     }
7162     if (cx == XXPAU && !sleepcan) {     /* SLEEP CANCELLATION is OFF */
7163         sleep(x);
7164         return(success = 1);
7165     }
7166
7167     /* WAIT, or else SLEEP with cancellation allowed... */
7168
7169     do {                                /* Sleep loop */
7170         int mdmsig;
7171         if (sleepcan) {                 /* Keyboard cancellation allowed? */
7172             if (y = conchk()) {         /* Did they type something? */
7173 #ifdef COMMENT
7174                 while (y--) coninc(0);  /* Yes, gobble it all up */
7175 #else
7176                 /* There is a debate over whether PAUSE should absorb    */
7177                 /* its cancelling character(s).  There are several       */
7178                 /* reasons why it should gobble at least one character:  */
7179                 /* (1) MS-DOS Kermit does it                             */
7180                 /* (2) if not, subsequent PAUSE commands will terminate  */
7181                 /*     immediately                                       */
7182                 /* (3) if not, subsequent ASK commands will use it as    */
7183                 /*     valid input.  If \13, then it will get no input   */
7184                 /* (4) if not, then the character appears on the command */
7185                 /*     line after all enclosing macros are complete.     */
7186                 kbchar = coninc(0);     /* Gobble one up */
7187 #endif /* COMMENT */
7188                 break;                  /* And quit PAUSing or WAITing */
7189             }
7190         }
7191         if (cx == XXWAI) {              /* WAIT (z == modem signal mask) */
7192             debug(F101,"WAIT x","",x);
7193             if (z > 0) {                /* Looking for any modem signals? */
7194                 mdmsig = ttgmdm();      /* Yes, get them */
7195                 if (mdmsig < 0)         /* Failed */
7196                   return(success = 0);
7197                 if ((mdmsig & z) == z)  /* Got what we wanted? */
7198                   return(success = 1);  /* Succeed */
7199             }
7200             if (x == 0)                 /* WAIT 0 and didn't get our signals */
7201               break;
7202         }
7203         sleep(1);                       /* No interrupt, sleep one second */
7204     } while (--x > 0);
7205
7206     if (cx == XXWAI)                    /* If WAIT and loop exhausted */
7207       success = (z == 0);               /* Fail. */
7208     else                                /*  */
7209       success = (x == 0);               /* Set SUCCESS/FAILURE for PAUSE. */
7210     return(success);
7211
7212 #else  /* New code uses chained FDBs and allows FILE waits... */
7213
7214     char * m = "";                      /* Help message */
7215     struct FDB nu, fl;                  /* Parse function descriptor blocks */
7216     int filewait = 0;
7217     int mdmsig = 0, fs = 0;
7218     char filedate[32];
7219
7220     kbchar = 0;
7221
7222     switch (cx) {
7223       case XXWAI: m = "seconds to wait, or time of day hh:mm:ss"; break;
7224       case XXPAU: m = "seconds to pause, or time of day hh:mm:ss"; break;
7225       case XXMSL: m = "milliseconds to sleep, or time of day hh:mm:ss"; break;
7226     }
7227     zz = -1L;
7228     cmfdbi(&nu,
7229            _CMNUM,                      /* Number */
7230            m,                           /* Help message */
7231            (cx == XXMSL) ? "100" : "1", /* Default */
7232            "",                          /* N/A */
7233            0,                           /* N/A */
7234            0,                           /* N/A */
7235            xxstring,                    /* Processing function */
7236            NULL,                        /* N/A */
7237            &fl                          /* Next */
7238            );
7239     cmfdbi(&fl,                         /* Time of day */
7240            _CMFLD,                      /* Field */
7241            "",                          /* hlpmsg */
7242            "",                          /* default */
7243            "",                          /* addtl string data */
7244            0,                           /* addtl numeric data 1 */
7245            0,                           /* addtl numeric data 2 */
7246            xxstring,                    /* processing func */
7247            NULL,                        /* N/A */
7248            NULL                         /* No next */
7249            );
7250     x = cmfdb(&nu);                     /* Parse a number or a field */
7251     if (x < 0) {
7252         if (x == -3)
7253           x = -2;
7254         return(x);
7255     }
7256     switch (cmresult.fcode) {
7257       case _CMNUM:                      /* Number */
7258         x = cmresult.nresult;
7259         break;
7260       case _CMFLD:                      /* Field */
7261         zz = tod2sec(cmresult.sresult); /* Convert to secs since midnight */
7262         if (zz < 0L) {
7263             printf("?Number, expression, or time of day required\n");
7264             return(-9);
7265         } else {
7266             char now[32];               /* Current time */
7267             char *p;
7268             long tnow;
7269             p = now;
7270             ztime(&p);
7271             tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
7272             if (zz < tnow)              /* User's time before now */
7273               zz += 86400L;             /* So make it tomorrow */
7274             zz -= tnow;         /* Seconds from now. */
7275         }
7276     }
7277     debug(F101,"PAUSE/WAIT/MSLEEP zz","",zz);
7278     switch (cx) {
7279       case XXPAU:                       /* PAUSE */
7280       case XXMSL:                       /* MSLEEP */
7281         if ((y = cmcfm()) < 0) return(y);
7282         break;
7283       case XXWAI:                       /* WAIT */
7284         z = 0;                          /* Modem signal mask */
7285         y = cmkey(waittab,nwaittab,"","",xxstring);
7286         if (y < 0) {
7287             if (y == -3) {
7288                 if ((y = cmcfm()) < 0)
7289                   return(y);
7290                 break;
7291             } else
7292               return(y);
7293         }
7294         if (y == WAIT_FIL) {            /* FILE */
7295             int wild = 0;
7296             if ((z = cmkey(wfswi,nwfswi,"event","",xxstring)) < 0)
7297               return(z);
7298             filewait = z;
7299             if (filewait == WF_MOD || filewait == WF_DEL)
7300               z = cmifi("Filename","",&s,&wild,xxstring);
7301             else
7302               z = cmfld("Filename","",&s,xxstring);
7303             if (z < 0)
7304               return(z);
7305             if (wild || ((filewait == WF_CRE) && iswild(s))) {
7306                 printf("?Wildcards not valid here\n");
7307                 return(-9);
7308             }
7309             ckstrncpy(tmpbuf,s,TMPBUFSIZ);
7310             if ((z = cmcfm()) < 0)
7311               return(z);
7312             break;
7313         } else if (y != WAIT_MDM) {     /* A modem signal */
7314             z |= y;                     /* OR the bit into the signal mask */
7315         }
7316         if (!filewait) {                /* Modem signals... */
7317             while (1) {                 /* Get zero or more signal names */
7318                 y = cmkey(mstab,nms,"modem signal","",xxstring);
7319                 if (y == -3) break;     /* -3 means they typed CR */
7320                 if (y < 0) return(y);   /* Other negatives are errors */
7321                 z |= y;                 /* OR the bit into the signal mask */
7322             }
7323             if ((y = cmcfm()) < 0) return(y);
7324             break;
7325         }
7326
7327       default:                          /* Shouldn't happen */
7328         return(-2);
7329     } /* switch (cx) */
7330
7331 /* Command is entered, now do it. */
7332
7333     if (zz > -1L) {                     /* Time of day given? */
7334         x = zz;
7335         if (zz != (long) x) {
7336             printf(
7337 "Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n"
7338                    );
7339             return(-9);
7340         }
7341     }
7342     if (sleepcan)
7343       concb((char)escape);              /* Ensure single-char wakeup */
7344
7345     if (cx == XXMSL) {                  /* Millisecond sleep */
7346         msleep(zz < 0 ? x : x * 1000);
7347         return(success = 1);
7348     }
7349     if (cx == XXPAU && !sleepcan) {     /* SLEEP CANCELLATION is OFF */
7350         sleep(x);
7351         return(success = 1);
7352     }
7353     if (filewait) {                     /* FILE... */
7354         fs = zchki(tmpbuf);             /* Check if file exists */
7355         switch (filewait) {
7356           case WF_DEL:
7357             if (fs == -1)
7358               return(success = 1);
7359             break;
7360           case WF_MOD:
7361             if (fs == -1) {
7362                 printf("?File does not exit: %s\n",tmpbuf);
7363                 return(-9);
7364             }
7365             s = zfcdat(tmpbuf);         /* Get current modification date */
7366             if (!s) s = "";
7367             if (ckstrncpy(filedate,s,32) != 17) {
7368                 printf("?Can't get modification time: %s\n",tmpbuf);
7369                 return(-9);
7370             }
7371             break;
7372           case WF_CRE:
7373             if (fs > -1)
7374               return(success = 1);
7375             break;
7376         }
7377     }
7378     do {                                /* Polling loop */
7379         if (sleepcan) {                 /* Keyboard cancellation allowed? */
7380             if ((y = conchk()) > 0) {   /* Did they type something? */
7381                 kbchar = coninc(0);     /* Yes, get first char they typed */
7382                 debug(F000,"WAIT kbchar","",kbchar);
7383 #ifdef COMMENT
7384                 while (--y > 0)         /* Gobble the rest up */
7385                   coninc(0);
7386 #endif /* COMMENT */
7387                 return(success = 0);    /* And quit PAUSing or WAITing */
7388             }
7389         }
7390         if (filewait == 0) {
7391             if (cx == XXWAI) {          /* WAIT for modem signals */
7392                 if (z != 0) {
7393                     mdmsig = ttgmdm();  /* Get them. */
7394                     debug(F101,"WAIT ttgmdm","",mdmsig);
7395                     if (mdmsig < 0)     /* Failure to get them? */
7396                       return(success = 0); /* Fail. */
7397                     if ((mdmsig & z) == z) /* Got desired ones? */
7398                       return(success = 1); /* Succeed. */
7399                 } else if (x == 0)
7400                   return(success = 0);
7401             }
7402         } else {                        /* FILE... */
7403             fs = zchki(tmpbuf);         /* Get file status */
7404             if (filewait == WF_MOD) {   /* Wait for modification */
7405                 if (fs == -1)           /* Failure to get status */
7406                   return(success = 0);  /* so WAIT fails. */
7407                 s = zfcdat(tmpbuf);     /* Get current modification time */
7408                 if (!s) s = "";         /* And compare with the time */
7409                 if (strcmp(s,filedate)) /* when the WAIT started */
7410                   return(success = 1);
7411             } else if (filewait == WF_DEL) { /* Wait for deletion */
7412                 if (fs == -1)           /* If file doesn't exist, */
7413                   return(success = 1);  /* succeed. */
7414             } else if (filewait == WF_CRE) { /* Wait for creation */
7415                 if (fs != -1)           /* If file exists */
7416                   return(success = 1);  /* succeed. */
7417             }
7418         }
7419         if (x < 1)                      /* SLEEP/WAIT/PAUSE 0 */
7420           break;
7421         sleep(waitinterval);            /* No interrupt, sleep */
7422         x -= waitinterval;              /* Deduct sleep time */
7423     } while (x > 0);
7424
7425     if (cx == XXWAI)                    /* WAIT time expired */
7426       success = (z == 0);               /* Succeed if no modem signals */
7427     else                                /* For SLEEP or PAUSE, success */
7428       success = (x == 0);               /* depends on whether it was */
7429     return(success);                    /* interrupted from the keyboard. */
7430 #endif /* OLDWAIT */
7431 }
7432 #endif /* NOSPL */
7433
7434 #ifdef OS2ORUNIX
7435 _PROTOTYP(int zcmpfn,(char *, char *));
7436 #endif /* OS2ORUNIX */
7437
7438 #ifndef NOFRILLS
7439 #ifdef NT
7440 int 
7441 dolink() {
7442     /* Parse a file or a directory name */
7443     int i, x, z, listing = 0, havename = 0, wild = 0, rc = 1;
7444     struct FDB sw, fi;
7445
7446     cmfdbi(&sw,                         /* 2nd FDB - optional /PAGE switch */
7447            _CMKEY,                      /* fcode */
7448            "Filename or switch",        /* hlpmsg */
7449            "",                          /* default */
7450            "",                          /* addtl string data */
7451            nqvswtab,                    /* addtl numeric data 1: tbl size */
7452            4,                           /* addtl numeric data 2: 4 = cmswi */
7453            xxstring,                    /* Processing function */
7454            qvswtab,                     /* Keyword table */
7455            &fi                          /* Pointer to next FDB */
7456            );
7457
7458     cmfdbi(&fi,                         /* 1st FDB - file to type */
7459            _CMIFI,                      /* fcode */
7460            "",                          /* hlpmsg */
7461            "",                          /* default */
7462            "",                          /* addtl string data */
7463            3,                           /* addtl numeric data 1 */
7464            0,                           /* addtl numeric data 2 */
7465            xxstring,
7466            NULL,
7467            NULL
7468            );
7469
7470     while (!havename) {
7471         x = cmfdb(&sw);                 /* Parse something */
7472         if (x < 0)                      /* Error */
7473           return(x);
7474         switch (cmresult.fcode) {
7475           case _CMKEY:
7476             switch (cmresult.nresult) {
7477               case DEL_LIS:
7478               case DEL_VRB:
7479                 listing = 1;
7480                 break;
7481               case DEL_NOL:
7482               case DEL_QUI:
7483                 listing = 0;
7484                 break;
7485             }
7486             break;
7487           case _CMIFI:
7488             s = cmresult.sresult;
7489             havename = 1;
7490             break;
7491           default:
7492             return(-2);
7493         }
7494     }
7495     wild = cmresult.nresult;            /* Source specification wild? */
7496
7497     ckstrncpy(line,s,LINBUFSIZ);        /* Make a safe copy of source name */
7498     s = line;
7499
7500     if (!wild)
7501       wild = iswild(line);
7502
7503     p = tmpbuf;                         /* Place for new name */
7504     if ((x = cmofi(wild ? "Target directory" : "New name",
7505                    "",&s,xxstring)) < 0) { /* Get new name */
7506         if (x == -3) {
7507             printf("?%s required\n", wild ? "Target directory" : "New name");
7508             return(-9);
7509         } else return(x);
7510     }
7511     ckstrncpy(p,s,TMPBUFSIZ);           /* Make a safe copy of the new name */
7512     if ((y = cmcfm()) < 0) return(y);
7513
7514     if (!wild) {                        /* Just one */
7515         if (listing) printf("%s => %s ",line,p);
7516         if (zlink(line,p) < 0) {
7517             if (listing) printf("(FAILED: %s\n",ck_errstr());
7518             rc = 0;
7519         } else {
7520             if (listing) printf("(OK)\n");
7521         }
7522         return(success = rc);
7523     }
7524     if (!isdir(p)) {                    /* Multiple */
7525         printf(                         /* if target is not a directory */
7526 "?Multiple source files not allowed if target is not a directory.\n");
7527         return(-9);
7528     }
7529 #ifdef COMMENT
7530     else {                              /* Show full path of target */
7531         char buf[CKMAXPATH];            /* (too much) */
7532         if (zfnqfp(p,CKMAXPATH,buf))
7533           ckstrncpy(tmpbuf,buf,TMPBUFSIZ);
7534     }
7535 #endif /* COMMENT */
7536
7537 #ifdef VMS
7538     conres();                           /* Let Ctrl-C work. */
7539 #endif /* VMS */
7540     debug(F110,"dolink line",line,0);
7541
7542 #ifdef ZXREWIND
7543     z = zxrewind();                     /* Rewind file list */
7544 #else
7545     z = nzxpand(s,0);                   /* Expand file list */
7546 #endif /* ZXREWIND */
7547     debug(F111,"dolink p",p,z);
7548
7549 #ifdef UNIX
7550     if (wild && z > 1)
7551       sh_sort(mtchs,NULL,z,0,0,filecase); /* Alphabetize the filename list */
7552 #endif /* UNIX */
7553
7554     while (z-- > 0) {
7555         if (!(z == 0 && !wild))
7556           znext(line);
7557         if (!line[0])
7558           break;
7559         if (listing) printf("%s => %s ",line,p);
7560         if (zlink(line,p) < 0) {
7561             if (listing) printf("(FAILED: %s\n",ck_errstr());
7562             rc = 0;
7563         } else {
7564             if (listing) printf("(OK)\n");
7565         }
7566     }
7567 #ifdef VMS
7568     concb((char)escape);
7569 #endif /* VMS */
7570     return(success = rc);
7571 }
7572 #endif /* NT */
7573
7574 #ifdef ZCOPY
7575 int
7576 docopy() {
7577     int i, x, listing = 0, nolist = 0, havename = 0;
7578     struct FDB sw, fi;
7579     int targetisdir = 0;
7580     int targetlen = 0;
7581     int swapping = 0;
7582     int appending = 0;
7583     int fromb64 = 0;
7584     int tob64 = 0;
7585     int wild = 0;
7586     int rc = 1;
7587
7588     cmfdbi(&sw,                         /* 2nd FDB - optional /PAGE switch */
7589            _CMKEY,                      /* fcode */
7590            "Filename or switch",        /* hlpmsg */
7591            "",                          /* default */
7592            "",                          /* addtl string data */
7593            ncopytab,                    /* addtl numeric data 1: tbl size */
7594            4,                           /* addtl numeric data 2: 4 = cmswi */
7595            xxstring,                    /* Processing function */
7596            copytab,                     /* Keyword table */
7597            &fi                          /* Pointer to next FDB */
7598            );
7599     cmfdbi(&fi,                         /* 1st FDB - file to type */
7600            _CMIFI,                      /* fcode */
7601            "",                          /* hlpmsg */
7602            "",                          /* default */
7603            "",                          /* addtl string data */
7604            0,                           /* addtl numeric data 1 */
7605            0,                           /* addtl numeric data 2 */
7606            xxstring,
7607            NULL,
7608            NULL
7609            );
7610
7611     while (!havename) {
7612         x = cmfdb(&sw);                 /* Parse something */
7613         if (x < 0)                      /* Error */
7614           return(x);
7615         switch (cmresult.fcode) {
7616           case _CMKEY:
7617             switch (cmresult.nresult) {
7618               case DEL_LIS:
7619               case DEL_VRB:
7620                 nolist = 0;
7621                 listing = 1;
7622                 break;
7623               case DEL_NOL:
7624               case DEL_QUI:
7625                 nolist = 1;
7626                 listing = 0;
7627                 break;
7628               case 999:
7629                 swapping = 1;
7630                 break;
7631               case 998:
7632                 appending = 1;
7633                 break;
7634 #ifndef NOSPL
7635               case 997:
7636                 fromb64 = 1;
7637                 break;
7638               case 996:
7639                 tob64 = 1;
7640                 break;
7641 #endif /* NOSPL */
7642             }
7643             break;
7644           case _CMIFI:
7645             s = cmresult.sresult;
7646             havename = 1;
7647             break;
7648           default:
7649             return(-2);
7650         }
7651     }
7652     wild = cmresult.nresult;
7653     ckstrncpy(line,s,LINBUFSIZ);        /* Make a safe copy of source name */
7654     s = line;
7655     p = tmpbuf;                         /* Place for new name */
7656
7657     /* Get destination name */
7658     if ((x = cmofi("destination name and/or directory",
7659 #ifdef UNIX
7660                    "."
7661 #else
7662                    ""
7663 #endif /* UNIX */
7664                    ,&s,xxstring)) < 0) {
7665         if (x == -3) {
7666             printf("?Name for destination file required\n");
7667             return(-9);
7668         } else return(x);
7669     }
7670     ckstrncpy(p,s,TMPBUFSIZ);           /* Safe copy of destination name */
7671     if ((y = cmcfm()) < 0) return(y);
7672     if (appending && swapping) {
7673         printf("?Sorry, /APPEND and /SWAP conflict\n");
7674         return(-9);
7675     }
7676 #ifdef COMMENT
7677 /*
7678   This unreasonably prevented "COPY /APPEND *.* bifile" from concatenating
7679   a bunch of files into one big file.
7680 */
7681     if (appending && wild) {
7682         printf("?Sorry, /APPEND can be used only with single files\n");
7683         return(-9);
7684     }
7685 #endif /* COMMENT */
7686     targetisdir = isdir(p);
7687     x = strlen(p);
7688     if (targetisdir) {
7689 #ifdef UNIXOROSK
7690         if (p[x-1] != '/') {
7691             ckstrncat(p,"/",TMPBUFSIZ);
7692             x++;
7693         }
7694 #else
7695 #ifdef OS2
7696         if (p[x-1] != '/') {
7697             ckstrncat(p,"/",TMPBUFSIZ);
7698             x++;
7699         }
7700 #else
7701 #ifdef STRATUS
7702         if (p[x-1] != '>') {
7703             ckstrncat(p,">",TMPBUFSIZ);
7704             x++;
7705         }
7706 #else
7707 #ifdef datageneral
7708         if (p[x-1] != ':') {
7709             ckstrncat(p,":",TMPBUFSIZ);
7710             x++;
7711         }
7712 #else
7713         if (p[x-1] != '/') {
7714             ckstrncat(p,"/",TMPBUFSIZ);
7715             x++;
7716         }
7717 #endif /* datageneral */
7718 #endif /* STRATUS */
7719 #endif /* OS2 */
7720 #endif /* UNIXOROSK */
7721     }
7722     targetlen = x;
7723
7724     if (!appending) {                   /* If /APPEND not given */
7725         if (wild && !targetisdir) {     /* No wildcards allowed */
7726             printf(                     /* if target is not a directory */
7727 "?Multiple source files not allowed if target is not a directory.\n");
7728             return(-9);
7729         }
7730     }
7731
7732 #ifdef VMS
7733     conres();                           /* Let Ctrl-C work. */
7734 #endif /* VMS */
7735     debug(F110,"docopy line",line,0);
7736     debug(F110,"docopy p",p,0);
7737
7738 #ifdef ZXREWIND
7739     z = zxrewind();                     /* Rewind file list */
7740 #else
7741     z = nzxpand(s,0);                   /* Expand file list */
7742 #endif /* ZXREWIND */
7743
7744 #ifdef UNIX
7745     if (wild)
7746       sh_sort(mtchs,NULL,z,0,0,filecase); /* Alphabetize the filename list */
7747 #endif /* UNIX */
7748
7749 #ifdef IKSD
7750     if (!targetisdir && zchki(p) > -1) { /* Destination file exists? */
7751         if (inserver && (!ENABLED(en_del)
7752 #ifdef CK_LOGIN
7753                          || isguest
7754 #endif /* CK_LOGIN */
7755                          )) {
7756             printf("?Sorry, overwriting existing files is disabled\n");
7757             return(-9);
7758         }
7759     }
7760 #endif /* IKSD */
7761
7762     if (tob64 && fromb64) {             /* To and from B64 = no conversion */
7763         tob64 = 0;
7764         fromb64 = 0;
7765     }
7766     debug(F110,"COPY dest",p,0);
7767
7768     while (z > 0) {
7769
7770         znext(line);
7771         if (!line[0])
7772           break;
7773
7774         errno = 0;                      /* Reset errno */
7775
7776         if (listing) printf("%s => %s ",line,p);
7777
7778         /* Straight copy */
7779         if (!swapping && !appending && !fromb64 && !tob64) {
7780             debug(F110,"COPY zcopy",line,0);
7781
7782             if ((x = zcopy(line,p)) < 0) { /* Let zcopy() do it. */
7783                 switch (x) {
7784                   case -2:
7785                     if (listing)
7786                       printf("(FAILED: Not a regular file)\n");
7787                     else if (!nolist)
7788                       printf("?Not a regular file - %s\n",line);
7789                     rc = 0;
7790                     break;
7791                   case -3:
7792                     if (listing)
7793                       printf("(FAILED: Not found or not accessible)\n");
7794                     else if (!nolist)
7795                       printf("?Not found or not accessible - %s\n",line);
7796                     rc = 0;
7797                     break;
7798                   case -4:
7799                     if (listing)
7800                       printf("(FAILED: Permission denied)\n");
7801                     else if (!nolist)
7802                       printf("?Permission denied - %s\n",line);
7803                     rc = 0;
7804                     break;
7805                   case -5:
7806                     if (listing)
7807                       printf("(Source and destination are the same file)\n");
7808                     else if (!nolist)
7809                       printf(
7810                           "?Source and destination are the same file - %s\n",
7811                           line
7812                           );
7813                     break;
7814                   case -6:
7815                     if (listing)
7816                       printf("(FAILED: Input/Output error)\n");
7817                     else if (!nolist)
7818                       printf("?Input/Output error - %s\n",line);
7819                     rc = 0;
7820                     break;
7821                   case -7:
7822                     if (listing)
7823                       printf("(FAILED: %s - %s)\n",p,ck_errstr());
7824                     else if (!nolist)
7825                       printf("?%s - %s\n",ck_errstr(),p);
7826                     rc = 0;
7827                     break;
7828                   default:
7829                     if (listing)
7830                       printf("(FAILED: %s)\n",ck_errstr());
7831                     else if (!nolist)
7832                       printf("?%s\n",ck_errstr());
7833                     rc = 0;
7834                 }
7835             } else {
7836                 if (listing) printf("(OK)\n");
7837             }
7838
7839         } else {                        /* Special options */
7840
7841             int prev, y, x = 0;         /* Variables needed for them */
7842             int i, t;
7843             char ibuf[100];
7844             char obuf[200];
7845             FILE * in = NULL;
7846             FILE * out = NULL;
7847
7848             if ((in = fopen(line,"r")) == NULL) { /* Open input file */
7849                 if (listing)
7850                   printf("(FAILED: %s)\n",ck_errstr());
7851                 else if (!nolist)
7852                   printf("?%s - %s)\n",ck_errstr(),line);
7853                 rc = 0;
7854                 continue;
7855             }
7856             if (targetisdir) {          /* Target is directory */
7857                 char * buf = NULL;      /* so append this filename to it */
7858                 zstrip(line,&buf);
7859                 p[targetlen] = NUL;
7860                 if (buf)
7861                   ckstrncat(p,buf,TMPBUFSIZ);
7862             }
7863 #ifdef OS2ORUNIX
7864             if (zcmpfn(line,p)) {       /* Input and output are same file? */
7865                 if (listing)
7866                   printf("(FAILED: Source and destination identical)\n");
7867                 else if (!nolist)
7868                   printf("?Source and destination identical - %s\n", line); 
7869                 rc = 0;
7870                 continue;
7871             }
7872 #endif /* OS2ORUNIX */
7873             if ((out = fopen(p, (appending ? "a" : "w"))) == NULL) {
7874                 fclose(in);
7875                 if (listing)
7876                   printf("(FAILED: %s - %s)\n",p,ck_errstr());
7877                 else if (!nolist)
7878                   printf("?%s - %s\n",p,ck_errstr());
7879                 rc = 0;
7880                 continue;
7881             }
7882 #ifndef NOSPL
7883             if (tob64) {                /* Converting to Base-64 */
7884
7885                 debug(F110,"COPY tob64",line,0);
7886
7887                 while (1) {             /* Loop... */
7888                     prev = x;
7889                     if ((x = fread(ibuf,1,54,in)) < 1) { /* EOF */
7890                         if (listing)
7891                           printf("(OK)\n");
7892                         break;
7893                     }
7894                     if (prev % 3) {
7895                         if (listing)
7896                           printf("(FAILED: Phase error at %d)\n",prev);
7897                         else if (!nolist)
7898                           printf("?Phase error at %d\n",prev);
7899                         rc = 0;
7900                         break;
7901                     }
7902                     if (swapping) {
7903                         if (x & 1) {
7904                             if (listing)
7905                               printf("(FAILED: Swap error)\n");
7906                             else if (!nolist)
7907                               printf("?Swap error\n");
7908                             rc = 0;
7909                             break;
7910                         }
7911                         for (i = 0; i < x; i+=2) {
7912                             t = ibuf[i];
7913                             ibuf[i] = ibuf[i+1];
7914                             ibuf[i+1] = t;
7915                         }
7916                     }
7917                     if ((y = b8tob64(ibuf,x,obuf,180)) < 0) {
7918                         if (listing)
7919                           printf("(FAILED: Encoding error)\n");
7920                         else if (!nolist)
7921                           printf("?Encoding error\n");
7922                         rc = 0;
7923                         break;
7924                     }
7925                     fprintf(out,"%s\n",obuf);
7926                 }
7927
7928             } else if (fromb64) {       /* Converting from Base 64 */
7929
7930                 debug(F110,"COPY fromb64",line,0);
7931
7932                 if ((out = fopen(p,appending ? "a" : "w")) == NULL) {
7933                     fclose(in);
7934                     if (listing)
7935                       printf("(FAILED: %s - %s)\n",p,ck_errstr());
7936                     else if (!nolist)
7937                       printf("?%s - %s\n",p,ck_errstr());
7938                     rc = 0;
7939                     continue;
7940                 }
7941                 x = 1;
7942                 while (x) {
7943                     x = fread(ibuf,1,80,in);
7944                     if ((y = b64tob8(ibuf,x,obuf,80)) < 0) {
7945                         if (listing)
7946                           printf("(FAILED: Decoding error)\n");
7947                         else if (!nolist)
7948                           printf("?Decoding error\n");
7949                         rc = 0;
7950                         break;
7951                     }
7952                     if (swapping) {
7953                         if (x & 1) {
7954                             if (listing)
7955                               printf("(FAILED: Swap error)\n");
7956                             else if (!nolist)
7957                               printf("?Swap error\n");
7958                             rc = 0;
7959                             break;
7960                         }
7961                         for (i = 0; i < y; i+=2) {
7962                             t = obuf[i];
7963                             obuf[i] = obuf[i+1];
7964                             obuf[i+1] = t;
7965                         }
7966                     }
7967                     if (y > 0) {
7968                         if (fwrite(obuf,1,y,out) < 1) {
7969                             if (listing)
7970                               printf("(FAILED: %s - %s)\n",p,ck_errstr());
7971                             else if (!nolist)
7972                               printf("?%s - %s\n",p,ck_errstr());
7973                             rc = 0;
7974                             break;
7975                         }
7976                     }
7977                 }
7978
7979             } else
7980 #endif /* NOSPL */
7981
7982             if (swapping) {             /* Swapping bytes */
7983
7984                 CHAR c[3];
7985                 c[2] = NUL;
7986
7987                 debug(F110,"COPY swapping",line,0);
7988
7989                 while (1) {
7990                     x = fread((char *)c,1,2,in);
7991                     if (x < 1) {
7992                         if (listing)
7993                           printf("(OK)\n");
7994                         break;
7995                     } else if (x == 1) {
7996                         c[1] = c[0];
7997                         c[0] = NUL;
7998                         printf(
7999                             "(WARNING: Odd byte count)");
8000                         if (!listing) printf("\n");
8001                     }
8002                     if (fprintf(out,"%c%c",c[1],c[0]) == EOF) {
8003                         if (listing)
8004                           printf("(FAILED: %s - %s)\n",p,ck_errstr());
8005                         else if (!nolist)
8006                           printf("?%s - %s\n",p,ck_errstr());
8007                         rc = 0;
8008                         break;
8009                     }
8010                 }
8011
8012             } else if (appending) {     /* Appending to target file */
8013
8014                 char c;
8015
8016                 debug(F110,"COPY appending",line,0);
8017
8018                 while (1) {
8019                     x = fread(&c,1,1,in);
8020                     if (x < 1) {
8021                         if (listing)
8022                           printf("(OK)\n");
8023                         break;
8024                     }
8025                     if (fwrite(&c,1,1,out) < 1) {
8026                         if (listing)
8027                           printf("(FAILED: %s - %s)\n",p,ck_errstr());
8028                         else if (!nolist)
8029                           printf("?%s - %s\n",p,ck_errstr());
8030                         rc = 0;
8031                         break;
8032                     }
8033                 }
8034             }
8035             if (out) fclose(out);
8036             if (in) fclose(in);
8037         }
8038 #ifdef VMSORUNIX
8039         concb((char)escape);
8040 #endif /* VMSORUNIX */
8041     }
8042     if (rc > -1) success = rc;
8043     return(rc);
8044 }
8045 #endif /* ZCOPY */
8046 #endif /* NOFRILLS */
8047
8048 #ifndef NORENAME
8049 #ifndef NOFRILLS
8050 #ifdef ZRENAME
8051 int
8052 dorenam() {
8053     /* Parse a file or a directory name */
8054     int i, x, z, listing = 0, havename = 0, wild = 0, rc = 1;
8055     int nolist = 0;
8056     struct FDB sw, fi;
8057
8058     cmfdbi(&sw,                         /* 2nd FDB - optional /PAGE switch */
8059            _CMKEY,                      /* fcode */
8060            "Filename or switch",        /* hlpmsg */
8061            "",                          /* default */
8062            "",                          /* addtl string data */
8063            nqvswtab,                    /* addtl numeric data 1: tbl size */
8064            4,                           /* addtl numeric data 2: 4 = cmswi */
8065            xxstring,                    /* Processing function */
8066            qvswtab,                     /* Keyword table */
8067            &fi                          /* Pointer to next FDB */
8068            );
8069
8070     cmfdbi(&fi,                         /* 1st FDB - file to type */
8071            _CMIFI,                      /* fcode */
8072            "",                          /* hlpmsg */
8073            "",                          /* default */
8074            "",                          /* addtl string data */
8075            3,                           /* addtl numeric data 1 */
8076            0,                           /* addtl numeric data 2 */
8077            xxstring,
8078            NULL,
8079            NULL
8080            );
8081
8082     while (!havename) {
8083         x = cmfdb(&sw);                 /* Parse something */
8084         if (x < 0)                      /* Error */
8085           return(x);
8086         switch (cmresult.fcode) {
8087           case _CMKEY:
8088             switch (cmresult.nresult) {
8089               case DEL_LIS:
8090               case DEL_VRB:
8091                 listing = 1;
8092                 break;
8093               case DEL_NOL:
8094               case DEL_QUI:
8095                 nolist = 1;
8096                 listing = 0;
8097                 break;
8098             }
8099             break;
8100           case _CMIFI:
8101             s = cmresult.sresult;
8102             havename = 1;
8103             break;
8104           default:
8105             return(-2);
8106         }
8107     }
8108     wild = cmresult.nresult;            /* Source specification wild? */
8109
8110     ckstrncpy(line,s,LINBUFSIZ);        /* Make a safe copy of source name */
8111     s = line;
8112
8113     if (!wild)
8114       wild = iswild(line);
8115
8116     p = tmpbuf;                         /* Place for new name */
8117     if ((x = cmofi(wild ? "Target directory" : "New name",
8118                    "",&s,xxstring)) < 0) { /* Get new name */
8119         if (x == -3) {
8120             printf("?%s required\n", wild ? "Target directory" : "New name");
8121             return(-9);
8122         } else return(x);
8123     }
8124     ckstrncpy(p,s,TMPBUFSIZ);           /* Make a safe copy of the new name */
8125     if ((y = cmcfm()) < 0) return(y);
8126
8127     if (!wild) {                        /* Just one */
8128         if (listing) printf("%s => %s ",line,p);
8129         if (zrename(line,p) < 0) {
8130             if (listing)
8131               printf("(FAILED: %s)\n",ck_errstr());
8132             else if (!nolist)
8133               printf("?%s\n",ck_errstr());
8134             rc = 0;
8135         } else {
8136             if (listing) printf("(OK)\n");
8137         }
8138         return(success = rc);
8139     }
8140     if (!isdir(p)) {                    /* Multiple */
8141         printf(                         /* if target is not a directory */
8142 "?Multiple source files not allowed if target is not a directory.\n");
8143         return(-9);
8144     }
8145 #ifdef COMMENT
8146     else {                              /* Show full path of target */
8147         char buf[CKMAXPATH];            /* (too much) */
8148         if (zfnqfp(p,CKMAXPATH,buf))
8149           ckstrncpy(tmpbuf,buf,TMPBUFSIZ);
8150     }
8151 #endif /* COMMENT */
8152
8153 #ifdef VMS
8154     conres();                           /* Let Ctrl-C work. */
8155 #endif /* VMS */
8156     debug(F110,"dorename line",line,0);
8157
8158 #ifdef ZXREWIND
8159     z = zxrewind();                     /* Rewind file list */
8160 #else
8161     z = nzxpand(s,0);                   /* Expand file list */
8162 #endif /* ZXREWIND */
8163     debug(F111,"dorename p",p,z);
8164
8165 #ifdef UNIX
8166     if (wild && z > 1)
8167       sh_sort(mtchs,NULL,z,0,0,filecase); /* Alphabetize the filename list */
8168 #endif /* UNIX */
8169
8170 /*
8171   Note: COPY, RENAME, DELETE and similar commands should have options to
8172   stop or proceed when they are operating on multiple files and the operation
8173   fails.
8174 */
8175     while (z-- > 0) {
8176         if (!(z == 0 && !wild))
8177           znext(line);
8178         if (!line[0])
8179           break;
8180         if (listing) printf("%s => %s ",line,p);
8181         if (zrename(line,p) < 0) {
8182             if (listing)
8183               printf("(FAILED: %s)\n",ck_errstr());
8184             else if (!nolist)
8185               printf("?%s - %s\n",ck_errstr(),line);
8186             rc = 0;
8187         } else {
8188             if (listing) printf("(OK)\n");
8189         }
8190     }
8191 #ifdef VMS
8192     concb((char)escape);
8193 #endif /* VMS */
8194     return(success = rc);
8195 }
8196 #endif /* ZRENAME */
8197 #endif /* NOFRILLS */
8198 #endif /* NORENAME */
8199
8200 #ifndef NOSPL
8201
8202 /* Do the RETURN command */
8203
8204 int
8205 doreturn(s) char *s; {
8206     int x;
8207     extern int tra_asg;
8208     char * line, * lp;
8209
8210     if (cmdlvl < 1) {
8211         printf("\n?Can't return from level %d\n",maclvl);
8212         return(success = 0);
8213     }
8214     line = malloc(LINBUFSIZ);
8215     if (line == NULL)
8216       return(success = 0);
8217     lp = line;                          /* Expand return value now */
8218     x = LINBUFSIZ-1;
8219     if (!s) s = "";
8220     debug(F110,"RETURN s",s,0);
8221     if (zzstring(s,&lp,&x) > -1) {
8222         s = line;
8223         debug(F110,"RETURN zzstring",s,0);
8224     }
8225
8226     /* Pop from all FOR/WHILE/SWITCH/XIFs */
8227     while ((maclvl > 0) &&
8228            (m_arg[maclvl-1][0]) &&
8229            (cmdstk[cmdlvl].src == CMD_MD) &&
8230            (!strncmp(m_arg[maclvl-1][0],"_xif",4) ||
8231             !strncmp(m_arg[maclvl-1][0],"_for",4) ||
8232             !strncmp(m_arg[maclvl-1][0],"_swi",4) ||
8233             !strncmp(m_arg[maclvl-1][0],"_whi",4))) {
8234         debug(F111,"RETURN IF/FOR/WHI/SWI pop",m_arg[maclvl-1][0],maclvl);
8235         dogta(XXPTA);                   /* Put args back */
8236         popclvl();                      /* Pop up two levels */
8237         popclvl();
8238     }
8239     if (tra_asg) {                      /* If tracing show return value */
8240         if (*s)
8241           printf("<<< %s: \"%s\"\n", m_arg[maclvl][0], s);
8242         else
8243           printf("<<< %s: (null)\n", m_arg[maclvl][0]);
8244     }
8245     popclvl();                          /* Pop from enclosing TAKE or macro */
8246     debug(F111,"RETURN tolevel",s,maclvl);
8247     if (!s) s = "";
8248     if (!*s) s = NULL;
8249     makestr(&(mrval[maclvl+1]),s);      /* Set the RETURN value */
8250     free(line);
8251     return(success = 1);                /* Macro succeeds if we RETURN */
8252 }
8253 #endif /* NOSPL */
8254
8255 #ifndef NOSPL
8256 /* Do the OPEN command */
8257
8258 int
8259 doopen()  {                             /* OPEN { append, read, write } */
8260     int x, y, z = 0; char *s;
8261     static struct filinfo fcb;          /* (must be static) */
8262     if ((x = cmkey(opntab,nopn,"mode","",xxstring)) < 0) {
8263         if (x == -3) {
8264             printf("?Mode required\n");
8265             return(-9);
8266         } else return(x);
8267     }
8268     switch (x) {
8269       case OPN_FI_R:                    /* Old file (READ) */
8270         if (chkfn(ZRFILE) > 0) {
8271             printf("?Read file already open\n");
8272             return(-2);
8273         }
8274         if ((z = cmifi("File to read","",&s,&y,xxstring)) < 0) {
8275             if (z == -3) {
8276                 printf("?Input filename required\n");
8277                 return(-9);
8278             } else return(z);
8279         }
8280         if (y) {                                /* No wildcards allowed */
8281             printf("\n?Please specify a single file\n");
8282             return(-2);
8283         }
8284         ckstrncpy(line,s,LINBUFSIZ);
8285         if ((int)strlen(line) < 1) return(-2);
8286         if ((z = cmnum("buffer size","4096",10,&y,xxstring)) < 0)
8287           return(z);
8288         if (y < 1) {
8289             printf("?Positive number required\n");
8290             return(-9);
8291         }
8292         if ((z = cmcfm()) < 0) return(z);
8293         readblock = y;
8294         if (readbuf)
8295           free((char *)readbuf);
8296         if (!(readbuf = (CHAR *) malloc(readblock+1))) {
8297             printf("?Can't allocate read buffer\n");
8298             return(-9);
8299         }
8300         return(success = zopeni(ZRFILE,line));
8301
8302 #ifndef MAC
8303 #ifndef NOPUSH
8304       case OPN_PI_R:                    /* Pipe/Process (!READ) */
8305         if (nopush) {
8306             printf("?Read from pipe disabled\n");
8307             return(success=0);
8308         }
8309         if (chkfn(ZRFILE) > 0) {
8310             printf("?Read file already open\n");
8311             return(-2);
8312         }
8313         if ((y = cmtxt("System command to read from","",&s,xxstring)) < 0) {
8314             if (y == -3) {
8315                 printf("?Command name required\n");
8316                 return(-9);
8317             } else return(y);
8318         }
8319         ckstrncpy(line,brstrip(s),LINBUFSIZ);
8320         if (!line[0]) return(-2);
8321         if ((y = cmcfm()) < 0) return(y);
8322         if (!readbuf) {
8323             if (!(readbuf = (CHAR *) malloc(readblock+1))) {
8324                 printf("?Can't allocate read buffer\n");
8325                 return(-9);
8326             }
8327         }
8328         return(success = zxcmd(ZRFILE,line));
8329
8330       case OPN_PI_W:                    /* Write to pipe */
8331         if (nopush) {
8332             printf("?Write to pipe disabled\n");
8333             return(success=0);
8334         }
8335         if (chkfn(ZWFILE) > 0) {
8336             printf("?Write file already open\n");
8337             return(-2);
8338         }
8339         if ((y = cmtxt("System command to write to","",&s,xxstring)) < 0) {
8340             if (y == -3) {
8341                 printf("?Command name required\n");
8342                 return(-9);
8343             } else return(y);
8344         }
8345         ckstrncpy(line,brstrip(s),LINBUFSIZ);
8346         if (!line[0]) return(-2);
8347         if ((y = cmcfm()) < 0) return(y);
8348         success = zxcmd(ZWFILE,line);
8349         if (!success && msgflg)
8350           printf("Can't open process for writing: %s\n",line);
8351         return(success);
8352 #endif /* NOPUSH */
8353 #endif /* MAC */
8354
8355       case OPN_FI_W:                    /* New file (WRITE) */
8356       case OPN_FI_A:                    /* (APPEND) */
8357         if ((z = cmofi("Name of local file to create","",&s,xxstring)) < 0) {
8358             if (z == -3) {
8359                 printf("?Filename required\n");
8360                 return(-9);
8361             } else return(z);
8362         }
8363         if (z == 2) {
8364             printf("?Sorry, %s is a directory name\n",s);
8365             return(-9);
8366         }
8367         if (chkfn(ZWFILE) > 0) {
8368             printf("?Write/Append file already open\n");
8369             return(-2);
8370         }
8371         fcb.bs = fcb.cs = fcb.rl = fcb.fmt = fcb.org = fcb.cc = fcb.typ = 0;
8372         fcb.lblopts = 0;
8373         fcb.dsp = (x == OPN_FI_W) ? XYFZ_N : XYFZ_A; /* Create or Append */
8374         ckstrncpy(line,s,LINBUFSIZ);
8375         if ((int)strlen(line) < 1) return(-2);
8376         if ((y = cmcfm()) < 0) return(y);
8377         return(success = zopeno(ZWFILE,line,NULL,&fcb));
8378
8379 #ifndef NOLOCAL
8380       case OPN_SER:                     /* OPEN PORT or LINE */
8381       case OPN_NET: {                   /* OPEN HOST */
8382           extern int didsetlin, ttnproto;
8383           if (x == OPN_NET) {
8384               z = ttnproto;
8385               ttnproto = NP_NONE;
8386           }
8387           if ((y = setlin((x == OPN_SER) ? XYLINE : XYHOST, 1, 0)) < 0) {
8388               if (x == OPN_NET)
8389                 ttnproto = z;
8390               success = 0;
8391           }
8392           didsetlin++;
8393           return(y);
8394       }
8395 #endif /* NOLOCAL */
8396
8397       default:
8398         printf("?Not implemented");
8399         return(-2);
8400     }
8401 }
8402 #endif /* NOSPL */
8403
8404 #ifndef NOXFER
8405 /*  D O X G E T  --  GET command parser with switches  */
8406
8407 #ifdef CK_LABELED
8408 int g_lf_opts = -1;
8409 extern int lf_opts;
8410 #endif /* CK_LABELED */
8411
8412 int
8413 doxget(cx) int cx; {
8414     extern int                          /* External variables we need */
8415 #ifdef RECURSIVE
8416       recursive,
8417 #endif /* RECURSIVE */
8418       xfermode, fdispla, protocol, usepipes,
8419       g_binary, g_xfermode, g_displa, g_rpath, g_usepipes;
8420     extern char * rcv_move;             /* Directory to move new files to */
8421     extern char * rcv_rename;           /* What to rename new files to */
8422     extern char * rcvexcept[];          /* RECEIVE / GET exception list */
8423     int opkt  =  0;                     /* Flag for O-Packet needed */
8424
8425 #ifdef PIPESEND
8426     extern int pipesend;
8427     extern char * rcvfilter;
8428 #endif /* PIPESEND */
8429     extern struct keytab rpathtab[];
8430     extern int nrpathtab;
8431     extern long calibrate;
8432     int asname = 0;                     /* Flag for have as-name */
8433     int konly = 0;                      /* Kermit-only function */
8434     int c, i, n, confirmed = 0;         /* Workers */
8435     int getval = 0;                     /* Whether to get switch value */
8436     int rcvcmd = 0;                     /* Whether it is the RECEIVE command */
8437     int mget = 0;                       /* Whether it is the MGET command */
8438     struct stringint {                  /* Temporary array for switch values */
8439         char * sval;
8440         int ival;
8441     } pv[SND_MAX+1];
8442     struct FDB sw, fl, cm;              /* FDBs for each parse function */
8443     char * cmdstr = "this command";
8444
8445 #ifdef NEWFTP
8446     if (cx == XXGET || cx == XXREGET || cx == XXMGET || cx == XXRETR) {
8447         extern int ftpget;
8448         extern int ftpisopen();
8449         if ((ftpget == 1) || ((ftpget == 2) && ftpisopen()))
8450           return(doftpget(cx,0));
8451     }
8452 #endif /* NEWFTP */
8453
8454     debug(F101,"xget cx","",cx);
8455
8456     oopts = -1;
8457     omode = -1;
8458
8459     for (i = 0; i <= SND_MAX; i++) {    /* Initialize switch values */
8460         pv[i].sval = NULL;
8461         pv[i].ival = -1;
8462     }
8463     /* Preset switch values based on top-level command that called us */
8464
8465     switch (cx) {
8466       case XXREC:                       /* RECEIVE */
8467         cmdstr = "RECEIVE";
8468         rcvcmd = 1; break;
8469       case XXGET:                       /* GET */
8470         cmdstr = "GET";
8471         konly = 1;
8472         break;
8473 #ifdef CK_RESEND
8474       case XXREGET:                     /* REGET */
8475         cmdstr = "REGET";
8476         konly = 1;
8477         pv[SND_BIN].ival = 1;           /* Implies /BINARY */
8478         pv[SND_RES].ival = 1; break;
8479 #endif /* CK_RESEND */
8480       case XXRETR:                      /* RETRIEVE */
8481         cmdstr = "RETRIEVE";
8482         konly = 1;
8483         pv[SND_DEL].ival = 1; break;
8484 #ifdef PIPESEND
8485       case XXCREC:                      /* CRECEIVE */
8486         cmdstr = "CRECEIVE";
8487         konly = 1;
8488         rcvcmd = 1;
8489         pv[SND_CMD].ival = 1; break;
8490       case XXCGET:                      /* CGET */
8491         cmdstr = "CGET";
8492         konly = 1;
8493         pv[SND_CMD].ival = 1; break;
8494 #endif /* PIPESEND */
8495 #ifndef NOMGET
8496       case XXMGET:                      /* MGET */
8497         cmdstr = "MGET";
8498         konly = 1;
8499         mget = 1; break;
8500 #endif /* NOMGET */
8501     }
8502     debug(F111,"xget rcvcmd",cmdstr,rcvcmd);
8503     debug(F101,"xget konly","",konly);
8504
8505 #ifdef CK_XYZ
8506     if (!rcvcmd && protocol != PROTO_K) {
8507         printf("?Sorry, %s works only with Kermit protocol\n",cmdstr);
8508         return(-9);
8509     }
8510 #endif /* CK_XYZ */
8511
8512     /* Set up chained parse functions... */
8513
8514     cmfdbi(&sw,                         /* First FDB - command switches */
8515            _CMKEY,                      /* fcode */
8516            rcvcmd ?
8517            "Optional name/template to store incoming files under, or switch" :
8518            "Remote filename, or switch", /* hlpmsg */
8519            "",                          /* default */
8520            "",                          /* addtl string data */
8521            rcvcmd ? nrcvtab : ngettab,  /* addtl numeric data 1: tbl size */
8522            4,                           /* addtl numeric data 2: 4 = cmswi */
8523            xxstring,                    /* Processing function */
8524            rcvcmd ? rcvtab : gettab,    /* Keyword table */
8525            &fl                          /* Pointer to next FDB */
8526            );
8527     if (rcvcmd || mget)                 /* RECEIVE or MGET */
8528       cmfdbi(&fl,
8529            _CMTXT,                      /* fcode */
8530            rcvcmd ?                     /* hlpmsg */
8531              "Output filename or Command" : /* Output filename */
8532              "File(s) to GET",              /* Files we are asking for */
8533            "",                          /* default */
8534            "",                          /* addtl string data */
8535            0,                           /* addtl numeric data 1 */
8536            0,                           /* addtl numeric data 2 */
8537 #ifdef CK_XYZ
8538            (protocol == PROTO_X || protocol == PROTO_XC) ?
8539              xxstring :
8540              (rcvcmd ? (xx_strp)0  : xxstring)
8541 #else
8542            rcvcmd ? (xx_strp)0  : xxstring /* Processing function */
8543 #endif /* CK_XYZ */
8544              ,
8545            NULL,
8546            &cm
8547            );
8548     else
8549       cmfdbi(&fl,                       /* Remote filename or command */
8550            _CMFLD,                      /* fcode */
8551            "Remote filename",           /* hlpmsg */
8552            "",                          /* default */
8553            "",                          /* addtl string data */
8554            0,                           /* addtl numeric data 1 */
8555            0,                           /* addtl numeric data 2 */
8556            xxstring,
8557            NULL,
8558            &cm
8559            );
8560     cmfdbi(&cm,                         /* Confirmation */
8561            _CMCFM,                      /* fcode */
8562            "",                          /* hlpmsg */
8563            "",                          /* default */
8564            "",                          /* addtl string data */
8565            0,                           /* addtl numeric data 1 */
8566            0,                           /* addtl numeric data 2 */
8567            NULL,
8568            NULL,
8569            NULL
8570            );
8571
8572     /* (See doxsend() for fuller commentary) */
8573
8574     while (1) {                         /* Parse 0 or more switches */
8575         x = cmfdb(&sw);                 /* Parse something */
8576         debug(F101,"xget cmfdb","",x);
8577         if (x < 0)                      /* Error */
8578           goto xgetx;                   /* or reparse needed */
8579         if (cmresult.fcode != _CMKEY)   /* Break out if not a switch */
8580           break;
8581         c = cmgbrk();                   /* Get break character */
8582         if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
8583             printf("?This switch does not take an argument\n");
8584             x = -9;
8585             goto xgetx;
8586         }
8587         if (!getval && (cmgkwflgs() & CM_ARG)) {
8588             printf("?This switch requires an argument\n");
8589             x = -9;
8590             goto xgetx;
8591         }
8592         n = cmresult.nresult;           /* Numeric result = switch value */
8593         debug(F101,"xget switch","",n);
8594
8595         switch (n) {                    /* Process the switch */
8596 #ifdef PIPESEND
8597           case SND_CMD:                 /* These take no args */
8598             if (nopush) {
8599                 printf("?Sorry, system command access is disabled\n");
8600                 x = -9;
8601                 goto xgetx;
8602             } else if (rcvfilter) {
8603                 printf(
8604 "?Sorry, no GET /COMMAND when RECEIVE FILTER selected\n");
8605                 x = -9;
8606                 goto xgetx;
8607             }
8608             if (rcvcmd)
8609               sw.hlpmsg = "Command, or switch"; /* Change help message */
8610             /* Fall thru... */
8611 #endif /* PIPESEND */
8612
8613           case SND_REC:                 /* /RECURSIVE */
8614             pv[SND_PTH].ival = PATH_REL; /* Implies relative pathnames */
8615             pv[n].ival = 1;             /* Set the recursive flag */
8616             break;
8617
8618           case SND_RES:                 /* /RECOVER */
8619             pv[SND_BIN].ival = 1;       /* Implies /BINARY */
8620             pv[n].ival = 1;             /* Set the resend flag */
8621             break;
8622
8623           case SND_DEL:                 /* /DELETE */
8624           case SND_SHH:                 /* /QUIET */
8625           case SND_CAL:                 /* /CALIBRATE */
8626           case SND_XPA:                 /* /TRANSPARENT */
8627             pv[n].ival = 1;             /* Just set the appropriate flag */
8628             break;
8629
8630           case SND_PIP:                 /* /PIPES:{ON,OFF} */
8631             if (!getval) {
8632                 pv[n].ival = 1;
8633                 break;
8634             }
8635             if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
8636               goto xgetx;
8637             if (!nopush)
8638               pv[n].ival = x;
8639             break;
8640
8641           /* File transfer modes - each undoes the others */
8642
8643           case SND_BIN:                 /* Binary */
8644           case SND_TXT:                 /* Text */
8645           case SND_IMG:                 /* Image */
8646           case SND_LBL:                 /* Labeled */
8647             pv[SND_BIN].ival = 0;       /* Unset all */
8648             pv[SND_TXT].ival = 0;
8649             pv[SND_IMG].ival = 0;
8650             pv[SND_LBL].ival = 0;
8651             pv[n].ival = 1;             /* Set the requested one */
8652             break;
8653
8654           case SND_EXC:                 /* Excludes */
8655             if (!getval) break;
8656             if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
8657                 if (x == -3) {
8658                     printf("?Pattern required\n");
8659                     x = -9;
8660                 }
8661                 goto xgetx;
8662             }
8663             if (pv[n].sval) free(pv[n].sval);
8664             y = strlen(s);
8665             if (y > 256) {
8666                 printf("?Pattern too long - 256 max\n");
8667                 x = -9;
8668                 goto xgetx;
8669             }
8670             pv[n].sval = malloc(y+1);
8671             if (pv[n].sval) {
8672                 strcpy(pv[n].sval,s);   /* safe */
8673                 pv[n].ival = 1;
8674             }
8675             break;
8676
8677 #ifdef COMMENT
8678           /* Not implemented */
8679           case SND_PRI:                 /* GET to printer */
8680             pv[n].ival = 1;
8681             if (!getval) break;
8682             if ((x = cmfld("Print options","",&s,xxstring)) < 0)
8683               goto xgetx;
8684             pv[n].sval = malloc((int)strlen(s)+1);
8685             if (pv[n].sval)
8686               strcpy(pv[n].sval,s);     /* safe */
8687             break;
8688 #endif /* COMMENT */
8689
8690           case SND_MOV:                 /* MOVE after */
8691           case SND_REN:                 /* RENAME after */
8692             if (!getval) break;
8693             if ((x = cmfld(n == SND_MOV ?
8694            "device and/or directory for source file after sending" :
8695            "new name for source file after sending",
8696                            "",
8697                            &s,
8698                            n == SND_MOV ? xxstring : NULL
8699                            )) < 0) {
8700                 if (x == -3) {
8701                     printf("%s\n", n == SND_MOV ?
8702                            "?Destination required" :
8703                            "?New name required"
8704                            );
8705                     x = -9;
8706                 }
8707                 goto xgetx;
8708             }
8709             if (pv[n].sval) {
8710                 free(pv[n].sval);
8711                 pv[n].sval = NULL;
8712             }
8713             s = brstrip(s);
8714             y = strlen(s);
8715             if (y > 0) {
8716                 pv[n].sval = malloc(y+1);
8717                 if (pv[n].sval) {
8718                     strcpy(pv[n].sval,s); /* safe */
8719                     pv[n].ival = 1;
8720                 }
8721             }
8722             break;
8723
8724           case SND_ASN:                 /* As-name */
8725             if (!getval) break;
8726             if (mget) {
8727                 printf("?Sorry, as-name not allowed with MGET\n");
8728                 x = -9;
8729                 goto xgetx;
8730             }
8731             if ((x = cmfld("Name to store it under","",&s,NULL)) < 0)
8732               goto xgetx;
8733             s = brstrip(s);
8734             if ((y = strlen(s)) > 0) {
8735                 if (pv[n].sval) free(pv[n].sval);
8736                 pv[n].sval = malloc(y+1);
8737                 if (pv[n].sval) {
8738                     strcpy(pv[n].sval,s); /* safe */
8739                     pv[n].ival = 1;
8740                 }
8741             }
8742             break;
8743
8744 #ifdef PIPESEND
8745           case SND_FLT:                 /* Filter */
8746             debug(F101,"xget /filter getval","",getval);
8747             if (!getval) break;
8748             if ((x = cmfld("Filter program to receive through",
8749                            "",&s,NULL)) < 0) {
8750                 if (x == -3)
8751                   s = "";
8752                 else
8753                   goto xgetx;
8754             }
8755             if (*s) s = brstrip(s);
8756             y = strlen(s);
8757             for (x = 0; x < y; x++) {   /* Make sure they included "\v(...)" */
8758                 if (s[x] != '\\') continue;
8759                 if (s[x+1] == 'v') break;
8760             }
8761             if (x == y) {
8762                 printf(
8763                 "?Filter must contain a replacement variable for filename.\n"
8764                        );
8765                 x = -9;
8766                 goto xgetx;
8767             }
8768             pv[n].ival = 1;
8769             if (pv[n].sval) {
8770                 free(pv[n].sval);
8771                 pv[n].sval = NULL;
8772             }
8773             if ((y = strlen(s)) > 0) {
8774                 if ((pv[n].sval = malloc(y+1)))
8775                   strcpy(pv[n].sval,s); /* safe */
8776             }
8777             break;
8778 #endif /* PIPESEND */
8779
8780           case SND_PTH:                 /* Pathnames */
8781             if (!getval) {
8782                 pv[n].ival = PATH_REL;
8783                 break;
8784             }
8785             if ((x = cmkey(rpathtab,nrpathtab,"","on",xxstring)) < 0)
8786               goto xgetx;
8787             pv[n].ival = x;             /* Ditto */
8788             break;
8789
8790           case SND_NAM:                 /* Filenames */
8791             if (!getval) break;
8792             if ((x = cmkey(fntab,nfntab,"","converted",xxstring)) < 0)
8793               goto xgetx;
8794             pv[n].ival = x;
8795             break;
8796
8797           case SND_PRO:                 /* Protocol to use */
8798             if (!getval) break;
8799             if ((x = cmkey(protos,nprotos,"File-transfer protocol","",
8800                            xxstring)) < 0) {
8801                 if (x == -3)
8802                   x = 0;
8803                 else
8804                   goto xgetx;
8805             }
8806             debug(F111,"xget /proto",atmbuf,x);
8807             pv[n].ival = x;
8808             if (konly && x != PROTO_K) {
8809                 printf(
8810 "?Sorry, this command works only with Kermit protocol\n"
8811                        );
8812                 x = -9;
8813                 goto xgetx;
8814             }
8815             break;
8816
8817           default:
8818             printf("?Unexpected switch value - %d\n",cmresult.nresult);
8819             x = -9;
8820             goto xgetx;
8821         }
8822     }
8823     debug(F101,"xget cmresult fcode","",cmresult.fcode);
8824
8825     cmarg = line;                       /* Initialize string pointers */
8826     cmarg2 = tmpbuf;
8827     asname = 0;
8828     line[0] = NUL;                      /* and buffers. */
8829     tmpbuf[0] = NUL;
8830
8831     switch (cmresult.fcode) {           /* How did we get out of switch loop */
8832       case _CMFLD:                      /* (3) Remote filespec */
8833         ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
8834         break;
8835       case _CMTXT:                      /* (4) As-name */
8836         if (rcvcmd) {
8837             ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ);
8838             if ((int)strlen(tmpbuf) > 0)
8839               asname = 1;
8840         } else {
8841             ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
8842         }
8843       case _CMCFM:                      /* (6) Confirmation */
8844         confirmed = 1;
8845         break;
8846       default:
8847         printf("?Unexpected function code: %d\n",cmresult.fcode);
8848         x = -9;
8849         goto xgetx;
8850     }
8851     debug(F110,"xget string",cmarg,0);
8852     debug(F101,"xget confirmed","",confirmed);
8853
8854     cmarg = brstrip(cmarg);             /* Strip any braces */
8855
8856     if (!confirmed) {                   /* CR not typed yet, get more fields */
8857         if (pv[SND_CMD].ival > 0) {
8858             debug(F100,"xget calling cmtxt","",0);
8859             x = cmtxt("Local command to pipe into","",&s,NULL);
8860             if (x < 0 && x != -3) goto xgetx;
8861             if (x != -3) {
8862                 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
8863                 asname = 1;
8864             }
8865         } else if (!rcvcmd) {
8866 #ifdef VMS
8867             /* cmofi() fails if you give it a directory name */
8868             x = cmfld("Name or directory for incoming file","",&s,NULL);
8869             debug(F111,"xget cmfld",s,x);
8870 #else
8871             x = cmofi("Name or directory for incoming file","",&s,NULL);
8872             debug(F111,"xget cmofi",s,x);
8873 #endif /* VMS */
8874             if (x < 0 && x != -3) goto xgetx;
8875             if (x != -3) {
8876                 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
8877                 if ((x = cmcfm()) < 0) goto xgetx;
8878                 asname = 1;
8879             }
8880         }
8881     }
8882     /* Arrive here with cmarg and cmarg2 all set */
8883
8884     debug(F111,"xget asname",cmarg2,asname);
8885     if (!asname) {
8886         if (pv[SND_ASN].sval)
8887           ckstrncpy(tmpbuf,pv[SND_ASN].sval,TMPBUFSIZ);
8888         else
8889           tmpbuf[0] = NUL;
8890     }
8891     cmarg2 = brstrip(cmarg2);           /* Strip outer braces if any. */
8892     debug(F110,"xget cmarg",cmarg,0);
8893     debug(F110,"xget cmarg2",cmarg2,0);
8894
8895     if (!*cmarg &&
8896         (cx == XXGET || cx == XXREGET || cx == XXCGET || cx == XXMGET)) {
8897         printf("?A remote file specification is required\n");
8898         x = -9;
8899         goto xgetx;
8900     }
8901 #ifdef PIPESEND
8902     if (pv[SND_CMD].ival > 0) {         /* /COMMAND sets pipesend flag */
8903         x = -9;
8904         if (!*cmarg2) {
8905             printf("?Command required\n");
8906             goto xgetx;
8907         } else if (nopush) {
8908             printf("?Sorry, system command access is disabled\n");
8909             goto xgetx;
8910         } else if (rcvfilter) {
8911             printf("?Sorry, no GET /COMMAND while RECEIVE FILTER selected\n");
8912             goto xgetx;
8913         } else
8914           pipesend = 1;
8915     }
8916     debug(F101,"xget /COMMAND pipesend","",pipesend);
8917 #endif /* PIPESEND */
8918
8919 #ifdef CK_RESEND
8920     if (pv[SND_RES].ival > 0) {         /* REGET or GET /RECOVER */
8921 #ifdef RECURSIVE
8922         if (pv[SND_REC].ival > 0) {     /* RECURSIVE */
8923 #ifdef COMMENT
8924             printf("?Unsupported option combination: /RECOVER /RECURSIVE\n");
8925             x = -9;
8926             goto xgetx;
8927 #else
8928             opkt = 1;
8929 #endif /* COMMENT */
8930         }
8931 #endif /* RECURSIVE */
8932         if (pv[SND_DEL].ival > 0) {     /* /DELETE */
8933 #ifdef COMMENT
8934             printf("?Unsupported option combination: /RECOVER /DELETE\n");
8935             x = -9;
8936             goto xgetx;
8937 #else
8938             opkt = 1;
8939 #endif /* COMMENT */
8940         }
8941     }
8942 #endif /* CK_RESEND */
8943
8944     if (pv[SND_EXC].ival > 0)           /* /EXCEPT */
8945       makelist(pv[SND_EXC].sval,rcvexcept,NSNDEXCEPT);
8946
8947 #ifdef IKS_OPTION
8948     if (!rcvcmd
8949 #ifdef CK_XYZ
8950          && protocol == PROTO_K
8951 #endif /* CK_XYZ */
8952          ) {
8953         if (!iks_wait(KERMIT_REQ_START,1)) {
8954             printf(
8955               "?A Kermit Server is not available to process this command\n");
8956             x = -9;                     /* correct the return code */
8957             goto xgetx;
8958         }
8959     }
8960 #endif /* IKS_OPTION */
8961
8962 #ifdef CK_XYZ
8963     {
8964         int po, pg;                     /* (for clarity) */
8965         po = pv[SND_PRO].ival;          /* /PROTOCOL option */
8966         pg = protocol;                  /* Protocol global  */
8967         if ((rcvcmd && !*cmarg2) &&     /* If no as-name was given */
8968             /* and /PROTOCOL is XMODEM or global protocol is XMODEM... */
8969             ((po <  0 && (pg == PROTO_X || pg == PROTO_XC)) ||
8970              (po > -1 && (po == PROTO_X || po == PROTO_XC)))
8971             ) {
8972             printf(
8973 "Sorry, you must specify a name when receiving a file with XMODEM protocol\n"
8974                    );
8975             x = -9;
8976             goto xgetx;
8977         }
8978     }
8979 #endif /* CK_XYZ */
8980
8981 #ifdef RECURSIVE
8982     if (pv[SND_REC].ival > 0) {         /* RECURSIVE */
8983         recursive = 1;
8984         pv[SND_PTH].ival = PATH_REL;    /* Implies relative pathnames too */
8985     }
8986 #endif /* RECURSIVE */
8987
8988     if (pv[SND_PIP].ival > -1) {
8989         g_usepipes = usepipes;
8990         usepipes = pv[SND_PIP].ival;
8991     }
8992
8993     /* Save global protocol parameters */
8994
8995     g_proto = protocol;
8996 #ifdef CK_LABELED
8997     g_lf_opts = lf_opts;                /* Save labeled transfer options */
8998 #endif /* CK_LABELED */
8999     g_urpsiz = urpsiz;                  /* Receive packet length */
9000     g_spsizf = spsizf;                  /* Send packet length flag */
9001     g_spsiz = spsiz;                    /* Send packet length */
9002     g_spsizr = spsizr;                  /* etc etc */
9003     g_spmax = spmax;
9004     g_wslotr = wslotr;
9005     g_prefixing = prefixing;
9006     g_fncact = fncact;
9007     g_fncnv = fncnv;
9008     g_fnspath = fnspath;
9009     g_fnrpath = fnrpath;
9010     g_xfrxla = xfrxla;
9011
9012     if (pv[SND_PRO].ival > -1) {        /* Change according to switch */
9013         protocol = pv[SND_PRO].ival;
9014         if (ptab[protocol].rpktlen > -1)   /* copied from initproto() */
9015             urpsiz = ptab[protocol].rpktlen;
9016         if (ptab[protocol].spktflg > -1)
9017             spsizf = ptab[protocol].spktflg;
9018         if (ptab[protocol].spktlen > -1) {
9019             spsiz = ptab[protocol].spktlen;
9020             if (spsizf)
9021                 spsizr = spmax = spsiz;
9022         }
9023         if (ptab[protocol].winsize > -1)
9024             wslotr = ptab[protocol].winsize;
9025         if (ptab[protocol].prefix > -1)
9026             prefixing = ptab[protocol].prefix;
9027         if (ptab[protocol].fnca > -1)
9028             fncact  = ptab[protocol].fnca;
9029         if (ptab[protocol].fncn > -1)
9030             fncnv   = ptab[protocol].fncn;
9031         if (ptab[protocol].fnsp > -1)
9032             fnspath = ptab[protocol].fnsp;
9033         if (ptab[protocol].fnrp > -1)
9034             fnrpath = ptab[protocol].fnrp;
9035     }
9036     debug(F101,"xget protocol","",protocol);
9037     debug(F111,"xget cmarg2",cmarg2,xfermode);
9038
9039     g_xfermode = xfermode;
9040     g_binary = binary;
9041     if (pv[SND_BIN].ival > 0) {         /* Change according to switch */
9042         xfermode = XMODE_M;
9043         binary = XYFT_B;                /* FILE TYPE BINARY */
9044         omode = GMOD_BIN;               /* O-Packet mode */
9045         debug(F101,"doxget /BINARY xfermode","",xfermode);
9046     } else if (pv[SND_TXT].ival > 0) {  /* Ditto for /TEXT */
9047         xfermode = XMODE_M;
9048         binary = XYFT_T;
9049         omode = GMOD_TXT;
9050         debug(F101,"doxget /TEXT xfermode","",xfermode);
9051     } else if (pv[SND_IMG].ival > 0) {
9052         xfermode = XMODE_M;
9053 #ifdef VMS
9054         binary = XYFT_I;
9055 #else
9056         binary = XYFT_B;
9057 #endif /* VMS */
9058         omode = GMOD_TXT;
9059         debug(F101,"doxget /IMAGE xfermode","",xfermode);
9060     }
9061 #ifdef CK_LABELED
9062     else if (pv[SND_LBL].ival > 0) {
9063         xfermode = XMODE_M;
9064         binary = XYFT_L;
9065         omode = GMOD_LBL;
9066         debug(F101,"doxget /LABELED xfermode","",xfermode);
9067     }
9068 #endif /* CK_LABELED */
9069     debug(F101,"xget binary","",binary);
9070     debug(F101,"xget omode","",omode);
9071
9072     if (pv[SND_XPA].ival > 0)           /* /TRANSPARENT */
9073       xfrxla = 0;                       /* Don't translate character sets */
9074
9075 #ifdef PIPESEND
9076     if (pv[SND_FLT].ival > 0)
9077       makestr(&rcvfilter,pv[SND_FLT].sval);
9078 #endif /* PIPESEND */
9079
9080 #ifdef CK_TMPDIR
9081     if (pv[SND_MOV].ival > 0) {
9082         int len;
9083         char * p = pv[SND_MOV].sval;
9084 #ifdef CK_LOGIN
9085         if (isguest) {
9086             printf("?Sorry, /MOVE-TO not available to guests\n");
9087             x = -9;
9088             goto xgetx;
9089         }
9090 #endif /* CK_LOGIN */
9091         len = strlen(p);
9092         if (!isdir(p)) {                /* Check directory */
9093 #ifdef CK_MKDIR
9094             char * s = NULL;
9095             s = (char *)malloc(len + 4);
9096             if (s) {
9097                 strcpy(s,p);            /* safe */
9098 #ifdef datageneral
9099                 if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
9100 #else
9101                 if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
9102 #endif /* datageneral */
9103                 s[len++] = 'X';
9104                 s[len] = NUL;
9105                 x = zmkdir(s);
9106                 free(s);
9107                 if (x < 0) {
9108                     printf("?Can't create \"%s\"\n",p);
9109                     x = -9;
9110                     goto xgetx;
9111                 }
9112             }
9113 #else
9114             printf("?Directory \"%s\" not found\n",p);
9115             x = -9;
9116             goto xgetx;
9117 #endif /* CK_MKDIR */
9118         }
9119         zfnqfp(p,LINBUFSIZ,line);
9120         makestr(&rcv_move,line);
9121     }
9122 #endif /* CK_TMPDIR */
9123
9124     if (pv[SND_REN].ival > 0) {         /* /RENAME-TO:name */
9125         char * p = pv[SND_REN].sval;
9126 #ifdef CK_LOGIN
9127         if (isguest) {
9128             printf("?Sorry, /RENAME-TO not available to guests\n");
9129             x = -9;
9130             goto xgetx;
9131         }
9132 #endif /* CK_LOGIN */
9133         if (!p) p = "";
9134         if (!*p) {
9135             printf("?New name required for /RENAME\n");
9136             x = -9;
9137             goto xgetx;
9138         }
9139         p = brstrip(p);
9140         makestr(&rcv_rename,p);
9141         debug(F110,"xget rcv_rename","",0);
9142     }
9143
9144 #ifdef CALIBRATE
9145     if (pv[SND_CAL].ival > 0)
9146       calibrate = 1L;
9147 #endif /* CALIBRATE */
9148     g_displa = fdispla;
9149     if (pv[SND_SHH].ival > 0)
9150       fdispla = 0;
9151     debug(F101,"xget display","",fdispla);
9152
9153     if (pv[SND_NAM].ival > -1) {        /* /FILENAMES */
9154         g_fncnv = fncnv;                /* Save global value */
9155         fncnv = pv[SND_NAM].ival;
9156         debug(F101,"xsend fncnv","",fncnv);
9157         /* We should also handle O packet filename option here */
9158         /* but we don't really need to since WHATAMI already handles it */
9159     }
9160     if (pv[SND_PTH].ival > -1) {        /* PATHNAMES */
9161         g_rpath = fnrpath;              /* Save global values */
9162         fnrpath = pv[SND_PTH].ival;
9163         debug(F101,"xsend fnrpath","",fnrpath);
9164 #ifndef NZLTOR
9165         if (fnrpath != PATH_OFF) {
9166             g_fncnv = fncnv;
9167             fncnv = XYFN_L;
9168             debug(F101,"xsend fncnv","",fncnv);
9169         }
9170         /* We should also handle O packet pathname option here */
9171         /* but we don't really need to since WHATAMI already handles it */
9172 #endif /* NZLTOR */
9173     }
9174
9175     /* Set protocol start state */
9176
9177     if (opkt) {                         /* Extended GET Options*/
9178         sstate = (CHAR) 'o';
9179         oopts = 0;
9180         if (pv[SND_DEL].ival > 0) oopts |= GOPT_DEL; /* GET /DELETE */
9181         if (pv[SND_RES].ival > 0) oopts |= GOPT_RES; /* GET /RECOVER */
9182         if (pv[SND_REC].ival > 0) oopts |= GOPT_REC; /* GET /RECURSIVE */
9183     } else if (rcvcmd)
9184       sstate = (CHAR) 'v';              /* RECEIVE or CRECEIVE */
9185     else if (pv[SND_DEL].ival > 0)
9186       sstate = (CHAR) 'h';              /* GET /DELETE (= RETRIEVE) */
9187     else if (pv[SND_RES].ival > 0)
9188       sstate = (CHAR) 'j';              /* GET /RECOVER (= REGET) */
9189     else
9190       sstate = (CHAR) 'r';              /* Regular GET */
9191     getcmd = 1;
9192     debug(F000,"xget sstate","",sstate);
9193 #ifdef MAC
9194     what = W_RECV;
9195     scrcreate();
9196 #endif /* MAC */
9197     if (local) {
9198         if (pv[SND_SHH].ival != 0)
9199           displa = 1;
9200         ttflui();
9201     }
9202     x = 0;
9203 #ifdef PIPESEND
9204     if (pipesend)
9205       goto xgetx;
9206 #endif /* PIPESEND */
9207
9208 #ifdef CK_TMPDIR
9209 /*
9210   cmarg2 is also allowed to be a device or directory name;
9211   even the name of a directory that doesn't exist.
9212 */
9213     y = strlen(cmarg2);
9214     debug(F111,"xget strlen(cmarg2)",cmarg2,y);
9215     if ((y > 0) &&
9216 #ifdef OS2
9217         ((isalpha(cmarg2[0]) &&
9218          cmarg2[1] == ':' &&
9219          cmarg2[2] == NUL) ||
9220         (cmarg[y-1] == '/' || cmarg[y-1] == '\\') ||
9221         isdir(cmarg2))
9222 #else
9223 #ifdef UNIXOROSK
9224         (cmarg2[y-1] == '/' || isdir(cmarg2))
9225 #else
9226 #ifdef VMS
9227         (cmarg2[y-1] == ']' || cmarg2[y-1] == '>' || isdir(cmarg2))
9228 #else
9229 #ifdef STRATUS
9230         (cmarg2[y-1] == '>' || isdir(cmarg2))
9231 #else
9232 #ifdef datageneral
9233         (cmarg2[y-1] == ':' || cmarg[0] == ':' || isdir(cmarg2))
9234 #else
9235         isdir(cmarg2)
9236 #endif /* datageneral */
9237 #endif /* STRATUS */
9238 #endif /* VMS */
9239 #endif /* UNIXOROSK */
9240 #endif /* OS2 */
9241         ) {
9242         debug(F110,"doxget RECEIVE cmarg2 disk or dir",cmarg2,0);
9243         if (!f_tmpdir) {
9244             int x;
9245             s = zgtdir();
9246             if (s) {
9247                 ckstrncpy(savdir,s,TMPDIRLEN); /* remember old disk/dir */
9248                 f_tmpdir = 1;   /* and that we did this */
9249             } else {
9250                 printf("?Can't get current directory\n");
9251                 cmarg2 = "";
9252                 f_tmpdir = 0;
9253                 x = -9;
9254                 goto xgetx;
9255             }
9256 #ifdef CK_MKDIR
9257             x = zchki(cmarg2);          /* Does as-name exist? */
9258             if (x == -1) {              /* Doesn't exist */
9259                 char * p = NULL;        /* Try to create it */
9260                 x = strlen(cmarg2);
9261                 if ((p = (char *)malloc(x+4))) {
9262                     sprintf(p,"%s%s",cmarg2,"x.x"); /* SAFE (prechecked) */
9263                     x = zmkdir(p);
9264                     free(p);
9265                     if (x < 0) {
9266                         printf("?Can't create %s\n",cmarg2);
9267                         x = -9;
9268                         goto xgetx;
9269                     }
9270                 }
9271             }
9272 #endif /* CK_MKDIR */
9273             if (!zchdir(cmarg2)) {      /* change to given disk/directory, */
9274                 printf("?Can't access %s\n",cmarg2);
9275                 x = -9;
9276                 goto xgetx;
9277             }
9278             cmarg2 = "";
9279         }
9280     }
9281 #endif /* CK_TMPDIR */
9282
9283     ckstrncpy(fspec,cmarg,CKMAXPATH);   /* Note - this is a REMOTE filespec */
9284     debug(F111,"xget fspec",fspec,fspeclen);
9285     debug(F110,"xget cmarg2",cmarg2,0);
9286
9287   xgetx:
9288     for (i = 0; i < SND_MAX; i++)
9289       if (pv[i].sval)
9290         free(pv[i].sval);
9291     return(x);
9292 }
9293 #endif /* NOXFER */
9294
9295 #ifndef NOSPL
9296
9297 /*
9298   D O G T A  --  Do _GETARGS or _PUTARGS Command.
9299
9300   Used by XIF, FOR, WHILE, and SWITCH, each of which are implemented as
9301   2-level macros; the first level defines the macro, the second runs it.
9302   This routine hides the fact that they are macros by importing the
9303   macro arguments (if any) from two levels up, to make them available
9304   in the IF, FOR, SWITCH, and WHILE commands themselves; for example as
9305   loop indices, etc, and within the IF/FOR/WHILE/SWITCH body itself.
9306   _PUTARGS is in case we changed any of these variables or used SHIFT
9307   on them, so the new values won't be lost as we pop up the stack.
9308 */
9309 int
9310 dogta(cx) int cx; {
9311     int i, n;
9312     char c, *p,  mbuf[4];
9313     extern int topargc, cmdint;
9314     extern char ** topxarg;
9315
9316     if ((y = cmcfm()) < 0)
9317       return(y);
9318     debug(F101,"dogta cx","",cx);
9319     debug(F101,"dogta maclvl","",maclvl);
9320     if (cx == XXGTA) {
9321         debug(F101,"dogta _GETARGS maclvl","",maclvl);
9322     } else if (cx == XXPTA) {
9323         debug(F101,"dogta _PUTARGS maclvl","",maclvl);
9324     } else {
9325         return(-2);
9326     }
9327     if (maclvl < 1)
9328       return(success = 0);
9329
9330     /* Make new copies of macro arguments /%0..9 */
9331
9332     mbuf[0] = '%'; mbuf[1] = '0'; mbuf[2] = NUL; /* Argument name buf */
9333
9334     if (cx == XXPTA) {                  /* Go NOINT because _PUTARGS */
9335         if (cmdint)                     /* temporarily changes maclvl. */
9336           connoi();                     /* Interrupts OFF. */
9337     }
9338     for (i = 0; i < 10; i++) {          /* For all args */
9339         c = (char) (i + '0');           /* Make name */
9340         mbuf[1] = (char) c;             /* Insert digit */
9341         if (cx == XXGTA) {              /* Get arg from level-minus-2 */
9342             if (maclvl == 1) p = g_var[c]; /* If at level 1 use globals 0..9 */
9343             else p = m_arg[maclvl-2][i];   /* Otherwise they're on the stack */
9344             addmac(mbuf,p);
9345 #ifdef COMMENT
9346             if (maclvl > 1)
9347               makestr(&(m_line[maclvl]),m_line[maclvl-2]);
9348 #endif /* COMMENT */
9349         } else if (cx == XXPTA) {       /* Put args level+2 */
9350             maclvl -= 2;                /* This is gross, it's because we're */
9351             addmac(mbuf,m_arg[maclvl+2][i]); /* adding macros two levels up */
9352             maclvl += 2;                     /* and addmac() uses maclvl. */
9353             count[cmdlvl - 2]  = count[cmdlvl];
9354             intime[cmdlvl - 2] = intime[cmdlvl];
9355             inpcas[cmdlvl - 2] = inpcas[cmdlvl];
9356             takerr[cmdlvl - 2] = takerr[cmdlvl];
9357             merror[cmdlvl - 2] = merror[cmdlvl];
9358             xquiet[cmdlvl - 2] = xquiet[cmdlvl];
9359         } else return(success = 0);     /* Bad call to this routine */
9360     }
9361     if (cx == XXPTA) {                  /* Restore interrupts if we */
9362         if (cmdint)                     /* turned them off above. */
9363           conint(trap,stptrap);
9364     }
9365     /* Now take care of the argument vector array \&_[], \v(return), */
9366     /* and \v(argc) by just copying the pointers. */
9367
9368     if (cx == XXGTA) {                  /* GETARGS from 2 levels up */
9369         if (maclvl == 1) {
9370             a_ptr[0] = topxarg;         /* \&_[] array */
9371             a_dim[0] = topargc - 1;     /* Dimension doesn't include [0] */
9372             m_xarg[maclvl] = topxarg;
9373             n_xarg[maclvl] = topargc;   /* But \v(argc) does include \%0 */
9374             macargc[maclvl] = topargc;
9375             makestr(&(mrval[maclvl+1]),mrval[0]); /* (see vnlook()) */
9376         } else {
9377             a_ptr[0] = m_xarg[maclvl-2];
9378             a_dim[0] = n_xarg[maclvl-2];
9379             m_xarg[maclvl] = m_xarg[maclvl-2];
9380             n_xarg[maclvl] = n_xarg[maclvl-2];
9381             macargc[maclvl] = n_xarg[maclvl-2];
9382             makestr(&(mrval[maclvl+1]),mrval[maclvl-1]); /* (see vnlook()) */
9383
9384         }
9385     } else {                            /* PUTARGS 2 levels up */
9386         if (maclvl > 1) {
9387             a_ptr[0] = m_xarg[maclvl];
9388             m_xarg[maclvl-2] = m_xarg[maclvl];
9389             a_dim[0] = n_xarg[maclvl];
9390             n_xarg[maclvl-2] = n_xarg[maclvl];
9391             macargc[maclvl-2] = n_xarg[maclvl];
9392         }
9393     }
9394     return(1);                  /* Internal command - don't change success */
9395 }
9396 #endif /* NOSPL */
9397
9398 #ifndef NOSPL
9399 /*
9400   Do the GOTO and [_]FORWARD commands.
9401   s = Label to search for, cx = function code: XXGOTO, XXFWD, or XXXFWD.
9402 */
9403 #ifdef BIGBUFOK
9404 #define LBLMAXLEN 255                   /* Max label length */
9405 #else
9406 #define LBLMAXLEN 63
9407 #endif /* BIGBUFOK */
9408
9409 int
9410 dogoto(s, cx) char *s; int cx; {
9411     int i, j, x, y, z, bc;
9412     int empty = 0, stopflg = 0;
9413     char * cmd;                         /* Name of this command */
9414     char tmplbl[LBLMAXLEN+1], *lp;      /* Current label from command stream */
9415     char tmp2[LBLMAXLEN+1];             /* SWITCH label conversion buffer */
9416     char tmp3[LBLMAXLEN+1];             /* Target label */
9417
9418     stopflg = (cx == XXXFWD);           /* _FORWARD (used in SWITCH) */
9419     bc = 0;                             /* Brace counter */
9420
9421     cmd = (cx == XXGOTO) ? "GOTO" : ((cx == XXFWD) ? "FORWARD" : "_FORWARD");
9422     if (!s) s = "";
9423     if (!*s) empty = 1;
9424
9425 #ifdef DEBUG
9426     if (deblog) {
9427         debug(F111,"GOTO command",cmd,cx);
9428         debug(F101,"GOTO cmdlvl","",cmdlvl);
9429         debug(F101,"GOTO maclvl","",maclvl);
9430         debug(F101,"GOTO tlevel","",tlevel);
9431         debug(F111,"GOTO target",s,empty);
9432     }
9433 #endif /* DEBUG */
9434     debug(F110,cmd,s,0);
9435     ckstrncpy(tmp3+1,s,LBLMAXLEN-1);
9436     s = tmp3+1;
9437     if (*s != ':') {                    /* Make copy of label */
9438         tmp3[0] = ':';                  /* guaranteed to start with ":" */
9439         s--;
9440     }
9441     if (!stopflg && !empty) {
9442         if (s[1] == '.' || s[1] == SP || s[1] == NUL) {
9443             printf("?Bad label syntax - '%s'\n",s);
9444             return(success = 0);
9445         }
9446     }
9447     if (cmdlvl == 0) {
9448         printf("?Sorry, %s only works in a command file or macro\n",cmd);
9449         return(success = 0);
9450     }
9451     y = strlen(s);                      /* y = length of target label */
9452     debug(F111,cmd,s,y);
9453
9454     while (cmdlvl > 0) {                /* As long as not at top level... */
9455         if (cmdstk[cmdlvl].src == CMD_MD) { /* GOTO inside macro */
9456             int i, m, flag;
9457             char *xp, *tp;
9458
9459             /* GOTO: rewind the macro; FORWARD: start at current position */
9460
9461             lp = (cx == XXGOTO) ? macx[maclvl] : macp[maclvl];
9462             m = (int)strlen(lp) - y + 1;
9463             debug(F010,"GOTO in macro",lp,0);
9464
9465             flag = 1;                   /* flag for valid label position */
9466             for (i = 0; i < m; i++,lp++) { /* search for label in macro body */
9467                 if (*lp == '{')         /* But only at this level */
9468                   bc++;                 /* Anything inside braces is off */
9469                 else if (*lp == '}')    /* limits. */
9470                   bc--;
9471                 if (stopflg && bc > 0)  /* This is good for SWITCH */
9472                   continue;             /* but interferes with WHILE, etc. */
9473                 if (*lp == ',') {
9474                     flag = 1;
9475                     continue;
9476                 }
9477                 if (flag) {             /* If in valid label position */
9478                     if (*lp == SP)      /* eat leading spaces */
9479                       continue;
9480                     if (*lp != ':') {   /* Look for label introducer */
9481                         flag = 0;       /* this isn't it */
9482                         continue;       /* keep looking */
9483                     }
9484                 }
9485                 if (!flag)              /* We don't have a label */
9486                   continue;             /*  so keep looking... */
9487                 xp = lp; tp = tmplbl;   /* Copy the label from the macro */
9488                 j = 0;                  /* to make it null-terminated */
9489                 while ((*tp = *xp)) {
9490                     if (j++ > LBLMAXLEN) /* j = length of word from macro */
9491                       break;
9492 #ifdef COMMENT
9493                     if (*tp < 33 || *tp == ',') /* Look for end of word */
9494 #else
9495                     if (!*tp || *tp == ',')     /* Look for end of word */
9496 #endif /* COMMENT */
9497                       break;
9498                     else tp++, xp++;    /* Next character */
9499                 }
9500                 *tp = NUL;              /* In case we stopped early */
9501                 /* Now do caseless string comparison, using longest length */
9502                 debug(F111,"macro GOTO label",s,y);
9503                 debug(F111,"macro target label",tmplbl,j);
9504                 if (stopflg) {          /* Allow variables as SWITCH labels */
9505                     int n = LBLMAXLEN - 1;
9506                     char * p = tmp2;
9507                     zzstring(tmplbl,&p,&n);
9508                     ckstrncpy(tmplbl,tmp2,LBLMAXLEN);
9509                     tmp2[49] = NUL;
9510                 }
9511                 debug(F111,"GOTO s",s,y);
9512                 debug(F111,"GOTO tmplbl",tmplbl,j);
9513                 debug(F101,"GOTO empty",ckitoa(stopflg),empty);
9514
9515                 if (empty) {               /* Empty target */
9516                     z = (!strcmp(s,":") && /* String is empty */
9517                          /* and Label is ":" or ":*"... */
9518                          (!strcmp(tmplbl,":") || !strcmp(tmplbl,":*")))
9519                         ? 0 : 1;
9520                     debug(F111,"GOTO","A",z);
9521                 } else if (stopflg) {
9522                     z = ckmatch(tmplbl,s,inpcas[cmdlvl],1) ? 0 : 1;
9523                     debug(F111,"GOTO","B",z);
9524                 } else {
9525                     z = (stopflg && inpcas[cmdlvl]) ?
9526                       strcmp(s,tmplbl) :
9527                         ckstrcmp(s,tmplbl,(y > j) ? y : j, 0);
9528                     debug(F111,"GOTO","C",z);
9529                 }
9530                 if (!z) {
9531                     break;
9532                 } else if (stopflg &&
9533                          !ckstrcmp(":default",tmplbl,(8 > j) ? 8 : j, 0)) {
9534                     debug(F100,"GOTO DEFAULT","",0);
9535                     break;
9536                 } else {
9537                     flag = 0;
9538                 }
9539             }
9540             debug(F111,"GOTO macro i",cmd,i);
9541             debug(F111,"GOTO macro m",cmd,m);
9542             if (i >= m) {               /* Didn't find the label */
9543                 debug(F101,"GOTO failed cmdlvl","",cmdlvl);
9544 #ifdef COMMENT
9545                 /* MOVED TO AFTER POPCLVL ABOUT 20 LINES DOWN 5 AUG 2002 */
9546                    if (stopflg)
9547                   return(0);
9548 #endif /* COMMENT */
9549                 if ((maclvl > 0) &&
9550                        (m_arg[maclvl-1][0]) &&
9551                        (cmdstk[cmdlvl].src == CMD_MD) &&
9552                        (!strncmp(m_arg[maclvl-1][0],"_xif",4) ||
9553                         !strncmp(m_arg[maclvl-1][0],"_for",4) ||
9554                         !strncmp(m_arg[maclvl-1][0],"_swi",4) ||
9555                         !strncmp(m_arg[maclvl-1][0],"_whi",4))) {
9556                     dogta(XXPTA);       /* Restore args */
9557                     debug(F101,"GOTO in XIF/FOR/WHI/SWI popping","",cmdlvl);
9558                     popclvl();          /* Pop an extra level */
9559                 }
9560                 debug(F101,"GOTO popping","",cmdlvl);
9561                 if (!popclvl()) {       /* pop up to next higher level */
9562                     printf("?Label '%s' not found\n",s); /* if none */
9563                     return(0);          /* Quit */
9564                 } else if (stopflg) {   /* SWITCH no case label match */
9565                     return(0);          /* and no DEFAULT lable. */
9566                 } else {
9567                     continue;        /* otherwise look again */
9568                 }
9569             }
9570             debug(F110,"GOTO found macro label",tmplbl,0);
9571             macp[maclvl] = lp;          /* set macro buffer pointer */
9572             return(1);
9573         } else if (cmdstk[cmdlvl].src == CMD_TF) {
9574             x = 0;                      /* GOTO issued in take file */
9575             debug(F111,"GOTO in TAKE file",cmd,cx);
9576             if (cx == XXGOTO) {         /* If GOTO, but not FORWARD, */
9577                 rewind(tfile[tlevel]);  /* search file from beginning */
9578                 tfline[tlevel] = 0;
9579             }
9580             while (! feof(tfile[tlevel])) {
9581 #ifdef COMMENT
9582 /* This is wrong - it lets us jump to labels inside inferior blocks */
9583                 tfline[tlevel]++;
9584                 if (fgets(line,LINBUFSIZ,tfile[tlevel]) == NULL) /* Get line */
9585 #else
9586                 if (getnct(line,LINBUFSIZ,tfile[tlevel],0) < 0)
9587 #endif /* COMMENT */
9588                   break;                /* If no more, done, label not found */
9589                 lp = line;              /* Got line */
9590                 while (*lp == SP || *lp == HT)
9591                   lp++;                 /* Strip leading whitespace */
9592                 if (*lp != ':') continue; /* Check for label introducer */
9593                 while (*(lp+1) == SP) { /* Remove space between : and name */
9594                     *(lp+1) = ':';
9595                     lp++;               /* Strip leading whitespace */
9596                 }
9597                 tp = lp;                /* Get end of word */
9598                 j = 0;
9599                 while (*tp) {           /* And null-terminate it */
9600                     if (*tp < 33) {
9601                         *tp = NUL;
9602                         break;
9603                     } else tp++, j++;
9604                 }
9605                 if (!ckstrcmp(lp,s,(y > j) ? y : j,0)) { /* Caseless compare */
9606                     x = 1;              /* Got it */
9607                     break;              /* done. */
9608                 } else if (stopflg &&
9609                            !ckstrcmp(":default",tmplbl,(8 > j) ? 8 : j,0)) {
9610                     x = 1;
9611                     break;
9612                 }
9613             }
9614             if (x == 0) {               /* If not found, print message */
9615                 debug(F101,"GOTO failed at cmdlvl","",cmdlvl);
9616                 if (stopflg)
9617                   return(0);
9618                 if (!popclvl()) {       /* pop up to next higher level */
9619                     printf("?Label '%s' not found\n",s); /* if none */
9620                     return(0);          /* quit */
9621                 } else continue;        /* otherwise look again */
9622             }
9623             return(x);                  /* Send back return code */
9624         }
9625     }
9626     printf("?Stack problem in GOTO %s\n",s); /* Shouldn't see this */
9627     return(0);
9628 }
9629 #endif /* NOSPL */
9630
9631 /* Finish parsing and do the IF, XIF, and WHILE commands */
9632
9633 #ifndef NOSPL
9634
9635 /*  C H K V A R  --  Check (if it's a) Variable  */
9636
9637
9638 #ifdef OLDCHKVAR
9639 /*
9640   Crude and disgusting, but needed for OS/2, DOS, and Windows, where filenames
9641   have backslashes in them.  How do we know if a backslash in a filename is a
9642   directory separator, or if it's a Kermit backslash?  This routine does a
9643   rough syntax check of the next few characters and if it looks like it MIGHT
9644   be a variable, then it tries to evaluate it, and if the result is not empty,
9645   we say it's a variable, although sometimes it might not be -- some cases are
9646   truly ambiguous.  For example there might a DOS directory called \%a, and
9647   we also have a variable with the same name.  This is all for the sake of not
9648   having to tell PC users that they have to double all backslashes in file
9649   and directory names.
9650 */
9651 #else
9652 /*
9653   Somewhat less crude & disgusting.  The previous method was nondeterministic
9654   and (worse) it interfered with macro argument passing.  So now we only
9655   check the syntax of backslash-items to see if they are variables, but we
9656   do NOT check their values.
9657 */
9658 #endif /* OLDCHKVAR */
9659 /*
9660   Call with a string pointer pointing at the backslash of the purported
9661   variable.  Returns 1 if it has the syntax of a variable, 0 if not.
9662 */
9663 int
9664 chkvar(s) char *s; {
9665     int z = 0;                          /* Return code - assume failure. */
9666     if (!s) s = "";                     /* Watch our for null pointers. */
9667     if (!*s) return(0);                 /* Empty arg so not a variable. */
9668     if (*s == CMDQ) {                   /* Object begins with backslash. */
9669         char c;
9670         c = s[1];                       /* Character following backslash. */
9671         if (c) {
9672             int t = 0;
9673             if (c == CMDQ)              /* Quoted backslash */
9674               return(1);
9675             c = (char) (islower(c) ? toupper(c) : c); /* Otherwise... */
9676             if (c == '%') {             /* Simple variable */
9677 #ifdef OLDCHKVAR
9678                 t = 1;
9679 #else
9680                 return(1);
9681 #endif /* OLDCHKVAR */
9682             } else if (c == '&') {      /* Array */
9683                 if (!s[2]) return(0);
9684                 if (s[3] == '[')
9685                   t = ckindex("]",s,4,0,1);
9686 #ifndef OLDCHKVAR
9687                 return((t > 0) ? 1 : 0);
9688 #endif /* OLDCHKVAR */
9689             } else if (c == '$' ||      /* Environment variable */
9690                        c == 'V' ||      /* Built-in variable */
9691                        c == 'M') {      /* Macro name */
9692                 t = (s[2] == '(');
9693 #ifndef OLDCHKVAR
9694                 return((t > 0) ? 1 : 0);
9695 #endif /* OLDCHKVAR */
9696             } else if (c == 'F') {      /* Function reference */
9697                 /* Don't actually call it - it might have side effects */
9698                 int x;
9699                 if ((x = ckindex("(",s,3,0,1))) /* Just check syntax */
9700                   if ((x = ckindex(")",s,x,0,1)))
9701                     z = 1;
9702                 /* Insert a better syntax check here if necessary */
9703             }
9704 #ifdef OLDCHKVAR
9705             if (t) {
9706                 t = 255;                /* This lets us test \v(xxx) */
9707                 lp = line;              /* and even \f...(xxx) */
9708                 zzstring(s,&lp,&t);     /* Evaluate it, whatever it is. */
9709                 t = strlen(line);       /* Get its length. */
9710                 debug(F111,"chkvar",line,t);
9711                 z = t > 0;              /* If length > 0, it's defined */
9712             }
9713 #endif /* OLDCHKVAR */
9714         }
9715     }
9716     return(z);
9717 }
9718
9719 /*  B O O L E X P  --  Evaluate a Boolean expression  */
9720
9721 #define BOOLLEN 1024
9722 static char boolval[BOOLLEN];
9723
9724 int
9725 boolexp(cx) int cx; {
9726     int x, y, z; char *s, *p;
9727     int parens = 0, pcount = 0, ecount = 0;
9728     char *q, *bx;
9729     struct FDB kw, nu;
9730 #ifdef FNFLOAT
9731     struct FDB fl;
9732     CKFLOAT f1 = 0.0, f2 = 0.0;
9733     int f1flag = 0, f2flag = 0;
9734 #endif /* FNFLOAT */
9735 #ifdef OS2
9736     extern int keymac;
9737 #endif /* OS2 */
9738
9739     not = 0;                            /* Flag for whether "NOT" was seen */
9740     z = 0;                              /* Initial IF condition */
9741     ifargs = 0;                         /* Count of IF condition words */
9742     bx = boolval;                       /* Initialize boolean value */
9743     *bx = NUL;
9744
9745   ifagain:
9746     cmfdbi(&kw,                         /* First FDB - command switches */
9747            _CMKEY,                      /* fcode */
9748            "Number, numeric-valued variable, Boolean expression, or keyword",
9749            "",                          /* default */
9750            "",                          /* addtl string data */
9751            nif,                         /* addtl numeric data 1: tbl size */
9752            0,                           /* addtl numeric data 2: 4 = silent */
9753            xxstring,                    /* Processing function */
9754            iftab,                       /* Keyword table */
9755            &nu                          /* Pointer to next FDB */
9756            );
9757     cmfdbi(&nu,                         /* 2nd FDB - An integer */
9758            _CMNUM,                      /* fcode */
9759            "",                          /* hlpmsg */
9760            "",                          /* Default */
9761            "",                          /* addtl string data */
9762            0,
9763            0,
9764            xxstring,
9765            NULL,
9766 #ifdef FNFLOAT
9767            &fl
9768 #else
9769            NULL
9770 #endif /* FNFLOAT */
9771            );
9772 #ifdef FNFLOAT
9773     cmfdbi(&fl,                         /* A floating-point number */
9774            _CMFLD,                      /* fcode */
9775            "",                          /* hlpmsg */
9776            "",                          /* default */
9777            "",                          /* addtl string data */
9778            0,                           /* addtl numeric data 1 */
9779            0,                           /* addtl numeric data 2 */
9780            xxstring,
9781            NULL,
9782            NULL
9783            );
9784 #endif /* FNFLOAT */
9785     x = cmfdb(&kw);                     /* Parse a keyword or a number */
9786     debug(F111,"boolval cmfdb","",x);
9787     if (x < 0) {
9788         if (x == -3)
9789           x = -2;
9790         return(x);
9791     }
9792     debug(F111,"boolval switch","",cmresult.fcode);
9793     switch (cmresult.fcode) {           /* What did we get? */
9794 #ifdef FNFLOAT
9795       case _CMFLD:                      /* A "field" */
9796         if (isfloat(cmresult.sresult,0)) { /* A floating-point number? */
9797             f1 = floatval;              /* Yes, get its value */
9798             f1flag = 1;                 /* remember we did this */
9799             ifc = 9999;                 /* Set special "if-code" */
9800         } else
9801           return(-2);
9802 #endif /* FNFLOAT */
9803       case _CMNUM:                      /* A number... */
9804         ifc = 9999;                     /* Set special "if-code" */
9805         break;
9806       case _CMKEY:                      /* A keyword */
9807         ifc = cmresult.nresult;         /* Get if-code */
9808         break;
9809       default:
9810         return(-2);
9811     }
9812     switch (ifc) {                      /* set z = 1 for true, 0 for false */
9813       case 9999:                        /* Number */
9814 #ifdef FNFLOAT
9815         if (f1flag) {
9816             z = (f1 == 0.0) ? 0 : 1;
9817         } else
9818 #endif /* FNFLOAT */
9819         z = (cmresult.nresult == 0) ? 0 : 1;
9820         break;
9821       case XXIFLP:                      /* Left paren */
9822         if (pcount == 0 && ifargs > 0)
9823           return(-2);
9824         parens = 1;
9825         pcount++;
9826         ifargs++;
9827         *bx++ = '(';
9828         goto ifagain;
9829       case XXIFRP:                      /* Right paren */
9830         if (!parens)
9831           return(-2);
9832         if (--pcount < 0)
9833           return(-2);
9834         ifargs++;
9835         *bx++ = ')';
9836         *bx = NUL;
9837         if (pcount == 0)
9838           goto ifend;
9839         goto ifagain;
9840       case XXIFAN:                      /* AND (&&) */
9841         ifargs++;
9842         if (!ecount)
9843           return(-2);
9844         *bx++ = '&';
9845         goto ifagain;
9846       case XXIFOR:                      /* OR (||) */
9847         ifargs++;
9848         if (!ecount)
9849           return(-2);
9850         *bx++ = '|';
9851         goto ifagain;
9852       case XXIFNO:                      /* IF NOT [ NOT [ NOT ... ] ] */
9853         if (bx > boolval) {             /* evala() doesn't like cascaded */
9854             if (*(bx-1) == '!') {       /* unary operators... */
9855                 *(bx-1) = NUL;          /* So here, two wrongs make a right. */
9856                 bx--;
9857             } else {
9858                 *bx++ = '!';
9859             }
9860         } else {
9861             *bx++ = '!';
9862         }
9863         ifargs++;
9864         goto ifagain;
9865       case XXIFTR:                      /* IF TRUE */
9866         z = 1;
9867         debug(F101,"if true","",z);
9868         ifargs += 1;
9869         break;
9870       case XXIFNT:                      /* IF FALSE */
9871         z = 0;
9872         debug(F101,"if true","",z);
9873         ifargs += 1;
9874         break;
9875       case XXIFSU:                      /* IF SUCCESS */
9876         z = ( success != 0 ) ? 1 : 0;
9877         debug(F101,"if success","",z);
9878         ifargs += 1;
9879         break;
9880       case XXIFFA:                      /* IF FAILURE */
9881         z = ( success == 0 ) ? 1 : 0;
9882         debug(F101,"if failure","",z);
9883         ifargs += 1;
9884         break;
9885
9886       case XXIFDE:                      /* IF DEFINED */
9887         if ((x = cmfld("Macro or variable name","",&s,NULL)) < 0)
9888           return((x == -3) ? -2 : x);
9889
9890         if (*s == CMDQ) {
9891             char * lp;
9892             char line[256];
9893             int t, x;
9894             if (*(s+1) == 'f' || *(s+1) == 'F') { /* Built-in function */
9895                 extern struct keytab fnctab[];
9896                 extern int nfuncs;
9897                 ckstrncpy(line,s+2,256);
9898                 if (line[0]) {
9899                     lp = ckstrchr(line,'(');
9900                     if (lp) *lp = NUL;
9901                     x = lookup(fnctab,line,nfuncs,&t);
9902                     z = x > -1;
9903                 }
9904                 debug(F111,"if defined function",line,z);
9905             } else if (*(s+1) == 'v' || *(s+1) == 'V') { /* 8.0.200 */
9906                 extern struct keytab vartab[];
9907                 extern int nvars;
9908                 z = 0;
9909                 if (*(s+2) == '(') {
9910                     ckstrncpy(line,s+3,256);
9911                     if (line[0]) {
9912                         lp = ckstrchr(line,')');
9913                         if (lp) *lp = NUL;
9914                         x = lookup(vartab,line,nvars,&t);
9915                         z = x > -1;
9916                         if (z) {        /* 8.0.203 */
9917                             int t;      /* It must have a value to succeed */
9918                             t = 255;    /* as in C-Kermit 6.0 and 7.0 */
9919                             lp = line;  /* (this was broken in 8.0.200-201) */
9920                             zzstring(s,&lp,&t);
9921                             t = strlen(line);
9922                             z = line[0] ? 1 : 0;
9923                         }
9924                     }
9925                 }
9926                 debug(F111,"if defined variable",line,z);
9927             } else {
9928                 z = chkvar(s);          /* Starts with backslash */
9929                 if (z > 0) {            /* Yes... */
9930                     t = 255;            /* than buffer so if zzstring fails  */
9931                     lp = line;          /* check for that -- overflow means */
9932                     line[0] = NUL;      /* the quantity is defined. */
9933                     x = zzstring(s,&lp,&t);
9934                     if ((x < 0 && t != 255) || !line[0])
9935                       z = 0;
9936                     debug(F111,"if defined zzstring",line,z);
9937                     debug(F101,"if defined zzstring t","",t);
9938                 }
9939             }
9940         } else {
9941             z = (mxlook(mactab,s,nmac) > -1); /* Look for exact match */
9942         }
9943         debug(F111,"if defined final",s,z);
9944         ifargs += 2;
9945         break;
9946
9947       case XXIFDC: {                    /* IF DECLARED */
9948           char * lp;
9949           char line[32];
9950           int j, k, t, x;
9951           if ((x = cmfld("Array name","",&s,NULL)) < 0)
9952             return((x == -3) ? -2 : x);
9953           if (*s == CMDQ) {
9954               if (*(s+1) != '&') {
9955                   t = 31;
9956                   lp = line;
9957                   line[0] = NUL;
9958                   x = zzstring(s,&lp,&t);
9959                   s = line;
9960               }
9961           }
9962           z = 0;
9963           if ((x = arraybounds(s,&j,&k)) > -1) {
9964               if (a_ptr[x]) {
9965                   if (j < 1)
9966                     z = 1;
9967                   else if (j <= a_dim[x])
9968                     z = 1;
9969                   if (z == 1 && k > a_dim[x])
9970                     z = 0;
9971               }
9972           }
9973           break;
9974       }
9975       case XXIFBG:                      /* IF BACKGROUND */
9976       case XXIFFG:                      /* IF FOREGROUND */
9977         bgchk();                        /* Check background status */
9978         if (ifc == XXIFFG)              /* Foreground */
9979           z = pflag ? 1 : 0;
9980         else z = pflag ? 0 : 1;         /* Background */
9981         ifargs += 1;
9982         break;
9983
9984       case XXIFCO:                      /* IF COUNT */
9985         z = ( --count[cmdlvl] > 0 );
9986         if (cx == XXWHI) count[cmdlvl] += 2; /* Don't ask... */
9987         debug(F101,"if count","",z);
9988         ifargs += 1;
9989         break;
9990
9991       case XXIFEX:                      /* IF EXIST */
9992 #ifdef CK_TMPDIR
9993       case XXIFDI:                      /* IF DIRECTORY */
9994 #endif /* CK_TMPDIR */
9995       case XXIFAB:                      /* IF ABSOLUTE */
9996         if ((x = cmfld(
9997                        ((ifc == XXIFDI) ? "Directory name" : "File"),
9998                        "",&s,
9999 #ifdef OS2
10000                        NULL             /* This allows \'s in filenames */
10001 #else
10002                        xxstring
10003 #endif /* OS2 */
10004                        )) < 0) {
10005             if (x == -3) {
10006                 extern int cmflgs;
10007                 if (cmflgs == 1) {
10008                     printf("?File or directory name required\n");
10009                     return(-9);
10010                 }
10011             } else return(x);
10012         }
10013         s = brstrip(s);
10014         if (ifc == XXIFAB) {
10015             z = isabsolute(s);
10016         } else if (ifc == XXIFEX) {
10017             z = (zgetfs(s) > -1L);
10018             debug(F101,"if exist 1","",z);
10019 #ifdef OS2
10020             if (!z) {                   /* File not found. */
10021                 int t;                  /* Try expanding variables */
10022                 t = LINBUFSIZ-1;        /* and looking again. */
10023                 lp = line;
10024                 zzstring(s,&lp,&t);
10025                 s = line;
10026                 z = ( zchki(s) > -1L );
10027                 debug(F101,"if exist 2","",z);
10028             }
10029 #endif /* OS2 */
10030 #ifdef CK_TMPDIR
10031         } else {
10032 #ifdef VMS
10033             z = (zchki(s) == -2)
10034 #else
10035 /* Because this doesn't catch $DISK1:[FOO]BLAH.DIR;1 */
10036             z = isdir(s)
10037 #ifdef OS2
10038               || (isalpha(s[0]) && s[1] == ':' && s[2] == NUL)
10039 #endif /* OS2 */
10040 #endif /* VMS */
10041               ;
10042             debug(F101,"if directory 1","",z);
10043
10044             if (!z) {                   /* File not found. */
10045                 int t;                  /* Try expanding variables */
10046                 t = LINBUFSIZ-1;        /* and looking again. */
10047                 lp = line;
10048                 zzstring(s,&lp,&t);
10049                 s = line;
10050                 z = isdir(s)
10051 #ifdef OS2
10052                   || (isalpha(s[0]) && s[1] == ':' && s[2] == NUL)
10053 #endif /* OS2 */
10054                     ;
10055                 debug(F101,"if directory 2","",z);
10056             }
10057 #endif /* CK_TMPDIR */
10058         }
10059         ifargs += 2;
10060         break;
10061
10062       case XXIFEQ:                      /* IF EQUAL (string comparison) */
10063       case XXIFLL:                      /* IF Lexically Less Than */
10064       case XXIFLG:                      /* If Lexically Greater Than */
10065         if ((x = cmfld("first word or variable name","",&s,xxstring)) < 0) {
10066             if (x == -3) {
10067                 printf("?Text required\n");
10068                 return(-9);
10069             } else return(x);
10070         }
10071         s = brstrip(s);                 /* Strip braces */
10072         x = (int)strlen(s);
10073         if (x > LINBUFSIZ-1) {
10074             printf("?IF: strings too long\n");
10075             return(-2);
10076         }
10077         lp = line;                      /* lp points to first string */
10078         ckstrncpy(line,s,LINBUFSIZ);
10079         if ((y = cmfld("second word or variable name","",&s,xxstring)) < 0) {
10080             if (y == -3) {
10081                 printf("?Text required\n");
10082                 return(-9);
10083             } else return(y);
10084         }
10085         s = brstrip(s);
10086         y = (int)strlen(s);
10087         if (x + y + 2 > LINBUFSIZ) {
10088             printf("?IF: strings too long\n");
10089             return(-2);
10090         }
10091         tp = lp + x + 2;                /* tp points to second string */
10092         strcpy(tp,s);                   /* safe (checked) */
10093         x = ckstrcmp(lp,tp,-1,inpcas[cmdlvl]); /* Use longest length */
10094         switch (ifc) {
10095           case XXIFEQ:                  /* IF EQUAL (string comparison) */
10096             z = (x == 0);
10097             break;
10098           case XXIFLL:                  /* IF Lexically Less Than */
10099             z = (x < 0);
10100             break;
10101           case XXIFLG:                  /* If Lexically Greater Than */
10102             z = (x > 0);
10103             break;
10104         }
10105         debug(F101,"IF EQ result","",z);
10106         ifargs += 3;
10107         break;
10108
10109       case XXIFVE:                      /* IF VERSION */
10110       case XXIFAE:                      /* IF (arithmetically) = */
10111       case XXIFNQ:                      /* IF != (not arithmetically equal) */
10112       case XXIFLT:                      /* IF <  */
10113       case XXIFLE:                      /* IF <= */
10114       case XXIFGE:                      /* IF >= */
10115       case XXIFGT: {                    /* IF >  */
10116
10117         /* Really should use longs here... */
10118         /* But cmnum parses ints. */
10119         int xx, n1 = 0, n2 = 0;
10120         if (ifc == XXIFVE) {
10121             n1 = (int) vernum;
10122         } else {
10123             x = cmfld("first number or variable name","",&s,xxstring);
10124             if (x == -3) {
10125                 printf("?Quantity required\n");
10126                 return(-9);
10127             }
10128             if (x < 0) return(x);
10129             debug(F101,"xxifgt cmfld","",x);
10130             ckstrncpy(line,s,LINBUFSIZ);
10131             lp = brstrip(line);
10132             debug(F110,"xxifgt exp1",lp,0);
10133
10134 /* The following bit is for compatibility with old versions of MS-DOS Kermit */
10135
10136             if (!ckstrcmp(lp,"count",5,0)) {
10137                 n1 = count[cmdlvl];
10138             } else if (!ckstrcmp(lp,"version",7,0)) {
10139                 n1 = (int) vernum;
10140             } else if (!ckstrcmp(lp,"argc",4,0)) {
10141                 n1 = (int) macargc[maclvl];
10142             } else {
10143
10144 /* End of compatibility bit */
10145
10146 #ifdef FNFLOAT
10147                 if (isfloat(lp,0) > 1) { /* Allow floating-point comparisons */
10148                     f1 = floatval;
10149                     f1flag = 1;
10150                 } else
10151 #endif /* FNFLOAT */
10152                   if (chknum(lp)) {
10153                       n1 = atoi(lp);
10154                   } else {              /* Check for arithmetic expression */
10155                       q = evala(lp);    /* cmnum() does this but ... */
10156                       if (chknum(q))    /* we're not using cmnum(). */
10157                         n1 = atoi(q);
10158                       else
10159                         return(-2);
10160                   }
10161             }
10162         }
10163         y = cmfld("number or variable name","",&s,xxstring);
10164         if (y == -3) {
10165             printf("?Quantity required\n");
10166             return(-9);
10167         }
10168         if (y < 0) return(y);
10169         s = brstrip(s);
10170         if (!*s) return(-2);
10171         if (ifc == XXIFVE) {
10172             tp = line;
10173         } else {
10174             x = (int)strlen(lp);
10175             tp = line + x + 2;
10176         }
10177         ckstrncpy(tp,s,LINBUFSIZ-x-2);
10178         debug(F110,"xxifgt exp2",tp,0);
10179         if (!ckstrcmp(tp,"count",5,0)) {
10180             n2 = count[cmdlvl];
10181         } else if (!ckstrcmp(tp,"version",7,0)) {
10182             n2 = (int) vernum;
10183         } else if (!ckstrcmp(tp,"argc",4,0)) {
10184             n2 = (int) macargc[maclvl];
10185         } else {
10186 #ifdef FNFLOAT
10187             if (isfloat(tp,0) > 1) {
10188                 f2 = floatval;
10189                 f2flag = 1;
10190             } else
10191 #endif /* FNFLOAT */
10192             if (chknum(tp)) {
10193                 n2 = atoi(tp);
10194             } else {
10195                 q = evala(tp);
10196                 if (chknum(q))
10197                   n2 = atoi(q);
10198                 else
10199                   return(-2);
10200             }
10201         }
10202         xx = (ifc == XXIFVE) ? XXIFGE : ifc;
10203
10204 #ifdef FNFLOAT
10205         if (f1flag && !f2flag) {
10206             f2 = (CKFLOAT)n2;
10207             f2flag = 1;
10208         }
10209         if (f2flag && !f1flag)
10210           f1 = (CKFLOAT)n1;
10211         if (f1flag)
10212           z = ((f1 <  f2 && xx == XXIFLT)
10213                || (f1 != f2 && xx == XXIFNQ)
10214                || (f1 <= f2 && xx == XXIFLE)
10215                || (f1 == f2 && xx == XXIFAE)
10216                || (f1 >= f2 && xx == XXIFGE)
10217                || (f1 >  f2 && xx == XXIFGT));
10218         else
10219 #endif /* FNFLOAT */
10220           z = ((n1 <  n2 && xx == XXIFLT)
10221                || (n1 != n2 && xx == XXIFNQ)
10222                || (n1 <= n2 && xx == XXIFLE)
10223                || (n1 == n2 && xx == XXIFAE)
10224                || (n1 >= n2 && xx == XXIFGE)
10225                || (n1 >  n2 && xx == XXIFGT));
10226         debug(F101,"xxifge z","",z);
10227         if (ifc == XXIFVE)
10228           ifargs += 2;
10229         else
10230           ifargs += 3;
10231         break;
10232       }
10233
10234       case XXIFNU:                      /* IF NUMERIC */
10235         x = cmfld("variable name or constant","",&s,NULL);
10236         if (x == -3) {
10237             extern int cmflgs;
10238             if (cmflgs == 1) {
10239                 printf("?Quantity required\n");
10240                 return(-9);
10241             }
10242         } else if (x < 0)
10243           return(x);
10244         x = LINBUFSIZ-1;
10245         lp = line;
10246         zzstring(s,&lp,&x);
10247         lp = line;
10248         debug(F110,"xxifnu quantity",lp,0);
10249         z = chknum(lp);
10250 #ifdef COMMENT
10251 /*
10252   This works, but it's not wise -- IF NUMERIC is mostly used to see if a
10253   string really does contain only numeric characters.  If they want to force
10254   evaluation, they can use \feval() on the argument string.
10255 */
10256         if (!z) {                       /* Not a number */
10257             x_ifnum = 1;                /* Avoid "eval" error messages */
10258             q = evala(lp);              /* Maybe it's an expression */
10259             z = chknum(q);              /* that evaluates to a number */
10260             x_ifnum = 0;                /* Put eval messages back to normal */
10261             if (z) debug(F110,"xxifnu exp",lp,0);
10262         }
10263 #endif /* COMMENT */
10264         debug(F101,"xxifnu chknum","",z);
10265         ifargs += 2;
10266         break;
10267
10268 #ifdef ZFCDAT
10269       case XXIFNE: {                    /* IF NEWER */
10270         char d1[20], * d2;              /* Buffers for 2 dates */
10271         if ((z = cmifi("First file","",&s,&y,xxstring)) < 0)
10272           return(z);
10273         ckstrncpy(d1,zfcdat(s),20);
10274         if ((z = cmifi("Second file","",&s,&y,xxstring)) < 0)
10275           return(z);
10276         d2 = zfcdat(s);
10277         if ((int)strlen(d1) != 17 || (int)strlen(d2) != 17) {
10278             printf("?Failure to get file date\n");
10279             return(-9);
10280         }
10281         debug(F110,"xxifnewer d1",d1,0);
10282         debug(F110,"xxifnewer d2",d2,0);
10283         z = (strcmp(d1,d2) > 0) ? 1 : 0;
10284         debug(F101,"xxifnewer","",z);
10285         ifargs += 2;
10286         break;
10287       }
10288 #endif /* ZFCDAT */
10289
10290 #ifdef CK_IFRO
10291       case XXIFRO:                      /* REMOTE-ONLY advisory */
10292         ifargs++;
10293 #ifdef NOLOCAL
10294         z = 1;
10295 #else
10296         z = remonly;
10297 #endif /* NOLOCAL */
10298         break;
10299 #endif /* CK_IFRO */
10300
10301       case XXIFAL:                      /* ALARM */
10302         ifargs++;
10303         debug(F101,"IF ALARM ck_alarm","",ck_alarm);
10304         debug(F110,"IF ALARM alrm_date",alrm_date,0);
10305         debug(F110,"IF ALARM alrm_time",alrm_time,0);
10306
10307         if (ck_alarm < 1L || alrm_date[0] < '0' || alrm_time[0] < '0') {
10308             z = 0;                      /* ALARM not SET */
10309             break;                      /* so IF ALARM fails */
10310         }
10311         /* Get current date and time */
10312         ckstrncpy(tmpbuf,ckcvtdate("",1),TMPBUFSIZ);
10313         s = tmpbuf;
10314         s[8] = NUL;
10315         z = (int) strncmp(tmpbuf,alrm_date,8); /* Compare dates */
10316         debug(F101,"IF ALARM date z","",z);
10317         if (z == 0) {                   /* Dates are the same */
10318             /* Compare times */
10319             z = (tod2sec(tmpbuf+9) >= atol(alrm_time)) ? 1 : -1;
10320             debug(F101,"IF ALARM time z","",z);
10321         }
10322         tmpbuf[0] = NUL;                /* z >= 0 if alarm is passed */
10323         z = ((z >= 0) ? 1 : 0);         /* z <  0 otherwise */
10324         debug(F101,"IF ALARM final z","",z);
10325         break;
10326
10327       case XXIFOP:                      /* IF OPEN */
10328         if ((x = cmkey(iotab,niot,"file or log","",xxstring)) < 0)
10329           return(x);
10330         if (x == 9999 || x == ZSTDIO) {
10331             bgchk();                    /* Check background status */
10332             z = pflag ? 1 : 0;
10333         } else if (x == 8888) {
10334             z = local ? ttchk() > -1 : 0;
10335 #ifdef CKLOGDIAL
10336         } else if (x == 7777) {
10337             extern int dialog;
10338             z = dialog ? 1 : 0;
10339 #endif /* CKLOGDIAL */
10340         } else
10341           z = (chkfn(x) > 0) ? 1 : 0;
10342         ifargs += 1;
10343         break;
10344
10345       case XXIFSD:                      /* Started-From-Dialer */
10346 #ifdef OS2
10347         z = StartedFromDialer;
10348 #else
10349         z = 0;
10350 #endif /* OS2 */
10351         break;
10352
10353       case XXIFTM:                      /* Terminal-Macro */
10354 #ifdef OS2
10355         z = cmdstk[cmdlvl].ccflgs & CF_KMAC;
10356 #else
10357         z = 0;
10358 #endif /* OS2 */
10359         break;
10360
10361       case XXIFEM:                      /* Emulation is active */
10362 #ifdef OS2
10363         z = 1;
10364 #else
10365         z = 0;
10366 #endif /* OS2 */
10367         break;
10368
10369       case XXIFIK:                      /* Running as IKSD? */
10370         z = inserver;
10371         break;
10372
10373       case XXIFTA:                      /* Connection is TAPI */
10374         z = 0;
10375 #ifndef NODIAL
10376 #ifdef CK_TAPI
10377         if (local && !network && tttapi)
10378           z = 1;
10379 #endif /* CK_TAPI */
10380 #endif /* NODIAL */
10381         break;
10382
10383       case XXIFMA:                      /* IF MATCH */
10384         x = cmfld("String or variable","",&s,xxstring);
10385         if (x == -3) {
10386             extern int cmflgs;
10387             if (cmflgs == 1) {
10388                 printf("?String required\n");
10389                 return(-9);
10390             }
10391         } else if (x < 0)
10392           return(x);
10393         ckstrncpy(line,s,LINBUFSIZ);
10394         s = brstrip(line);
10395         debug(F110,"xxifma string",line,0);
10396         x = cmfld("Pattern","",&p,xxstring);
10397         if (x == -3) {
10398             extern int cmflgs;
10399             if (cmflgs == 1) {
10400                 printf("?Pattern required\n");
10401                 return(-9);
10402             }
10403         } else if (x < 0)
10404           return(x);
10405         ckstrncpy(tmpbuf,p,TMPBUFSIZ);
10406         p = brstrip(tmpbuf);
10407         debug(F110,"xxifma pattern",tmpbuf,0);
10408         z = ckmatch(p,s,inpcas[cmdlvl],1);
10409         break;
10410
10411       case XXIFFL: {                    /* IF FLAG */
10412           extern int ooflag;
10413           z = ooflag;
10414           break;
10415       }
10416       case XXIFAV: {                    /* IF AVAILABLE */
10417           if ((x = cmkey(availtab,availtabn,"","",xxstring)) < 0)
10418             return(x);
10419           switch (x) {
10420             case AV_KRB4:
10421               z = ck_krb4_is_installed();
10422               break;
10423             case AV_KRB5:
10424               z = ck_krb5_is_installed();
10425               break;
10426             case AV_SRP:
10427               z = ck_srp_is_installed();
10428               break;
10429             case AV_SSL:
10430               z = ck_ssleay_is_installed();
10431               break;
10432             case AV_NTLM:
10433               z = ck_ntlm_is_installed();
10434               break;
10435             case AV_CRYPTO:
10436               z = ck_crypt_is_installed();
10437               break;
10438             case AV_SSH:
10439               z = ck_ssh_is_installed();
10440               break;
10441             default:
10442               z = 0;
10443           }
10444           break;
10445       }
10446       case XXIFAT:                      /* IF ASKTIMEOUT */
10447         z = asktimedout;
10448         break;
10449
10450       case XXIFRD:                      /* IF READABLE */
10451       case XXIFWR:                      /* IF WRITEABLE */
10452         if ((x = cmfld("File or directory name",
10453                        "",
10454                        &s,
10455 #ifdef OS2
10456                        NULL             /* This allows \'s in filenames */
10457 #else
10458                        xxstring
10459 #endif /* OS2 */
10460                        )) < 0) {
10461             if (x == -3) {
10462                 extern int cmflgs;
10463                 if (cmflgs == 1) {
10464                     printf("?File or directory name required\n");
10465                     return(-9);
10466                 }
10467             } else return(x);
10468         }
10469         s = brstrip(s);
10470 /*
10471   zchk[io]() do not do what we want here for directories, so we set
10472   a global flag telling it to behave specially in this case.  Othewise
10473   we'd have to change the API and change all ck?fio.c modules accordingly.
10474 */
10475         y = 0;                          /* Try-again control */
10476 #ifdef OS2
10477   ifrdagain:
10478 #endif /* OS2 */
10479         if (ifc == XXIFRD) {            /* IF READABLE */
10480             zchkid = 1;
10481             z = zchki(s) > -1;
10482             zchkid = 0;
10483         } else if (ifc == XXIFWR) {     /* IF WRITEABLE */
10484             zchkod = 1;
10485             z = zchko(s) > -1;
10486             zchkod = 0;
10487         }
10488 #ifdef OS2
10489         if (!z && !y) {                 /* File not found. */
10490             int t;                      /* Try expanding variables */
10491             t = LINBUFSIZ-1;            /* and looking again. */
10492             lp = line;
10493             zzstring(s,&lp,&t);
10494             s = line;
10495             z = zchko(s) > -1;
10496             y++;
10497             goto ifrdagain;
10498         }
10499 #endif /* OS2 */
10500         ifargs += 2;
10501         break;
10502       case XXIFQU:                      /* IF QUIET */
10503         z = quiet ? 1 : 0;
10504         debug(F101,"if quiet","",z);
10505         ifargs += 1;
10506         break;
10507
10508       case XXIFWI:                      /* WILD */
10509         if ((x = cmfld("File specification","",&s,xxstring)) < 0) return(x);
10510         z = iswild(s);
10511         break;
10512
10513       case XXIFCK:                      /* C-KERMIT */
10514 #ifdef OS2
10515         z = 0;
10516 #else
10517         z = 1;
10518 #endif /* OS2 */
10519         break;
10520
10521       case XXIFK9:                      /* K-95 */
10522 #ifdef OS2
10523         z = 1;
10524 #else
10525         z = 0;
10526 #endif /* OS2 */
10527         break;
10528
10529       case XXIFGU:                      /* GUI */
10530 #ifdef KUI
10531         z = 1;
10532 #else
10533         z = 0;
10534 #endif /* KUI */
10535         break;
10536
10537       case XXIFMS:                      /* MS-KERMIT */
10538         z = 0;
10539         break;
10540
10541       case XXIFLO:                      /* IF LOCAL */
10542         z = local ? 1 : 0;
10543         break;
10544
10545       case XXIFCM: {                    /* IF COMMAND */
10546           extern struct keytab cmdtab[];
10547           extern int ncmd;
10548           if ((x = cmfld("Word","",&s,xxstring)) < 0)
10549             return(x);
10550           z = lookup(cmdtab,s,ncmd,&y);
10551           z = (z == -2 || z > -1) ? 1 : 0;
10552           break;
10553       }
10554 #ifdef CKFLOAT
10555       case XXIFFP:                      /* IF FLOAT */
10556         if ((x = cmfld("Number","",&s,xxstring)) < 0)
10557           if (x != -3)                  /* e.g. empty variable */
10558             return(x);
10559         z = isfloat(s,0);
10560         break;
10561 #endif /* CKFLOAT */
10562
10563       case XXIFKB:                      /* KBHIT */
10564         z = conchk();
10565         if (z < 0) z = 0;
10566         if (z > 1) z = 1;
10567         break;
10568
10569       case XXIFKG: {                    /* KERBANG */
10570           extern int cfilef;
10571           z = (xcmdsrc == 0) ? 0 : cfilef;
10572           break;
10573       }
10574
10575       default:                          /* Shouldn't happen */
10576         return(-2);
10577     } /* end of switch */
10578
10579     if (z)
10580       *bx++ = '1';
10581     else
10582       *bx++ = '0';
10583     *bx = NUL;
10584     if (bx > boolval + BOOLLEN - 2) {
10585         printf("?Boolean expression too long");
10586         return(-9);
10587     }
10588     ecount++;                           /* Expression counter */
10589     debug(F101,"boolexp parens","",parens);
10590     debug(F101,"boolexp pcount","",pcount);
10591     if (parens && pcount > 0)
10592       goto ifagain;
10593
10594   ifend:                                /* No more - done */
10595     *bx = NUL;
10596     z = atoi(evalx(boolval));
10597     debug(F111,"boolexp boolval",boolval,z);
10598     return(z);
10599 }
10600
10601 /*  D O I F  --  Do the IF command  */
10602
10603 int
10604 doif(cx) int cx; {
10605     int x, y, z; char *s, *p;
10606     char *q;
10607 #ifdef OS2
10608     extern int keymac;
10609 #endif /* OS2 */
10610
10611     debug(F101,"doif cx","",cx);
10612
10613     z = boolexp(cx);                    /* Evaluate the condition(s) */
10614     debug(F010,"doif cmdbuf",cmdbuf,0);
10615     debug(F101,"doif boolexp","",z);
10616     if (z < 0)
10617       return(z);
10618
10619     if (cx == XXIF) {                   /* Allow IF to have XIF semantics. */
10620         char * p;
10621         p = cmpeek();
10622         if (!p) p = "";
10623         while (*p) {
10624             if (*p == SP || *p == HT)
10625               p++;
10626             else
10627               break;
10628         }
10629         if (*p == '{')
10630           cx = XXIFX;
10631     }
10632     switch (cx) {                       /* Separate handling for IF and XIF */
10633
10634       case XXASSER:                     /* And ASSERT */
10635         if ((x = cmcfm()) < 0)
10636           return(x);
10637         return(success = z);
10638
10639       case XXIF:                        /* This is IF... */
10640         ifcmd[cmdlvl] = 1;              /* We just completed an IF command */
10641         debug(F101,"doif condition","",z);
10642         if (z) {                        /* Condition is true */
10643             iftest[cmdlvl] = 1;         /* Remember that IF succeeded */
10644             if (maclvl > -1) {          /* In macro, */
10645                 pushcmd(NULL);          /* save rest of command. */
10646             } else if (tlevel > -1) {   /* In take file, */
10647                 debug(F100, "doif: pushing command", "", 0);
10648                 pushcmd(NULL);          /* save rest of command. */
10649             } else {                    /* If interactive, */
10650                 cmini(ckxech);          /* just start a new command */
10651                 printf("\n");           /* (like in MS-DOS Kermit) */
10652                 if (pflag) prompt(xxstring);
10653             }
10654         } else {                        /* Condition is false */
10655             iftest[cmdlvl] = 0;         /* Remember command failed. */
10656             if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
10657               return(y);                /* Gobble up rest of line */
10658         }
10659         return(0);
10660
10661       case XXIFX: {                     /* This is XIF (Extended IF) */
10662           char *p;
10663           char e[5];
10664           int i;
10665           if ((y = cmtxt("Object command","",&s,NULL)) < 0)
10666             return(y);                  /* Get object command. */
10667           p = s;
10668           lp = line;
10669           debug(F110,"doif THEN part",s,-54);
10670           if (litcmd(&p,&lp,LINBUFSIZ - 1) < 0) { /* Quote THEN-part */
10671               return(-2);
10672           }
10673           debug(F111,"doif THEN part 2",line,z);
10674
10675           while (*p == SP) p++;         /* Strip trailing spaces */
10676           ifcmd[cmdlvl] = 0;            /* Assume ELSE part in same line */
10677           iftest[cmdlvl] = z ? 1 : 0;
10678           if (*p) {                     /* At end? */
10679               if (!z) {                 /* No, use ELSE-part, if any */
10680                   for (i = 0; i < 4; i++) e[i] = *p++;
10681                   if (ckstrcmp(e,"else",4,0)) /* See if we have an ELSE */
10682                     return(-2);         /* Something else - error. */
10683                   debug(F010,"doif ELSE line 1",p,0);
10684                   while (*p == SP) p++; /* Skip spaces */
10685                   if (*p != '{') {      /* Brace ELSE part if necessary */
10686                       ckmakmsg(tmpbuf,TMPBUFSIZ,"{",p," }",NULL);
10687                       p = tmpbuf;
10688                       debug(F010,"doif ELSE line 2",p,0);
10689                   }
10690                   lp = line;            /* Write over THEN part... */
10691                   *lp = NUL;            /* with ELSE part. */
10692                   if (litcmd(&p,&lp,LINBUFSIZ - 2) < 0) {
10693                       return(-2);
10694                   }
10695                   while (*p == SP) p++; /* Strip trailing spaces */
10696                   if (*p) return(-2);   /* Should be nothing here. */
10697                   debug(F010,"doif ELSE line 3",line,0);
10698               }
10699           } else {                      /* At end, treat like an IF command */
10700               if (!z) line[0] = NUL;    /* Condition not true and no ELSE */
10701               ifcmd[cmdlvl] = 1;        /* Allow ELSE on next line */
10702               debug(F101,"IF condition","",z);
10703           }
10704           if (line[0]) {
10705               x = mlook(mactab,"_xif",nmac); /* Get index of "_xif" macro. */
10706               if (x < 0) {                      /* Not there? */
10707                   addmmac("_xif",xif_def);      /* Put it back. */
10708                   if (mlook(mactab,"_xif",nmac) < 0) { /* Look it up again. */
10709                       printf("?XIF macro gone!\n");
10710                       return(success = 0);
10711                   }
10712               }
10713               dodo(x,line,cmdstk[cmdlvl].ccflgs | CF_IMAC);
10714           }
10715           return(0);
10716       }
10717       case XXWHI: {                     /* WHILE Command */
10718           p = cmdbuf;                   /* Capture IF condition */
10719           ifcond[0] = NUL;              /* from command buffer */
10720           while (*p == SP) p++;
10721           while (*p != SP) p++;
10722           ifcp = ifcond;
10723           ifcp += ckstrncpy(ifcp,"{ \\flit(if ( not ",IFCONDLEN);
10724 #ifdef COMMENT
10725 /*
10726   This doesn't work because it breaks on the first left brace, which does
10727   not necessarily start the command list, e.g. "while equal \%a {\35}".
10728 */
10729           while (*p != '{' && *p != NUL) *ifcp++ = *p++;
10730           p = " ) goto _..bot) } ";
10731           while (*ifcp++ = *p++) ;
10732 #else
10733 /*
10734   The command parser sets cmbptr to the spot where it left off parsing in
10735   the command buffer.
10736 */
10737           {
10738               extern char * cmbptr;
10739               if (cmbptr) {
10740                   while (p < cmbptr && *p != NUL)
10741                     *ifcp++ = *p++;
10742                   p = " ) goto _..bot) } ";
10743                   while ((*ifcp++ = *p++)) ;
10744               } else {
10745                   printf("?Internal error parsing WHILE condition\n");
10746                   return(-9);
10747               }
10748           }
10749 #endif /* COMMENT */
10750
10751           debug(F110,"WHILE cmd",ifcond,0);
10752
10753           if ((y = cmtxt("Object command","",&s,NULL)) < 0)
10754             return(y);                  /* Get object command. */
10755           p = s;
10756           lp = line;
10757           if (litcmd(&p,&lp,LINBUFSIZ - 2) < 0) { /* Quote object command */
10758               return(-2);
10759           }
10760           debug(F101,"WHILE body",line,-54);
10761           if (line[0]) {
10762               char *p;
10763               x = mlook(mactab,"_while",nmac); /* index of "_while" macro. */
10764               if (x < 0) {              /* Not there? */
10765                   addmmac("_while",whil_def); /* Put it back. */
10766                   if (mlook(mactab,"_while",nmac) < 0) { /* Look it up again */
10767                       printf("?WHILE macro definition gone!\n");
10768                       return(success = 0);
10769                   }
10770               }
10771               p = malloc((int)strlen(ifcond) + (int)strlen(line) + 2);
10772               if (p) {
10773                   strcpy(p,ifcond);     /* safe (prechecked) */
10774                   strcat(p,line);       /* safe (prechecked) */
10775                   debug(F010,"WHILE dodo",p,0);
10776                   dodo(x,p,cmdstk[cmdlvl].ccflgs | CF_IMAC);
10777                   free(p);
10778                   p = NULL;
10779               } else {
10780                   printf("?Can't allocate storage for WHILE command");
10781                   return(success = 0);
10782               }
10783           }
10784           return(0);
10785       }
10786       default:
10787         return(-2);
10788     }
10789 }
10790 #endif /* NOSPL */
10791
10792 /* Set up a TAKE command file */
10793
10794 int
10795 dotake(s) char *s; {
10796 #ifndef NOSPL
10797     extern int tra_cmd;
10798 #endif /* NOSPL */
10799 #ifndef NOLOCAL
10800 #ifdef OS2
10801     extern int term_io;
10802     int term_io_sav = term_io;
10803 #endif /* OS2 */
10804 #endif /* NOLOCAL */
10805     int slen;
10806
10807     debug(F110,"dotake",s,0);
10808     if (!s) s = "";
10809     if (!*s) return(success = 0);
10810     slen = strlen(s);
10811     debug(F101,"dotake len","",slen);
10812
10813     if ((tfile[++tlevel] = fopen(s,"r")) == NULL) {
10814         perror(s);
10815         debug(F110,"dotake fail",s,0);
10816         tlevel--;
10817         return(success = 0);
10818     } else {
10819         tfline[tlevel] = 0;             /* Line counter */
10820 #ifdef VMS
10821         conres();                       /* So Ctrl-C will work */
10822 #endif /* VMS */
10823 #ifndef NOLOCAL
10824 #ifdef OS2
10825         term_io = 0;                    /* Disable Terminal Emulator I/O */
10826 #endif /* OS2 */
10827 #endif /* NOLOCAL */
10828 #ifndef NOSPL
10829         cmdlvl++;                       /* Entering a new command level */
10830         debug(F111,"CMD +F",s,cmdlvl);
10831         debug(F101,"dotake cmdlvl","",cmdlvl);
10832         debug(F101,"dotake tlevel","",tlevel);
10833         if (cmdlvl > CMDSTKL) {
10834             debug(F100,"dotake stack overflow","",0);
10835             cmdlvl--;
10836             debug(F111,"CMD*-F",s,cmdlvl);
10837             fclose(tfile[tlevel--]);
10838             printf("?TAKE files and/or DO commands nested too deeply\n");
10839             return(success = 0);
10840         }
10841         if (tfnam[tlevel]) {            /* Copy the filename */
10842             free(tfnam[tlevel]);
10843             tfnam[tlevel] = NULL;
10844         }
10845         if ((tfnam[tlevel] = malloc(strlen(s) + 1))) {
10846             strcpy(tfnam[tlevel],s);    /* safe */
10847         } else {
10848             printf("?Memory allocation failure\n");
10849             return(success = 0);
10850         }
10851         ifcmd[cmdlvl] = 0;              /* Set variables for this cmd file */
10852         iftest[cmdlvl] = 0;
10853         count[cmdlvl]  = count[cmdlvl-1];  /* Inherit this */
10854         intime[cmdlvl] = intime[cmdlvl-1]; /* Inherit this */
10855         inpcas[cmdlvl] = inpcas[cmdlvl-1]; /* Inherit this */
10856         takerr[cmdlvl] = takerr[cmdlvl-1]; /* Inherit this */
10857         merror[cmdlvl] = merror[cmdlvl-1]; /* Inherit this */
10858         xquiet[cmdlvl] = quiet;
10859         xcmdsrc = CMD_TF;
10860         cmdstk[cmdlvl].src = CMD_TF;    /* Say we're in a TAKE file */
10861         cmdstk[cmdlvl].lvl = tlevel;    /* nested at this level */
10862         cmdstk[cmdlvl].ccflgs = cmdstk[cmdlvl-1].ccflgs;
10863 #else
10864         takerr[tlevel] = takerr[tlevel-1]; /* Inherit this */
10865 #endif /* NOSPL */
10866     }
10867 #ifndef NOSPL
10868     if (tra_cmd)
10869       printf("[%d] +F: \"%s\"\n",cmdlvl,s);
10870 #endif /* NOSPL */
10871 #ifndef NOLOCAL
10872 #ifdef OS2
10873     term_io = term_io_sav;
10874 #endif /* OS2 */
10875 #endif /* NOLOCAL */
10876     return(1);
10877 }
10878 #endif /* NOICP */