source: trunk/third/kermit/ckuus6.c @ 10780

Revision 10780, 109.7 KB checked in by brlewis, 27 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r10779, which included commits to RCS files with non-trunk default branches.
RevLine 
[10779]1#include "ckcsym.h"
2#ifndef NOICP
3 
4/*  C K U U S 6 --  "User Interface" for Unix Kermit (Part 6)  */
5
6/*
7  Author: Frank da Cruz (fdc@columbia.edu),
8  Columbia University Academic Information Systems, New York City.
9
10  Copyright (C) 1985, 1996, Trustees of Columbia University in the City of New
11  York.  The C-Kermit software may not be, in whole or in part, licensed or
12  sold for profit as a software product itself, nor may it be included in or
13  distributed with commercial products or otherwise distributed by commercial
14  concerns to their clients or customers without written permission of the
15  Office of Kermit Development and Distribution, Columbia University.  This
16  copyright notice must not be removed, altered, or obscured.
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 datageneral
30#define fgets(stringbuf,max,fd) dg_fgets(stringbuf,max,fd)
31#endif /* datageneral */
32
33/* External Kermit Variables, see ckmain.c for description. */
34 
35extern xx_strp xxstring;
36
37extern int size, rpsiz, urpsiz, local, stdinf, sndsrc, xitsta,
38  displa, binary, parity, escape, flow, cmd_rows,
39  turn, duplex, nfils, ckxech, pktlog, seslog, tralog, stdouf,
40  turnch, dfloc, keep, maxrps, warn, cnflg, tlevel, pflag, msgflg,
41  mdmtyp, zincnt, fblksiz, frecl, frecfm, atcapr, atdiso, verwho, quiet;
42extern int repars, techo, network;
43 
44#ifdef CK_IFRO
45extern int remonly;
46#endif /* CK_IFRO */
47
48#ifdef OS2
49extern int StartedFromDialer ;
50#ifndef NT
51#define INCL_NOPM
52#define INCL_VIO                        /* Needed for ckocon.h */
53#include <os2.h>
54#undef COMMENT
55#else
56#define APIRET ULONG
57#include <windows.h>
58#endif /* NT */
59#include "ckocon.h"
60#endif /* OS2 */
61
62extern long vernum, speed;
63extern char *versio, *protv, *ckxv, *ckzv, *fnsv, *connv, *dftty, *cmdv;
64extern char *dialv, *loginv, *for_def[], *whil_def[], *xif_def[], *sw_def[];
65extern char *ckxsys, *ckzsys, *cmarg, *cmarg2;
66extern char *DIRCMD, *PWDCMD, *DELCMD, *WHOCMD, ttname[], filnam[];
67extern CHAR sstate;
68extern char *zinptr;
69
70#ifndef NOMSEND                         /* Multiple SEND */
71extern char *msfiles[];
72#endif /* NOMSEND */
73extern char fspec[];                    /* Most recent filespec */
74
75#ifdef CK_TMPDIR
76extern int f_tmpdir;                    /* Directory changed temporarily */
77extern char savdir[];                   /* For saving current directory */
78extern char * dldir;
79#endif /* CK_TMPDIR */
80
81/* Declarations from cmd package */
82 
83#ifdef DCMDBUF
84extern char *cmdbuf, *atmbuf;           /* Command buffers */
85#else
86extern char cmdbuf[], atmbuf[];         /* Command buffers */
87#endif /* DCMDBUF */
88
89#ifndef NOPUSH
90extern int nopush ;
91#endif /* NOPUSH */
92
93#ifndef NOSPL
94extern struct mtab *mactab;
95extern int nmac;
96extern long ck_alarm;
97extern char alrm_date[], alrm_time[];
98extern int x_ifnum;
99#endif /* NOSPL */
100
101/* Declarations from ck?fio.c module */
102 
103extern int backgrd;                     /* Kermit executing in background */
104 
105#ifdef COMMENT
106/*
107  These must be on stack!
108*/
109#ifndef NOSPL
110extern char vnambuf[];                  /* Buffer for variable names */
111extern char *vnp;                       /* Pointer to same */
112#endif /* NOSPL */
113#endif /* COMMENT */
114
115extern char psave[];                    /* For saving & restoring prompt */
116extern char *tp;                        /* Temporary buffer */
117
118int readblock = 4096;                   /* READ buffer size */
119CHAR * readbuf = NULL;                  /* Pointer to read buffer */
120int readsize = 0;                       /* Number of chars actually read */
121
122/* Keyword tables specific to this module */
123
124/* Modem signal table */
125
126struct keytab mstab[] = {
127#ifdef COMMENT
128/* The forms preceded by backslash are for MS-DOS Kermit compatibility. */
129/* But... \dsr doesn't work because \d = decimal constant introducer */
130    "\\cd",  BM_DCD, CM_INV,            /* Carrier Detect */
131    "\\cts", BM_CTS, CM_INV,            /* Clear To Send  */
132    "\\dsr", BM_DSR, CM_INV,            /* Data Set Ready */
133    "\\ri",  BM_RNG, CM_INV,            /* Ring Indicator */
134#endif /* COMMENT */
135    "cd",    BM_DCD, 0,                 /* Carrier Detect */
136    "cts",   BM_CTS, 0,                 /* Clear To Send  */
137    "dsr",   BM_DSR, 0,                 /* Data Set Ready */
138    "ri",    BM_RNG, 0                  /* Ring Indicator */
139};
140int nms = (sizeof(mstab) / sizeof(struct keytab));
141
142#ifndef NOSPL
143struct keytab opntab[] = {
144#ifndef NOPUSH
145    "!read",  XYFZ_Y, 0,
146    "!write", XYFZ_X, 0,
147#endif /* NOPUSH */
148    "append", XYFZ_A, 0,
149    "read",   XYFZ_O, 0,
150    "write",  XYFZ_N, 0
151};
152int nopn = (sizeof(opntab) / sizeof(struct keytab));
153
154struct keytab iftab[] = {               /* IF commands */
155    "<",          XXIFLT, 0,
156    "=",          XXIFAE, 0,
157    ">",          XXIFGT, 0,
158    "alarm",      XXIFAL, 0,
159    "background", XXIFBG, 0,
160    "count",      XXIFCO, 0,
161    "defined",    XXIFDE, 0,
162#ifdef CK_TMPDIR
163    "directory",  XXIFDI, 0,
164#endif /* CK_TMPDIR */
165#ifdef COMMENT
166    "eof",        XXIFEO, 0,
167#endif /* COMMENT */
168    "emulation",  XXIFEM, 0,
169    "equal",      XXIFEQ, 0,
170    "error",      XXIFFA, CM_INV,
171    "exist",      XXIFEX, 0,
172    "failure",    XXIFFA, 0,
173    "false",      XXIFNT, 0,
174    "foreground", XXIFFG, 0,
175    "llt",        XXIFLL, 0,
176    "lgt",        XXIFLG, 0,
177#ifdef OS2
178    "terminal-macro", XXIFTM, CM_INV,
179#endif /* OS2 */
180#ifdef ZFCDAT
181    "newer",      XXIFNE, 0,
182#endif /* ZFCDAT */
183    "not",        XXIFNO, 0,
184    "ok",         XXIFSU, CM_INV,
185    "numeric",    XXIFNU, 0,
186    "remote-only",XXIFRO, 0,
187    "started-from-dialer",XXIFSD, CM_INV,
188    "success",    XXIFSU, 0,
189    "true",       XXIFTR, 0
190};
191int nif = (sizeof(iftab) / sizeof(struct keytab));
192#endif /* NOSPL */
193
194/* Variables and symbols local to this module */
195 
196#ifndef NODIAL
197_PROTOTYP(static int ddcvt, (char *, FILE *, int) );
198_PROTOTYP(static int dncvt, (int, int) );
199_PROTOTYP(char * getdname, (void) );
200
201char *dialnum = (char *)0;              /* Remember DIAL number for REDIAL */
202int dirline = 0;                        /* Dial directory line number */
203extern char * dialdir[];                /* Dial directory file names */
204extern int dialdpy;                     /* DIAL DISPLAY on/off */
205extern int ndialdir;                    /* How many dial directories */
206#ifdef NETCONN
207extern int nnetdir;                     /* How many network directories */
208#endif /* NETCONN */
209extern int ntollfree;                   /* Toll-free call info */
210extern char *dialtfc[];
211extern int tttapi;
212extern int dialatmo;
213extern char * dialnpr, * dialsfx;
214extern char * diallcc;                  /* Dial local country code */
215extern char * diallac;                  /* Dial local area code */
216extern char * dialixp, * dialixs;
217extern char * dialldp, * diallds, * dialtfp;
218extern char * dialpxx, * dialpxi, * dialpxo;
219extern int dialcnf;                     /* DIAL CONFIRMATION */
220int dialsrt = 1;                        /* DIAL SORT ON */
221int dialrstr = 6;                       /* DIAL RESTRICTION */
222
223extern int dialsta;                     /* Dial status */
224int dialrtr = 0,                        /* Dial retries */
225    dialint = 10;                       /* Dial retry interval */
226extern long dialcapas;                  /* Modem capabilities */
227extern int dialcvt;                     /* DIAL CONVERT-DIRECTORY */
228#endif /* NODIAL */
229
230#ifndef NOSPL
231int ifc,                                /* IF case */
232    not = 0,                            /* Flag for IF NOT */
233    ifargs;                             /* Count of IF condition words */
234char ifcond[100];                       /* IF condition text */
235char *ifcp;                             /* Pointer to IF condition text */
236#ifdef DCMDBUF
237extern int *ifcmd, *count, *iftest, *intime, *inpcas, *takerr, *merror;
238#else
239extern int ifcmd[];                     /* Last command was IF */
240extern int iftest[];                    /* Last IF was true */
241extern int count[];                     /* For IF COUNT, one for each cmdlvl */
242extern int intime[];
243extern int inpcas[];
244extern int takerr[];
245extern int merror[];
246#endif /* DCMDBUF */
247#else
248extern int takerr[];
249#endif /* NOSPL */
250
251#ifdef DCMDBUF
252extern char *line;                      /* Character buffer for anything */
253extern char *tmpbuf;
254#else
255extern char line[], tmpbuf[];
256#endif /* DCMDBUF */
257extern char *lp;                        /* Pointer to line buffer */
258
259int cwdf = 0;                           /* CWD has been done */
260
261#ifndef NOSERVER
262/* Flags for ENABLE/DISABLE */
263extern int en_cwd, en_cpy, en_del, en_dir, en_fin,
264   en_get, en_hos, en_ren, en_sen, en_set, en_spa, en_typ, en_who, en_bye,
265   en_asg, en_que, en_ret, en_mai, en_pri;
266#endif /* NOSERVER */
267
268extern FILE *tfile[];                   /* File pointers for TAKE command */
269extern char *tfnam[];                   /* Names of TAKE files */
270extern int tfline[];                    /* TAKE-file line number */
271
272extern int success;                     /* Command success/failure flag */
273
274#ifndef NOSPL
275extern int maclvl;                      /* Macro to execute */
276extern char *macx[];                    /* Index of current macro */
277extern char *mrval[];                   /* Macro return value */
278extern char *macp[];                    /* Pointer to macro */
279extern int macargc[];                   /* ARGC from macro invocation */
280
281extern char *m_arg[MACLEVEL][NARGS];    /* Stack of macro arguments */
282extern char *g_var[];                   /* Global variables %a, %b, etc */
283 
284#ifdef DCMDBUF
285extern struct cmdptr *cmdstk;           /* The command stack itself */
286#else
287extern struct cmdptr cmdstk[];          /* The command stack itself */
288#endif /* DCMDBUF */
289extern int cmdlvl;                      /* Current position in command stack */
290#endif /* NOSPL */
291
292#define xsystem(s) zsyscmd(s)
293
294static int x, y, z = 0;
295static char *s, *p;
296
297#ifdef OS2
298_PROTOTYP( int os2settitle, (char *, int) );
299#endif /* OS2 */
300
301extern struct keytab yesno[];
302extern int nyesno;
303
304#ifndef NOSPL
305
306/* Do the ASK, ASKQ, GETOK, and READ commands */
307
308int
309doask(cx) int cx; {
310    extern int cmflgs;
311#ifdef CK_RECALL
312    int sv_recall;
313    extern int on_recall;
314#endif /* CK_RECALL */
315
316    char vnambuf[VNAML];                /* Buffer for variable names */
317    char *vnp = NULL;                   /* Pointer to same */
318    if (cx != XXGOK && cx != XXRDBL) {  /* Get variable name */
319        if ((y = cmfld("Variable name","",&s,NULL)) < 0) {
320            if (y == -3) {
321                printf("?Variable name required\n");
322                return(-9);
323            } else return(y);
324        }
325        strcpy(vnambuf,s);              /* Make a copy. */
326        vnp = vnambuf;
327        if (vnambuf[0] == CMDQ &&
328            (vnambuf[1] == '%' || vnambuf[1] == '&'))
329          vnp++;
330        y = 0;
331        if (*vnp == '%' || *vnp == '&') {
332            if ((y = parsevar(vnp,&x,&z)) < 0)
333              return(y);
334        }
335    }
336    if (cx == XXREA || cx == XXRDBL) {  /* READ or READBLOCK command */
337        if ((y = cmcfm()) < 0)          /* Get confirmation */
338          return(y);
339        if (chkfn(ZRFILE) < 1) {        /* File open? */
340            printf("?Read file not open\n");
341            return(0);
342        }
343        if (!(s = (char *)readbuf)) {           /* Where to read into. */
344            printf("?Oops, no READ buffer!\n");
345            return(0);
346        }
347#ifdef BINREAD
348        if (cx == XXRDBL) {             /* READBLOCK */
349            y = zxin(ZRFILE, s, readblock);
350            if (y < 1) {
351                zclose(ZRFILE);         /* close the file, */
352                return(success = 0);
353            }
354            readsize = y;
355            printf("READBLOCK %d\n",y);
356        } else
357#endif /* BINREAD */
358          {
359            y = zsinl(ZRFILE, s, readblock); /* Read a line. */
360            debug(F111,"read zsinl",s,y);
361            if (y < 0) {                /* On EOF or other error, */
362                zclose(ZRFILE);         /* close the file, */
363                delmac(vnp);            /* delete the variable, */
364                return(success = 0);    /* and return failure. */
365            } else {                    /* Read was OK. */
366                readsize = (int) strlen(s);
367                success = (addmac(vnp,s) < 0 ? 0 : 1); /* Define variable */
368                debug(F111,"read addmac",vnp,success);
369                return(success);        /* Return success. */
370            }
371        }
372    }
373
374    /* ASK, ASKQ, or GETOK */
375
376    if ((y = cmtxt("Prompt, enclose in { braces } to preserve\n\
377leading and trailing spaces, precede question mark with backslash (\\).",
378                   cx == XXGOK ? "{ Yes or no? }" : "",
379                   &p,NULL)) < 0) {
380        return(y);
381    }
382#ifdef VMS
383/*
384  In VMS, whenever a TAKE file or macro is active, we had to restore the
385  original console modes or else Ctrl-C/Ctrl-Y would not work.  But here we
386  go interactive again, so we have to temporarily put them back.
387*/
388    if (cmdlvl > 0)
389      concb((char)escape);
390#endif /* VMS */
391     
392    cmsavp(psave,PROMPTL);              /* Save old prompt */
393    cmsetp(brstrip(p));                 /* Make new prompt */
394reprompt:
395    if (cx == XXASKQ) {                 /* For ASKQ, */
396        concb((char)escape);            /* put console in cbreak mode */
397        cmini(0);                       /* and no-echo mode. */
398    } else {                            /* For others, regular echoing. */
399        cmini(ckxech);
400    }
401    x = -1;                             /* This means to reparse. */
402    cmflgs = 0;
403    if (pflag) prompt(xxstring);        /* Issue prompt. */
404reparse:
405    cmres();
406    if (cx == XXGOK) {
407#ifdef CK_RECALL
408        sv_recall = on_recall;
409        on_recall = 0;
410#endif /* CK_RECALL */
411        x = cmkey(yesno,nyesno,"","",xxstring); /* GETOK uses keyword table */
412        if (x < 0) {                    /* Parse error */
413            if (x == -3) {              /* No answer? */
414                printf("Please respond Yes or No\n"); /* Make them answer */
415                cmini(ckxech);
416                goto reprompt;
417            } else if (x == -1) {
418                goto reparse;
419            } else
420              goto reprompt;
421        }
422        if (cmcfm() < 0)                /* Get confirmation */
423          goto reparse;
424        cmsetp(psave);                  /* Restore prompt */
425#ifdef VMS
426        if (cmdlvl > 0)                 /* In VMS and not at top level, */
427          conres();                     /*  restore console again. */
428#endif /* VMS */
429#ifdef CK_RECALL
430        on_recall = sv_recall;
431#endif /* CK_RECALL */
432        return(x);                      /* Return success or failure */
433    } else if (cx == XXGETC) {          /* GETC */
434        char tmp[2];
435        x = coninc(0);                  /* Just read one character */
436        if (x > -1) {
437            printf("\r\n");
438            tmp[0] = (char) (x & 0xff);
439            tmp[1] = NUL;
440            y = addmac(vnp,tmp);        /* Add it to the macro table. */
441            debug(F111,"getc addmac",vnp,y);
442            cmsetp(psave);              /* Restore old prompt. */
443        } else y = -1;
444        return(success = y < 0 ? 0 : 1);
445    } else {                            /* ASK or ASKQ */
446#ifdef CK_RECALL
447        sv_recall = on_recall;
448        on_recall = 0;
449#endif /* CK_RECALL */
450        y = cmdgquo();                  /* Get current quoting */
451        cmdsquo(0);                     /* Turn off quoting */
452        while (x == -1) {               /* Prompt till they answer */
453            x = cmtxt("Please respond.","",&s,NULL);
454            debug(F111,"ASK cmtxt",s,x);
455            cmres();
456        }
457        cmdsquo(y);                     /* Restore previous quoting */
458#ifdef CK_RECALL
459        on_recall = sv_recall;
460#endif /* CK_RECALL */
461        if (cx == XXASKQ)               /* ASKQ must echo CRLF here */
462          printf("\r\n");
463        if (x < 0) {                    /* If cmtxt parse error, */
464            cmsetp(psave);              /* restore original prompt */
465#ifdef VMS
466            if (cmdlvl > 0)             /* In VMS and not at top level, */
467              conres();                 /*  restore console again. */
468#endif /* VMS */
469            return(x);                  /* and return cmtxt's error code. */
470        }
471        if (*s == NUL) {                /* If user typed a bare CR, */
472            cmsetp(psave);              /* Restore old prompt, */
473            delmac(vnp);                /* delete variable if it exists, */
474#ifdef VMS
475            if (cmdlvl > 0)             /* In VMS and not at top level, */
476              conres();                 /*  restore console again. */
477#endif /* VMS */
478            return(success = 1);        /* and return. */
479        }
480        y = addmac(vnp,s);              /* Add it to the macro table. */
481        debug(F111,"ask addmac",vnp,y);
482        cmsetp(psave);                  /* Restore old prompt. */
483#ifdef VMS
484        if (cmdlvl > 0)                 /* In VMS and not at top level, */
485          conres();                     /*  restore console again. */
486#endif /* VMS */
487        return(success = y < 0 ? 0 : 1);
488    }
489}
490#endif /* NOSPL */
491
492#ifndef NOSPL
493int
494doincr(cx) int cx; {                    /* INCREMENT, DECREMENT */
495    char vnambuf[VNAML+1];              /* Buffer for variable names */
496
497    if ((y = cmfld("Variable name","",&s,NULL)) < 0) {
498        if (y == -3) {
499            printf("?Variable name required\n");
500            return(-9);
501        } else return(y);
502    }
503    strncpy(vnambuf,s,VNAML);
504    if ((y = cmnum("by amount","1",10,&x,xxstring)) < 0)
505      return(y);
506    if ((y = cmcfm()) < 0)
507      return(y);
508
509    z = (cx == XXINC ? 1 : 0);          /* Increment or decrement? */
510
511    if (incvar(vnambuf,x,z) < 0) {
512        printf("?Variable %s not defined or not numeric\n",vnambuf);
513        return(success = 0);
514    }
515    return(success = 1);
516}
517#endif /* NOSPL */
518
519
520/* Do the (_)DEFINE, (_)ASSIGN, and UNDEFINE commands */
521
522#ifndef NOSPL
523int
524dodef(cx) int cx; {
525    char vnambuf[VNAML];                /* Buffer for variable names */
526    char *vnp;                          /* Pointer to same */
527    if (cx == XXDFX || cx == XXASX)
528      y = cmfld("Macro or variable name","",&s,xxstring); /* eval var name */
529    else
530      y = cmfld("Macro or variable name","",&s,NULL);     /* don't evaluate */
531    if (y < 0) {
532        if (y == -3) {
533            printf("?Variable name required\n");
534            return(-9);
535        } else return(y);
536    }
537    debug(F111,"dodef success",s,success);
538    strcpy(vnambuf,s);
539    vnp = vnambuf;
540    if (vnambuf[0] == CMDQ && (vnambuf[1] == '%' || vnambuf[1] == '&')) vnp++;
541    if (*vnp == '%' || *vnp == '&') {
542        if ((y = parsevar(vnp,&x,&z)) < 0) return(y);
543        if (cx == XXUNDEF) {            /* Undefine */
544            if ((y = cmcfm()) < 0) return(y);
545            delmac(vnp);
546            return(success = 1);
547        }
548        debug(F101,"dodef","",x);
549        if (y == 1) {                   /* Simple variable */
550            if ((y = cmtxt("Definition of variable","",&s,NULL)) < 0)
551              return(y);
552            s = brstrip(s);
553            debug(F110,"xxdef var name",vnp,0);
554            debug(F110,"xxdef var def",s,0);
555        } else if (y == 2) {            /* Array element */
556            if ((y = arraynam(s,&x,&z)) < 0) return(y);
557            if (x == 96) {
558                printf("?Argument vector array is read-only\n");
559                return(-9);
560            }
561            if (chkarray(x,z) < 0) return(-2);
562            if ((y = cmtxt("Definition of array element","",&s,NULL)) < 0)
563              return(y);
564            debug(F110,"xxdef array ref",vnp,0);
565            debug(F110,"xxdef array def",s,0);
566        }
567    } else {                            /* Macro */
568        if (cx == XXUNDEF) {            /* Undefine */
569            if ((y = cmcfm()) < 0) return(y);
570            delmac(vnp);
571            return(success = 1);
572        }
573        if ((y = cmtxt("Definition of macro","",&s,NULL)) < 0) return(y);
574        debug(F110,"xxdef macro name",vnp,0);
575        debug(F110,"xxdef macro def",s,0);
576        if (*s == '{') {                /* Allow macro def to be bracketed. */
577            s++;                        /* If it is, remove the brackets. */
578            y = (int)strlen(s);         /* FOR command depends on this! */
579            if (y > 0 && s[y-1] == '}') s[y-1] = NUL;
580        }
581    }
582    if (*s == NUL) {                    /* No arg given, undefine */
583        delmac(vnp);                    /* silently... */
584        return(success = 1);            /* even if it doesn't exist... */
585    }
586
587    /* Defining a new macro or variable */
588
589    if (cx == XXASS || cx == XXASX) {   /* ASSIGN rather than DEFINE? */
590        int t;
591        t = LINBUFSIZ-1;
592        lp = line;                      /* If so, expand its value now */
593        zzstring(s,&lp,&t);
594        s = line;
595    }
596    debug(F111,"calling addmac",s,(int)strlen(s));
597
598    y = addmac(vnp,s);                  /* Add it to the appropriate table. */
599    if (y < 0) {
600        printf("?%s failed\n",(cx == XXASS || cx == XXASX) ?
601               "ASSIGN" : "DEFINE");
602        return(success = 0);
603    } else if (cx == XXASX || cx == XXDFX) /* For _ASG or _DEF, */
604      return(1);                           /* don't change success variable */
605    else
606      return(success = 1);
607}
608#endif /* NOSPL */
609
610
611#ifndef NODIAL
612/*
613   L U D I A L  --  Lookup up dialing directory entry.
614 
615   Call with string to look up and file descriptor of open dialing directory
616   file.  On success, returns number of matches found, with numbers stored
617   in an array accessible via getdnum().
618*/
619static char *dn_p[MAXDNUMS + 1];        /* Dial Number pointers */
620static char *dn_p2[MAXDNUMS + 1];       /* Converted dial number pointers */
621static int dn_x[MAXDNUMS + 1];          /* Type of call */
622static int dncount = 0;
623char * d_name = NULL;                   /* Dial name pointer */
624
625char *                                  /* Get dial directory entry name */
626getdname() {
627    return(d_name ? d_name : "");
628}
629
630char *
631getdnum(n) int n; {                     /* Get dial number n from directory */
632    if (n < 0 || n > dncount || n > MAXDNUMS)
633      return("");
634    else
635      return(dn_p[n]);
636}
637
638char *                  /* Check area code for spurious leading digit */
639chk_ac(i,buf) int i; char buf[]; {
640    char *p;
641    if (!buf)
642      return("");
643    p = (char *) buf;                   /* Country we are calling: */
644    if (i ==  44 ||                     /* UK */
645        i ==  49 ||                     /* Germany */
646        i ==  39 ||                     /* Italy */
647        i ==  31 ||                     /* Netherlands */
648        i == 351 ||                     /* Portugal */
649        i ==  55 ||                     /* Brazil */
650        i == 972 ||                     /* Israel */
651        i ==  41 ||                     /* Switzerland */
652        i ==  43 ||                     /* Austria */
653        i ==  42 ||                     /* Czech Republic */
654        i ==  36 ||                     /* Hungary */
655        i ==  30 ||                     /* Greece */
656        i == 352 ||                     /* Luxembourg */
657        i ==  48 ||                     /* Poland */
658        i ==  27 ||                     /* South Africa */
659        ((i == 33) && ((int) strcmp(zzndate(),"19961017") > 0)) /* France */
660        ) {
661        if (buf[0] == '0')
662          p++;
663    } else if (i == 358) {              /* Finland */
664        char c = '9';
665        if ((int) strcmp(zzndate(),"19961011") > 0)
666          c = '0';
667        if (buf[0] == c)                /* But only until 12 Oct 96! */
668          p++;
669    }
670    return(p);
671}
672
673static int
674dncvt(k,cx) int k, cx; {                /* Dial Number Convert */
675    int i, j, n, what;
676    char *ss;
677    char *p, *pxo;
678    char **pp;
679    char *lac;
680    char *npr;
681    char *sfx;
682    char ccbuf[128];
683    int cc;
684    char acbuf[24];
685    char *acptr;
686    char outbuf[256];
687
688#define DN_INTERN 0
689#define DN_FREE   1
690#define DN_LOCAL  2
691#define DN_UNK    3
692#define DN_LONG   4
693#define DN_INTL   5
694/*
695  First pass for strict (punctuation-based) interpretation.
696  If it fails, we try the looser (length-based) one.
697*/
698    what = 0;                           /* Type of call */
699    s = dn_p[k];                        /* Number to be converted. */
700    debug(F111,"dncvt",s,k);
701    if (dn_p2[k]) {
702        free(dn_p2[k]);
703        dn_p2[k] = NULL;
704    }
705    if (!s) {
706        printf("Error - No phone number to convert\n");
707        return(-1);
708    }
709    pp = &(dn_p2[k]);                   /* Address for converted number */
710
711    if (tttapi) {                       /* When using TAPI */
712        npr = "";                       /* TAPI supplies all the */
713        sfx = "";                       /* prefixes and suffixes */
714        pxo = "";
715    } else {
716        npr = dialnpr ? dialnpr : "";
717        sfx = dialsfx ? dialsfx : "";
718        pxo = dialpxo ? dialpxo : "";
719    }
720    lac = diallac ? diallac : "";       /* Local area code */
721
722    outbuf[0] = NUL;                    /* Initialize conversion buffer */
723    ss = s;                             /* Remember original string */
724
725    if (*s != '+') {                    /* Literal number */
726        sprintf(outbuf,                 /* Sandwich it between */
727                "%s%s%s%s",             /* DIAL PREFIX and SUFFIX */
728                pxo,npr,s,sfx
729                );
730        makestr(pp, outbuf);
731        dn_x[k] = DN_UNK;               /* Sort key is "unknown". */
732        return(0);                      /* Done. */
733    }
734    i = 0;                              /* Portable number */
735    s++;                                /* Tiptoe past the plus sign */
736    ccbuf[0] = NUL;                     /* Do country code first */
737
738    if (!diallcc) {                     /* Do we know our own? */
739        if (cx != XXLOOK)
740          printf("Error - prior SET DIAL COUNTRY-CODE command required\n");
741        return(-1);
742    }
743
744    /* Parse the number */
745
746    while (1) {                         /* Get the country code */
747        while (*s == HT || *s == SP)
748          s++;
749        if (!s)                         /* Not in standard format */
750          break;
751        if (*s == '(') {                /* Beginning of area code  */
752            s++;                        /* Skip past parenthesis   */
753            ccbuf[i] = NUL;             /* End of country code */
754            if (!s) {                   /* Check for end of string */
755                printf("Error - phone number ends prematurely: \"%s\"\n",ss);
756                return(-1);
757            }
758            break;
759        } else {                        /* Collect country code */
760            if (isdigit(*s))
761              ccbuf[i++] = *s;          /* copy this character */
762            s++;
763            if (!*s || i > 127)         /* watch out for memory leak */
764              break;
765        }
766    }
767    cc = atoi(ccbuf);                   /* Numeric version of country code */
768
769    i = 0;                              /* Now get area code */
770    acbuf[0] = NUL;                     /* Initialize area-code buffer */
771    acptr = acbuf;                      /* and pointer. */
772    while (1) {
773        while (*s == HT || *s == SP)    /* Ignore whitespace */
774          s++;
775        if (!s)                         /* String finished */
776          break;
777        if (*s == ')') {                /* End of area code  */
778            s++;                        /* Skip past parenthesis   */
779            acbuf[i] = NUL;             /* Terminate area-code buffer */
780            break;
781        } else {                        /* Part of area code */
782            if (isdigit(*s))            /* If it's a digit, */
783              acbuf[i++] = *s;          /* copy this character */
784            s++;                        /* Point to next */
785            if (!*s || i > 23)          /* Watch out for overflow */
786              break;
787        }
788    }
789
790/*
791   Here we strip any leading 0 for countries that we know have
792   0 as a long-distance prefix and do not have any area codes that
793   start with 0 (ditto for "9" in Finland...)
794*/
795    i = atoi(ccbuf);
796    acptr = chk_ac(i,acbuf);
797
798    while (*s == HT || *s == SP)        /* Skip whitespace */
799      s++;
800
801/* printf("S=[%s], ACPTR=[%s]\n",s,acptr); */
802
803    if (*s && *acptr) {                 /* Area code was delimited */
804
805        while (*s == '-' || *s == '.')  /* Skip past gratuitious punctuation */
806          s++;
807        if (!*s) s--;                   /* But not to end of string */
808
809        if (strcmp(diallcc,ccbuf)) {    /* Out of country? */
810            char * p2;
811            if (!dialixp) {             /* Need intl-prefix */
812                if (cx != XXLOOK)
813                  printf("Error - No international dialing prefix defined\n");
814                return(-1);
815            }
816            what = dn_x[k] = DN_INTL;
817            if (tttapi) {
818                p  = "";                /* Intl-suffix */
819                p2 = "";                /* Intl-prefix */
820            } else {
821                p  = dialixp ? dialixp : ""; /* Intl-prefix */
822                p2 = dialixs ? dialixs : ""; /* Intl-suffix */
823            }
824            sprintf(outbuf,             /* Form the final phone number */
825                    "%s%s%s%s%s%s%s%s",
826                    pxo,npr,p,ccbuf,acptr,s,p2,sfx
827                    );
828        } else if (strcmp(lac,acptr)) { /* In-country */
829            char * p2;
830#ifdef COMMENT
831/* Wrong - Sometimes it has to be null, e.g. for NANP 10-digit dialing... */
832            if (!dialldp) {             /* Out of area code */
833                if (cx != XXLOOK)       /* Need ld-prefix */
834                  printf("Error - No long-distance prefix defined\n");
835                return(-1);
836            }
837#endif /* COMMENT */
838            if (!diallac && cx != XXLOOK) { /* Don't know my own area code */
839                if (cc == 1)
840                  printf("WARNING - Prior SET DIAL AREA-CODE needed\n");
841            }
842
843            what = dn_x[k] = DN_LONG;   /* Long-distance */
844
845            for (i = 0; i < ntollfree; i++) { /* Check for toll-free call */
846                if (!strcmp(acptr,dialtfc[i])) {
847                    what = dn_x[k] = DN_FREE;             
848                    break;
849                }
850            }
851            if (tttapi) {               /* TAPI supplies its own */
852                p  = "";                /* ld-suffix */
853                p2 = "";                /* ld-prefix */
854            } else if (what == DN_FREE) { /* Toll-free call */
855                p = dialtfp ? dialtfp : (dialldp ? dialldp : "");
856                p2 = "";                /* no suffix */
857            } else {                    /* normal long distance */
858                p  = dialldp ? dialldp : ""; /* ld-prefix */
859                p2 = diallds ? diallds : ""; /* ld-suffix */
860            }
861            sprintf(outbuf,"%s%s%s%s%s%s%s", /* Form the number to be dialed */
862                    pxo,npr,p,acptr,s,p2,sfx
863                    );
864        } else {                        /* Same country, same area code */
865            what = dn_x[k] = DN_LOCAL;  /* So it's a local call. */
866            if (!dialpxo || tttapi) {   /* TAPI or not dialing out from PBX */
867                sprintf(outbuf,"%s%s%s",
868                        npr,s,sfx
869                        );
870            } else {                    /* Dialing from a PBX and not TAPI */
871                if (dialpxx) {          /* Is it internal? */
872                    i = (int) strlen(dialpxx);
873                    j = (int) strlen(s);
874                    x = -1;
875                    if (j > i)
876                      x = xxstrcmp(dialpxx,s,i);
877                    if (!x) {
878                        what = dn_x[k] = DN_INTERN;   /* Internal call. */
879                        s += i;
880                        p = (dialpxi) ? dialpxi : ""; /* Internal prefix */
881                        sprintf(outbuf,"%s%s%s%s",   
882                                npr,p,s,sfx
883                                );
884                    } else {    /* External local call */
885                        sprintf(outbuf,"%s%s%s%s",
886                                dialpxo,npr,s,sfx
887                                );
888                    }
889                }
890            }
891        }
892
893    } else {                            /* Area code was not delimited */
894
895        char xbuf[256];                 /* Comparison based only on length */
896        char ybuf[256];
897        s = ss;
898        for (i = 0; i < 255; i++) {
899            if (!*s)
900              break;
901            while (!isdigit(*s))        /* Only pay attention to digits */
902              s++;
903            xbuf[i] = *s++;
904        }
905        xbuf[i] = NUL;
906        sprintf(ybuf,"%s%s",diallcc,lac);
907        n = (int) strlen(ybuf);
908        if (n > 0 && !xxstrcmp(xbuf,ybuf,n)) { /* Local call */
909            dn_x[k] = DN_LOCAL;
910            s = xbuf + n;
911            sprintf(outbuf,"%s%s%s%s",pxo,npr,s,sfx);
912        } else {                        /* Not local */
913            sprintf(ybuf,"%s",diallcc);
914            n = (int) strlen(ybuf);
915            if (n > 0 && !xxstrcmp(xbuf,ybuf,n)) { /* Long distance */
916                char * p2;
917                dn_x[k] = DN_LONG;
918#ifdef COMMENT
919                if (!dialldp) {
920                    if (cx != XXLOOK && !tttapi)
921                      printf("Error - No long-distance prefix defined\n");
922                    return(-1);
923                }
924#endif /* COMMENT */
925                if (tttapi) {
926                    p = "";
927                    p2 = "";
928                } else {
929                    p = dialldp ? dialldp : "";
930                    p2 = diallds ? diallds : "";
931                }
932                s = xbuf + n;
933                while (*s == '-' || *s == '.')
934                  s++;
935                sprintf(outbuf,"%s%s%s%s%s%s",pxo,npr,p,s,p2,sfx);
936            } else {
937                char * p2;              /* International */
938                dn_x[k] = DN_INTL;
939                if (!dialixp) {
940                    if (cx != XXLOOK && !tttapi) {
941                        printf(
942                          "Error - No international dialing prefix defined\n"
943                               );
944                        return(-1);
945                    }
946                }
947                if (tttapi) {
948                    p = "";
949                    p2 = "";
950                } else {
951                    p = dialixp ? dialixp : "";
952                    p2 = dialixs ? dialixs : "";
953                }
954                sprintf(outbuf,"%s%s%s%s%s%s",pxo,npr,p,xbuf,p2,sfx);
955            }
956        }
957    }
958    makestr(pp, outbuf);
959    return(0);
960}
961
962static int
963ddcvt(s, f, n) char * s; FILE * f; int n; { /* Dial Directory Convert */
964    char *line, *s2;                    /* buffers */
965#ifdef VMS
966    char * temp;
967#endif /* VMS */
968    char *info[8];                      /* Pointers to words from entry */
969    FILE * f2;
970    int x, rc;
971    rc = -1;
972
973    if (!s || !f)                       /* No filename or file */
974      return(-1);
975    if ((int) strlen(s) < 1)
976      return(-1);
977    if (!(line = malloc(1024)))         /* Allocate input buffer */
978      return(-1);
979    f2 = NULL;
980
981    fclose(f);
982    znewn(s,&s2);                       /* s2 = address of static buffer */
983#ifdef VMS
984    temp = s2;                          /* Swap - otherwise the new */
985    s2 = s;                             /* version has the older version */
986    s = temp;                           /* number... */
987    if (temp =  (char *)malloc((int)strlen(s)+1))
988      strcpy(temp,s);
989    if (dialdir[n])                     /* Replace filename in list */
990      free(dialdir[n]);
991    dialdir[n] = temp;
992    s = temp;
993#else
994    if (zrename(s,s2) < 0) {            /* Not VMS - rename old file */
995        perror(s2);                     /* to new (wierd) name. */
996        goto ddexit;
997    }
998#endif /* VMS */
999    if ((f = fopen(s2,"r")) == NULL) {  /* Reopen old file with wierd name */
1000        dirline = 0;                    /* (or in VMS, old version) */
1001        perror(s2);
1002        goto ddexit;
1003    }
1004    if ((f2 = fopen(s,"w")) == NULL) {  /* Create new file with old name */
1005        perror(s);                      /* (or in VMS, new version) */
1006        goto ddexit;
1007    }
1008    printf("\nSaving old directory as %s.\nConverting %s...",s2,s);
1009    fprintf(f2,"; %s - Kermit dialing directory\n", s);
1010    fprintf(f2,"%-16s %-20s ; %5s %-6s ; %s\n",
1011               "; Name","Number","Speed","Parity","Comment"
1012               );
1013
1014    while (1) {
1015        line[0] = NUL;                  /* Read a line */
1016        if (fgets(line,1023,f) == NULL)
1017          break;
1018        if (!line[0]) {                 /* Empty line */
1019            fprintf(f2,"\n");
1020            continue;
1021        }
1022        x = (int) strlen(line);         /* Strip line terminator, */
1023        while (x-- > 0) {               /* if any. */
1024            if (line[x] <= SP)
1025              line[x] = NUL;
1026            else
1027              break;
1028        }
1029        xwords(line,5,info,1);          /* Parse it the old way */
1030        for (x = 1; x < 6; x++)
1031          if (!info[x]) info[x] = "";
1032        fprintf(f2,"%-16s %-20s ; %5s %-6s %s\n",
1033               info[1],info[2],info[3],info[4],info[5]
1034               );
1035    }   
1036    printf(" OK\n\n");
1037    rc = 0;                             /* Success */
1038  ddexit:
1039    if (f) fclose(f);
1040    if (f2) fclose(f2);
1041    if (line) free(line);
1042    return(rc);
1043}
1044
1045int                                     /* s = name to look up   */
1046#ifdef CK_ANSIC                         /* cx = index of command */
1047ludial(char *s, int cx)                 /* (DIAL, LOOKUP, etc)   */
1048#else
1049ludial(s, cx) char *s; int cx;
1050#endif /* CK_ANSIC */
1051/* ludial */ {
1052
1053    int dd, n1, n2, n3, i, j, t;        /* Workers */
1054    int olddir, newdir, oldentry, newentry;
1055    int pass = 0;
1056    int oldflg = 0;
1057    int ambiguous = 0;                  /* Flag for lookup was ambiguous */
1058    char *info[7];                      /* Pointers to words from entry */
1059    char *pp;                           /* Pointer to element of array */
1060    FILE * f;
1061    char *line;                         /* File input buffer */
1062
1063/* #define LUDEBUG */
1064
1065#ifdef LUDEBUG
1066int zz = 1;
1067#endif /* LUDEBUG */
1068
1069    if (!s || ndialdir < 1)             /* Validate arguments */
1070      return(-1);
1071
1072    if ((n1 = (int) strlen(s)) < 1)     /* Length of string to look up */
1073      return(-1);
1074
1075    if (!(line = malloc(1024)))         /* Allocate input buffer */
1076      return(-1);
1077
1078#ifdef LUDEBUG
1079if (zz) printf("LUDIAL 1 s[%s], n1=%d\n",s,n1);
1080#endif /* LUDEBUG */
1081
1082    pass = 0;
1083  lu_again:
1084    f = NULL;                           /* Dial directory file descriptor */
1085    t = dncount = 0;                    /* Dial-number match count */
1086    dd = 0;                             /* Directory counter */
1087    olddir = 0;
1088    newdir = 0;
1089/*
1090  We need to recognize both old- and new-style directories.
1091  But we can't allow old-style and new-style entries in the same
1092  directory because there is no way to tell for sure the difference between
1093  and old-style entry like this:
1094
1095    foo  5551212  9600
1096
1097  and a new-style literal entry like this:
1098
1099    foo  555 9600
1100
1101  I.e. is the "9600" a speed, or part of the phone number?
1102*/
1103    while (1) {                         /* We make one pass */
1104        if (!f) {                       /* Directory not open */
1105            if (dd >= ndialdir)         /* No directories left? */
1106              break;                    /* Done. */
1107            if ((f = fopen(dialdir[dd],"r")) == NULL) { /* Open it */
1108                perror(dialdir[dd]);    /* Can't, print message saying why */
1109                if (line) {
1110                    free(line);
1111                    line = NULL;
1112                }
1113                dd++;                   /* Go on to next one, if any... */
1114                continue;
1115            }
1116            dirline = 0;                /* Directory file line number */
1117            if (dialdpy && !pass)
1118              printf("Opening: %s...\n",dialdir[dd]);
1119            dd++;
1120            if (!oldflg) olddir = 0;
1121            newdir = 0;
1122        }
1123        oldentry = 0;
1124        newentry = 0;
1125        line[0] = NUL;
1126        if (getnct(line,1023,f,1) < 0) { /* Read a line */
1127            if (f) {                    /* f can be clobbered! */
1128                fclose(f);              /* Close the file */
1129                f = NULL;               /* Indicate next one needs opening */
1130                oldflg = 0;
1131            }
1132            continue;
1133        }
1134        if (!line[0])                   /* Empty line */
1135          continue;
1136#ifdef LUDEBUG
1137if (zz) printf("LUDIAL 2 s[%s]\n",s);
1138#endif /* LUDEBUG */
1139
1140        /* Make a copy and parse it the old way */
1141        /* A copy is needed because xwords() pokes NULs into the string */
1142
1143        if (pp = malloc((int)strlen(line) + 1)) {
1144            strcpy(pp,line);
1145            xwords(pp,5,info,0);        /* Parse it the old way */
1146
1147#ifdef LUDEBUG
1148if (zz) printf("LUDIAL 3 s[%s]\n",s);
1149#endif /* LUDEBUG */
1150
1151            if (!info[1])
1152              continue;
1153            if (*info[1] == ';') {      /* If full-line comment, */
1154                newdir = 1;             /* (only new directories have them) */
1155                continue;               /* keep reading. */
1156            }
1157            if (!info[2])
1158              continue;
1159            if (*info[2] == '+')
1160              newentry = 1;
1161            if (info[4]) {
1162                if ((*info[4] == '=') ||
1163                    !xxstrcmp(info[4],"none", 4) ||
1164                    !xxstrcmp(info[4],"even", 4) ||
1165                    !xxstrcmp(info[4],"space",5) ||
1166                    !xxstrcmp(info[4],"mark", 4) ||
1167                    !xxstrcmp(info[4],"odd",  3)
1168                    )
1169                  oldentry = 1;
1170            }
1171        }
1172        if (pp) {
1173            free(pp);
1174            pp = NULL;
1175        }
1176
1177        /* Check consistency */
1178
1179        if ((oldentry || olddir) && (newentry || newdir)) {
1180            printf(
1181"\nERROR: You seem to have old- and new-format entries mixed in your\n");
1182            printf(
1183"dialing directory.  You'll have to edit it by hand to convert it to the\n");
1184#ifndef NOHELP
1185            printf("new format.  Type HELP DIAL for further information.\n\n");
1186#else
1187            printf("new format.\n\n");
1188#endif /* NOHELP */
1189            if (line) {
1190                free(line);
1191                line = NULL;
1192            }
1193            return(-1);
1194        }
1195        if (!olddir && oldentry) {
1196            int convert = 0;
1197            olddir = 1;
1198            if (dialcvt == 2) {         /* 2 == ASK */
1199                printf(
1200"\nWARNING: Old-style dialing directory detected:\n%s\n\n", line);
1201                convert = getyesno("Shall I convert it for you? ");
1202            } else
1203              convert = dialcvt;
1204            if (convert) {
1205                if (ddcvt(dialdir[dd-1],f,dd-1) < 0) {
1206                    oldflg = 1;
1207                    printf(
1208"  Sorry, can't convert.");
1209                    printf(
1210"  Will ignore speed and parity fields, continuing...\n\n");
1211                } else {
1212                    olddir = newdir = 0;
1213                }
1214                dd--;
1215                f = NULL;
1216                continue;
1217            } else {
1218                if (dialcvt == 2)
1219                  printf(
1220"  OK, will ignore speed and parity fields, continuing...\n\n");
1221                olddir = 1;
1222            }
1223        }
1224
1225#ifdef LUDEBUG
1226if (zz) printf("LUDIAL XX s[%s], n1=%d\n",s,n1);
1227#endif /* LUDEBUG */
1228
1229        /* Now parse again for real */
1230
1231        if (oldentry)                   /* Parse it the old way */
1232          xwords(line,5,info,0);
1233        else                            /* Parse it the new way */
1234          xwords(line,2,info,1);
1235
1236#ifdef LUDEBUG
1237if (zz) printf("LUDIAL YY s[%s], n1=%d\n",s,n1);
1238if (zz) printf("%s [%s]\n",info[1],info[2]);
1239#endif /* LUDEBUG */
1240
1241        if (info[1]) {                  /* First word is entry name */
1242            if ((n3 = (int) strlen(info[1])) < 1) /* Its length */
1243              continue;                 /* If no first word, keep reading. */
1244            if (n3 < n1)                /* Search name is longer */
1245              continue;                 /* Can't possibly match */
1246            if (ambiguous && n3 != n1)
1247              continue;
1248
1249#ifdef LUDEBUG
1250if (zz) printf("MATCHING: [%s] [%s], n1=%d\n",s,info[1],n1);
1251#endif /* LUDEBUG */
1252
1253            if (xxstrcmp(s,info[1],n1)) /* Caseless string comparison */
1254              continue;
1255
1256#ifdef LUDEBUG
1257if (zz) printf("MATCH OK: [%s] [%s], n1=%d\n",s,info[1],n1);
1258#endif /* LUDEBUG */
1259
1260            if (!info[2])               /* No phone number given */
1261              continue;
1262            if ((n2 = (int) strlen(info[2])) < 1) /* Length of phone number */
1263              continue;                 /* Ignore empty phone numbers */
1264
1265            /* Got one */
1266
1267            if (!(pp = (char *)malloc(n2 + 1))) { /* Allocate storage for it */
1268                printf("?internal error - ludial malloc 1\n");
1269                if (line) {
1270                    free(line);
1271                    line = NULL;
1272                }
1273                dncount = 0;
1274                return(-1);
1275            }
1276            strcpy(pp,info[2]);         /* Copy number into malloc'd storage */
1277
1278            if (dncount > MAXDNUMS) {
1279                printf("Warning: %d matches found, %d max\n",
1280                       dncount,
1281                       MAXDNUMS
1282                       );
1283                dncount = MAXDNUMS;
1284                break;
1285            }
1286            dn_p[dncount++] = pp;       /* Add pointer to array. */
1287            if (dncount == 1) {         /* First one... */
1288                if (d_name) free(d_name);
1289                if (!(d_name = (char *)malloc(n3 + 1))) { /* Save its name */
1290                    printf("?internal error - ludial malloc 2\n");
1291                    if (line) {
1292                        free(line);
1293                        line = NULL;
1294                    }
1295                    dncount = 0;
1296                    return(-1);
1297                }
1298                t = n3;                 /* And its length */
1299                strcpy(d_name,info[1]);
1300            } else {                    /* Second or subsequent one */
1301
1302#ifdef LUDEBUG
1303                if (zz)
1304                  printf("d_name=[%s],info[1]=%s,t=[%d]\n",d_name,info[1],t);
1305#endif /* LUDEBUG */
1306
1307                if ((int) strlen(info[1]) == t) /* Lengths compare */
1308                  if (!xxstrcmp(d_name,info[1],t)) /* Caseless compare OK */
1309                    continue;
1310
1311                /* Name given by user matches entries with different names */
1312
1313                if (ambiguous)          /* Been here before */
1314                  break;
1315
1316                ambiguous = 1;          /* Now an exact match is required */
1317                for (j = 0; j < dncount; j++) { /* Clean out previous list */
1318                    if (dn_p[j]) {
1319                        free(dn_p[j]);
1320                        dn_p[j] = NULL;
1321                    }
1322                }
1323                pass++;                 /* Second pass... */
1324                goto lu_again;          /* Do it all over again. */
1325            }
1326        }
1327    }
1328    if (line) free(line);
1329    if (dncount == 0 && ambiguous) {
1330        printf(" Lookup: \"%s\" - ambiguous%s\n",
1331               s,
1332               cx == XXLOOK ? "" : " - dialing skipped"
1333               );
1334        return(-2);
1335    }
1336    return(dncount);
1337}
1338
1339static char *dscopy = NULL;
1340
1341int
1342dodial(cx) int cx; {                    /* DIAL or REDIAL */
1343    int i = 0, x = 0;                   /* Workers */
1344    int sparity = -1;                   /* For saving global parity value */
1345    int partial  = 0;                   /* For partial dial */
1346    int previous = 0;
1347    int len = 0;
1348    int literal = 0;
1349
1350    char *p = NULL, *s3 = NULL, **s2 = NULL;
1351    int j = 0, t = 0, n = 0;
1352
1353    if (cx == XXPDIA) {                 /* Shortcut... */
1354        cx = XXDIAL;
1355        partial = 1;
1356    }
1357    previous = dialsta;                 /* Status of previous call, if any */
1358
1359    if (cx != XXLOOK) {
1360        if (mdmtyp < 1) {
1361            if (network)
1362              printf("Please SET HOST first, and then SET MODEM\n");
1363            else
1364              printf("Sorry, you must SET MODEM first\n");
1365            dialsta = DIA_NOMO;
1366            return(0);
1367        }
1368        if (!local) {
1369            printf("Sorry, you must SET LINE or SET HOST first\n");
1370            dialsta = DIA_NOLI;
1371            return(0);
1372        }
1373        if (!network &&
1374            (speed < 0L)
1375#ifdef UNIX
1376            && (strcmp(ttname,"/dev/null"))
1377#else
1378#ifdef OSK
1379            && (strcmp(ttname,"/nil"))
1380#endif /* OSK */
1381#endif /* UNIX */
1382            ) {
1383            printf("Sorry, you must SET SPEED first\n");
1384            dialsta = DIA_NOSP;
1385            return(0);
1386        }
1387    }
1388    s = NULL;                           /* Initialize user's dial string */
1389    if (cx == XXRED) {                  /* REDIAL or... */
1390        if ((y = cmcfm()) < 0)
1391          return(y);
1392    } else if (cx == XXANSW) {          /* ANSWER or ... */
1393        if ((y = cmnum("timeout (seconds)","0",10,&x,xxstring)) < 0)
1394          return(y);
1395        dialatmo = x;
1396        if ((y = cmcfm()) < 0)
1397          return(y);
1398    } else {                            /* DIAL or LOOKUP */
1399        if (ndialdir > 0)
1400          s3 = "Number to dial or entry from dial directory";
1401        else
1402          s3 = "Number to dial";
1403        if ((x = cmtxt(s3, dialnum ? dialnum : "",&s,xxstring)) < 0)
1404          return(x);
1405        if (s) {
1406            len = (int) strlen(s);
1407            if (len > 1) {              /* Strip outer braces if given */
1408                if (*s == '{') {
1409                    if (s[len-1] == '}') {
1410                        s[len-1] = NUL;
1411                        s++;
1412                        len -= 2;
1413                    }
1414                }
1415            }
1416        }               
1417    }
1418    if (cx != XXANSW) {
1419        for (j = 0; j < MAXDNUMS; j++) { /* Initialize dial-number list */
1420            if (!dialnum) {             /* First time dialing */
1421                dn_p[j] = NULL;         /* initialize all pointers. */
1422                dn_p2[j] = NULL;
1423            } else if (dn_p[j]) {       /* Not the first time, */
1424                free(dn_p[j]);          /* free previous, if any, */
1425                dn_p[j] = NULL;         /* then set to NULL. */
1426                if (dn_p2[j])
1427                  free(dn_p2[j]);
1428                dn_p2[j] = NULL;
1429            } else break;               /* Already NULL */
1430        }
1431        if (len == 0)
1432          s = NULL;
1433        if (!s)
1434          s = dialnum;
1435        if (!s) {
1436            if (cx == XXLOOK)
1437              printf("?Lookup what?\n");
1438            else
1439              printf("%s\n", (cx == XXRED) ?
1440                   "?No DIAL command given yet" :
1441                   "?You must specify a number to dial"
1442                   );
1443            return(-9);
1444        }
1445
1446    /* Now we have the "raw" dial or lookup string and s is not NULL */
1447
1448        makestr(&dscopy,s);             /* Put it in a safe place */
1449        s = dscopy;
1450        n = 0;
1451
1452        debug(F111,"dodial",s,ndialdir);
1453
1454        if (isalpha(*s)) {
1455            if (ndialdir > 0) {         /* Do we have a dialing directory? */
1456                n = ludial(s,cx);       /* Look up what the user typed */
1457                if (n == 0)
1458                  printf(" Lookup: \"%s\" - not found%s\n",
1459                         s,
1460                         cx == XXLOOK ? "" : " - dialing as given\n"
1461                         );
1462            }
1463            debug(F101,"dodial",s,n);
1464            if (n < 0 && cx != XXLOOK) { /* Error out if they wanted to dial */
1465                if (n == -1)            /* -2 means ludial already gave msg */
1466                  printf(" Lookup: fatal error - dialing skipped\n");
1467                dialsta = DIA_DIR;
1468                return(-9);
1469            }   
1470        } else {                        /* "=" forces no lookup. */
1471            n = 0;
1472            if (*s == '=') {            /* If number starts with = sign */
1473                s++;                    /* strip it */
1474                literal = 1;            /* remember this */
1475                while (*s == SP) s++;   /* and then also any leading spaces */
1476            }
1477            if (ndialdir > 0)
1478              printf(" Lookup: skipped\n");
1479        }
1480
1481        /* Save DIAL or successful LOOKUP string for future DIAL or REDIAL */
1482        /* But don't save pieces of partial dial ... */
1483
1484        if ((cx == XXDIAL && partial == 0 && previous != DIA_PART) ||
1485            (cx == XXLOOK && n > 0)) {
1486            makestr(&dialnum,dscopy);
1487        }
1488        if (n > 0) {
1489            if (!quiet && !backgrd && dialdpy) {
1490                if (!strcmp(d_name,s))
1491                  printf(" Lookup: \"%s\" - exact match\n",s);
1492                else
1493                  printf(" Lookup: \"%s\" - uniquely matches \"%s\"\n",
1494                         s,
1495                         d_name
1496                         );
1497            }
1498            if ((cx == XXLOOK) || (n > 1)  && !quiet && !backgrd && dialdpy) {
1499                printf(" %d telephone number%sfound for \"%s\"%s\n",
1500                       n,
1501                       (n == 1) ? " " : "s ",
1502                       s,
1503                       (n > 0) ? ":" : "."
1504                       );
1505                s3 = getdname();
1506            }
1507            for (i = 0; i < n; i++) {   /* Convert */
1508                dn_x[i] = -1;
1509                if (dncvt(i,cx) < 0) {
1510                    if (cx != XXLOOK) {
1511                        dialsta = DIA_DIR;
1512                        return(-9);
1513                    }
1514                }
1515            }
1516            if (dialsrt && n > 1) {     /* Sort into optimal order */
1517                for (i = 0; i < n-1; i++) {
1518                    for (j = i+1; j < n; j++) {
1519                        if (dn_x[j] < dn_x[i]) {
1520                            t = dn_x[j];
1521                            dn_x[j] = dn_x[i];
1522                            dn_x[i] = t;
1523                            p = dn_p[j];
1524                            dn_p[j] = dn_p[i];
1525                            dn_p[i] = p;
1526                            p = dn_p2[j];
1527                            dn_p2[j] = dn_p2[i];
1528                            dn_p2[i] = p;
1529                        }
1530                    }
1531                }
1532            }
1533            if ((cx == XXLOOK) || (n > 1)  && !quiet && !backgrd && dialdpy) {
1534                int nn = n;
1535                if (cx != XXLOOK)
1536                  if (n > 12) nn = 12;
1537                for (i = 0; i < nn; i++) {
1538                    printf("%3d. %-12s  %-20s =>  %-20s  (%d)\n",i+1,
1539                           s3, dn_p[i],
1540                           dn_p2[i] ? dn_p2[i] : "(processing failed)",
1541                           dn_x[i]
1542                           );
1543                }
1544                if (cx != XXLOOK && n != nn)
1545                  printf("And %d more...\n", n - nn);
1546            }
1547        } else if (n == 0) {            /* Not found in directory */
1548            makestr(&(dn_p[0]),literal ? s : dscopy);
1549            makestr(&d_name,literal ? s : dscopy);
1550            dncount = 1;
1551            n = 1;
1552            if (dncvt(0,cx) < 0) {      /* In case they typed a */
1553                dialsta = DIA_DIR;      /* portable-format number ... */
1554                return(-9);
1555            }
1556        }
1557
1558#ifdef NETCONN
1559        /* It's not good that the networks directory depends on NOT-NODIAL.. */
1560        if (cx == XXLOOK && dscopy) {   /* Networks here too... */
1561            extern char *nh_p[], *nh_p2[], *n_name;
1562            extern char *nh_px[4][MAXDNUMS+1];
1563            n = 0;
1564            if (nnetdir > 0) {          /* Do we have a network directory? */
1565                dirline = 0;
1566                n = lunet(dscopy);      /* Look up what the user typed */
1567            }
1568            if (n > -1) {
1569                int k;
1570                if (cx == XXLOOK && n == 0)
1571                  printf(" Lookup: \"%s\" - not found\n",dscopy);
1572                else
1573                  printf("%s %d network entr%s found for \"%s\"%s\n",
1574                         cx == XXLOOK ? " Lookup:" : "",
1575                         n,
1576                         (n == 1) ? "y" : "ies",
1577                         dscopy,
1578                         (n > 0) ? ":" : "."
1579                         );
1580
1581                for (i = 0; i < n; i++) {
1582
1583                    printf("%3d. %-12s => %-9s %s",
1584                           i+1,n_name,nh_p2[i],nh_p[i]);
1585                    for (k = 0; k < 4; k++) {
1586                        if (nh_px[k][i])
1587                          printf(" %s",nh_px[k][i]);
1588                        else
1589                          break;
1590                    }
1591                    printf("\n");
1592                }
1593            }
1594        }
1595#endif /* NETCONN */
1596        if (cx == XXLOOK)
1597          return(success = 1);
1598    } /* cx != XXANSW */
1599
1600#ifdef VMS
1601    conres();                   /* So Ctrl-C/Y will work */
1602#endif /* VMS */
1603/*
1604  Some modems do not react well to parity.  Also, if we are dialing through a
1605  TCP/IP TELNET modem server, parity can be fatally misinterpreted as TELNET
1606  negotiations.
1607
1608  This should work even if the user interrupts the DIAL command, because the
1609  DIAL module has its own interrupt handler.  BUT... if, for some reason, a
1610  dialing device actually *requires* parity (e.g. CCITT V.25bis says that even
1611  parity should be used), this might prevent successful dialing.  For that
1612  reason, we don't do this for V.25bis modems.
1613*/
1614    sparity = parity;                   /* Save current parity */
1615    if (dialcapas & CKD_V25 == 0)       /* If not V.25bis...  */
1616      parity = 0;                       /* Set parity to NONE */
1617
1618    if (cx == XXANSW) {                 /* ANSWER */
1619        success = ckdial("",0,0,1);
1620        goto dialfin;
1621    }
1622
1623/* Edit 192 adds the ability to dial repeatedly. */
1624
1625    i = 0;
1626    do {
1627        if (i > 0) printf("\nDial attempt %d of %d...\n", i+1, dialrtr);
1628        success = 0;
1629        /* And the ability to dial alternate numbers. */
1630        /* Loop to dial each in a list of numbers for the same name... */
1631        for (j = 0; j < n && !success; j++) { /* until one answers. */
1632            s = dn_p2[j];               /* Next number in list */
1633            if (dn_x[j] >= dialrstr) {  /* Dial restriction */
1634                printf("Restricted: %s, skipping...\n",dn_p[j]);
1635                continue;
1636            }
1637            if (!s) s = dn_p[j];
1638            if (i == 0 && dialcnf) {
1639                printf("Dialing %s\n",s);
1640                x = getyesno(" Is this number correct? ");
1641                if (!x) {
1642                    char **p;
1643#ifdef CK_RECALL
1644                    int sv_recall;
1645                    extern int on_recall;
1646#endif /* CK_RECALL */
1647                    cmsavp(psave,PROMPTL);
1648                    cmsetp(
1649#ifdef OS2
1650" Please enter the correct number,\r\n or press Enter to skip: "
1651#else
1652" Please enter the correct number,\r\n or press Return to skip: "
1653#endif /* OS2 */
1654);
1655                    cmini(ckxech);
1656                    x = -1;
1657                    if (pflag) prompt(NULL);
1658#ifdef CK_RECALL
1659                    sv_recall = on_recall;
1660                    on_recall = 0;
1661#endif /* CK_RECALL */
1662                    y = cmdgquo();
1663                    cmdsquo(0);
1664                    while (x < 0) {
1665                        x = cmtxt("Corrected phone number","",&s,NULL);
1666                        cmres();
1667                    }
1668                    if ((int) strlen(s) < 1) {
1669                        cmsetp(psave);
1670                        continue;
1671                    }
1672                    makestr(&(dn_p2[j]), s);
1673                    cmdsquo(y);
1674#ifdef CK_RECALL
1675                    on_recall = sv_recall;
1676#endif /* CK_RECALL */
1677                    cmsetp(psave);
1678                }
1679            }
1680#ifdef COMMENT
1681/* for testing without dialing ... */
1682            success = 0;
1683#else
1684            success = ckdial(s,i,j,partial ? 3 : 0); /* Dial it */
1685            if (!success)
1686              if (dialsta < 8 ||        /* Break out if unrecoverable error */
1687                  dialsta == DIA_INTR ||
1688                  dialsta == DIA_ERR ||
1689                  previous == DIA_PART
1690                  )
1691              break;
1692#endif /* COMMENT */
1693        }
1694        if (success)                    /* Succeeded, leave the outer loop */
1695          break;
1696        if (dialsta < 8 ||              /* Break out if unrecoverable error */
1697            dialsta == DIA_INTR ||
1698            dialsta == DIA_ERR ||
1699            previous == DIA_PART)
1700          break;
1701        if (++i >= dialrtr)             /* Break out if too many tries */
1702          break;
1703        if (!backgrd && !quiet) {
1704                printf(
1705"\nWill redial in %d second%s- press any key to redial immediately.\n",
1706                       dialint,
1707                       dialint == 1 ? " " : "s "
1708                       );
1709                printf("Ctrl-C to cancel...\n");
1710            }
1711            x = dialint;                /* Redial interval */
1712            while (x-- > 0) {
1713                if (y = conchk())       /* Did they type something? */
1714                  break;                /* If so, wake up */
1715                sleep(1);               /* No interrupt, sleep a sec */
1716            }
1717    } while (!success);
1718
1719  dialfin:
1720
1721    if (cx != XXLOOK) {
1722        bleep(success ? BP_NOTE : BP_FAIL);
1723#ifdef OS2
1724        setint();                       /* Fix OS/2 interrupts */
1725#endif /* OS2 */
1726        if (sparity > -1)
1727          parity = sparity;             /* Restore parity if we saved it */
1728#ifdef OS2
1729        ttres();                        /* Restore DIAL device */
1730#endif /* OS2 */
1731#ifdef VMS
1732        concb((char)escape);            /* Restore console */
1733#endif /* VMS */
1734#ifdef OS2
1735        {                               /* Set session title */
1736            char * p, name[72];         /* in window list. */
1737            char * q;
1738            if (cx == XXANSW) {
1739                q = "Incoming call";
1740            } else {
1741                if (d_name)
1742                  q = d_name;
1743                else if (dialnum)
1744                  q = dialnum;
1745                else if (ttname[0])
1746                  q = ttname;
1747                else q = "";
1748            }
1749            p = name;
1750            if (success) {
1751                strncpy(name,q,48);
1752                while (*p) {            /* Uppercase it for emphasis. */
1753                    if (islower(*p))
1754                      *p = toupper(*p);
1755                    p++;
1756                }
1757            } else
1758              name[0] = '\0' ;
1759            os2settitle((char *) name, TRUE);
1760        }
1761#endif /* OS2 */
1762    }
1763    return(success);
1764}
1765#endif /* NODIAL */
1766
1767/*  D O T Y P E  --  Type a file  */
1768
1769int
1770dotype(file) char * file; {             /* Do the TYPE command */
1771#ifdef VMS
1772    char command[512];
1773    sprintf(command,"type %s",file);    /* Construct TYPE command */
1774    conres();                           /* Let user interrupt */
1775    success = zshcmd((char *)command);  /* Execute it */
1776    concb((char)escape);                /* Back to console CBREAK mode */
1777    return(success);
1778#else
1779    char * p, name[257];
1780#ifdef MAC
1781    int count = 100;
1782#endif /* MAC */
1783    int rc = 1;
1784    int c;
1785    int save;
1786
1787    save = binary;                      /* Save file type */
1788
1789#ifdef OS2
1790    if (*file) {
1791        strcpy( name, file );           /* Change / to \. */
1792        p = name;
1793        while (*p) {
1794            if (*p == '/') *p = '\\';
1795            p++;
1796        }
1797    } else
1798      return(0);
1799#else
1800    strcpy(name, file);
1801#endif /* OS2 */
1802
1803    if (zchki(name) == -2)              /* It's a directory */
1804      return(0);
1805
1806    binary = 0;                         /* Set file type to text for zopeni */
1807    if (!zopeni(ZIFILE, name)) {        /* Not a directory, open it */
1808        binary = save;                  /* Failed, restore file type */
1809        return(0);                      /* and return */
1810    }
1811    while ((c = zminchar()) != -1) {    /* Loop for all characters in file */
1812#ifdef MAC
1813        /*
1814         * It is expensive to run the miniparser so don't do it for
1815         * every character.
1816         */
1817        if (--count < 0) {
1818            count = 100;
1819            miniparser(1);
1820            if (sstate == 'a') {
1821                sstate = '\0';
1822                rc = 0;
1823                break;
1824            }
1825        }
1826#else /* Not MAC */
1827        if (putchar(c) == EOF) {        /* Echo character on screen */
1828            rc = 0;
1829            break;
1830        }
1831#endif /* MAC */
1832    }
1833    zclose(ZIFILE);                     /* Done, close the file */
1834    binary = save;
1835    return(rc);
1836#endif /* VMS */
1837}
1838
1839int                                     /* Do the DIRECTORY command */
1840dodir() {
1841#ifndef MAC
1842    char *dc;
1843#endif /* MAC */
1844#ifdef MAC
1845/*
1846  This is a crude, do-it-yourself directory command.  It shows all the
1847  files in the current directory: size and name of each file.  Only regular
1848  files are shown.  With a little more work, it could also show directories,
1849  and mark files as regular or directories, and it could also show dates.
1850  See sample code in zldir() routine in ckmfio.c.
1851*/
1852    char mac_name[65];
1853    long mac_len, nfiles, nbytes;
1854    extern long mac_znextlen;           /* See ckmfio.c for this. */
1855
1856    if ((y = cmcfm()) < 0)
1857      return(y);
1858
1859    nfiles = nbytes = 0L;
1860    printf("\nDirectory of %s\n\n",zgtdir());
1861    x = zxpand(":");
1862    while (x-- > 0) {
1863        if (!znext(mac_name))
1864            break;
1865        mac_len = zchki(mac_name);
1866        if (mac_len > -1L) {
1867            nfiles++;
1868            nbytes += mac_znextlen;
1869            printf("%10ld %s\n", mac_znextlen, mac_name);
1870        }
1871    }
1872    printf("\n%ld file%s, %ld byte%s\n\n",
1873           nfiles,
1874           (nfiles == 1) ? "" : "s",
1875           nbytes,
1876           (nbytes == 1) ? "" : "s"
1877           );
1878    return(success = 1);
1879#else
1880#ifdef VMS
1881    if ((x = cmtxt("Directory/file specification","",&s,xxstring)) < 0)
1882     return(x);
1883    /* now do this the same as a shell command - helps with LAT  */
1884    conres();                           /* Make console normal */
1885    lp = line;
1886    if (!(dc = getenv("CK_DIR"))) dc = DIRCMD;
1887    sprintf(lp,"%s %s",dc,s);
1888    debug(F110,"DIR string", line, 0);
1889    x = zshcmd(lp);
1890    debug(F101,"DIR return code", "", x);
1891    concb((char)escape);
1892    return(success = (x > 0) ? 1 : 0);
1893#else
1894#ifdef AMIGA
1895    if ((x = cmtxt("Directory/file specification","",&s,xxstring)) < 0)
1896      return(x);
1897#else
1898#ifdef datageneral
1899    if ((x = cmtxt("Directory/file specification","+",&s,xxstring)) < 0)
1900        return(x);
1901#else
1902#ifdef OS2
1903#ifdef ONETERMUPD
1904    {
1905        char name[257], *p = NULL;
1906        char * mstr = NULL, * dstr = NULL;
1907        long len, ndirs, nfiles, nbytes;
1908        short month, date, year, hour, minute, seconds;
1909
1910        /* Note: cmifi2() parses a filespec OR a directory name */
1911
1912        x = cmifi2("Device, directory, and/or file specification",
1913                   "*",
1914                   &s,
1915                   &y,
1916                   1,
1917                   NULL,
1918                   xxstring
1919                   );
1920        if (x == -4 || x == -1)
1921          return(x);
1922        if (x == -2) {
1923#ifdef OS2
1924            if (!ckindex(".",s,1,0,0) && !ckindex("*",s,1,0,0)) {
1925                if (s[1] == ':' && s[2] == NUL) /* e.g. "dir a:" */
1926                  sprintf(line,"%s*.*",s);
1927                else
1928                  sprintf(line,"%s.*",s);
1929                s = line;
1930                if (zxpand(s) < 1) {
1931                    printf("%s - not found\n",s);
1932                    return(-9);
1933                }
1934            } else {
1935#endif /* OS2 */
1936                printf("%s - not found\n",s);
1937                return(-9);
1938#ifdef OS2
1939            }
1940#endif /* OS2 */
1941        }
1942        if ((y = cmcfm()) < 0)
1943          return(y);
1944
1945        /* Lower-level functions change / to \. */
1946        p = s;
1947        while (*p) {                    /* Change them back to \ */
1948            if (*p == '/') *p = '\\';
1949            p++;
1950        }
1951        ndirs = nfiles = nbytes = 0L;
1952        printf("\nDirectory of %s\n\n",s);
1953        if (zchki(s) == -2) {
1954            /* Found a directory */
1955#ifdef OS2
1956            if (p != s) {
1957                p--;
1958                if (*p == '\\' || *p == '/')
1959                  strcat(s, "*.*");
1960                else if (*p == ':')
1961                  strcat(s, ".\\*.*");
1962                else
1963                  strcat(s, "\\*.*");
1964            } else {
1965                strcat(s, "*.*");
1966            }
1967#else
1968            if (p != s) {
1969                p--;
1970                if (*p == '\\' || *p == '/')
1971                  strcat(s, "*");
1972                else if (*p == ':')
1973                  strcat(s, ".");
1974                else
1975                  strcat(s, "\\*");
1976            } else {
1977                strcat(s, "*");
1978            }
1979#endif
1980        }
1981#ifdef OS2
1982        else if (!ckindex(".",s,1,0,0) && !ckindex("*",s,1,0,0)) {
1983            sprintf(line,"%s.*",s);
1984            s = line;
1985        }
1986#endif /* OS2 */
1987
1988        x = zxpand(s);
1989        while (x-- > 0) {
1990            if (!znext(name))
1991              break;
1992            dstr = zfcdat(name);
1993            month = (dstr[4]-48)*10 + (dstr[5]-48);
1994            switch(month) {
1995              case 1:  mstr = "Jan"; break;
1996              case 2:  mstr = "Feb"; break;
1997              case 3:  mstr = "Mar"; break;
1998              case 4:  mstr = "Apr"; break;
1999              case 5:  mstr = "May"; break;
2000              case 6:  mstr = "Jun"; break;
2001              case 7:  mstr = "Jul"; break;
2002              case 8:  mstr = "Aug"; break;
2003              case 9:  mstr = "Sep"; break;
2004              case 10: mstr = "Oct"; break;
2005              case 11: mstr = "Nov"; break;
2006              case 12: mstr = "Dec"; break;
2007              default: mstr = "   ";
2008            }
2009            date   = (dstr[6]-48)*10 + (dstr[7]-48);
2010            year  = (((dstr[0]-48)*10
2011                      + (dstr[1]-48))*10
2012                     + (dstr[2]-48))*10
2013                       + (dstr[3]-48);
2014            hour  = (dstr[9]-48)*10 + (dstr[10]-48);
2015            minute = (dstr[12]-48)*10 + (dstr[13]-48);
2016            seconds = (dstr[15]-48)*10 + (dstr[16]-48);
2017            len = zchki(name);
2018            /* find just the name of the file */
2019            for (p = name + (int) strlen(name);
2020                 p != name && *p != '/'
2021                 && *p != '\\' && *p != ':' ;
2022                 p--
2023                 )
2024              ;
2025            if (*p == '/' || *p == '\\' || *p == ':')
2026              p++ ;
2027
2028            if (len > -1L) {
2029                nfiles++;
2030                nbytes += len;
2031                printf(" %3s-%02d-%04d  %02d:%02d %10ld %s\n",
2032                       mstr, date, year, hour, minute, len, p
2033                       );
2034            } else {
2035                ndirs++;
2036                printf(" %3s-%02d-%04d  %02d:%02d %10s %s\n",
2037                       mstr, date, year, hour, minute, "<DIR>", p);
2038            }
2039        }
2040        printf("\n%ld director%s, %ld file%s, %ld byte%s\n\n",
2041               ndirs,
2042               (ndirs == 1) ? "y" : "ies",
2043               nfiles,
2044               (nfiles == 1) ? "" : "s",
2045               nbytes,
2046               (nbytes == 1) ? "" : "s"
2047               );
2048        return(success = 1);
2049    }
2050#else /* ONETERMUPD */
2051    tmpbuf[0] = NUL;
2052    if ((x = cmifi2(
2053"Device, directory, and/or file specification,\n\
2054 or switch(es), or '> file'","*.*",
2055                    &s,&y,1,NULL,xxstring)) < 0) {
2056        debug(F101,"DIR cmifi2","",x);
2057        if (x == -3) {                  /* Done. */
2058            goto sw_skip;
2059        } else if (x == -2 && (*s == '/' || *s == '>')) {
2060            strncpy(tmpbuf,s,TMPBUFSIZ); /* Switch or redirect */
2061            if ((y = cmcfm()) < 0)
2062              return(y);
2063            else
2064              goto sw_skip;
2065        } else if (x == -2 && !strchr(s,'.')) { /* Maybe ".*" is missing */
2066            goto fs_copy;
2067        } else if (x == -2) {
2068            printf("%s - not found\n",s);
2069            return(-9);
2070        } else
2071          return(x);
2072    }
2073#endif /* ONETERMUPD */
2074#else /* General Case */
2075    if ((x = cmdir("Directory/file specification","",&s,xxstring)) < 0)
2076      if (x != -3) return(x);
2077#endif /* OS2 */
2078#endif /* datageneral */
2079#endif /* AMIGA */
2080
2081#ifdef OS2
2082fs_copy:
2083#endif /* OS2 */
2084    debug(F110,"DIR fs_copy",s,0);
2085    strncpy(tmpbuf,s,TMPBUFSIZ);        /* Copy the filespec */
2086
2087#ifdef OS2
2088    {   /* Lower level functions change / to \, not good for CMD.EXE. */
2089        /* Only do this to filenames, not switches! */
2090        char *p = tmpbuf;
2091        while (*p) {                    /* Change them back to \ */
2092            if (*p == '/') *p = '\\';
2093            p++;
2094        }
2095    }
2096    debug(F110,"DIR tmpbuf 1",tmpbuf,0);
2097    /* Now parse trailing switches like /P/O-D... */
2098    if ((x = cmtxt("Optional switches and/or redirect for OS/2 DIR command",
2099                   "",&s,xxstring)) < 0)
2100      return(x);
2101    strcat(tmpbuf,s);                   /* Append them to the filespec */
2102    debug(F110,"DIR tmpbuf 2",tmpbuf,0);
2103sw_skip:
2104#else
2105    if ((y = cmcfm()) < 0) return(y);
2106#endif /* OS2 */
2107    s = tmpbuf;
2108    lp = line;
2109    if (!(dc = getenv("CK_DIR"))) dc = DIRCMD;
2110    sprintf(lp,"%s %s",dc,s);
2111    debug(F110,"DIR",line,0);
2112    xsystem(line);
2113    return(success = 1);                /* who cares... */
2114#endif /* VMS */
2115#endif /* MAC */
2116}
2117
2118#ifndef NOSERVER
2119#ifndef NOFRILLS
2120/* Do the ENABLE and DISABLE commands */
2121
2122int
2123doenable(y,x) int y, x; {
2124    switch (x) {
2125      case EN_ALL:
2126        en_cwd = en_cpy = en_del = en_dir = en_fin = en_get = y;
2127        en_ren = en_sen = en_set = en_spa = en_typ = en_who = en_ret = y;
2128        en_mai = en_pri = y;
2129#ifndef datageneral
2130        en_bye = y;
2131#endif /* datageneral */
2132#ifndef NOPUSH
2133        if (!nopush)
2134          en_hos = y;
2135#endif /* NOPUSH */
2136#ifndef NOSPL
2137        en_asg = en_que = y;
2138#endif /* NOSPL */
2139        break;
2140      case EN_BYE:
2141#ifndef datageneral
2142/*
2143  In Data General AOS/VS Kermit can't log out its superior process.
2144*/
2145        en_bye = y;
2146#endif /* datageneral */
2147        break;
2148    case EN_CPY:
2149        en_cpy = y;
2150        break;
2151      case EN_CWD:
2152        en_cwd = y;
2153        break;
2154      case EN_DEL:
2155        en_del = y;
2156        break;
2157      case EN_DIR:
2158        en_dir = y;
2159        break;
2160      case EN_FIN:
2161        en_fin = y;
2162        break;
2163      case EN_GET:
2164        en_get = y;
2165        break;
2166#ifndef NOPUSH
2167      case EN_HOS:
2168        if (!nopush)
2169         en_hos = y;
2170        break;
2171#endif /* NOPUSH */
2172    case EN_REN:
2173        en_ren = y;
2174        break;
2175      case EN_SEN:
2176        en_sen = y;
2177        break;
2178      case EN_SET:
2179        en_set = y;
2180        break;
2181      case EN_SPA:
2182        en_spa = y;
2183        break;
2184      case EN_TYP:
2185        en_typ = y;
2186        break;
2187      case EN_WHO:
2188        en_who = y;
2189        break;
2190#ifndef NOSPL
2191      case EN_ASG:
2192        en_asg = y;
2193        break;
2194      case EN_QUE:
2195        en_que = y;
2196        break;
2197#endif /* NOSPL */
2198      case EN_RET:
2199        en_ret = y;
2200        break;
2201      case EN_MAI:
2202        en_mai = y;
2203        break;
2204      case EN_PRI:
2205        en_pri = y;
2206        break;
2207      default:
2208        return(-2);
2209    }
2210    return(1);
2211}
2212#endif /* NOFRILLS */
2213#endif /* NOSERVER */
2214
2215#ifndef NOFRILLS
2216int
2217dodel() {                               /* DELETE */
2218#ifndef MAC
2219    long zl;
2220#endif /* MAC */
2221    if ((x = cmifi("File(s) to delete","",&s,&y,xxstring)) < 0) {
2222        if (x == -3) {
2223            printf("?A file specification is required\n");
2224            return(-9);
2225        } else return(x);
2226    }
2227#ifdef MAC
2228    strcpy(line,s);
2229#else
2230    strncpy(tmpbuf,s,TMPBUFSIZ);        /* Make a safe copy of the name. */
2231#ifdef OS2
2232    {   /* Lower level functions change / to \, not good for CMD.EXE. */
2233        char *p = tmpbuf;
2234        while (*p) {                    /* Change them back to \ */
2235            if (*p == '/') *p = '\\';
2236            p++;
2237        }
2238    }
2239    debug(F110,"xxdel tmpbuf",tmpbuf,0);
2240    strcpy(line,tmpbuf);                /* Now copy it back */
2241#else /* OS2 */
2242   debug(F110,"xxdel tmpbuf",tmpbuf,0);
2243   sprintf(line,"%s %s",DELCMD,tmpbuf); /* Construct the system command. */
2244#endif /* OS2 */
2245#endif /* MAC */
2246    debug(F110,"xxdel line",line,0);
2247    if ((y = cmcfm()) < 0) return(y);   /* Confirm the user's command. */
2248#ifdef VMS
2249    conres();
2250#endif /* VMS */
2251#ifdef MAC
2252    s = line;
2253    success = (zdelet(line) == 0);
2254#else
2255#ifdef OS2
2256    {
2257        int filespace = 0;
2258        int len = 0;
2259        int count = 0;
2260
2261        s = line;
2262        z = zxpand(line);
2263        if (z > 0) {
2264            int i;
2265            success = 1;
2266
2267            if ( msgflg )
2268              printf("\n");
2269
2270            for ( i = 0; i < z; i++) {
2271                znext(tmpbuf);
2272                len = zchki(tmpbuf);
2273                if (len >= 0) {
2274                    zdelet(tmpbuf);
2275                    if (zchki(tmpbuf) < 0) {
2276                        filespace += len;
2277                        count++;
2278                        if (msgflg)
2279                          printf(" %s - deleted\n",tmpbuf);
2280                    } else {
2281                        success = 0;
2282                        if (msgflg)
2283                          printf(" %s - not deleted\n",tmpbuf);
2284                    }
2285                }
2286            }
2287            if (msgflg)
2288              printf("\n%d files deleted, %d bytes freed\n",count,filespace);
2289        } else {
2290            if (msgflg)
2291              printf("?Can not delete file: %s\n", line );
2292        }
2293    }
2294#else /* OS2 */
2295    s = tmpbuf;
2296    xsystem(line);                      /* Let the system do it. */
2297    zl = zchki(tmpbuf);
2298    success = (zl == -1L);
2299#endif /* OS2 */
2300#endif /* MAC */
2301#ifndef OS2
2302    if (msgflg)
2303      printf("%s - %sdeleted\n",s, success ? "" : "not ");
2304#ifdef VMS
2305    concb((char)escape);
2306#endif /* VMS */
2307#endif /* OS2 */
2308    return(success);
2309}
2310#endif /* NOFRILLS */
2311
2312#ifndef NOSPL                           /* The ELSE command */
2313int
2314doelse() {
2315    if (!ifcmd[cmdlvl]) {
2316        printf("?ELSE doesn't follow IF\n");
2317        return(-2);
2318    }
2319#ifdef COMMENT
2320/*
2321  Wrong.  This prevents IF..ELSE IF...ELSE IF...ELSE IF...ELSE...
2322  from working.
2323*/
2324    ifcmd[cmdlvl] = 0;
2325#endif /* COMMENT */
2326    if (!iftest[cmdlvl]) {              /* If IF was false do ELSE part */
2327        if (maclvl > -1) {              /* In macro, */
2328            pushcmd();                  /* save rest of command. */
2329        } else if (tlevel > -1) {       /* In take file, */
2330            pushcmd();                  /* save rest of command. */
2331        } else {                        /* If interactive, */
2332            cmini(ckxech);              /* just start a new command */
2333            printf("\n");               /* (like in MS-DOS Kermit) */
2334            if (pflag) prompt(xxstring);
2335        }
2336    } else {                            /* Condition is false */
2337        if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
2338          return(y);                    /* Gobble up rest of line */
2339    }
2340    return(0);
2341}
2342#endif /* NOSPL */
2343
2344#ifndef NOSPL
2345int
2346doswitch() {
2347    char *lp, *ap;                      /* macro argument pointer */
2348
2349    /* Get variable name */
2350    if ((y = cmfld("Variable name","",&s,xxstring)) < 0)
2351      return(y);
2352    if (*s == CMDQ) {
2353        if (chkvar(s) < 1) {
2354            printf("?Variable name required\n");
2355            return(-9);
2356        }
2357    }
2358    lp = line;
2359    strcpy(lp,"_switx ");               /* _switx + space */
2360    lp += (int)strlen(line);
2361    ap = lp;
2362    debug(F110,"SWITCH",atmbuf,0);
2363    strcpy(lp,atmbuf);                  /* + variable name */
2364    lp += (int)strlen(atmbuf);
2365    strcat(lp," ");                     /* + space */
2366    lp++;
2367    debug(F110,"SWITCH 2",line,0);
2368
2369    /* Get body */
2370
2371    if ((y = cmtxt("series of cases","",&s,NULL)) < 0) return(y);
2372    if ((int)strlen(s) < 1) return(-2);
2373   
2374    if (litcmd(&s,&lp) < 0) {
2375        printf("?Unbalanced brackets\n");
2376        return(0);
2377    }
2378    debug(F110,"SWITCH 3",line,0);
2379
2380    x = mlook(mactab,"_switx",nmac);    /* Look up SWITCH macro definition */
2381    if (x < 0) {                        /* Not there? */
2382        addmmac("_switx",sw_def);       /* Put it back. */
2383        if ((x = mlook(mactab,"_switx",nmac)) < 0) { /* Look it up again. */
2384            printf("?SWITCH macro definition gone!\n"); /* Shouldn't happen. */
2385            return(success = 0);
2386        }
2387    }
2388    debug(F110,"SWITCH command",line,0); /* Execute the SWITCH macro. */
2389    return(success = dodo(x,ap,cmdstk[cmdlvl].ccflgs));
2390}
2391
2392int
2393dofor() {                               /* The FOR command. */
2394    int fx, fy, fz;                     /* loop variables */
2395    char *ap;                           /* macro argument pointer */
2396
2397    if ((y = cmfld("Variable name","",&s,NULL)) < 0) { /* Get variable name */
2398        if (y == -3) {
2399            printf("?Variable name required\n");
2400            return(-9);
2401        } else return(y);
2402    }
2403    if ((y = parsevar(s,&x,&z)) < 0)    /* Check it. */
2404      return(y);
2405
2406    lp = line;                          /* Build a copy of the command */
2407    strcpy(lp,"_forx ");
2408    lp += (int)strlen(line);            /* "_for" macro. */
2409    ap = lp;                            /* Save pointer to macro args. */
2410
2411    if (*s == CMDQ) s++;                /* Skip past backslash if any. */
2412    while (*lp++ = *s++) ;              /* copy it */
2413    lp--; *lp++ = SP;                   /* add a space */
2414
2415    if ((y = cmnum("initial value","",10,&fx,xxstring)) < 0) {
2416        if (y == -3) return(-2);
2417        else return(y);
2418    }
2419    debug(F101,"dofor fx","",fx);
2420    s = atmbuf;                         /* Copy the atom buffer */
2421
2422    if ((int)strlen(s) < 1) goto badfor;
2423/*
2424  In edit 192, we change the loop variables to be evaluated at loop entry,
2425  not each time through the loop.  This was required in order to allow
2426  \v(argc) to be used as a loop variable, or in a loop-variable expression.
2427  Thus, we can't have FOR loops that modify their own exit conditions by
2428  changing the final value or the increment.  The problem with \v(argc) was
2429  that it is on the macro stack; after entry into the _forx macro, it is at
2430  the wrong
2431*/
2432        sprintf(tmpbuf,"%d",fx);        /* Substitute actual value */
2433        s = tmpbuf;
2434
2435    while (*lp++ = *s++) ;              /* (what they actually typed) */
2436    lp--; *lp++ = SP;
2437
2438    if ((y = cmnum("final value","",10,&fy,xxstring)) < 0) {
2439        if (y == -3) return(-2);
2440        else return(y);
2441    }
2442    debug(F101,"dofor fy","",fy);
2443    s = atmbuf;                         /* Same deal */
2444    if ((int)strlen(s) < 1) goto badfor;
2445
2446        sprintf(tmpbuf,"%d",fy);
2447        s = tmpbuf;
2448
2449    while (*lp++ = *s++) ;
2450    lp--;
2451    *lp++ = SP;
2452
2453    if ((y = cmnum("increment","1",10,&fz,xxstring)) < 0) {
2454        if (y == -3) return(-2);
2455        else return(y);
2456    }
2457    debug(F101,"dofor fz","",fz);
2458    s = atmbuf;                         /* Same deal */
2459    if ((int)strlen(s) < 1) goto badfor;
2460
2461        sprintf(tmpbuf,"%d",fz);
2462        s = tmpbuf;
2463
2464    while (*lp++ = *s++) ;
2465    lp--; *lp++ = SP;
2466
2467    /* Insert the appropriate comparison operator */
2468    if (fz < 0)
2469      *lp++ = '<';
2470    else
2471      *lp++ = '>';
2472    *lp++ = SP;
2473
2474    if ((y = cmtxt("Command to execute","",&s,NULL)) < 0) return(y);
2475    if ((int)strlen(s) < 1) return(-2);
2476   
2477    if (litcmd(&s,&lp) < 0) {
2478        printf("?Unbalanced brackets\n");
2479        return(0);
2480    }
2481#ifdef COMMENT
2482/* Too strict */
2483    if (fz == 0) {
2484        printf("?Zero increment not allowed\n");
2485        return(0);
2486    }
2487#endif /* COMMENT */
2488    x = mlook(mactab,"_forx",nmac);     /* Look up FOR macro definition */
2489    if (x < 0) {                        /* Not there? */
2490        addmmac("_forx",for_def);       /* Put it back. */
2491        if ((x = mlook(mactab,"_forx",nmac)) < 0) { /* Look it up again. */
2492            printf("?FOR macro definition gone!\n"); /* Shouldn't happen. */
2493            return(success = 0);
2494        }
2495    }
2496    debug(F110,"FOR command",line,0);   /* Execute the FOR macro. */
2497    return(success = dodo(x,ap,cmdstk[cmdlvl].ccflgs));
2498
2499badfor: printf("?Incomplete FOR command\n");
2500    return(-2);
2501}
2502#endif /* NOSPL */
2503
2504#ifndef NOFRILLS
2505/* Do the BUG command */
2506
2507int
2508dobug() {
2509    int n;
2510#ifdef COMMENT
2511    printf("\n%s,%s\n Numeric: %ld",versio,ckxsys,vernum);
2512    if (verwho) printf("-%d",verwho);
2513#endif /* COMMENT */
2514    printf(
2515"\nBefore requesting technical support from Columbia U., please consult:\n\n"
2516           );
2517    n = 6;
2518#ifdef NT
2519    printf(" . Your \"Kermit 95\" user manual.\n");
2520    printf(" . The technical reference manual, \"Using C-Kermit\".\n");
2521    printf(" . The READ.ME file in Kermit 95's directory on your disk.\n");
2522    n += 3;
2523#else
2524    printf(" . The book \"Using C-Kermit\".\n");
2525    n += 1;   
2526#ifndef OS2
2527    printf(" . The CKCKER.UPD and CKCKER.BWR files.\n");
2528    n += 1;   
2529#endif /* OS2 */
2530#ifdef UNIX
2531    printf(" . The CKUKER.BWR and CKUINS.DOC files.\n");
2532    n += 1;   
2533#else
2534#ifdef VMS
2535    printf(" . The CKVKER.BWR and CKVINS.DOC files.\n");
2536    n += 1;   
2537#else
2538#ifdef OS2ONLY
2539    printf(" . The CKERMIT.INF file (use the UPDATES command).\n");
2540    n += 1;   
2541#else
2542#ifdef datageneral
2543    printf(" . The CKDKER.BWR file\n");
2544    n += 1;   
2545#else
2546#ifdef STRATUS
2547    printf(" . The CKLKER.BWR file\n");
2548    n += 1;   
2549#else
2550#ifdef AMIGA
2551    printf(" . The CKIKER.BWR file\n");
2552    n += 1;
2553#else
2554#ifdef GEMDOS
2555    printf(" . The CKSKER.BWR file\n");
2556    n += 1;
2557#else
2558#ifdef MAC
2559    printf(" . The CKMKER.BWR file\n");
2560    n += 1;
2561#else
2562#ifdef OSK
2563    printf(" . The CK9KER.BWR file\n");
2564    n += 1;
2565#else
2566    printf(" . The appropriate system-dependent CK?KER.BWR file\n");
2567    n += 1;
2568#endif
2569#endif
2570#endif
2571#endif
2572#endif
2573#endif
2574#endif
2575#endif
2576#endif
2577#endif /* NT */
2578
2579    printf(" . Your own organization's support staff, if any.\n");
2580    printf(
2581" . The comp.protocols.kermit.* newsgroups if you have Netnews access.\n");
2582    printf(
2583" . Our FAQ, \
2584http://www.columbia.edu/kermit/faq.html, if you have Web access.\n");
2585    n += 2;
2586    if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
2587    printf("\n\
2588If you still need help or have a bug to report after consulting these sources,"
2589           );
2590    printf("\nsend e-mail to:\n\n");
2591    n += 2;
2592    if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
2593    printf("  kermit-support@columbia.edu\n\n");
2594    n += 1;
2595    if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
2596    printf("Or contact us by post:\n\n");
2597    printf(
2598"  Kermit, Columbia University, 612 W 115 Street, New York NY  10025, USA\n\n"
2599           );
2600    n += 1;
2601    if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
2602    printf("Or by fax at +1 (212) 663-8202.\n\n");
2603    n += 1;
2604    if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
2605    printf("Telephone support is available too:\n\n");
2606    n += 1;
2607    if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
2608    printf("  +1 (900) 555-5595, USA only, $2.50 per minute\n");
2609    if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
2610    printf("  +1 (212) 854-5126, from anywhere, $25.00 per call, MC/Visa\n\n");
2611    n += 1;
2612    if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
2613#ifndef NOSHOW
2614#ifndef NOFRILLS
2615    printf(
2616"Before reporting problems, please use the SHOW VERSION and SHOW FEATURES\n");
2617    if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
2618    printf(
2619"commands to get detailed program version and configuration information.\n\n");
2620#endif /* NOFRILLS */
2621#endif /* NOSHOW */
2622    return(1);
2623}
2624#endif /* NOFRILLS */
2625
2626#ifndef NOSPL
2627
2628/*  T O D 2 S E C  --  Convert time of day as hh:mm:ss to secs since midnite */
2629/*
2630  Call with a string hh:mm or hh:mm:ss.
2631  Returns a 0 to 86400 on success, or a negative number on failure.
2632*/
2633long
2634tod2sec(t) char * t; {
2635    long t2;
2636    long hh = 0L, mm = 0L, ss = 0L;
2637
2638    if (!t) t = "";
2639    if (!*t)
2640      return(-3);
2641    debug(F110,"tod2sec",t,0);
2642
2643    if (isdigit(*t))                    /* Get hours from argument */
2644      hh = *t++ - '0';
2645    else
2646      return(-1L);
2647    if (isdigit(*t))
2648      hh = hh * 10 + *t++ - '0';
2649    if (hh > 24L)
2650      return(-1L);
2651    if (*t == ':')
2652      t++;
2653    else if (!*t)
2654      goto xtod2sec;
2655    else
2656      return(-1L);
2657               
2658    if (isdigit(*t))                    /* Minutes */
2659      mm = *t++ - '0';
2660    else
2661      return(-1L);
2662    if (isdigit(*t))
2663      mm = mm * 10 + *t++ - '0';
2664    if (mm > 60L)
2665      return(-1L);
2666    if (*t == ':')
2667      t++;
2668    else if (!*t)
2669      goto xtod2sec;
2670    else
2671      return(-1L);
2672
2673    if (isdigit(*t))                    /* Seconds */
2674      ss = *t++ - '0';
2675    else
2676      return(-1L);
2677    if (isdigit(*t))
2678      ss = ss * 10 + *t++ - '0';
2679    if (ss > 60L)
2680      return(-1L);
2681
2682    if (*t > 32)                        /* No trailing junk allowed */
2683      return(-1L);
2684
2685  xtod2sec:
2686
2687    t2 = hh * 3600L + mm * 60L + ss;    /* Seconds since midnight from arg */
2688    debug(F100,"tod2sec t2","",t2);
2689
2690    return(t2);
2691}
2692
2693int
2694dopaus(cx) int cx; {
2695    long zz;
2696
2697    zz = -1L;
2698    x_ifnum = 1;                        /* Turn off internal complaints */
2699    if (cx == XXWAI)
2700      y = cmnum("seconds to wait, or time of day hh:mm:ss","1",10,&x,xxstring);
2701    else if (cx == XXPAU)
2702      y = cmnum("seconds to pause, or time of day hh:mm:ss",
2703                "1",10,&x,xxstring);
2704    else
2705      y = cmnum("milliseconds to sleep, or time of day hh:mm:ss",
2706                "100",10,&x,xxstring);
2707    x_ifnum = 0;
2708    if (y < 0) {
2709        if (y == -2) {                  /* Invalid number or expression */
2710            zz = tod2sec(atmbuf);       /* Convert to secs since midnight */
2711            if (zz < 0L) {
2712                printf("?Number, expression, or time of day required\n");
2713                return(-9);
2714            } else {
2715                char now[32];           /* Current time */
2716                char *p;
2717                long tnow;
2718                p = now;
2719                ztime(&p);
2720                tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
2721                if (zz < tnow)          /* User's time before now */
2722                  zz += 86400L;         /* So make it tomorrow */
2723                zz -= tnow;             /* Seconds from now. */
2724            }
2725        } else
2726          return(y);
2727    }
2728    if (x < 0) x = 0;
2729    switch (cx) {
2730      case XXPAU:                       /* PAUSE */
2731      case XXMSL:                       /* MSLEEP */
2732        if ((y = cmcfm()) < 0) return(y);
2733        break;
2734      case XXWAI:                       /* WAIT */
2735        z = 0;                          /* Modem signal mask */
2736        while (1) {                     /* Read zero or more signal names */
2737            y = cmkey(mstab,nms,"modem signal","",xxstring);
2738            if (y == -3) break;         /* -3 means they typed CR */
2739            if (y < 0) return(y);       /* Other negatives are errors */
2740            z |= y;                     /* OR the bit into the signal mask */
2741        }
2742        break;
2743
2744      default:                          /* Shouldn't happen */
2745        return(-2);
2746    }
2747
2748/* Command is entered, now do it. */
2749
2750    if (zz > -1L) {                     /* Time of day given? */
2751        x = zz;
2752        if (zz != (long) x) {
2753            printf(
2754"Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n"
2755                   );
2756            return(-9);
2757        }
2758    }
2759    if (cx == XXMSL) {                  /* Millisecond sleep */
2760        msleep(zz < 0 ? x : x * 1000);
2761        return(success = 1);
2762    }
2763    while (x--) {                       /* Sleep loop */
2764        int mdmsig;
2765        if (y = conchk()) {             /* Did they type something? */
2766#ifdef COMMENT
2767            while (y--) coninc(0);      /* Yes, gobble it up */
2768#else
2769            /* There is a debate over whether PAUSE should absorb    */
2770            /* its cancelling character(s).  There are several       */
2771            /* reasons why it should gobble at least one character:  */
2772            /* (1) MS-DOS Kermit does it                             */
2773            /* (2) if not, subsequent PAUSE commands will terminate  */
2774            /*     immediately                                       */
2775            /* (3) if not, subsequent ASK commands will use it as    */
2776            /*     valid input.  If \13, then it will get no input   */
2777            /* (4) if not, then the character appears on the command */
2778            /*     line after all enclosing macros are complete      */
2779            coninc(0);                  /* Gobble one up */
2780#endif /* COMMENT */
2781            break;                      /* And quit PAUSing or WAITing */
2782        }
2783        if (cx == XXWAI && z != 0) {
2784            mdmsig = ttgmdm();
2785            if (mdmsig < 0) return(success = 0);
2786            if ((mdmsig & z) == z) return(success = 1);
2787        }
2788        sleep(1);                       /* No interrupt, sleep one second */
2789    }
2790    if (cx == XXWAI) success = 0;
2791    else success = (x == -1);           /* Set SUCCESS/FAILURE for PAUSE. */
2792    return(0);
2793}
2794#endif /* NOSPL */
2795
2796
2797#ifndef NOFRILLS
2798#ifdef ZCOPY
2799int
2800docopy() {
2801    if ((x = cmifi("File to copy","",&s,&y,xxstring)) < 0) {
2802        if (x == -3) {
2803            printf("?Name of existing file required\n");
2804            return(-9);
2805        } else return(x);
2806    }
2807    if (y) {                            /* No wildcards allowed */
2808        printf("\n?Please specify a single file\n");
2809        return(-9);
2810    }
2811    strcpy(line,s);                     /* Make a safe copy of source name */
2812    p = line + (int)strlen(line) + 2;   /* Place for destination name */
2813    if ((x = cmofi("destination name","",&s,xxstring)) < 0) {
2814        /* Get destination name */
2815        if (x == -3) {
2816            printf("?Name for destination file required\n");
2817            return(-9);
2818        } else return(x);
2819    }
2820    strcpy(p,s);                        /* Safe copy of destination name */
2821    if ((y = cmcfm()) < 0) return(y);
2822#ifdef VMS
2823    conres();                           /* Let Ctrl-C work. */
2824#endif /* VMS */
2825    debug(F110,"docopy line",line,0);
2826    debug(F110,"docopy p",p,0);
2827    if (zcopy(line,p) < 0) {
2828        printf("?Can't copy %s to %s\n",line,p);
2829#ifdef VMS
2830        concb((char)escape);
2831#endif /* VMS */
2832        return(-9);
2833    } else {
2834#ifdef VMS
2835        concb((char)escape);
2836#endif /* VMS */
2837        return(success = 1);
2838    }
2839}
2840#endif /* ZCOPY */
2841#endif /* NOFRILLS */
2842
2843#ifndef NOFRILLS
2844#ifdef ZRENAME
2845int
2846dorenam() {
2847    if ((x = cmifi("File to rename","",&s,&y,xxstring)) < 0) {
2848        if (x == -3) {
2849            printf("?Name of existing file required\n");
2850            return(-9);
2851        } else return(x);
2852    }
2853    if (y) {                            /* No wildcards allowed */
2854        printf("\n?Please specify a single file\n");
2855        return(-9);
2856    }
2857    strcpy(line,s);                     /* Make a safe copy of the old name */
2858    p = line + (int)strlen(line) + 2;   /* Place for new name */
2859    if ((x = cmofi("New name","",&s,xxstring)) < 0) { /* Get new name */
2860        if (x == -3) {
2861            printf("?New name for file required\n");
2862            return(-9);
2863        } else return(x);
2864    }
2865    strcpy(p,s);                        /* Make a safe copy of the new name */
2866    if ((y = cmcfm()) < 0) return(y);
2867#ifdef VMS
2868    conres();                           /* Let Ctrl-C work. */
2869#endif /* VMS */
2870    debug(F110,"dorename line",line,0);
2871    debug(F110,"dorename p",p,0);
2872    if (zrename(line,p) < 0) {
2873        printf("?Can't rename %s to %s\n",line,p);
2874#ifdef VMS
2875        concb((char)escape);
2876#endif /* VMS */
2877        return(-9);
2878    } else {
2879#ifdef VMS
2880        concb((char)escape);
2881#endif /* VMS */
2882        return(success = 1);
2883    }
2884}
2885#endif /* ZRENAME */
2886#endif /* NOFRILLS */
2887
2888#ifndef NOSPL
2889
2890/* Do the RETURN command */
2891
2892int
2893doreturn(s) char *s; {
2894    int x; char *p;
2895    if (maclvl < 0) {
2896        printf("\n?Can't return from level %d\n",maclvl);
2897        return(success = 0);
2898    }
2899    lp = line;                          /* Expand return value now */
2900    x = LINBUFSIZ-1;
2901    if (zzstring(s,&lp,&x) > -1) {
2902        s = line;
2903        debug(F110,"RETURN parse",s,0);
2904    }
2905    debug(F101,"RETURN maclvl 1","",maclvl);
2906    /* Pop from all FOR/WHILE/XIFs */
2907    while ((maclvl > 0) &&
2908           (m_arg[maclvl-1][0]) &&
2909           (cmdstk[cmdlvl].src == CMD_MD) &&
2910           (!strncmp(m_arg[maclvl-1][0],"_xif",4) ||
2911            !strncmp(m_arg[maclvl-1][0],"_for",4) ||
2912            !strncmp(m_arg[maclvl-1][0],"_whi",4))) {
2913        debug(F110,"RETURN popping",m_arg[maclvl-1][0],0);
2914        dogta(XXPTA);           /* Put args back */
2915        popclvl();              /* Pop up two levels */
2916        popclvl();
2917        debug(F101,"RETURN maclvl 2","",maclvl);
2918    }
2919    popclvl();                          /* Pop from enclosing TAKE or macro */
2920    debug(F101,"RETURN maclvl 3","",maclvl);
2921
2922    x = (int)strlen(s);                 /* Length of return value */
2923    if (x > 0) {                        /* Have return value? */
2924        p = malloc(x+2);                /* Allocate a place to keep it */
2925        if (mrval[maclvl+1]) {          /* Free old one, if any */
2926            free(mrval[maclvl+1]);
2927            mrval[maclvl+1] = NULL;
2928        }
2929        if (p) {                        /* Did we get a place? */
2930            strcpy(p, s);               /* Yes, copy the string into it. */
2931            mrval[maclvl+1] = p;        /* Make return value point to it. */
2932            debug(F110,"RETURN copy",mrval[maclvl],0);
2933        } else {                        /* No, could not get space. */
2934            mrval[maclvl+1] = NULL;     /* Return null pointer. */
2935            x = 0;                      /* Set failure return code. */
2936        }
2937    } else mrval[maclvl+1] = NULL;      /* Blank return code */
2938    return(success = x ? 1 : 0);        /* Return status code */       
2939}
2940#endif /* NOSPL */
2941
2942#ifndef NOSPL
2943/* Do the OPEN command */
2944
2945int
2946doopen()  {                             /* OPEN { append, read, write } */
2947    int x, y, z; char *s;
2948    static struct filinfo fcb;          /* (must be static) */
2949    if ((x = cmkey(opntab,nopn,"mode","",xxstring)) < 0) {
2950        if (x == -3) {
2951            printf("?Mode required\n");
2952            return(-9);
2953        } else return(x);
2954    }
2955    switch (x) {
2956      case XYFZ_O:                      /* Old file (READ) */
2957        if (chkfn(ZRFILE) > 0) {
2958            printf("?Read file already open\n");
2959            return(-2);
2960        }
2961        if ((z = cmifi("File to read","",&s,&y,xxstring)) < 0) {
2962            if (z == -3) {
2963                printf("?Input filename required\n");
2964                return(-9);
2965            } else return(z);
2966        }
2967        if (y) {                                /* No wildcards allowed */
2968            printf("\n?Please specify a single file\n");
2969            return(-2);
2970        }
2971        strcpy(line,s);
2972        if ((int)strlen(line) < 1) return(-2);
2973        if ((z = cmnum("buffer size","4096",10,&y,xxstring)) < 0)
2974          return(z);
2975        if (y < 1) {
2976            printf("?Positive number required\n");
2977            return(-9);
2978        }
2979        if ((z = cmcfm()) < 0) return(z);
2980        readblock = y;
2981        if (readbuf)
2982          free(readbuf);
2983        if (!(readbuf = (CHAR *) malloc(readblock+1))) {
2984            printf("?Can't allocate read buffer\n");
2985            return(-9);
2986        }
2987        return(success = zopeni(ZRFILE,line));
2988
2989#ifndef MAC
2990#ifndef NOPUSH
2991      case XYFZ_Y:                      /* Pipe/Process (READ) */
2992        if (nopush) {
2993            printf("?Read from pipe disabled\n");
2994            return(success=0);
2995        }
2996        if (chkfn(ZRFILE) > 0) {
2997            printf("?Read file already open\n");
2998            return(-2);
2999        }
3000        if ((y = cmtxt("System command to read from","",&s,xxstring)) < 0) {
3001            if (y == -3) {
3002                printf("?Command name required\n");
3003                return(-9);
3004            } else return(y);
3005        }
3006        strcpy(line,s);
3007        if ((int)strlen(line) < 1) return(-2);
3008        if ((y = cmcfm()) < 0) return(y);
3009        if (!readbuf) {
3010            if (!(readbuf = (CHAR *) malloc(readblock+1))) {
3011                printf("?Can't allocate read buffer\n");
3012                return(-9);
3013            }
3014        }
3015        return(success = zxcmd(ZRFILE,line));
3016
3017      case XYFZ_X:                      /* Write to pipe */
3018        if (nopush) {
3019            printf("?Write to pipe disabled\n");
3020            return(success=0);
3021        }
3022        if (chkfn(ZWFILE) > 0) {
3023            printf("?Write file already open\n");
3024            return(-2);
3025        }
3026        if ((y = cmtxt("System command to write to","",&s,xxstring)) < 0) {
3027            if (y == -3) {
3028                printf("?Command name required\n");
3029                return(-9);
3030            } else return(y);
3031        }
3032        strcpy(line,s);
3033        if ((int)strlen(line) < 1) return(-2);
3034        if ((y = cmcfm()) < 0) return(y);
3035        success = zxcmd(ZWFILE,line);
3036        if (!success && msgflg)
3037          printf("Can't open process for writing: %s\n",line);
3038        return(success);
3039#endif /* NOPUSH */
3040#endif /* MAC */
3041
3042      case XYFZ_N:                      /* New file (WRITE) */
3043      case XYFZ_A:                      /* (APPEND) */
3044        if ((z = cmofi("Name of local file to create","",&s,xxstring)) < 0) {
3045            if (z == -3) {
3046                printf("?Filename required\n");
3047                return(-9);
3048            } else return(z);
3049        }
3050        if (z == 2) {
3051            printf("?Sorry, %s is a directory name\n",s);
3052            return(-9);
3053        }
3054        if (chkfn(ZWFILE) > 0) {
3055            printf("?Write/Append file already open\n");
3056            return(-2);
3057        }
3058        fcb.bs = fcb.cs = fcb.rl = fcb.fmt = fcb.org = fcb.cc = fcb.typ = 0;
3059        fcb.lblopts = 0;
3060        fcb.dsp = x;                    /* Create or Append */
3061        strcpy(line,s);
3062        if ((int)strlen(line) < 1) return(-2);
3063        if ((y = cmcfm()) < 0) return(y);
3064        return(success = zopeno(ZWFILE,line,NULL,&fcb));
3065
3066      default:
3067        printf("?Not implemented");
3068        return(-2);
3069    }
3070}
3071#endif /* NOSPL */
3072
3073/* Finish parsing and do the GET or REGET command */
3074
3075int
3076doget(cx) int cx; {
3077    int x, y, rc;
3078    char *cbp;
3079
3080#ifdef CK_TMPDIR
3081    if (dldir && !f_tmpdir) {   /* If they have a download directory */
3082        if (s = zgtdir()) {             /* Get current directory, */
3083            if (zchdir(line)) { /* change to download directory */
3084                strncpy(savdir,s,TMPDIRLEN);
3085                f_tmpdir = 1;   /* remember that we did this */
3086            }
3087        }
3088    }
3089#endif /* CK_TMPDIR */
3090
3091    cmarg2 = "";                        /* Initialize as-name to nothing */
3092    x = 0;
3093#ifdef NOFRILLS
3094    if (*cmarg == NUL) {
3095        printf("?Remote filespec required\n");
3096        rc = -3;
3097        goto endget;
3098    }
3099#else
3100/*
3101  If remote file name omitted, get foreign and local names separately.
3102  But multine GET is allowed only if NOFRILLS is not defined.
3103*/
3104    if (*cmarg == NUL) {
3105 
3106        if (tlevel > -1
3107#ifndef NOSPL
3108            && cmdstk[cmdlvl].src == CMD_TF
3109#endif /* NOSPL */
3110            ) {
3111
3112/* Input is from a command file. */
3113
3114            /* Read 2nd line of GET command */
3115
3116            if (getnct(cmdbuf,CMDBL,tfile[tlevel],0) < 0) {
3117                printf("Command file ends prematurely in multiline GET\n");
3118                popclvl();
3119                rc = -9;
3120                goto endget;
3121            }
3122            cmres();                    /* Parse it */
3123            if ((x = cmtxt("Oofa","",&s,xxstring)) < 0) {
3124                rc = x;
3125                goto endget;
3126            }
3127            strcpy(line,brstrip(s));    /* Make a safe copy */
3128            cmarg = line;               /* Point to remote filename */
3129            if (*cmarg == NUL) {        /* Make sure there is one */
3130                printf("Remote filename missing in multiline GET\n");
3131                rc = -9;
3132                goto endget;
3133            }
3134            lp = line + strlen(line) + 1; /* Place for as-name */
3135
3136            /* And third line... */
3137
3138            cmarg2 = "";                /* Assume no as-name */
3139            if (getnct(cmdbuf,CMDBL,tfile[tlevel],0) < 0) { /* Get next line */
3140                popclvl();              /* There isn't one. */
3141            } else {                    /* There is... */
3142                if (*cmdbuf >= ' ') {   /* Parse as output filename */
3143                    cmres();
3144                    if ((x = cmofi("Mupeen",cmarg,&s,xxstring)) < 0) {
3145                        rc = x;
3146                        goto endget;
3147                    }
3148                    strcpy(lp,s);       /* Make a safe copy */
3149                    cmarg2 = lp;        /* Point as-name pointer at it */
3150                }
3151            }
3152            x = 0;                      /* Return code OK */
3153
3154#ifndef NOSPL
3155/* Reading commands from a macro definition */
3156
3157        } else if (cmdlvl > 0 && cmdstk[cmdlvl].src == CMD_MD) {
3158
3159            /* Read second line of GET command */
3160
3161            cbp = cmdbuf;
3162            if (getncm(cbp,CMDBL) < 0) {
3163                printf("Macro definition ends prematurely in multiline GET\n");
3164                rc = -9;
3165                goto endget;
3166            }
3167            cmres();
3168            if ((x = cmtxt("Oofa","",&s,xxstring)) < 0) return(x);
3169            if (*s == NUL) {            /* Make sure we got something */
3170                printf("Remote filename missing in multiline GET\n");
3171                rc = -9;
3172                goto endget;
3173            }
3174            strcpy(line,brstrip(s));    /* Copy filename to safe place */
3175            cmarg = line;               /* Point to it */
3176            x = strlen(line);           /* Get its length */
3177            lp = line + x + 1;          /* Where to put the next bit */
3178            y = LINBUFSIZ - x - 1;      /* Room left for next bit */
3179
3180            /* And third line... */
3181
3182            cmarg2 = "";                /* Assume no as-name */
3183            if (getncm(lp,y) > -1 && *lp >= ' ') { /* Read next line */
3184                x = strlen(lp);
3185                if (lp[x-1] == CR) lp[x-1] = NUL; /* Remove CR */
3186                cbp = cmdbuf;           /* Interpret the line */
3187                *cbp = NUL;             /* ... */
3188                y = CMDBL;              /* into the command buffer */
3189                zzstring(lp,&cbp,&y);
3190                if (*cmdbuf) {          /* If we have something */
3191                    cmres();            /* parse it as an output filename */
3192                    strcat(cmdbuf," ");
3193                    if ((x = cmofi("Mupeen","",&s,NULL)) < 0) {
3194                        rc = x;
3195                        goto endget;
3196                    }
3197                    strcpy(lp,s);       /* Copy the name to safe place */
3198                    cmarg2 = lp;        /* and make as-name pointer */
3199                }
3200            }
3201            x = 0;                      /* Return code OK */
3202#endif /* NOSPL */
3203        } else {                        /* Input is from terminal */
3204 
3205            cmsavp(psave,PROMPTL);
3206            cmsetp(" Remote file specification: "); /* Make new one */
3207            cmini(ckxech);
3208            x = -1;
3209            if (pflag) prompt(xxstring);
3210            while (x == -1) {           /* Prompt till they answer */
3211                x = cmtxt("Name of remote file(s)","",&cmarg,xxstring);
3212                debug(F111," cmtxt",cmarg,x);
3213            }
3214            if (x < 0) {
3215                cmsetp(psave);
3216                rc = x;
3217                goto endget;
3218            }
3219            if (*cmarg == NUL) {        /* If user types a bare CR, */
3220                printf("(cancelled)\n"); /* Forget about this. */
3221                cmsetp(psave);          /* Restore old prompt, */
3222                rc = 0;
3223                goto endget;
3224            }
3225            strcpy(line,brstrip(cmarg)); /* Make a safe copy */
3226            cmarg = line;
3227            cmsetp(" Local name to store it under: "); /* New prompt */
3228            cmini(ckxech);
3229            x = -1;
3230            if (pflag) prompt(xxstring);
3231            while (x == -1) {           /* Again, parse till answered */
3232                x = cmofi("Local file name","",&cmarg2,xxstring);
3233            }
3234            if (x < 0) {                /* Parse error */
3235                if (x == -3) {          /* CR = cancel */
3236                    printf("(cancelled)\n"); /* Print message */
3237                    x = 0;              /* Avoid further messages */
3238                }
3239                cmsetp(psave);          /* Restore prompt */
3240                rc = x;
3241                goto endget;
3242            }       
3243            x = -1;                     /* Get confirmation. */
3244            while (x == -1) x = cmcfm();
3245            cmsetp(psave);              /* Restore old prompt. */
3246        }
3247    }
3248#endif /* NOFRILLS */
3249
3250    if (x == 0) {                       /* Good return from cmtxt or cmcfm, */
3251        debug(F110,"xxget cmarg",cmarg,0);
3252        strncpy(fspec,cmarg,CKMAXPATH);
3253        debug(F111,"xxget fspec",fspec,CKMAXPATH);
3254        if (cx == XXRETR)
3255          sstate = (CHAR) 'h';
3256        else
3257          sstate = (CHAR) ((cx == XXGET) ? 'r' : 'j'); /* Set start state. */
3258        if (local) {
3259            displa = 1;
3260            ttflui();
3261        }
3262    }
3263#ifndef NOFRILLS
3264#ifdef CK_TMPDIR
3265/* cmarg2 is also allowed to be a device or directory name */
3266
3267    y = strlen(cmarg2);
3268    if (
3269#ifdef OS2
3270        (isalpha(cmarg2[0]) &&
3271         cmarg2[1] == ':' &&
3272         cmarg2[2] == '\0') ||
3273        isdir(cmarg2)
3274#else
3275#ifdef UNIX
3276        (y > 0 && cmarg2[y-1] == '/') || isdir(cmarg2)
3277#else
3278#ifdef OSK
3279        (y > 0) && isdir(cmarg2)
3280#else
3281#ifdef VMS
3282        (y > 0) && isdir(cmarg2)
3283#else
3284#ifdef STRATUS
3285        (y > 0) && isdir(cmarg2)
3286#endif /* STRATUS */
3287#endif /* VMS */
3288#endif /* OSK */
3289#endif /* UNIX */
3290
3291#endif /* OS2 */
3292        ) {
3293        debug(F110,"RECEIVE arg disk or dir",cmarg2,0);
3294        if (!f_tmpdir) {
3295            s = zgtdir();
3296            if (s) {
3297                strncpy(savdir,s,TMPDIRLEN); /* remember old disk/dir */
3298                f_tmpdir = 1;   /* and that we did this */
3299                cmarg2 = "";    /* and we don't have an as-name. */
3300            } else {
3301                printf("?Can't get current directory\n");
3302                cmarg2 = "";
3303                f_tmpdir = 0;
3304                rc = -9;
3305                goto endget;
3306            }
3307            if (!zchdir(cmarg2)) {      /* change to given disk/directory, */
3308                printf("?Can't access %s\n",cmarg2);
3309                cmarg2 = "";
3310                rc = -9;
3311                goto endget;
3312            }
3313        }
3314    }
3315#endif /* CK_TMPDIR */
3316#endif /* NOFRILLS */
3317
3318    return(x);
3319
3320  endget:
3321#ifdef CK_TMPDIR
3322    if (f_tmpdir) {
3323        zchdir(savdir);
3324        f_tmpdir = 0;
3325    }
3326#endif /* CK_TMPDIR */
3327    return(rc);
3328}
3329
3330#ifndef NOSPL
3331
3332/*
3333  _ G E T A R G S
3334
3335  Used by XIF, FOR, and WHILE, each of which are implemented as 2-level
3336  macros; the first level defines the macro, the second runs it.
3337  This routine hides the fact that they are macros by importing the
3338  macro arguments (if any) from two levels up, to make them available
3339  in the XIF, FOR, and WHILE commands themselves; for example as loop
3340  indices, etc.
3341*/
3342int
3343dogta(cx) int cx; {
3344    int i; char c; char mbuf[4]; char *p;
3345
3346    if ((y = cmcfm()) < 0)
3347      return(y);
3348    if (cx == XXGTA)
3349      debug(F101,"_getargs maclvl","",maclvl);
3350    else if (cx == XXPTA)
3351      debug(F101,"_putargs maclvl","",maclvl);
3352    else
3353      return(-2);
3354    if (maclvl < 1)
3355      return(success = 0);
3356
3357    debug(F101,"success","",success);
3358
3359    mbuf[0] = '%'; mbuf[1] = '0'; mbuf[2] = '\0'; /* Argument name buf */
3360    for (i = 0; i < 10; i++) {          /* For all args */
3361        c = (char) (i + '0');           /* Make name */
3362        mbuf[1] = (char) c;             /* Insert digit */
3363        if (cx == XXGTA) {              /* Get arg from level-minus-2 */
3364            if (maclvl == 1) p = g_var[c]; /* If at level 1 use globals 0..9 */
3365            else p = m_arg[maclvl-2][i]; /* Otherwise they're on the stack */
3366            if (!p) {
3367                debug(F111,"_getarg p","(null pointer)",i);
3368            } else debug(F111,"_getarg p",p,i);
3369            addmac(mbuf,p);
3370        } else if (cx == XXPTA) {       /* Put args level+2 */
3371#ifndef MAC
3372            connoi();                   /* Turn off interrupts. */
3373#endif /* MAC */
3374            maclvl -= 2;                /* This is gross.. */
3375            p = m_arg[maclvl+2][i];
3376            if (p)
3377              debug(F111,"_putarg m_arg[maclvl+2][i]",p,i);
3378            else
3379              debug(F111,"_putarg m_arg[maclvl+2][i]","(null pointer)",i);
3380            addmac(mbuf,m_arg[maclvl+2][i]);
3381            maclvl += 2;
3382#ifndef MAC
3383            conint(trap,stptrap);       /* Restore interrupts */
3384#endif /* MAC */
3385        } else return(success = 0);
3386    }
3387    debug(F101,"_get/putarg exit","",i);
3388    debug(F101,"_get/putarg exit maclvl","",maclvl);
3389    debug(F101,"_get/putarg exit argc maclvl","",macargc[maclvl]);
3390
3391    if (cx == XXGTA && maclvl > 1) {
3392        macargc[maclvl] = macargc[maclvl - 2];
3393        /* macargc[maclvl - 1] = macargc[maclvl - 2]; */
3394    }
3395
3396#ifdef COMMENT
3397/*
3398  Internal commands don't change success variable if they succeed.
3399*/
3400    return(success = 1);
3401#else
3402    return(1);
3403#endif /* COMMENT */
3404
3405}
3406#endif /* NOSPL */
3407
3408#ifndef NOSPL
3409/*
3410  Do the GOTO and FORWARD commands.
3411  s = Label to search for, cx = function code, XXGOTO or XXFWD.
3412*/
3413int
3414dogoto(s, cx) char *s; int cx; {
3415    int i, j, x, y, z, bc;
3416    int stopflg;
3417    char tmplbl[50], *lp;
3418
3419    stopflg = (cx == XXXFWD);           /* _FORWARD (used in SWITCH) */
3420    bc = 0;                             /* Brace counter */
3421
3422    debug(F101,"goto cx","",cx);
3423    debug(F101,"goto cmdlvl","",cmdlvl);
3424    debug(F101,"goto maclvl","",maclvl);
3425    debug(F101,"goto tlevel","",tlevel);
3426    debug(F110,"goto before conversion",s,0);
3427    y = (int)strlen(s);
3428    if (*s != ':') {                    /* If the label mentioned */
3429        for (i = y; i > 0; i--) {       /* does not begin with a colon, */
3430            s[i] = s[i-1];              /* then insert one. */
3431        }                               /* Also, convert to lowercase. */
3432        s[0] = ':';
3433        s[++y] = '\0';
3434    }
3435    debug(F111,"goto after conversion",s,y);
3436    if (s[1] == '.' || s[1] == SP || s[1] == NUL) {
3437        printf("?Bad label syntax - '%s'\n",s);
3438        return(success = 0);
3439    }
3440    if (cmdlvl == 0) {
3441        printf("?Sorry, GOTO only works in a command file or macro\n");
3442        return(success = 0);
3443    }
3444    while (cmdlvl > 0) {                /* Only works inside macros & files */
3445        if (cmdstk[cmdlvl].src == CMD_MD) { /* GOTO inside macro */
3446            int i, m, flag;
3447            char *xp, *tp;
3448
3449            /* GOTO: rewind the macro; FORWARD: start at current position */
3450
3451            lp = (cx == XXGOTO) ? macx[maclvl] : macp[maclvl];
3452            m = (int)strlen(lp) - y + 1;
3453            debug(F111,"goto in macro",lp,m);
3454
3455            flag = 1;                   /* flag for valid label position */
3456            for (i = 0; i < m; i++,lp++) { /* search for label in macro body */
3457                if (*lp == '{')         /* But only at this level */
3458                  bc++;                 /* Anything inside braces is off */
3459                else if (*lp == '}')    /* limits. */
3460                  bc--;
3461                if (stopflg && bc > 0)  /* This is good for SWITCH */
3462                  continue;             /* but interferes with WHILE, etc. */
3463                if (*lp == ',') {
3464                    flag = 1;
3465                    continue;
3466                }
3467                if (flag) {             /* If in valid label position */
3468                    if (*lp == SP)      /* eat leading spaces */
3469                      continue;
3470                    if (*lp != ':') {   /* Look for label introducer */
3471                        flag = 0;       /* this isn't it */
3472                        continue;       /* keep looking */
3473                    }
3474                }
3475                if (!flag)              /* We don't have a label */
3476                  continue;             /*  so keep looking... */
3477                xp = lp; tp = tmplbl;   /* Copy the label from the macro */
3478                j = 0;                  /* to make it null-terminated */
3479                while (*tp = *xp) {
3480                    if (j++ > 50) break;  /* j = length of word from macro */
3481                    if (*tp < 33 || *tp == ',') /* Look for end of word */
3482                      break;
3483                    else tp++, xp++;    /* Next character */
3484                }
3485                *tp = '\0';             /* In case we stopped early */
3486                /* Now do caseless string comparison, using longest length */
3487                debug(F111,"macro GOTO label",s,y);
3488                debug(F111,"macro target label",tmplbl,j);
3489                z = (stopflg && inpcas[cmdlvl]) ?
3490                  strcmp(s,tmplbl) :
3491                    xxstrcmp(s,tmplbl,(y > j) ? y : j);
3492                if (!z)
3493                  break;
3494                else if (stopflg &&
3495                    !xxstrcmp(":default",tmplbl,(8 > j) ? 8 : j))
3496                  break;
3497                else
3498                  flag = 0;
3499            }
3500            if (i == m) {               /* didn't find the label */
3501                debug(F101,"goto failed at cmdlvl","",cmdlvl);
3502                if (stopflg)
3503                  return(0);
3504                if (!popclvl()) {       /* pop up to next higher level */
3505                    printf("?Label '%s' not found\n",s); /* if none */
3506                    return(0);          /* quit */
3507                } else continue;        /* otherwise look again */
3508            }
3509            debug(F110,"goto found macro label",lp,0);
3510            macp[maclvl] = lp;          /* set macro buffer pointer */
3511            return(1);
3512        } else if (cmdstk[cmdlvl].src == CMD_TF) {
3513            x = 0;                      /* GOTO issued in take file */
3514            if (cx == XXGOTO) {         /* If GOTO, but not FORWARD, */
3515                rewind(tfile[tlevel]);  /* search file from beginning */
3516                tfline[tlevel] = 0;
3517            }
3518            while (! feof(tfile[tlevel])) {
3519                if (fgets(line,LINBUFSIZ,tfile[tlevel]) == NULL) /* Get line */
3520                  break;                /* If no more, done, label not found */
3521                tfline[tlevel]++;
3522                lp = line;              /* Got line */
3523                while (*lp == SP || *lp == HT)
3524                  lp++;                 /* Strip leading whitespace */
3525                if (*lp != ':') continue; /* Check for label introducer */
3526                tp = lp;                /* Get end of word */
3527                j = 0;
3528                while (*tp) {           /* And null-terminate it */
3529                    if (*tp < 33) {
3530                        *tp = '\0';
3531                        break;
3532                    } else tp++, j++;
3533                }
3534                if (!xxstrcmp(lp,s,(y > j) ? y : j)) { /* Caseless compare */
3535                    x = 1;              /* Got it */
3536                    break;              /* done. */
3537                } else if (stopflg &&
3538                           !xxstrcmp(":default",tmplbl,(8 > j) ? 8 : j)) {
3539                    x = 1;
3540                    break;
3541                }
3542            }
3543            if (x == 0) {               /* If not found, print message */
3544                debug(F101,"goto failed at cmdlvl","",cmdlvl);
3545                if (stopflg)
3546                  return(0);
3547                if (!popclvl()) {       /* pop up to next higher level */
3548                    printf("?Label '%s' not found\n",s); /* if none */
3549                    return(0);          /* quit */
3550                } else continue;        /* otherwise look again */
3551            }
3552            return(x);                  /* Send back return code */
3553        }
3554    }
3555    printf("?Stack problem in GOTO %s\n",s); /* Shouldn't see this */
3556    return(0);
3557}
3558#endif /* NOSPL */
3559
3560/* Finish parsing and do the IF, XIF, and WHILE commands */
3561
3562char *
3563brstrip(p) char *p; {
3564    if (!p) return("");
3565    if (*p == '{') {
3566        int x;
3567        x = (int)strlen(p) - 1;
3568        if (p[x] == '}') {
3569            p[x] = NUL;
3570            p++;
3571        }
3572    }
3573    return(p);
3574}
3575
3576#ifndef NOSPL
3577
3578/*  C H K V A R  --  Check (if it's a) Variable  */
3579 
3580/*
3581  Crude and disgusting, but needed for OS/2, DOS, and Windows, where filenames
3582  have backslashes in them.  How do we know if a backslash in a filename is a
3583  directory separator, or if it's a Kermit backslash?  This routine does a
3584  rough syntax check of the next few characters and if it looks like it MIGHT
3585  be a variable, then it tries to evaluate it, and if the result is not empty,
3586  we say it's a variable, although sometimes it might not be -- some cases are
3587  truly ambiguous.  For example there might a DOS directory called \&a, and
3588  we also have a variable with the same name.  This is all for the sake of not
3589  having to tell PC users that they have to double all backslashes in file
3590  and directory names.
3591
3592  Call with a string pointer pointing at the backslash of the suspected
3593  variable.  Returns 1 if it seems to be a variable, 0 if not.
3594*/
3595int
3596chkvar(s) char *s; {
3597    int z = 0;                          /* Return code - assume failure */
3598    if ((int)strlen(s) < 1) return(-2);
3599    if (*s == CMDQ) {                   /* Object begins with backslash. */
3600        char c;
3601        c = s[1];                       /* Character following backslash */
3602        if (c) {
3603            int t = 0;
3604            c = (char) (islower(c) ? toupper(c) : c);
3605            if (c == '%') {             /* Simple variable */
3606                t = 1;
3607            } else if (c == '&') {      /* Array */
3608                if (s[3] == '[')
3609                  t = ckindex("]",s,4,0,1);
3610            } else if (c == '$' ||      /* Environment variable */
3611                       c == 'V' ||      /* Built-in variable */
3612                       c == 'M')        /* Macro name */
3613                t = (s[2] == '(');
3614            else if (c == 'F') {        /* Function reference */
3615                int x;
3616                if (x = ckindex("(",s,3,0,1))
3617                  if (x = ckindex(")",s,x,0,1))
3618                    t = 1;
3619            }
3620            if (t) {
3621                t = LINBUFSIZ-1;        /* This lets us test \v(xxx) */
3622                lp = line;              /* and even \f...(xxx) */
3623                zzstring(s,&lp,&t);     /* Evaluate it, whatever it is. */
3624                t = strlen(line);       /* Get its length. */
3625                debug(F111,"chkvar",line,t);
3626                z = t > 0;              /* If length > 0, it's defined */
3627            }
3628        }
3629    }
3630    return(z);
3631}
3632
3633/*  D O I F  --  Do the IF command  */
3634
3635int
3636doif(cx) int cx; {
3637    int x, y, z; char *s, *p;
3638    char *q;
3639    _PROTOTYP(char * evala, (char *));         
3640#ifdef OS2
3641    extern int keymac;
3642#endif /* OS2 */
3643
3644    not = 0;                            /* Flag for whether "NOT" was seen */
3645    z = 0;                              /* Initial IF condition */
3646    ifargs = 0;                         /* Count of IF condition words */
3647
3648ifagain:
3649    if ((ifc = cmkeyx(iftab,nif,"","",xxstring)) < 0) { /* If what?... */
3650        if (ifc == -3) {
3651            printf("?Condition required\n");
3652            return(-9);
3653        } else if (chknum(atmbuf)) {
3654            ifc = 9999;
3655        } else {
3656            if (ifc == -9)
3657              printf("?No keywords match - \"%s\"\n", atmbuf);
3658            return(ifc);
3659        }
3660    }
3661    if (ifc == 9999)
3662      z = !(atoi(atmbuf) == 0);
3663    else
3664    switch (ifc) {                      /* set z = 1 for true, 0 for false */
3665      case XXIFNO:                      /* IF NOT */
3666        not ^= 1;                       /* So NOT NOT NOT ... will work */
3667        ifargs++;
3668        goto ifagain;
3669      case XXIFTR:                      /* IF TRUE */
3670        z = 1;
3671        debug(F101,"if true","",z);
3672        ifargs += 1;
3673        break;
3674      case XXIFNT:                      /* IF FALSE */
3675        z = 0;
3676        debug(F101,"if true","",z);
3677        ifargs += 1;
3678        break;
3679      case XXIFSU:                      /* IF SUCCESS */
3680        z = ( success != 0 );
3681        debug(F101,"if success","",z);
3682        ifargs += 1;
3683        break;
3684      case XXIFFA:                      /* IF FAILURE */
3685        z = ( success == 0 );
3686        debug(F101,"if failure","",z);
3687        ifargs += 1;
3688        break;
3689      case XXIFDE:                      /* IF DEFINED */
3690        if ((x = cmfld("Macro or variable name","",&s,NULL)) < 0) {
3691            if (x == -3) return(-2);
3692            else return(x);
3693        }
3694        if (*s == CMDQ)
3695          z = chkvar(s);                        /* \-thing */
3696        else
3697          z = ( mxlook(mactab,s,nmac) > -1 ); /* Look for exact match */
3698        debug(F111,"if defined",s,z);
3699        ifargs += 2;
3700        break;
3701
3702      case XXIFBG:                      /* IF BACKGROUND */
3703      case XXIFFG:                      /* IF FOREGROUND */   
3704        bgchk();                        /* Check background status */
3705        if (ifc == XXIFFG)              /* Foreground */
3706          z = pflag ? 1 : 0;
3707        else z = pflag ? 0 : 1;         /* Background */
3708        ifargs += 1;
3709        break;
3710
3711      case XXIFCO:                      /* IF COUNT */
3712        z = ( --count[cmdlvl] > 0 );
3713        if (cx == XXWHI) count[cmdlvl] += 2; /* Don't ask... */
3714        debug(F101,"if count","",z);
3715        ifargs += 1;
3716        break;
3717
3718      case XXIFEX:                      /* IF EXIST */
3719#ifdef CK_TMPDIR
3720      case XXIFDI:                      /* IF DIRECTORY */
3721#endif /* CK_TMPDIR */
3722        if ((x = cmfld(
3723                       ((ifc == XXIFEX) ? "File" : "Directory name"),
3724                       "",&s,
3725#ifdef OS2
3726                       NULL             /* This allows \'s in filenames */
3727#else
3728                       xxstring
3729#endif /* OS2 */
3730                       )) < 0) {
3731            if (x == -3) {
3732                extern int cmflgs;
3733                if (cmflgs == 1) {
3734                    printf("?File or directory name required\n");
3735                    return(-9);
3736                }
3737            } else return(x);
3738        }
3739        if (ifc == XXIFEX) {
3740            z = (zchki(s) > -1L);
3741            debug(F101,"if exist 1","",z);
3742#ifdef OS2         
3743            if (!z) {                   /* File not found. */
3744                int t;                  /* Try expanding variables */
3745                t = LINBUFSIZ-1;        /* and looking again. */
3746                lp = line;
3747                zzstring(s,&lp,&t);
3748                s = line;
3749                z = ( zchki(s) > -1L );
3750                debug(F101,"if exist 2","",z);
3751            }
3752#endif /* OS2 */
3753#ifdef CK_TMPDIR
3754        } else {
3755#ifdef VMS
3756            z = (zchki(s) == -2)
3757#else
3758/* Because this doesn't catch $DISK1:[FOO]BLAH.DIR;1 */
3759            z = isdir(s)
3760#ifdef OS2
3761              || (isalpha(cmarg2[0]) &&
3762                  cmarg2[1] == ':' &&
3763                  cmarg2[2] == '\0')
3764#endif /* OS2 */
3765#endif /* VMS */
3766              ;
3767            debug(F101,"if directory 1","",z);
3768
3769            if (!z) {                   /* File not found. */
3770                int t;                  /* Try expanding variables */
3771                t = LINBUFSIZ-1;        /* and looking again. */
3772                lp = line;
3773                zzstring(s,&lp,&t);
3774                s = line;
3775                z = isdir(s)
3776#ifdef OS2
3777                  || (isalpha(cmarg2[0]) &&
3778                      cmarg2[1] == ':' &&
3779                      cmarg2[2] == '\0')
3780#endif /* OS2 */
3781                    ;
3782                debug(F101,"if directory 2","",z);
3783            }
3784#endif /* CK_TMPDIR */
3785        }
3786        ifargs += 2;
3787        break;
3788
3789      case XXIFEQ:                      /* IF EQUAL (string comparison) */
3790      case XXIFLL:                      /* IF Lexically Less Than */
3791      case XXIFLG:                      /* If Lexically Greater Than */
3792        if ((x = cmfld("first word or variable name","",&s,xxstring)) < 0) {
3793            if (x == -3) {
3794                printf("?Text required\n");
3795                return(-9);
3796            } else return(x);
3797        }
3798        s = brstrip(s);                 /* Strip braces */
3799        x = (int)strlen(s);
3800        if (x > LINBUFSIZ-1) {
3801            printf("?IF: strings too long\n");
3802            return(-2);
3803        }
3804        lp = line;                      /* lp points to first string */
3805        strcpy(lp,s);
3806        if ((y = cmfld("second word or variable name","",&s,xxstring)) < 0) {
3807            if (y == -3) {
3808                printf("?Text required\n");
3809                return(-9);
3810            } else return(y);
3811        }
3812        s = brstrip(s);
3813        y = (int)strlen(s);
3814        if (x + y + 2 > LINBUFSIZ) {
3815            printf("?IF: strings too long\n");
3816            return(-2);
3817        }
3818        tp = lp + y + 2;                /* tp points to second string */
3819        strcpy(tp,s);
3820        debug(F111,"IF EQ string 1, x",lp,x);
3821        debug(F111,"IF EQ string 2, y",tp,y);
3822        if (inpcas[cmdlvl]) {           /* INPUT CASE OBSERVE */
3823            x = strcmp(lp,tp);
3824            debug(F101,"IF EQ strcmp","",x);
3825        } else {                                /* INPUT CASE IGNORE */
3826            x = xxstrcmp(lp,tp,(y > x) ? y : x); /* Use longest length */
3827            debug(F101,"IF EQ xxstrcmp","",x);
3828        }
3829        switch (ifc) {
3830          case XXIFEQ:                  /* IF EQUAL (string comparison) */
3831            z = (x == 0);
3832            break;
3833          case XXIFLL:                  /* IF Lexically Less Than */
3834            z = (x < 0);
3835            break;
3836          case XXIFLG:                  /* If Lexically Greater Than */
3837            z = (x > 0);
3838            break;
3839        }
3840        ifargs += 3;
3841        break;
3842
3843      case XXIFAE:                      /* IF (arithmetically) = */
3844      case XXIFLT:                      /* IF (arithmetically) < */
3845      case XXIFGT: {                    /* IF (arithmetically) > */
3846        /* Really should use longs here... */
3847        /* But cmnum parses ints. */
3848        int n1, n2;
3849        x = cmfld("first number or variable name","",&s,xxstring);
3850        if (x == -3) {
3851            printf("?Quantity required\n");
3852            return(-9);
3853        }
3854        if (x < 0) return(x);
3855        debug(F101,"xxifgt cmfld","",x);
3856        lp = line;
3857        strcpy(lp,s);
3858        debug(F110,"xxifgt exp1",lp,0);
3859
3860/* The following bit is for compatibility with old versions of MS-DOS Kermit */
3861
3862        if (!xxstrcmp(lp,"count",5)) {
3863            n1 = count[cmdlvl];
3864        } else if (!xxstrcmp(lp,"version",7)) {
3865            n1 = (int) vernum;
3866        } else if (!xxstrcmp(lp,"argc",4)) {
3867            n1 = (int) macargc[maclvl];
3868        } else {
3869
3870/* End of compatibility bit */
3871
3872            if (chknum(lp)) {
3873                n1 = atoi(lp);
3874            } else {                    /* Check for arithmetic expression */
3875                q = evala(lp);          /* cmnum() does this but ... */
3876                if (chknum(q))          /* we're not using cmnum(). */
3877                  n1 = atoi(q);
3878                else
3879                  return(-2);
3880            }           
3881        }
3882        y = cmfld("second number or variable name","",&s,xxstring);
3883        if (y == -3) {
3884            printf("?Quantity required\n");
3885            return(-9);
3886        }
3887        if (y < 0) return(y);
3888        if ((int)strlen(s) < 1) return(-2);
3889        x = (int)strlen(lp);
3890        tp = line + x + 2;
3891        strcpy(tp,s);
3892        debug(F110,"xxifgt exp2",tp,0);
3893        if (!xxstrcmp(tp,"count",5)) {
3894            n2 = count[cmdlvl];
3895        } else if (!xxstrcmp(tp,"version",7)) {
3896            n2 = (int) vernum;
3897        } else if (!xxstrcmp(tp,"argc",4)) {
3898            n2 = (int) macargc[maclvl];
3899        } else {
3900            if (chknum(tp)) {
3901                n2 = atoi(tp);
3902            } else {
3903                q = evala(tp);
3904                if (chknum(q))
3905                  n2 = atoi(q);
3906                else
3907                  return(-2);
3908            }           
3909        }
3910        debug(F101,"xxifft ifc","",ifc);
3911        z = ((n1 <  n2 && ifc == XXIFLT)
3912          || (n1 == n2 && ifc == XXIFAE)
3913          || (n1 >  n2 && ifc == XXIFGT));
3914        debug(F101,"xxifft n1","",n1);
3915        debug(F101,"xxifft n2","",n2);
3916        debug(F101,"xxifft z","",z);
3917        ifargs += 3;
3918        break; }
3919
3920      case XXIFNU:                      /* IF NUMERIC */
3921        x = cmfld("variable name or constant","",&s,xxstring);
3922        if (x == -3) {
3923            extern int cmflgs;
3924            if (cmflgs == 1) {
3925                printf("?Quantity required\n");
3926                return(-9);
3927            }
3928        } else if (x < 0)
3929          return(x);
3930        debug(F111,"xxifnu cmfld",s,x);
3931        lp = line;
3932        strcpy(lp,s);
3933        debug(F110,"xxifnu quantity",lp,0);
3934        z = chknum(lp);
3935#ifdef COMMENT
3936/*
3937  This works, but it's not wise -- IF NUMERIC is mostly used to see if a
3938  string really does contain only numeric characters.  If they want to force
3939  evaluation, they can use \feval().
3940*/
3941        if (!z) {                       /* Not a number */
3942            x_ifnum = 1;                /* Avoid "eval" error messages */
3943            q = evala(lp);              /* Maybe it's an expression */
3944            z = chknum(q);              /* that evaluates to a number */
3945            x_ifnum = 0;                /* Put eval messages back to normal */
3946            if (z) debug(F110,"xxifnu exp",lp,0);
3947        }
3948#endif /* COMMENT */
3949        debug(F101,"xxifnu chknum","",z);
3950        ifargs += 2;
3951        break;
3952
3953#ifdef ZFCDAT
3954      case XXIFNE: {                    /* IF NEWER */
3955        char d1[20], * d2;              /* Buffers for 2 rrrrrrrrrrdates */
3956        if ((z = cmifi("First file","",&s,&y,xxstring)) < 0)
3957          return(z);
3958        strcpy(d1,zfcdat(s));
3959        if ((z = cmifi("Second file","",&s,&y,xxstring)) < 0)
3960          return(z);
3961        d2 = zfcdat(s);
3962        if ((int)strlen(d1) != 17 || (int)strlen(d2) != 17) {
3963            printf("?Failure to get file date\n");
3964            return(-9);
3965        }
3966        debug(F110,"xxifnewer d1",d1,0);
3967        debug(F110,"xxifnewer d2",d2,0);
3968        z = (strcmp(d1,d2) > 0) ? 1 : 0;
3969        debug(F101,"xxifnewer","",z);
3970        ifargs += 2;
3971        break;
3972      }
3973#endif /* ZFCDAT */
3974
3975#ifdef CK_IFRO
3976      case XXIFRO:                      /* REMOTE-ONLY advisory */
3977        ifargs++;
3978#ifdef NOLOCAL
3979        z = 1;
3980#else
3981        z = remonly;
3982#endif /* NOLOCAL */
3983        break;
3984#endif /* CK_IFRO */
3985
3986      case XXIFAL: {                    /* ALARM */
3987          ifargs++;
3988          if (ck_alarm < 1L || alrm_date[0] < '0' || alrm_time[0] < '0') {
3989              z = 0;                    /* ALARM not SET */
3990              break;                    /* so IF ALARM fails */
3991          }
3992          x = 9;                        /* Compare current date */
3993          s = tmpbuf;                   /* and time with alarm time */
3994          zzstring("\\v(ndate)",&s,&x);
3995          z = (int) strncmp(tmpbuf,alrm_date,8); /* Compare dates */
3996          debug(F111,"IF ALARM date",alrm_date,z);
3997          if (z >= 0) {
3998              x = 6;                    /* If dates equal, compare times */
3999              s = tmpbuf;
4000              zzstring("\\v(ntime)",&s,&x);
4001              z = strncmp(tmpbuf,alrm_time,5);
4002              debug(F111,"IF ALARM time",alrm_time,z);
4003          }     
4004          tmpbuf[0] = NUL;              /* z >= 0 if alarm is passed */
4005          z = (z>=0 ? 1 : 0);           /* z <  0 otherwise */
4006          debug(F101,"IF ALARM","",z);
4007        }
4008        break;
4009
4010#ifdef OS2
4011      case XXIFSD:                      /* Started-From-Dialer */
4012        ifargs++;
4013        z = StartedFromDialer;
4014        break;
4015
4016      case XXIFTM:                      /* Terminal-Macro */
4017        ifargs++;
4018        z = cmdstk[cmdlvl].ccflgs & CF_KMAC;
4019        break;
4020#endif /* OS2 */
4021
4022      case XXIFEM:                      /* Emulation is active */
4023#ifdef OS2     
4024        z = 1;
4025#else
4026        z = 0;
4027#endif /* OS2 */
4028        break;
4029
4030      default:                          /* Shouldn't happen */
4031        return(-2);
4032    }
4033    if (not) z = !z;                    /* Handle NOT here for both IF & XIF */
4034
4035    switch (cx) {                       /* Separate handling for IF and XIF */
4036
4037      case XXIF:                        /* This is IF... */
4038        ifcmd[cmdlvl] = 1;              /* We just completed an IF command */
4039        debug(F101,"IF condition","",z);
4040        if (z) {                        /* Condition is true */
4041            iftest[cmdlvl] = 1;         /* Remember that IF succeeded */
4042            if (maclvl > -1) {          /* In macro, */
4043                pushcmd();              /* save rest of command. */
4044            } else if (tlevel > -1) {   /* In take file, */
4045                debug(F100, "doif: pushing command", "", 0);
4046                pushcmd();              /* save rest of command. */
4047            } else {                    /* If interactive, */
4048                cmini(ckxech);          /* just start a new command */
4049                printf("\n");           /* (like in MS-DOS Kermit) */
4050                if (pflag) prompt(xxstring);
4051            }
4052        } else {                        /* Condition is false */
4053            iftest[cmdlvl] = 0;         /* Remember command failed. */
4054            if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
4055              return(y);                /* Gobble up rest of line */
4056        }
4057        return(0);
4058
4059      case XXIFX: {                     /* This is XIF (Extended IF) */
4060          char *p;
4061          char e[5];
4062          int i;
4063          if ((y = cmtxt("Object command","",&s,NULL)) < 0)
4064            return(y);                  /* Get object command. */
4065          p = s;
4066          lp = line;
4067          if (litcmd(&p,&lp) < 0) {     /* Insert quotes in THEN-part */
4068              return(-2);
4069          }
4070          if (!z) {                     /* Use ELSE-part, if any */
4071              lp = line;                /* Write over THEN part. */
4072              *lp = NUL;
4073              while (*p == SP) p++;     /* Strip trailing spaces */
4074              if (*p) {                 /* At end? */
4075                  for (i = 0; i < 4; i++) e[i] = *p++; /* No, check for ELSE */
4076                  if (xxstrcmp(e,"else",4)) return(-2); /* No, syntax error */
4077                  if (litcmd(&p,&lp) < 0) { /* Insert quotes */
4078                      return(-2);
4079                  }
4080                  while (*p == SP) p++; /* Strip trailing spaces */
4081                  if (*p) return(-2);   /* Should be nothing here. */
4082              }
4083          }
4084          if (line[0]) {
4085              x = mlook(mactab,"_xif",nmac); /* get index of "_xif" macro. */
4086              if (x < 0) {                      /* Not there? */
4087                  addmmac("_xif",xif_def);      /* Put it back. */
4088                  if (mlook(mactab,"_xif",nmac) < 0) { /* Look it up again. */
4089                      printf("?XIF macro gone!\n");
4090                      return(success = 0);
4091                  }
4092              }
4093              dodo(x,line,cmdstk[cmdlvl].ccflgs); /* Do the XIF macro */
4094          }
4095          return(0);
4096      }
4097      case XXWHI: {                     /* WHILE Command */
4098          p = cmdbuf;                   /* Capture IF condition */
4099          ifcond[0] = NUL;              /* from command buffer */
4100          while (*p == SP) p++;
4101          while (*p != SP) p++;
4102          ifcp = ifcond;
4103          strcpy(ifcp,"{ \\flit(if not ");
4104          ifcp += (int)strlen(ifcp);
4105          while (*p != '{' && *p != NUL) *ifcp++ = *p++;
4106          p = " goto _..bot) } ";
4107          while (*ifcp++ = *p++) ;
4108          debug(F110,"WHILE cmd",ifcond,0);
4109
4110          if ((y = cmtxt("Object command","",&s,NULL)) < 0)
4111            return(y);                  /* Get object command. */
4112          p = s;
4113          lp = line;
4114          if (litcmd(&p,&lp) < 0) {     /* Insert quotes in object command */
4115              return(-2);
4116          }
4117          debug(F110,"WHILE body",line,0);
4118          if (line[0]) {
4119              char *p;
4120              x = mlook(mactab,"_while",nmac); /* index of "_while" macro. */
4121              if (x < 0) {              /* Not there? */
4122                  addmmac("_while",whil_def); /* Put it back. */
4123                  if (mlook(mactab,"_while",nmac) < 0) { /* Look it up again */
4124                      printf("?WHILE macro definition gone!\n");
4125                      return(success = 0);
4126                  }
4127              }
4128              p = malloc((int)strlen(ifcond) + (int)strlen(line) + 2);
4129              if (p) {
4130                  strcpy(p,ifcond);
4131                  strcat(p,line);
4132                  debug(F110,"WHILE dodo",p,0);
4133                  dodo(x,p,cmdstk[cmdlvl].ccflgs);
4134                  free(p);
4135                  p = NULL;
4136              } else {
4137                  printf("?Can't allocate storage for WHILE command");
4138                  return(success = 0);
4139              }
4140          }
4141          return(0);
4142      }
4143      default:
4144        return(-2);
4145    }
4146}
4147#endif /* NOSPL */
4148
4149/* Set up a TAKE command file */
4150
4151int
4152dotake(s) char *s; {
4153    if ((tfile[++tlevel] = fopen(s,"r")) == NULL) {
4154        perror(s);
4155        debug(F110,"Failure to open",s,0);
4156        tlevel--;
4157        return(success = 0);
4158    } else {
4159        tfline[tlevel] = 0;             /* Line counter */
4160#ifdef VMS
4161        conres();                       /* So Ctrl-C will work */
4162#endif /* VMS */
4163#ifndef NOSPL
4164        cmdlvl++;                       /* Entering a new command level */
4165        if (cmdlvl > CMDSTKL) {
4166            cmdlvl--;
4167            printf("?TAKE files and/or DO commands nested too deeply\n");
4168            return(success = 0);
4169        }
4170        if (tfnam[tlevel]) {            /* Copy the filename */
4171            free(tfnam[tlevel]);
4172            tfnam[tlevel] = NULL;
4173        }
4174        if (tfnam[tlevel] = malloc(strlen(s) + 1))
4175          strcpy(tfnam[tlevel],s);
4176        ifcmd[cmdlvl] = 0;              /* Set variables for this cmd file */
4177        iftest[cmdlvl] = 0;
4178        count[cmdlvl]  = count[cmdlvl-1];  /* Inherit this */
4179        intime[cmdlvl] = intime[cmdlvl-1]; /* Inherit this */
4180        inpcas[cmdlvl] = inpcas[cmdlvl-1]; /* Inherit this */
4181        takerr[cmdlvl] = takerr[cmdlvl-1]; /* Inherit this */
4182        merror[cmdlvl] = merror[cmdlvl-1]; /* Inherit this */
4183        cmdstk[cmdlvl].src = CMD_TF;    /* Say we're in a TAKE file */
4184        cmdstk[cmdlvl].lvl = tlevel;    /* nested at this level */
4185        cmdstk[cmdlvl].ccflgs = cmdstk[cmdlvl-1].ccflgs;
4186#else
4187        takerr[tlevel] = takerr[tlevel-1]; /* Inherit this */
4188#endif /* NOSPL */
4189    }
4190    return(1);
4191}
4192#endif /* NOICP */
Note: See TracBrowser for help on using the repository browser.