| #include "ckcsym.h" |
| |
| int xcmdsrc = 0; |
| |
| #ifdef NOICP |
| int cmdsrc() { return(0); } |
| #endif /* NOICP */ |
| |
| /* C K U U S 5 -- "User Interface" for C-Kermit, part 5 */ |
| |
| /* |
| Authors: |
| Frank da Cruz <fdc@columbia.edu>, |
| The Kermit Project, Columbia University, New York City |
| Jeffrey E Altman <jaltman@secure-endpoints.com> |
| Secure Endpoints Inc., New York City |
| |
| Copyright (C) 1985, 2004, |
| Trustees of Columbia University in the City of New York. |
| All rights reserved. See the C-Kermit COPYING.TXT file or the |
| copyright text in the ckcmai.c module for disclaimer and permissions. |
| */ |
| |
| /* Includes */ |
| |
| #include "ckcdeb.h" |
| #include "ckcasc.h" |
| #include "ckcker.h" |
| #include "ckuusr.h" |
| |
| #ifdef DCMDBUF |
| char *line; /* Character buffer for anything */ |
| char *tmpbuf; |
| #else |
| char line[LINBUFSIZ+1]; |
| char tmpbuf[TMPBUFSIZ+1]; /* Temporary buffer */ |
| #endif /* DCMDBUF */ |
| |
| #ifndef NOICP |
| |
| #include "ckcnet.h" |
| #ifndef NOCSETS |
| #include "ckcxla.h" |
| #endif /* NOCSETS */ |
| #ifdef MAC |
| #include "ckmasm.h" |
| #endif /* MAC */ |
| #ifdef CK_SSL |
| #include "ck_ssl.h" |
| #endif /* CK_SSL */ |
| |
| #ifdef OS2 |
| #include "ckoetc.h" |
| #ifndef NT |
| #define INCL_NOPM |
| #define INCL_VIO /* Needed for ckocon.h */ |
| #include <os2.h> |
| #undef COMMENT |
| #else /* NT */ |
| #include <windows.h> |
| #define TAPI_CURRENT_VERSION 0x00010004 |
| #include <tapi.h> |
| #include <mcx.h> |
| #include "ckntap.h" |
| #define APIRET ULONG |
| extern int DialerHandle; |
| extern int StartedFromDialer; |
| #endif /* NT */ |
| #include "ckocon.h" |
| #include "ckokey.h" |
| #ifdef KUI |
| #include "ikui.h" |
| #endif /* KUI */ |
| #ifdef putchar |
| #undef putchar |
| #endif /* putchar */ |
| #define putchar(x) conoc(x) |
| extern int cursor_save ; |
| extern bool cursorena[] ; |
| #endif /* OS2 */ |
| |
| /* For formatted screens, "more?" prompting, etc. */ |
| |
| #ifdef FT18 |
| #define isxdigit(c) isdigit(c) |
| #endif /* FT18 */ |
| |
| #ifdef STRATUS /* Stratus Computer, Inc. VOS */ |
| #ifdef putchar |
| #undef putchar |
| #endif /* putchar */ |
| #define putchar(x) conoc(x) |
| #ifdef getchar |
| #undef getchar |
| #endif /* getchar */ |
| #define getchar(x) coninc(0) |
| #endif /* STRATUS */ |
| |
| /* External variables */ |
| |
| extern int carrier, cdtimo, local, quiet, backgrd, bgset, sosi, xsuspend, |
| binary, escape, xargs, flow, cmdmsk, duplex, ckxech, seslog, what, |
| inserver, diractive, tlevel, cwdf, nfuncs, msgflg, remappd, hints, mdmtyp, |
| zincnt, cmask, rcflag, success, xitsta, pflag, tnlm, tn_nlm, xitwarn, |
| debses, xaskmore, parity, saveask, wasclosed, whyclosed, cdactive, |
| rcdactive, keepallchars; |
| |
| #ifdef LOCUS |
| extern int locus, autolocus; |
| #endif /* LOCUS */ |
| |
| #ifndef NOMSEND |
| extern int addlist; |
| #endif /* NOMSEND */ |
| |
| #ifdef CK_SPEED |
| extern int prefixing; |
| #endif /* CK_SPEED */ |
| |
| extern int g_matchdot; |
| |
| #ifdef RECURSIVE |
| extern int recursive; |
| #endif /* RECURSIVE */ |
| extern int xfiletype; |
| |
| #ifdef IKSDCONF |
| extern char * iksdconf; |
| extern int iksdcf; |
| #endif /* IKSDCONF */ |
| |
| #ifdef CK_RECALL |
| extern int on_recall; |
| #endif /* CK_RECALL */ |
| |
| extern int ngetpath, exitonclose; |
| extern char * getpath[]; |
| extern CHAR * epktmsg; |
| |
| extern char * snd_move; |
| extern char * snd_rename; |
| extern char * rcv_move; |
| extern char * rcv_rename; |
| extern char * g_snd_move; |
| extern char * g_snd_rename; |
| extern char * g_rcv_move; |
| extern char * g_rcv_rename; |
| |
| extern char * nm[]; |
| |
| #ifdef CK_UTSNAME |
| extern char unm_mch[]; |
| extern char unm_mod[]; |
| extern char unm_nam[]; |
| extern char unm_rel[]; |
| extern char unm_ver[]; |
| #endif /* CK_UTSNAME */ |
| |
| #ifndef NOPUSH |
| #ifndef NOFRILLS |
| extern char editor[]; |
| extern char editfile[]; |
| extern char editopts[]; |
| #ifdef BROWSER |
| extern char browser[]; |
| extern char browsopts[]; |
| extern char browsurl[]; |
| #endif /* BROWSER */ |
| #endif /* NOFRILLS */ |
| #endif /* NOPUSH */ |
| |
| #ifndef NOSERVER |
| extern char * x_user, * x_passwd, * x_acct; |
| #endif /* NOSERVER */ |
| |
| #ifdef CKLOGDIAL |
| extern int dialog; |
| extern char diafil[]; |
| #endif /* CKLOGDIAL */ |
| |
| #ifdef CKROOT |
| extern int ckrooterr; |
| #endif /* CKROOT */ |
| |
| #ifndef NOSPL |
| extern int cfilef, xxdot; |
| extern char cmdfil[]; |
| |
| struct localvar * localhead[CMDSTKL]; |
| struct localvar * localtail = NULL; |
| struct localvar * localnext = NULL; |
| |
| _PROTOTYP( VOID shosexp, (void) ); |
| _PROTOTYP( static VOID shoinput, (void) ); |
| _PROTOTYP( static char gettok, (void) ); |
| _PROTOTYP( static VOID factor, (void) ); |
| _PROTOTYP( static VOID term, (void) ); |
| _PROTOTYP( static VOID termp, (void) ); |
| _PROTOTYP( static VOID exprp, (void) ); |
| _PROTOTYP( static VOID expr, (void) ); |
| _PROTOTYP( static VOID simple, (void) ); |
| _PROTOTYP( static VOID simpler, (void) ); |
| _PROTOTYP( static VOID simplest, (void) ); |
| _PROTOTYP( static long xparse, (void) ); |
| #endif /* NOSPL */ |
| #ifndef NOSHOW |
| _PROTOTYP( int sho_iks, (void) ); |
| #endif /* NOSHOW */ |
| |
| #ifdef MAC |
| char * ckprompt = "Mac-Kermit>"; /* Default prompt for Macintosh */ |
| char * ikprompt = "IKSD>"; |
| #else /* Not MAC */ |
| #ifdef NOSPL |
| #ifdef OS2 |
| char * ckprompt = "K-95> "; /* Default prompt for Win32 */ |
| char * ikprompt = "IKSD> "; |
| #else |
| char * ckprompt = "C-Kermit>"; |
| char * ikprompt = "IKSD>"; |
| #endif /* NT */ |
| #else /* NOSPL */ |
| #ifdef OS2 |
| /* Default prompt for OS/2 and Win32 */ |
| #ifdef NT |
| char * ckprompt = "[\\freplace(\\flongpath(\\v(dir)),/,\\\\)] K-95> "; |
| char * ikprompt = "[\\freplace(\\flongpath(\\v(dir)),/,\\\\)] IKSD> "; |
| #else /* NT */ |
| char * ckprompt = "[\\freplace(\\v(dir),/,\\\\)] K-95> "; |
| char * ikprompt = "[\\freplace(\\v(dir),/,\\\\)] IKSD> "; |
| #endif /* NT */ |
| #else /* OS2 */ |
| #ifdef VMS |
| char * ckprompt = "\\v(dir) C-Kermit>"; /* Default prompt VMS */ |
| char * ikprompt = "\\v(dir) IKSD>"; |
| #else |
| char * ckprompt = "(\\v(dir)) C-Kermit>"; /* Default prompt for others */ |
| char * ikprompt = "(\\v(dir)) IKSD>"; |
| #endif /* VMS */ |
| #endif /* NT */ |
| #endif /* NOSPL */ |
| #endif /* MAC */ |
| |
| #ifndef CCHMAXPATH |
| #define CCHMAXPATH 257 |
| #endif /* CCHMAXPATH */ |
| char inidir[CCHMAXPATH] = { NUL, NUL }; /* Directory INI file executed from */ |
| |
| #ifdef TNCODE |
| extern int tn_b_nlm; /* TELNET BINARY newline mode */ |
| #endif /* TNCODE */ |
| |
| #ifndef NOKVERBS |
| extern struct keytab kverbs[]; /* Table of \Kverbs */ |
| extern int nkverbs; /* Number of \Kverbs */ |
| #endif /* NOKVERBS */ |
| |
| #ifndef NOPUSH |
| extern int nopush; |
| #endif /* NOPUSH */ |
| |
| #ifdef CK_RECALL |
| extern int cm_recall; |
| #endif /* CK_RECALL */ |
| |
| extern char *ccntab[]; |
| |
| /* Printer stuff */ |
| |
| extern char *printername; |
| extern int printpipe; |
| #ifdef BPRINT |
| extern int printbidi, pportparity, pportflow; |
| extern long pportspeed; |
| #endif /* BPRINT */ |
| |
| #ifdef OS2 |
| _PROTOTYP (int os2getcp, (void) ); |
| _PROTOTYP (int os2getcplist, (int *, int) ); |
| #ifdef OS2MOUSE |
| extern int tt_mouse; |
| #endif /* OS2MOUSE */ |
| extern int tt_update, tt_updmode, updmode, tt_utf8; |
| #ifndef IKSDONLY |
| extern int tt_status[]; |
| #endif /* IKSDONLY */ |
| #ifdef PCFONTS |
| extern struct keytab term_font[]; |
| #else |
| #ifdef KUI |
| extern struct keytab * term_font; |
| #endif /* KUI */ |
| #endif /* PCFONTS */ |
| extern int ntermfont, tt_font, tt_font_size; |
| extern unsigned char colornormal, colorunderline, colorstatus, |
| colorhelp, colorselect, colorborder, colorgraphic, colordebug, |
| colorreverse, colorcmd, coloritalic; |
| extern int priority; |
| extern struct keytab prtytab[]; |
| extern int nprty; |
| char * cmdmac = NULL; |
| #endif /* OS2 */ |
| |
| #ifdef VMS |
| _PROTOTYP (int zkermini, (char *, int, char *) ); |
| #endif /* VMS */ |
| |
| extern long vernum; |
| extern int inecho, insilence, inbufsize, nvars, inintr; |
| extern char *protv, *fnsv, *cmdv, *userv, *ckxv, *ckzv, *ckzsys, *xlav, |
| *cknetv, *clcmds; |
| #ifdef OS2 |
| extern char *ckyv; |
| #endif /* OS2 */ |
| #ifdef CK_AUTHENTICATION |
| extern char * ckathv; |
| #endif /* CK_AUTHENTICATION */ |
| #ifdef CK_SSL |
| extern char * cksslv; |
| #endif /* CK_SSL */ |
| #ifdef CK_ENCRYPTION |
| #ifndef CRYPT_DLL |
| extern char * ckcrpv; |
| #endif /* CRYPT_DLL */ |
| #endif /* CK_ENCRYPTION */ |
| |
| #ifdef SSHBUILTIN |
| extern char *cksshv; |
| #ifdef SFTP_BUILTIN |
| extern char *cksftpv; |
| #endif /* SFTP_BUILTIN */ |
| #endif /* SSHBUILTIN */ |
| |
| #ifdef TNCODE |
| extern char *cktelv; |
| #endif /* TNCODE */ |
| #ifndef NOFTP |
| #ifndef SYSFTP |
| extern char * ckftpv; |
| #endif /* SYSFTP */ |
| #endif /* NOFTP */ |
| |
| extern int srvidl; |
| |
| #ifdef OS2 |
| extern char *ckonetv; |
| extern int interm; |
| #ifdef CK_NETBIOS |
| extern char *ckonbiv; |
| #endif /* CK_NETBIOS */ |
| #ifdef OS2MOUSE |
| extern char *ckomouv; |
| #endif /* OS2MOUSE */ |
| #endif /* OS2 */ |
| |
| #ifndef NOLOCAL |
| extern char *connv; |
| #endif /* NOLOCAL */ |
| #ifndef NODIAL |
| extern char *dialv; |
| #endif /* NODIAL */ |
| #ifndef NOSCRIPT |
| extern char *loginv; |
| extern int secho; |
| #endif /* NOSCRIPT */ |
| |
| #ifndef NODIAL |
| extern int nmdm, dirline; |
| extern struct keytab mdmtab[]; |
| #endif /* NODIAL */ |
| |
| extern int network, nettype, ttnproto; |
| |
| #ifdef OS2 |
| #ifndef NOTERM |
| /* SET TERMINAL items... */ |
| extern int tt_type, tt_arrow, tt_keypad, tt_wrap, tt_answer, tt_scrsize[]; |
| extern int tt_bell, tt_roll[], tt_ctstmo, tt_cursor, tt_pacing, tt_type_mode; |
| extern char answerback[]; |
| extern struct tt_info_rec tt_info[]; /* Indexed by terminal type */ |
| extern int max_tt; |
| #endif /* NOTERM */ |
| #endif /* OS2 */ |
| |
| _PROTOTYP( VOID shotrm, (void) ); |
| _PROTOTYP( int shofea, (void) ); |
| |
| #ifdef OS2 |
| extern int tt_rows[], tt_cols[]; |
| #else /* OS2 */ |
| extern int tt_rows, tt_cols; |
| #endif /* OS2 */ |
| extern int cmd_rows, cmd_cols; |
| |
| #ifdef CK_TMPDIR |
| extern int f_tmpdir; /* Directory changed temporarily */ |
| extern char savdir[]; /* Temporary directory */ |
| #endif /* CK_TMPDIR */ |
| |
| #ifndef NOLOCAL |
| extern int tt_crd, tt_escape; |
| #endif /* NOLOCAL */ |
| |
| #ifndef NOCSETS |
| extern int language, nfilc, tcsr, tcsl, tcs_transp, fcharset; |
| extern struct keytab fcstab[]; |
| extern struct csinfo fcsinfo[]; |
| #ifndef MAC |
| extern struct keytab ttcstab[]; |
| #endif /* MAC */ |
| #endif /* NOCSETS */ |
| |
| extern long speed; |
| |
| #ifndef NOXMIT |
| extern int xmitf, xmitl, xmitp, xmitx, xmits, xmitw, xmitt; |
| extern char xmitbuf[]; |
| #endif /* NOXMIT */ |
| |
| extern char **xargv, *versio, *ckxsys, *dftty, *lp; |
| |
| #ifdef DCMDBUF |
| extern char *cmdbuf, *atmbuf; /* Command buffers */ |
| #ifndef NOSPL |
| extern char *savbuf; /* Command buffers */ |
| #endif /* NOSPL */ |
| #else |
| extern char cmdbuf[], atmbuf[]; /* Command buffers */ |
| #ifndef NOSPL |
| extern char savbuf[]; /* Command buffers */ |
| #endif /* NOSPL */ |
| #endif /* DCMDBUF */ |
| |
| extern char toktab[], ttname[], psave[]; |
| extern CHAR sstate, feol; |
| extern int cmflgs, techo, repars, ncmd; |
| extern struct keytab cmdtab[]; |
| |
| #ifndef NOSETKEY |
| KEY *keymap; |
| #ifndef OS2 |
| #define mapkey(x) keymap[x] |
| #endif /* OS2 */ |
| MACRO *macrotab; |
| _PROTOTYP( VOID shostrdef, (CHAR *) ); |
| #endif /* NOSETKEY */ |
| |
| extern int cmdlvl; |
| |
| #ifndef NOSPL |
| extern struct mtab *mactab; |
| extern struct keytab mackey[]; |
| extern struct keytab vartab[], fnctab[], iftab[]; |
| extern int maclvl, nmac, mecho, fndiags, fnerror, fnsuccess, nif; |
| #endif /* NOSPL */ |
| |
| FILE *tfile[MAXTAKE]; /* TAKE file stack */ |
| char *tfnam[MAXTAKE]; |
| int tfline[MAXTAKE]; |
| |
| int topcmd = -1; /* cmdtab index of current command */ |
| int havetoken = 0; |
| extern int dblquo; /* Doublequoting enabled */ |
| |
| #ifdef DCMDBUF /* Initialization filespec */ |
| char *kermrc = NULL; |
| #else |
| char kermrcb[KERMRCL]; |
| char *kermrc = kermrcb; |
| #endif /* DCMDBUF */ |
| |
| int noherald = 0; |
| int cm_retry = 1; /* Command retry enabled */ |
| xx_strp xxstring = zzstring; |
| |
| #ifndef NOXFER |
| extern int displa, bye_active, protocol, pktlog, remfile, rempipe, unkcs, |
| keep, lf_opts, fncnv, pktpaus, autodl, xfrcan, xfrchr, xfrnum, srvtim, |
| srvdis, query, retrans, streamed, reliable, crunched, timeouts, |
| fnrpath, autopath, rpackets, spackets, epktrcvd, srvping; |
| |
| #ifdef CK_AUTODL |
| extern int inautodl, cmdadl; |
| #endif /* CK_AUTODL */ |
| |
| #ifndef NOSERVER |
| extern int en_asg, en_cwd, en_cpy, en_del, en_dir, en_fin, en_bye, en_ret, |
| en_get, en_hos, en_que, en_ren, en_sen, en_set, en_spa, en_typ, en_who, |
| en_mai, en_pri, en_mkd, en_rmd, en_xit, en_ena; |
| #endif /* NOSERVER */ |
| |
| extern int atcapr, |
| atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko, |
| attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso; |
| |
| #ifdef STRATUS |
| extern int atfrmi, atfrmo, atcrei, atcreo, atacti, atacto; |
| #endif /* STRATUS */ |
| |
| #ifdef CK_PERMS |
| extern int atlpri, atlpro, atgpri, atgpro; |
| #endif /* CK_PERMS */ |
| |
| #ifdef CK_LOGIN |
| extern char * anonfile; /* Anonymous login init file */ |
| extern char * anonroot; /* Anonymous file-system root */ |
| extern char * userfile; /* Forbidden user file */ |
| extern int isguest; /* Flag for anonymous user */ |
| #endif /* CK_LOGIN */ |
| #endif /* NOXFER */ |
| |
| #ifdef DCMDBUF |
| int *xquiet = NULL; |
| #else |
| int xquiet[CMDSTKL]; |
| #endif /* DCMDBUF */ |
| |
| char * prstring[CMDSTKL]; |
| |
| #ifndef NOSPL |
| |
| extern long ck_alarm; |
| extern char alrm_date[], alrm_time[]; |
| |
| /* Local declarations */ |
| |
| static int nulcmd = 0; /* Flag for next cmd to be ignored */ |
| |
| /* Definitions for predefined macros */ |
| |
| /* First, the single-line macros, installed with addmac()... */ |
| |
| /* IBM-LINEMODE macro */ |
| char *m_ibm = "set parity mark, set dupl half, set handsh xon, set flow none"; |
| |
| /* FATAL macro */ |
| char *m_fat = "if def \\%1 echo \\%1, if not = \\v(local) 0 hangup, stop 1"; |
| |
| #ifdef CK_SPEED |
| #ifdef IRIX65 |
| char *m_fast = "set win 30, set rec pack 4000, set prefix cautious"; |
| #else |
| #ifdef IRIX |
| /* Because of bug in telnet server */ |
| char *m_fast = "set window 30, set rec pack 4000, set send pack 4000,\ |
| set pref cautious"; |
| #else |
| #ifdef pdp11 |
| char *m_fast = "set win 3, set rec pack 1024, set prefix cautious"; |
| #else |
| #ifdef BIGBUFOK |
| char *m_fast = "set win 30, set rec pack 4000, set prefix cautious"; |
| #else |
| char *m_fast = "set win 4, set rec pack 2200, set prefix cautious"; |
| #endif /* BIGBUFOK */ |
| #endif /* IRIX */ |
| #endif /* IRIX65 */ |
| #endif /* pdp11 */ |
| #ifdef pdp11 |
| char *m_cautious = "set win 2, set rec pack 512, set prefixing cautious"; |
| #else |
| char *m_cautious = "set win 4, set rec pack 1000, set prefixing cautious"; |
| #endif /* pdp11 */ |
| char *m_robust = "set win 1, set rec pack 90, set prefixing all, \ |
| set reliable off, set clearchannel off"; |
| #else |
| #ifdef BIGBUFOK |
| #ifdef IRIX65 |
| char *m_fast = "set win 30, set rec pack 4000"; |
| #else |
| #ifdef IRIX |
| char *m_fast = "set win 30, set rec pack 4000, set send pack 4000"; |
| #else |
| char *m_fast = "set win 30, set rec pack 4000"; |
| #endif /* IRIX */ |
| #endif /* IRIX65 */ |
| #else /* Not BIGBUFOK */ |
| char *m_fast = "set win 4, set rec pack 2200"; |
| #endif /* BIGBUFOK */ |
| char *m_cautious = "set win 4, set rec pack 1000"; |
| char *m_robust = "set win 1, set rec pack 90, set reliable off"; |
| #endif /* CK_SPEED */ |
| |
| #ifdef VMS |
| char *m_purge = "run purge \\%*"; |
| #endif /* VMS */ |
| |
| #ifdef OS2 |
| char *m_manual = "browse \\v(exedir)docs/manual/kermit95.htm"; |
| #endif /* OS2 */ |
| |
| /* Now the multiline macros, defined with addmmac()... */ |
| |
| /* FOR macro for \%i-style loop variables (see dofor()...) */ |
| |
| char *for_def[] = { "_assign _for\\v(cmdlevel) { _getargs,", |
| "def \\\\\\%1 \\feval(\\%2),:_..top,if \\%5 \\\\\\%1 \\%3 goto _..bot,", |
| "\\%6,:_..inc,incr \\\\\\%1 \\%4,goto _..top,:_..bot,_putargs},", |
| "def break goto _..bot, def continue goto _..inc,", |
| "do _for\\v(cmdlevel) \\%1 \\%2 \\%3 \\%4 { \\%5 },_assign _for\\v(cmdlevel)", |
| ""}; |
| |
| /* This is the FOR macro when the loop variable is itself a macro */ |
| |
| char *foz_def[] = { "_assign _for\\v(cmdlevel) { _getargs,", |
| "def \\%1 \\feval(\\%2),:_..top,if \\%5 \\%1 \\%3 goto _..bot,", |
| "\\%6,:_..inc,incr \\%1 \\%4,goto _..top,:_..bot,_putargs},", |
| "def break goto _..bot, def continue goto _..inc,", |
| "do _for\\v(cmdlevel) \\%1 \\%2 \\%3 \\%4 { \\%5 },_assign _for\\v(cmdlevel)", |
| ""}; |
| |
| /* WHILE macro */ |
| char *whil_def[] = { "_assign _whi\\v(cmdlevel) {_getargs,", |
| ":_..inc,\\%1,\\%2,goto _..inc,:_..bot,_putargs},", |
| "_def break goto _..bot, _def continue goto _..inc,", |
| "do _whi\\v(cmdlevel),_assign _whi\\v(cmdlevel)", |
| ""}; |
| |
| /* SWITCH macro */ |
| char *sw_def[] = { "_assign _sw_\\v(cmdlevel) {_getargs,", |
| "_forward {\\%1},\\%2,:default,:_..bot,_putargs},_def break goto _..bot,", |
| "do _sw_\\v(cmdlevel),_assign _sw_\\v(cmdlevel)", |
| ""}; |
| |
| /* XIF macro */ |
| char *xif_def[] = { |
| "_assign _if\\v(cmdlevel) {_getargs,\\%1,_putargs},", |
| "do _if\\v(cmdlevel),_assign _if\\v(cmdlevel)", |
| ""}; |
| |
| /* |
| Variables declared here for use by other ckuus*.c modules. |
| Space is allocated here to save room in ckuusr.c. |
| */ |
| #ifdef DCMDBUF |
| struct cmdptr *cmdstk; |
| int |
| *ifcmd = NULL, |
| *count = NULL, |
| *iftest = NULL, |
| *intime = NULL, |
| *inpcas = NULL, |
| *takerr = NULL, |
| *merror = NULL; |
| #else |
| struct cmdptr cmdstk[CMDSTKL]; |
| int ifcmd[CMDSTKL], count[CMDSTKL], iftest[CMDSTKL], intime[CMDSTKL], |
| inpcas[CMDSTKL], takerr[CMDSTKL], merror[CMDSTKL]; |
| #endif /* DCMDBUF */ |
| |
| /* Macro stack */ |
| |
| #ifdef COMMENT |
| char *topline = NULL; /* Program invocation arg line */ |
| char *m_line[MACLEVEL] = { NULL, NULL }; /* Stack of macro invocation lines */ |
| #endif /* COMMENT */ |
| |
| char **m_xarg[MACLEVEL]; /* Pointers to arg vector arrays */ |
| int n_xarg[MACLEVEL]; /* Sizes of arg vector arrays */ |
| char *m_arg[MACLEVEL][NARGS]; /* Args of each level */ |
| int macargc[MACLEVEL]; /* Argc of each level */ |
| char *macp[MACLEVEL]; /* Current position in each macro */ |
| char *macx[MACLEVEL]; /* Beginning of each macro def */ |
| char *mrval[MACLEVEL]; /* RETURN value at each level */ |
| int lastcmd[MACLEVEL]; /* Last command at each level */ |
| int topargc = 0; /* Argc at top level */ |
| char **topxarg = NULL; /* Argv at top level */ |
| char *toparg[MAXARGLIST+2]; |
| |
| /* Global Variables */ |
| |
| char *g_var[GVARS+1]; /* Global \%a..z pointers */ |
| extern char varnam[]; /* \%x variable name buffer */ |
| |
| /* Arrays -- Dimension must be 'z' - ARRAYBASE + 1 */ |
| /* Note: a_link[x] < 0 means no link; >= 0 is a link */ |
| |
| char **a_ptr[32]; /* Array pointers, for arrays a-z */ |
| int a_dim[32]; /* Dimensions for each array */ |
| int a_link[32]; /* Link (index of linked-to-array) */ |
| |
| char **aa_ptr[CMDSTKL][32]; /* Array stack for automatic arrays */ |
| int aa_dim[CMDSTKL][32]; /* Dimensions for each array */ |
| |
| /* INPUT command buffers and variables */ |
| |
| char * inpbuf = NULL; /* Buffer for INPUT and REINPUT */ |
| extern char * inpbp; /* Global/static pointer to it */ |
| char inchar[2] = { NUL, NUL }; /* Last character that was INPUT */ |
| int incount = 0; /* INPUT character count */ |
| extern int instatus; /* INPUT status */ |
| static char * i_text[] = { /* INPUT status text */ |
| "success", "timeout", "interrupted", "internal error", "i/o error" |
| }; |
| |
| char lblbuf[LBLSIZ]; /* Buffer for labels */ |
| |
| #else /* NOSPL */ |
| |
| int takerr[MAXTAKE]; |
| #endif /* NOSPL */ |
| |
| static char *prevdir = NULL; |
| |
| int pacing = 0; /* OUTPUT pacing */ |
| |
| char *tp; /* Temporary buffer pointer */ |
| |
| int timelimit = 0, asktimer = 0; /* Timers for time-limited commands */ |
| |
| #ifdef CK_APC /* Application Program Command (APC) */ |
| int apcactive = APC_INACTIVE; |
| int apcstatus = APC_OFF; /* OFF by default everywhere */ |
| #ifdef DCMDBUF |
| char *apcbuf; |
| #else |
| char apcbuf[APCBUFLEN]; |
| #endif /* DCMDBUF */ |
| #endif /* CK_APC */ |
| |
| extern char pktfil[], |
| #ifdef DEBUG |
| debfil[], |
| #endif /* DEBUG */ |
| #ifdef TLOG |
| trafil[], |
| #endif /* TLOG */ |
| sesfil[]; |
| |
| #ifndef NOFRILLS |
| extern int rmailf, rprintf; /* REMOTE MAIL & PRINT items */ |
| extern char optbuf[]; |
| #endif /* NOFRILLS */ |
| |
| extern int noinit; /* Flat to skip init file */ |
| |
| #ifndef NOSPL |
| static struct keytab kcdtab[] = { /* Symbolic directory names */ |
| #ifdef NT |
| { "appdata", VN_APPDATA, 0 }, |
| { "common", VN_COMMON, 0 }, |
| { "desktop", VN_DESKTOP, 0 }, |
| #endif /* NT */ |
| { "download", VN_DLDIR, 0 }, |
| #ifdef OS2ORUNIX |
| { "exedir", VN_EXEDIR, 0 }, |
| #endif /* OS2ORUNIX */ |
| { "home", VN_HOME, 0 }, |
| { "inidir", VN_INI, 0 }, |
| #ifdef UNIX |
| { "lockdir", VN_LCKDIR, 0 }, |
| #endif /* UNIX */ |
| #ifdef NT |
| { "personal", VN_PERSONAL, 0 }, |
| #endif /* NT */ |
| { "startup", VN_STAR, 0 }, |
| { "textdir", VN_TXTDIR, 0 }, |
| { "tmpdir", VN_TEMP, 0 } |
| }; |
| static int nkcdtab = (sizeof(kcdtab) / sizeof(struct keytab)); |
| #endif /* NOSPL */ |
| |
| #ifndef NOSPL |
| _PROTOTYP( VOID freelocal, (int) ); |
| _PROTOTYP( static long expon, (long, long) ); |
| _PROTOTYP( static long gcd, (long, long) ); |
| _PROTOTYP( static long fact, (long) ); |
| |
| int /* Initialize macro data structures. */ |
| macini() { /* Allocate mactab and preset the first element. */ |
| int i; |
| if (!(mactab = (struct mtab *) malloc(sizeof(struct mtab) * MAC_MAX))) |
| return(-1); |
| mactab[0].kwd = NULL; |
| mactab[0].mval = NULL; |
| mactab[0].flgs = 0; |
| for (i = 0; i < MACLEVEL; i++) |
| localhead[i] = NULL; |
| return(0); |
| } |
| #endif /* NOSPL */ |
| |
| /* C M D S R C -- Returns current command source */ |
| |
| /* 0 = top level, 1 = file, 2 = macro, -1 = error (shouldn't happen) */ |
| |
| /* |
| As of 19 Aug 2000 this routine is obsolete. The scalar global variable |
| xcmdsrc can be checked instead to save the overhead of a function call. |
| */ |
| int |
| cmdsrc() { |
| #ifdef COMMENT |
| return(xcmdsrc); |
| #else |
| #ifndef NOSPL |
| if (cmdlvl == 0) |
| return(0); |
| else if (cmdstk[cmdlvl].src == CMD_MD) |
| return(2); |
| else if (cmdstk[cmdlvl].src == CMD_TF) |
| return(1); |
| else |
| return(-1); |
| #else |
| if (tlevel < 0) |
| return(0); |
| else |
| return(1); |
| #endif /* NOSPL */ |
| #endif /* COMMENT */ |
| } |
| |
| /* C M D I N I -- Initialize the interactive command parser */ |
| |
| static int cmdinited = 0; /* Command parser initialized */ |
| extern int cmdint; /* Interrupts are allowed */ |
| #ifdef CK_AUTODL |
| int cmdadl = 1; /* Autodownload */ |
| #else |
| int cmdadl = 0; |
| #endif /* CK_AUTODL */ |
| |
| char * k_info_dir = NULL; /* Where to find text files */ |
| #ifdef UNIX |
| static char * txtdir[] = { |
| "/usr/local/doc/", /* Linux, SunOS, ... */ |
| "/usr/share/lib/", /* HP-UX 10.xx... */ |
| "/usr/share/doc/", /* Other possibilities... */ |
| "/usr/local/lib/", /* NOTE: Each of these is tried */ |
| "/usr/local/share/", /* as is, and also with a kermit */ |
| "/usr/local/share/doc/", /* subdirectory. */ |
| "/usr/local/share/lib/", |
| "/opt/kermit/", /* Solaris */ |
| "/opt/kermit/doc/", |
| "/opt/", |
| "/usr/doc/", |
| "/doc/", |
| "" |
| }; |
| #endif /* UNIX */ |
| |
| /* |
| lookup() cache to speed up script execution. |
| |
| This is a static cache. Items are stored in decreasing frequency of |
| reference based on statistics from a range of scripts. This gives |
| better performance than a dynamic cache, which would require a lot more |
| code and also would require system-dependent elements including system |
| calls (e.g. to get subsecond times for entry aging). |
| */ |
| #ifdef USE_LUCACHE /* Set in ckuusr.h */ |
| #define LUCACHE 32 /* Change this to reduce cache size */ |
| int lusize = 0; |
| char * lucmd[LUCACHE]; |
| int luval[LUCACHE]; |
| int luidx[LUCACHE]; |
| struct keytab * lutab[LUCACHE]; |
| #endif /* USE_LUCACHE */ |
| |
| static VOID |
| luinit() { /* Initialize lookup() cache */ |
| int x, y; |
| |
| #ifdef USE_LUCACHE |
| x = lookup(cmdtab,"if",ncmd,&y); |
| lucmd[lusize] = "if"; |
| luval[lusize] = x; |
| luidx[lusize] = y; |
| lutab[lusize] = cmdtab; |
| if (++lusize > LUCACHE) return; |
| |
| x = lookup(iftab,"not",nif,&y); |
| lucmd[lusize] = "not"; |
| luval[lusize] = x; |
| luidx[lusize] = y; |
| lutab[lusize] = iftab; |
| if (++lusize > LUCACHE) return; |
| |
| x = lookup(vartab,"cmdlevel",nvars,&y); |
| lucmd[lusize] = "cmdlevel"; |
| luval[lusize] = x; |
| luidx[lusize] = y; |
| lutab[lusize] = vartab; |
| if (++lusize > LUCACHE) return; |
| |
| x = lookup(cmdtab,"goto",ncmd,&y); |
| lucmd[lusize] = "goto"; |
| luval[lusize] = x; |
| luidx[lusize] = y; |
| lutab[lusize] = cmdtab; |
| if (++lusize > LUCACHE) return; |
| |
| x = lookup(iftab,">",nif,&y); |
| lucmd[lusize] = ">"; |
| luval[lusize] = x; |
| luidx[lusize] = y; |
| lutab[lusize] = iftab; |
| if (++lusize > LUCACHE) return; |
| |
| x = lookup(cmdtab,"incr",ncmd,&y); |
| lucmd[lusize] = "incr"; |
| luval[lusize] = x; |
| luidx[lusize] = y; |
| lutab[lusize] = cmdtab; |
| if (++lusize > LUCACHE) return; |
| |
| x = lookup(cmdtab,"def",ncmd,&y); |
| lucmd[lusize] = "def"; |
| luval[lusize] = x; |
| luidx[lusize] = y; |
| lutab[lusize] = cmdtab; |
| if (++lusize > LUCACHE) return; |
| |
| x = lookup(cmdtab,"_assign",ncmd,&y); |
| lucmd[lusize] = "_assign"; |
| luval[lusize] = x; |
| luidx[lusize] = y; |
| lutab[lusize] = cmdtab; |
| if (++lusize > LUCACHE) return; |
| |
| x = lookup(cmdtab,"echo",ncmd,&y); |
| lucmd[lusize] = "echo"; |
| luval[lusize] = x; |
| luidx[lusize] = y; |
| lutab[lusize] = cmdtab; |
| if (++lusize > LUCACHE) return; |
| |
| x = lookup(fnctab,"eval",nfuncs,&y); |
| lucmd[lusize] = "eval"; |
| luval[lusize] = x; |
| luidx[lusize] = y; |
| lutab[lusize] = fnctab; |
| if (++lusize > LUCACHE) return; |
| |
| x = lookup(fnctab,"lit",nfuncs,&y); |
| lucmd[lusize] = "lit"; |
| luval[lusize] = x; |
| luidx[lusize] = y; |
| lutab[lusize] = fnctab; |
| if (++lusize > LUCACHE) return; |
| |
| x = lookup(cmdtab,"do",ncmd,&y); |
| lucmd[lusize] = "do"; |
| luval[lusize] = x; |
| luidx[lusize] = y; |
| lutab[lusize] = cmdtab; |
| if (++lusize > LUCACHE) return; |
| |
| x = lookup(cmdtab,"_getargs",ncmd,&y); |
| lucmd[lusize] = "_getargs"; |
| luval[lusize] = x; |
| luidx[lusize] = y; |
| lutab[lusize] = cmdtab; |
| if (++lusize > LUCACHE) return; |
| |
| x = lookup(iftab,"<",nif,&y); |
| lucmd[lusize] = "<"; |
| luval[lusize] = x; |
| luidx[lusize] = y; |
| lutab[lusize] = iftab; |
| if (++lusize > LUCACHE) return; |
| |
| x = lookup(cmdtab,"_putargs",ncmd,&y); |
| lucmd[lusize] = "_putargs"; |
| luval[lusize] = x; |
| luidx[lusize] = y; |
| lutab[lusize] = cmdtab; |
| if (++lusize > LUCACHE) return; |
| |
| x = lookup(cmdtab,"asg",ncmd,&y); |
| lucmd[lusize] = "asg"; |
| luval[lusize] = x; |
| luidx[lusize] = y; |
| lutab[lusize] = cmdtab; |
| if (++lusize > LUCACHE) return; |
| |
| x = lookup(cmdtab,"else",ncmd,&y); |
| lucmd[lusize] = "else"; |
| luval[lusize] = x; |
| luidx[lusize] = y; |
| lutab[lusize] = cmdtab; |
| #endif /* USE_LUCACHE */ |
| } |
| |
| VOID |
| cmdini() { |
| int i = 0, x = 0, y = 0, z = 0, skip = 0; |
| char * p; |
| #ifdef TTSPDLIST |
| long * ss = NULL; |
| extern int nspd; |
| extern struct keytab * spdtab; |
| #endif /* TTSPDLIST */ |
| |
| #ifndef NOSPL |
| /* |
| On stack to allow recursion! |
| */ |
| char vnambuf[VNAML]; /* Buffer for variable names */ |
| #endif /* NOSPL */ |
| |
| if (cmdinited) /* Already initialized */ |
| return; /* Don't do it again */ |
| |
| for (i = 0; i < CMDSTKL; i++) /* Prompt strings for each */ |
| prstring[i] = NULL; /* command level */ |
| |
| #ifndef NOCSETS |
| p = getenv("K_CHARSET"); /* Set default file character set */ |
| if (p) { /* from environment */ |
| x = lookup(fcstab,p,nfilc,&y); |
| if (x > -1) |
| fcharset = x; |
| } |
| #endif /* NOCSETS */ |
| |
| p = getenv("K_INFO_DIRECTORY"); /* Find Kermit info directory */ |
| if (p && *p && strlen(p) <= CKMAXPATH) |
| makestr(&k_info_dir,p); |
| if (!k_info_dir) { |
| p = getenv("K_INFO_DIR"); |
| if (p && *p && strlen(p) <= CKMAXPATH) |
| makestr(&k_info_dir,p); |
| } |
| #ifdef UNIX |
| if (k_info_dir) { /* Look for Kermit docs directory */ |
| if (zchki(k_info_dir) == -2) { |
| char xbuf[CKMAXPATH+32], *s = ""; |
| if (ckrchar(k_info_dir) != '/') |
| s = "/"; |
| ckmakmsg(xbuf,CKMAXPATH+32,k_info_dir,s,"ckubwr.txt",NULL); |
| if (zchki(xbuf) < 0) |
| makestr(&k_info_dir,NULL); |
| } |
| } |
| if (!k_info_dir) { |
| char xbuf[CKMAXPATH+32]; |
| int i; |
| for (i = 0; *(txtdir[i]); i++) { |
| ckmakmsg(xbuf,CKMAXPATH+32,txtdir[i],"ckubwr.txt",NULL,NULL); |
| if (zchki(xbuf) > 0) { |
| makestr(&k_info_dir,txtdir[i]); |
| debug(F110,"k_info_dir 1",k_info_dir,0); |
| break; |
| } |
| ckmakmsg(xbuf,CKMAXPATH+32, |
| txtdir[i],"kermit/","ckubwr.txt",NULL); |
| if (zchki(xbuf) > 0) { |
| ckmakmsg(xbuf,CKMAXPATH+32,txtdir[i],"kermit/",NULL,NULL); |
| makestr(&k_info_dir,xbuf); |
| debug(F110,"k_info_dir 2",k_info_dir,0); |
| break; |
| } |
| ckmakmsg(xbuf,CKMAXPATH+32, |
| txtdir[i],"ckermit/","ckubwr.txt",NULL); |
| if (zchki(xbuf) > 0) { |
| ckmakmsg(xbuf,CKMAXPATH+32,txtdir[i],"ckermit/",NULL,NULL); |
| makestr(&k_info_dir,xbuf); |
| debug(F110,"k_info_dir 3",k_info_dir,0); |
| break; |
| } |
| } |
| if (k_info_dir) { /* Make sure it ends with "/" */ |
| if (ckrchar(k_info_dir) != '/') { |
| char xbuf[CKMAXPATH+32]; |
| ckmakmsg(xbuf,CKMAXPATH+32,k_info_dir,"/",NULL,NULL); |
| makestr(&k_info_dir,xbuf); |
| } |
| } |
| } |
| #else |
| #ifdef OS2 |
| { |
| char xdir[CKMAXPATH+8], *s = ""; |
| extern char startupdir[]; |
| xdir[0] = NUL; |
| if (ckrchar(startupdir) != '/') |
| s = "/"; |
| if (strlen(s) + strlen(startupdir) + 5 < CKMAXPATH + 8 ) |
| ckmakmsg(xdir,CKMAXPATH+8,s,startupdir,"DOC/",NULL); |
| makestr(&k_info_dir,xdir); |
| } |
| #endif /* OS2 */ |
| #endif /* UNIX */ |
| |
| #ifdef TTSPDLIST |
| if (!spdtab && (ss = ttspdlist())) { /* Get speed list if necessary */ |
| int j, k, m = 0, n; /* Create sorted keyword table */ |
| char buf[16]; |
| char * p; |
| if ((spdtab = |
| (struct keytab *) malloc(sizeof(struct keytab) * ss[0]))) { |
| for (i = 1; i <= ss[0]; i++) { /* ss[0] = number of elements */ |
| if (ss[i] < 1L) break; /* Shouldn't happen */ |
| buf[0] = NUL; /* Make string */ |
| sprintf(buf,"%ld",ss[i]); /* SAFE */ |
| if (ss[i] == 8880L) |
| ckstrncpy(buf,"75/1200",sizeof(buf)); |
| if (ss[i] == 134L) |
| ckstrncat(buf,".5",16); |
| n = strlen(buf); |
| if ((n > 0) && (p = (char *)malloc(n+1))) { |
| if (m > 0) { /* Have at least one in list */ |
| for (j = 0; /* Find slot */ |
| j < m && strcmp(buf,spdtab[j].kwd) > 0; |
| j++ |
| ) |
| ; |
| if (j < m) { /* Must insert */ |
| for (k = m-1; k >= j; k--) { /* Move others down */ |
| spdtab[k+1].kwd = spdtab[k].kwd; |
| spdtab[k+1].flgs = spdtab[k].flgs; |
| spdtab[k+1].kwval = spdtab[k].kwval; |
| } |
| } |
| } else /* First one */ |
| j = 0; |
| ckstrncpy(p,buf,n+1); /* Add new speed */ |
| spdtab[j].kwd = p; |
| spdtab[j].flgs = 0; |
| spdtab[j].kwval = (int) ss[i] / 10; |
| m++; /* Count this one */ |
| } |
| } |
| } |
| nspd = m; |
| } |
| #endif /* TTSPDLIST */ |
| |
| #ifndef NOSPL |
| /* Allocate INPUT command buffer */ |
| if (!inpbuf) { |
| if (!(inpbuf = (char *) malloc(INPBUFSIZ+1))) |
| fatal("cmdini: no memory for INPUT buffer"); |
| } |
| for (x = 0; x < INPBUFSIZ; x++) /* Initialize it */ |
| inpbuf[x] = NUL; |
| inpbp = inpbuf; /* Initialize pointer */ |
| inbufsize = INPBUFSIZ; /* and size. */ |
| #endif /* NOSPL */ |
| |
| #ifdef DCMDBUF |
| if (cmsetup() < 0) fatal("Can't allocate command buffers!"); |
| |
| #ifndef NOSPL |
| /* Allocate command stack allowing command parser to call itself */ |
| |
| if (!(cmdstk = (struct cmdptr *) malloc(sizeof(struct cmdptr)*CMDSTKL))) |
| fatal("cmdini: no memory for cmdstk"); |
| if (!(ifcmd = (int *) malloc(sizeof(int)*CMDSTKL))) |
| fatal("cmdini: no memory for ifcmd"); |
| if (!(count = (int *) malloc(sizeof(int)*CMDSTKL))) |
| fatal("cmdini: no memory for count"); |
| if (!(iftest = (int *) malloc(sizeof(int)*CMDSTKL))) |
| fatal("cmdini: no memory for iftest"); |
| if (!(intime = (int *) malloc(sizeof(int)*CMDSTKL))) |
| fatal("cmdini: no memory for intime"); |
| if (!(inpcas = (int *) malloc(sizeof(int)*CMDSTKL))) |
| fatal("cmdini: no memory for inpcas"); |
| if (!(takerr = (int *) malloc(sizeof(int)*CMDSTKL))) |
| fatal("cmdini: no memory for takerr"); |
| if (!(merror = (int *) malloc(sizeof(int)*CMDSTKL))) |
| fatal("cmdini: no memory for merror"); |
| if (!(xquiet = (int *) malloc(sizeof(int)*CMDSTKL))) |
| fatal("cmdini: no memory for xquiet"); |
| if (!kermrc) |
| if (!(kermrc = (char *) malloc(KERMRCL+1))) |
| fatal("cmdini: no memory for kermrc"); |
| #ifdef CK_APC |
| /* Application Program Command buffer */ |
| if (!(apcbuf = malloc(APCBUFLEN + 1))) |
| fatal("cmdini: no memory for apcbuf"); |
| #endif /* CK_APC */ |
| #endif /* NOSPL */ |
| |
| /* line[] and tmpbuf[] are the two string buffers used by the command parser */ |
| |
| if (!(line = malloc(LINBUFSIZ + 1))) |
| fatal("cmdini: no memory for line"); |
| if (!(tmpbuf = malloc(LINBUFSIZ + 1))) |
| fatal("cmdini: no memory for tmpbuf"); |
| #endif /* DCMDBUF */ |
| |
| #ifndef NOSPL |
| #ifdef CK_MINPUT |
| { /* Initialize MINPUT pointers */ |
| int i; |
| extern char *ms[]; |
| for (i = 0; i < MINPMAX; i++) |
| ms[i] = NULL; |
| } |
| #endif /* CK_MINPUT */ |
| |
| if (macini() < 0) /* Allocate macro buffers */ |
| fatal("Can't allocate macro buffers!"); |
| |
| ifcmd[0] = 0; /* Command-level related variables. */ |
| iftest[0] = 0; /* Initialize variables at top level */ |
| count[0] = 0; /* of stack... */ |
| intime[0] = 0; |
| inpcas[0] = 0; |
| takerr[0] = 0; |
| merror[0] = 0; |
| xquiet[0] = quiet; |
| #endif /* NOSPL */ |
| |
| #ifndef NOSPL |
| cmdlvl = 0; /* Initialize the command stack */ |
| xcmdsrc = CMD_KB; |
| cmdstk[cmdlvl].src = CMD_KB; /* Source is console */ |
| cmdstk[cmdlvl].lvl = 0; /* Level is 0 */ |
| cmdstk[cmdlvl].ccflgs = 0; /* No flags */ |
| #endif /* NOSPL */ |
| |
| tlevel = -1; /* Take file level = keyboard */ |
| for (i = 0; i < MAXTAKE; i++) /* Initialize command file names */ |
| tfnam[i] = NULL; |
| |
| cmsetp(ckprompt); /* Set up C-Kermit's prompt */ |
| /* Can't set IKSD prompt here since */ |
| /* we do not yet know if we are IKSD */ |
| #ifndef NOSPL |
| |
| initmac(); /* Initialize macro table */ |
| |
| /* Predefine built-in one-line macros */ |
| |
| addmac("ibm-linemode",m_ibm); /* IBM-LINEMODE */ |
| addmac("fatal",m_fat); /* FATAL macro */ |
| y = addmac("fast",m_fast); /* FAST macro */ |
| addmac("cautious",m_cautious); /* CAUTIOUS macro */ |
| addmac("robust",m_robust); /* ROBUST macro */ |
| #ifdef OS2 |
| addmac("manual",m_manual); /* MANUAL macro */ |
| #endif /* OS2 */ |
| #ifdef VMS |
| addmac("purge",m_purge); /* PURGE macro */ |
| #endif /* VMS */ |
| |
| /* |
| Predefine built-in multiline macros; these are top-level commands |
| that are implemented internally as macros. NOTE: When adding a new |
| one of these, remember to update the END and RETURN commands to |
| account for it, or else END and RETURN from within it won't work right. |
| */ |
| x = addmmac("_forx",for_def); /* FOR macro */ |
| if (x > -1) mactab[x].flgs = CM_INV; |
| x = addmmac("_forz",foz_def); /* Other FOR macro */ |
| if (x > -1) mactab[x].flgs = CM_INV; |
| x = addmmac("_xif",xif_def); /* XIF macro */ |
| if (x > -1) mactab[x].flgs = CM_INV; |
| x = addmmac("_while",whil_def); /* WHILE macro */ |
| if (x > -1) mactab[x].flgs = CM_INV; |
| x = addmmac("_switx",sw_def); /* SWITCH macro */ |
| if (x > -1) mactab[x].flgs = CM_INV; |
| |
| /* Fill in command-line argument vector */ |
| |
| sprintf(vnambuf,"\\&@[%d]",xargs); /* SAFE */ |
| if (inserver) { /* But hidden in IKSD */ |
| y = -1; |
| xargs = 0; |
| } else |
| y = arraynam(vnambuf,&x,&z); /* goes in array \&@[] */ |
| |
| tmpbuf[0] = NUL; |
| if (y > -1) { |
| int j = -1; |
| int yy = 0; |
| dclarray((char)x,z); /* Declare the array */ |
| #ifndef NOTAKEARGS |
| /* Macro argument vector */ |
| sprintf(vnambuf,"\\&_[%d]",z); /* SAFE */ |
| yy = arraynam(vnambuf,&x,&z); /* goes in array \&_[] */ |
| if (yy > -1) /* Name is OK */ |
| dclarray((char)x,z); /* Declare the array */ |
| #endif /* NOTAKEARGS */ |
| skip = 0; |
| for (i = 0; i < xargs; i++) { /* Fill the arrays */ |
| sprintf(vnambuf,"\\&@[%d]",i); /* SAFE */ |
| addmac(vnambuf,xargv[i]); |
| if (cfilef && i == 0) |
| continue; |
| #ifdef KERBANG |
| if (skip) { |
| j = 0; |
| skip = 0; |
| continue; |
| } |
| #endif /* KERBANG */ |
| if (j < 0 && /* Assign items after "=" or "--"*/ |
| (!strcmp(xargv[i],"=") || !strcmp(xargv[i],"--")) |
| ) { |
| j = 0; /* to \%1..\%9 */ |
| #ifdef KERBANG |
| } else if (j < 0 && |
| (!strcmp(xargv[i],"+") || |
| !strncmp(xargv[i],"+ ",2) || |
| !strncmp(xargv[i],"+\t",2)) |
| ) { |
| skip = 1; |
| continue; |
| #endif /* KERBANG */ |
| } else if (j > -1) { |
| j++; |
| if (j <= 9) { |
| vnambuf[0] = '\\'; |
| vnambuf[1] = '%'; |
| vnambuf[2] = (char)(j+'0'); |
| vnambuf[3] = NUL; |
| addmac(vnambuf,xargv[i]); |
| } |
| if (yy > -1) { |
| char c, * p; |
| int flag = 0; |
| p = xargv[i]; |
| makestr(&(toparg[j]),p); |
| while ((c = *p++)) { if (c == SP) { flag++; break; } } |
| if (flag) |
| ckstrncat(tmpbuf,"\"",TMPBUFSIZ); |
| ckstrncat(tmpbuf,xargv[i],TMPBUFSIZ); |
| if (flag) |
| ckstrncat(tmpbuf,"\"",TMPBUFSIZ); |
| ckstrncat(tmpbuf," ",TMPBUFSIZ); |
| } |
| } |
| } |
| if (cfilef) { |
| addmac("\\%0",cmdfil); |
| if (yy > -1) |
| makestr(&(toparg[0]),cmdfil); |
| } else { |
| addmac("\\%0",xargv[0]); |
| if (yy > -1) |
| makestr(&(toparg[0]),xargv[0]); |
| } |
| if (yy > -1) { |
| topargc = (j < 0) ? 1 : j + 1; |
| topxarg = toparg; |
| #ifdef COMMENT |
| /* This needs work */ |
| if (!cfilef) |
| makestr(&topline,tmpbuf); |
| #endif /* COMMENT */ |
| } else { |
| topargc = 0; |
| topxarg = NULL; |
| } |
| a_dim[0] = topargc - 1; |
| a_ptr[0] = topxarg; |
| debug(F111,"a_dim[0]","A",a_dim[0]); |
| } |
| *vnambuf = NUL; |
| #endif /* NOSPL */ |
| |
| luinit(); /* Initialize lookup() cache */ |
| |
| /* Get our home directory now. This needed in lots of places. */ |
| |
| cmdinited = 1; |
| } |
| |
| #ifdef NT |
| _PROTOTYP(char * GetAppData,(int)); |
| #endif /* NT */ |
| |
| VOID |
| doinit() { |
| #ifdef CKROOT |
| extern int ckrooterr; |
| #endif /* CKROOT */ |
| int x = 0, ok = 0; |
| #ifdef OS2 |
| char * ptr = 0; |
| #endif /* OS2 */ |
| |
| if (!cmdinited) |
| cmdini(); |
| |
| #ifdef MAC |
| return; /* Mac Kermit has no init file */ |
| |
| #else /* !MAC */ |
| |
| /* If skipping init file ('-Y' on Kermit command line), return now. */ |
| |
| if (noinit) { |
| kermrc[0] = '\0'; |
| inidir[0] = '\0'; |
| /* |
| But returning from here results in inidir[] never being set to anything. |
| Instead it should be set to wherever the init file *would* have been |
| executed from. So this bit of code should be removed, and then we should |
| sprinkle "if (noinit)" tests throughout the following code until we have |
| set inidir[], and then return without actually taking the init file. |
| */ |
| return; |
| } |
| |
| #ifdef OS2 |
| /* |
| The -y init file must be fully specified or in the current directory. |
| KERMRC is looked for via INIT, DPATH and PATH in that order. Finally, our |
| own executable file path is taken and the .EXE suffix is replaced by .INI |
| and this is tried as the initialization file. |
| */ |
| #ifdef CK_LOGIN |
| debug(F101,"doinit inserver","",inserver); |
| debug(F101,"doinit isguest","",isguest); |
| debug(F110,"doinit anonfile",anonfile,0); |
| |
| if (isguest && anonfile) { |
| ckstrncpy(line, anonfile, LINBUFSIZ+1); |
| } else |
| #endif /* CK_LOGIN */ |
| if (rcflag) { |
| ckstrncpy(line,kermrc,LINBUFSIZ+1); |
| #ifdef CK_LOGIN |
| } else if (inserver) { |
| char * appdata = NULL; |
| #ifdef NT |
| appdata = GetAppData(1); |
| if ( appdata ) { |
| ckmakmsg(line,LINBUFSIZ+1,appdata, |
| "Kermit 95/k95.ini",NULL,NULL); |
| if ( zchki(line) < 0 ) |
| line[0] = '\0'; |
| } |
| if (line[0] == 0) { |
| appdata = GetAppData(0); |
| if ( appdata ) { |
| ckmakmsg(line,LINBUFSIZ+1,appdata, |
| "Kermit 95/k95.ini",NULL,NULL); |
| if ( zchki(line) < 0 ) |
| line[0] = '\0'; |
| } |
| } |
| #endif /* NT */ |
| if (line[0] == 0) { |
| appdata = zhome(); |
| if ( appdata ) { |
| ckmakmsg(line,LINBUFSIZ+1,appdata, |
| #ifdef NT |
| "k95.ini", |
| #else /* NT */ |
| "k2.ini", |
| #endif /* NT */ |
| NULL,NULL); |
| if ( zchki(line) < 0 ) |
| line[0] = '\0'; |
| } |
| } |
| debug(F110,"doinit inserver inifile",line,0); |
| #endif /* CK_LOGIN */ |
| } else { |
| char * env = 0; |
| #ifdef NT |
| env = getenv("K95.KSC"); |
| #else |
| env = getenv("K2.KSC"); |
| #endif /* NT */ |
| if (!env) { |
| #ifdef NT |
| env = getenv("K95.INI"); |
| #else |
| env = getenv("K2.INI"); |
| #endif /* NT */ |
| } |
| if (!env) |
| env = getenv("CKERMIT.INI"); |
| if (!env) |
| env = getenv("CKERMIT_INI"); |
| line[0] = '\0'; |
| |
| debug(F110,"doinit env",env,0); |
| if (env) |
| ckstrncpy(line,env,LINBUFSIZ+1); |
| |
| #ifdef NT |
| if (line[0] == 0) { |
| env = GetAppData(1); |
| if ( env ) { |
| ckmakmsg(line,LINBUFSIZ+1,env,"Kermit 95/k95.ini",NULL,NULL); |
| if ( zchki(line) < 0 ) |
| line[0] = '\0'; |
| } |
| } |
| if (line[0] == 0) { |
| env = GetAppData(0); |
| if ( env ) { |
| ckmakmsg(line,LINBUFSIZ+1,env,"Kermit 95/k95.ini",NULL,NULL); |
| if ( zchki(line) < 0 ) |
| line[0] = '\0'; |
| } |
| } |
| #endif /* NT */ |
| |
| if (line[0] == 0) { |
| env = zhome(); |
| if ( env ) { |
| ckmakmsg(line,LINBUFSIZ+1,env, |
| #ifdef NT |
| "k95.ini", |
| #else /* NT */ |
| "k2.ini", |
| #endif /* NT */ |
| NULL,NULL); |
| if ( zchki(line) < 0 ) |
| line[0] = '\0'; |
| } |
| } |
| |
| if (line[0] == 0) |
| _searchenv(kermrc,"INIT",line); |
| if (line[0] == 0) |
| _searchenv(kermrc,"DPATH",line); |
| if (line[0] == 0) |
| _searchenv(kermrc,"PATH",line); |
| if (line[0] == 0) { |
| char *pgmptr = GetLoadPath(); |
| if (pgmptr && strlen(pgmptr) < LINBUFSIZ-8) { |
| lp = strrchr(pgmptr, '\\'); |
| if (lp) { |
| strncpy(line, pgmptr, lp - pgmptr); |
| #ifdef NT |
| strcpy(line + (lp - pgmptr), "/k95.ini"); |
| #else /* NT */ |
| strcpy(line + (lp - pgmptr), "/k2.ini"); |
| #endif /* NT */ |
| } else { |
| lp = strrchr(pgmptr, '.'); |
| if (lp) { |
| strncpy(line, pgmptr, lp - pgmptr); |
| strcpy(line + (lp - pgmptr), ".ini"); |
| } |
| } |
| } |
| } |
| } |
| |
| #ifdef CKROOT |
| if (!zinroot(line)) { |
| debug(F110,"doinit setroot violation",line,0); |
| return; |
| } |
| #endif /* CKROOT */ |
| |
| debug(F110,"doinit fopen()",line,0); |
| if ((tfile[0] = fopen(line,"r")) != NULL) { |
| ok = 1; |
| tlevel = 0; |
| tfline[tlevel] = 0; |
| if (tfnam[tlevel] = malloc(strlen(line)+1)) |
| strcpy(tfnam[tlevel],line); /* safe */ |
| #ifndef NOSPL |
| cmdlvl++; |
| xcmdsrc = CMD_TF; |
| cmdstk[cmdlvl].src = CMD_TF; |
| cmdstk[cmdlvl].lvl = tlevel; |
| cmdstk[cmdlvl].ccflgs = 0; |
| ifcmd[cmdlvl] = 0; |
| iftest[cmdlvl] = 0; |
| count[cmdlvl] = count[cmdlvl-1]; /* Inherit from previous level */ |
| intime[cmdlvl] = intime[cmdlvl-1]; |
| inpcas[cmdlvl] = inpcas[cmdlvl-1]; |
| takerr[cmdlvl] = takerr[cmdlvl-1]; |
| merror[cmdlvl] = merror[cmdlvl-1]; |
| xquiet[cmdlvl] = quiet; |
| #endif /* NOSPL */ |
| debug(F110,"doinit init file",line,0); |
| } else { |
| debug(F100,"doinit no init file","",0); |
| } |
| ckstrncpy(kermrc,line,KERMRCL); |
| for (ptr = kermrc; *ptr; ptr++) /* Convert backslashes to slashes */ |
| if (*ptr == '\\') |
| *ptr = '/'; |
| #else /* not OS2 */ |
| lp = line; |
| lp[0] = '\0'; |
| debug(F101,"doinit rcflag","",rcflag); |
| #ifdef GEMDOS |
| zkermini(line, rcflag, kermrc); |
| #else |
| #ifdef VMS |
| { |
| int x; |
| x = zkermini(line,LINBUFSIZ,kermrc); |
| debug(F111,"CUSTOM zkermini",line,x); |
| if (x == 0) |
| line[0] = NUL; |
| } |
| #else /* not VMS */ |
| #ifdef CK_LOGIN |
| debug(F101,"doinit isguest","",isguest); |
| if (isguest) |
| ckstrncpy(lp, anonfile ? anonfile : kermrc, LINBUFSIZ); |
| else |
| #endif /* CK_LOGIN */ |
| if (rcflag) { /* If init file name from cmd line */ |
| ckstrncpy(lp,kermrc,LINBUFSIZ); /* use it, */ |
| } else { /* otherwise... */ |
| #ifdef CK_INI_A /* If we've a system-wide init file */ |
| /* And it takes precedence over the user's... */ |
| ckstrncpy(lp,CK_SYSINI,KERMRCL); /* Use it */ |
| if (zchki(lp) < 0) { /* (if it exists...) */ |
| #endif /* CK_INI_A */ |
| char * homdir; |
| char * env = 0; |
| line[0] = NUL; |
| |
| /* Add support for environment variable */ |
| env = getenv("CKERMIT.INI"); |
| if (!env) |
| env = getenv("CKERMIT_INI"); |
| if (env) |
| ckstrncpy(lp,env,KERMRCL); |
| |
| if (lp[0] == 0) { |
| homdir = zhome(); |
| if (homdir) { /* Home directory for init file. */ |
| ckstrncpy(lp,homdir,KERMRCL); |
| #ifdef STRATUS |
| ckstrncat(lp,">",KERMRCL);/* VOS dirsep */ |
| #else |
| if (lp[0] == '/') ckstrncat(lp,"/",KERMRCL); |
| #endif /* STRATUS */ |
| } |
| ckstrncat(lp,kermrc,KERMRCL);/* Append default file name */ |
| } |
| #ifdef CK_INI_A |
| } |
| #endif /* CK_INI_A */ |
| #ifdef CK_INI_B /* System-wide init defined? */ |
| /* But user's ini file takes precedence */ |
| if (zchki(lp) < 0) /* If user doesn't have her own, */ |
| ckstrncpy(lp,CK_SYSINI,KERMRCL); /* use system-wide one. */ |
| #endif /* CK_INI_B */ |
| } |
| #endif /* VMS */ |
| #endif /* GEMDOS */ |
| |
| #ifdef AMIGA |
| reqoff(); /* Disable requestors */ |
| #endif /* AMIGA */ |
| |
| #ifdef USE_CUSTOM |
| /* If no init file was found, execute the customization file */ |
| debug(F110,"CUSTOM 1",line,0); |
| if (!line[0] || zchki(line) < 0) { |
| int x; |
| #ifdef OS2 |
| x = ckmakestr(line,LINBUFSIZ,GetAppData(1),"/","K95CUSTOM.INI",NULL); |
| debug(F111,"CUSTOM 2",line,x); |
| if (zchki(line) < 0) { |
| x = ckmakestr(line,LINBUFSIZ,GetAppData(0),"/","K95USER.INI",NULL); |
| debug(F111,"CUSTOM 3",line,x); |
| } |
| #else /* OS2 */ |
| x = ckstrncpy(line,zhome(),LINBUFSIZ); |
| #ifndef VMS |
| /* VMS zhome() returns "SYS$LOGIN:" */ |
| if (line[x-1] != DIRSEP) { |
| line[x++] = DIRSEP; |
| line[x] = NUL; |
| } |
| #endif /* VMS */ |
| x = ckstrncat(line,MYCUSTOM,LINBUFSIZ); |
| debug(F111,"CUSTOM 4",line,x); |
| #endif /* OS2 */ |
| } |
| debug(F110,"CUSTOM 5",line,0); |
| #endif /* USE_CUSTOM */ |
| |
| #ifdef CKROOT |
| if (!zinroot(line)) { |
| debug(F110,"doinit setroot violation",line,0); |
| return; |
| } |
| #endif /* CKROOT */ |
| |
| debug(F110,"doinit ini file is",line,0); |
| if ((tfile[0] = fopen(line,"r")) != NULL) { /* Try to open init file. */ |
| ok = 1; |
| tlevel = 0; |
| tfline[tlevel] = 0; |
| if ((tfnam[tlevel] = malloc(strlen(line)+1))) |
| strcpy(tfnam[tlevel],line); /* safe */ |
| |
| ckstrncpy(kermrc,line,KERMRCL); |
| |
| #ifndef NOSPL |
| cmdlvl++; |
| ifcmd[cmdlvl] = 0; |
| iftest[cmdlvl] = 0; |
| count[cmdlvl] = count[cmdlvl-1]; /* Inherit from previous level */ |
| intime[cmdlvl] = intime[cmdlvl-1]; |
| inpcas[cmdlvl] = inpcas[cmdlvl-1]; |
| takerr[cmdlvl] = takerr[cmdlvl-1]; |
| merror[cmdlvl] = merror[cmdlvl-1]; |
| xquiet[cmdlvl] = quiet; |
| debug(F101,"doinit open ok","",cmdlvl); |
| xcmdsrc = CMD_TF; |
| cmdstk[cmdlvl].src = CMD_TF; |
| cmdstk[cmdlvl].lvl = tlevel; |
| cmdstk[cmdlvl].ccflgs = 0; |
| #endif /* NOSPL */ |
| } else if (rcflag) { |
| /* Print an error message only if a specific file was asked for. */ |
| printf("?%s - %s\n", ck_errstr(), line); |
| } |
| |
| #ifdef datageneral |
| /* If CKERMIT.INI not found in home directory, look in searchlist */ |
| if (/* homdir && */ (tlevel < 0)) { |
| ckstrncpy(lp,kermrc,LINBUFSIZ); |
| if ((tfile[0] = fopen(line,"r")) != NULL) { |
| ok = 1; |
| tlevel = 0; |
| tfline[tlevel] = 0; |
| if (tfnam[tlevel] = malloc(strlen(line)+1)) |
| strcpy(tfnam[tlevel],line); /* safe */ |
| #ifndef NOSPL |
| cmdlvl++; |
| xcmdsrc = CMD_TF; |
| cmdstk[cmdlvl].src = CMD_TF; |
| cmdstk[cmdlvl].lvl = tlevel; |
| cmdstk[cmdlvl].ccflgs = 0; |
| ifcmd[cmdlvl] = 0; |
| iftest[cmdlvl] = 0; |
| count[cmdlvl] = count[cmdlvl-1]; /* Inherit from previous level */ |
| intime[cmdlvl] = intime[cmdlvl-1]; |
| inpcas[cmdlvl] = inpcas[cmdlvl-1]; |
| takerr[cmdlvl] = takerr[cmdlvl-1]; |
| merror[cmdlvl] = merror[cmdlvl-1]; |
| xquiet[cmdlvl] = quiet; |
| #endif /* NOSPL */ |
| } |
| } |
| #endif /* datageneral */ |
| |
| #ifdef AMIGA /* Amiga... */ |
| reqpop(); /* Restore requestors */ |
| #endif /* AMIGA */ |
| #endif /* OS2 */ |
| #endif /* MAC */ |
| |
| /* Assign value to inidir */ |
| |
| if (!ok) { |
| inidir[0] = NUL; |
| } else { |
| ckstrncpy(inidir, kermrc, CCHMAXPATH); |
| x = strlen(inidir); |
| if (x > 0) { |
| int i; |
| for (i = x - 1; i > 0; i-- ) { |
| if (ISDIRSEP(inidir[i])) { |
| inidir[i+1] = NUL; |
| break; |
| } |
| } |
| } |
| #ifdef NT |
| GetShortPathName(inidir,inidir,CCHMAXPATH); |
| #endif /* NT */ |
| } |
| } |
| |
| VOID |
| doiksdinit() { |
| #ifdef CK_SSL |
| /* IKSD doesn't request client certs */ |
| ssl_verify_flag = SSL_VERIFY_NONE; |
| #endif /* CK_SSL */ |
| |
| if (!cmdinited) |
| cmdini(); |
| |
| #ifdef IKSDCONF |
| #ifdef OS2 |
| line[0] = '\0'; |
| _searchenv(iksdconf,"INIT",line); |
| if (line[0] == 0) |
| _searchenv(iksdconf,"DPATH",line); |
| if (line[0] == 0) |
| _searchenv(iksdconf,"PATH",line); |
| if (line[0] == 0) { |
| char *pgmptr = GetLoadPath(); |
| if (pgmptr && strlen(pgmptr) < LINBUFSIZ-8) { |
| lp = strrchr(pgmptr, '\\'); |
| if (lp) { |
| strncpy(line, pgmptr, lp - pgmptr); |
| strcpy(line + (lp - pgmptr), "\\"); |
| strcpy(line + (lp - pgmptr + 1), iksdconf); |
| } else { |
| lp = strrchr(pgmptr, '.'); |
| if (lp) { |
| strncpy(line, pgmptr, lp - pgmptr); |
| strcpy(line + (lp - pgmptr), ".ksc"); |
| } |
| } |
| } |
| } |
| debug(F110,"doiksdinit() line",line,0); |
| tfile[0] = fopen(line,"r"); |
| #else /* OS2 */ |
| tfile[0] = fopen(iksdconf,"r"); |
| #endif /* OS2 */ |
| if (tfile[0] != NULL) { |
| tlevel = 0; |
| tfline[tlevel] = 0; |
| #ifdef OS2 |
| if (tfnam[tlevel] = malloc(strlen(line)+1)) |
| strcpy(tfnam[tlevel],line); |
| #else /* OS2 */ |
| if ((tfnam[tlevel] = malloc(strlen(iksdconf)+1))) |
| strcpy(tfnam[tlevel],iksdconf); |
| #endif /* OS2 */ |
| #ifndef NOSPL |
| cmdlvl++; |
| xcmdsrc = CMD_TF; |
| cmdstk[cmdlvl].src = CMD_TF; |
| cmdstk[cmdlvl].lvl = tlevel; |
| cmdstk[cmdlvl].ccflgs = 0; |
| ifcmd[cmdlvl] = 0; |
| iftest[cmdlvl] = 0; |
| count[cmdlvl] = count[cmdlvl-1]; /* Inherit from previous level */ |
| intime[cmdlvl] = intime[cmdlvl-1]; |
| inpcas[cmdlvl] = inpcas[cmdlvl-1]; |
| takerr[cmdlvl] = takerr[cmdlvl-1]; |
| merror[cmdlvl] = merror[cmdlvl-1]; |
| xquiet[cmdlvl] = quiet; |
| #endif /* NOSPL */ |
| debug(F110,"doiksdinit file ok",tfnam[tlevel],0); |
| } else { |
| debug(F110,"doiksdinit open failed",tfnam[tlevel],0); |
| } |
| #endif /* IKSDCONF */ |
| } |
| |
| #ifndef NOSPL |
| /* |
| G E T N C M |
| |
| Get next command from current macro definition. Command is copied |
| into string pointed to by argument s, max length n. Returns: |
| 0 if a string was copied; |
| -1 if there was no string to copy. |
| */ |
| int |
| getncm(s,n) char *s; int n; { |
| int y = 0; /* Character counter */ |
| int quote = 0; |
| int kp = 0; /* Brace up-down counter */ |
| int pp = 0; /* Parenthesis up-down counter */ |
| #ifndef NODQMACRO |
| int dq = 0; /* Doublequote counter */ |
| #endif /* NODQMACRO */ |
| char *s2; /* Copy of destination pointer */ |
| |
| s2 = s; /* Initialize string pointers */ |
| *s = NUL; /* and destination buffer */ |
| |
| /* debug(F010,"getncm entry",macp[maclvl],0); */ |
| |
| for (y = 0; /* Loop for n bytes max */ |
| macp[maclvl] && *macp[maclvl] && y < n; |
| y++, s++, macp[maclvl]++) { |
| |
| *s = *macp[maclvl]; /* Get next char from macro def */ |
| |
| #ifndef COMMENT |
| /* |
| This is to allow quoting of parentheses, commas, etc, in function |
| arguments, but it breaks just about everything else. DON'T REMOVE THIS |
| COMMENT! (Otherwise you'll wind up adding the same code again and breaking |
| everything again.) <-- The preceding warning should be obsolete since the |
| statements below have been fixed, but in case of fire, remove the "n" from |
| the <#>ifndef above. NEW WARNING: code added 12 Apr 2002 to exempt the |
| opening brace in \{nnn} from being treated as a quoted brace. |
| */ |
| if (!quote && *s == CMDQ) { |
| quote = 1; |
| continue; |
| } |
| if (quote) { |
| int notquote = 0; |
| quote = 0; |
| if (*s == '{') { /* Check for \{nnn} (8.0.203) */ |
| char c, * p; |
| p = macp[maclvl] + 1; |
| while ((c = *p++)) { |
| if (isdigit(c)) |
| continue; |
| else if (c == '}') { |
| notquote++; |
| break; |
| } else { |
| break; |
| } |
| } |
| } |
| if (notquote == 0) |
| continue; |
| } |
| #endif /* COMMENT */ |
| |
| /* |
| Allow braces around macro definition to prevent commas from being turned to |
| end-of-lines and also treat any commas within parens as text so that |
| multiple-argument functions won't cause the command to break prematurely. |
| 19 Oct 2001: Similar treatment was added for doublequotes, so |
| |
| define foo { echo "one, two, three" } |
| |
| would work as expected. This doesn't seem to have broken anything but |
| if something comes up later, rebuild with NODQMACRO defined. |
| */ |
| if (*s == '{') kp++; /* Count braces */ |
| if (*s == '}' && kp > 0) kp--; |
| if (*s == '(') pp++; /* Count parentheses. */ |
| if (*s == ')' && pp > 0) pp--; |
| #ifndef NODQMACRO |
| #ifndef COMMENT |
| /* Too many false positives */ |
| /* No, not really -- this is indeed the best we can do */ |
| /* Reverted to this method Sun May 11 18:43:45 2003 */ |
| if (*s == '"') dq = 1 - dq; /* Account for doublequotes */ |
| #else /* Fri Apr 4 13:21:29 2003 */ |
| /* The code below breaks the SWITCH statement */ |
| /* There is no way to make this work -- it would require */ |
| /* building in all the knowledge of command parser. */ |
| if (dblquo && (*s == '"')) { /* Have doublequote */ |
| if (dq == 1) { /* Close quote only if... */ |
| if ((*(macp[maclvl]+1) == SP) || /* followed by space or... */ |
| (!*(macp[maclvl]+1)) || /* at end or ... */ |
| /* Next char is command separator... */ |
| /* Sun May 11 17:24:12 2003 */ |
| (kp < 1 && pp < 1 && (*(macp[maclvl]+1) == ',')) |
| ) |
| dq = 0; /* Close the quote */ |
| } else if (dq == 0) { |
| /* Open quote only if at beginning or preceded by space */ |
| if (s > s2) { |
| if (*(s-1) == SP) |
| dq = 1; |
| } else if (s == s2) { |
| dq = 1; |
| } |
| } |
| } |
| #endif /* COMMENT */ |
| #endif /* NODQMACRO */ |
| if (*s == ',' && pp <= 0 && kp <= 0 |
| #ifndef NODQMACRO |
| && dq == 0 |
| #endif /* NODQMACRO */ |
| ) { |
| macp[maclvl]++; /* Comma not in {} or () */ |
| /* debug(F110,"next cmd",s,0); */ |
| kp = pp = 0; /* so we have the next command */ |
| break; |
| } |
| } /* Reached end. */ |
| #ifdef COMMENT |
| /* DON'T DO THIS - IT BREAKS EVERYTHING */ |
| *s = NUL; |
| #endif /* COMMENT */ |
| if (*s2 == NUL) { /* If nothing was copied, */ |
| /* debug(F100,"XXX getncm eom","",0); */ |
| popclvl(); /* pop command level. */ |
| return(-1); |
| } else { /* otherwise, tack CR onto end */ |
| *s++ = CR; |
| *s = '\0'; |
| /* debug(F110,"XXX getncm OK",s,0); */ |
| if (mecho && pflag) /* If MACRO ECHO ON, echo the cmd */ |
| printf("%s\n",s2); |
| } |
| return(0); |
| } |
| |
| /* D O M A C -- Define and then execute a macro */ |
| |
| int |
| domac(name, def, flags) char *name, *def; int flags; { |
| int x, m; |
| #ifndef NOLOCAL |
| #ifdef OS2 |
| extern int term_io; |
| int term_io_sav = term_io; |
| term_io = 0; /* Disable Terminal Emulator I/O */ |
| #endif /* OS2 */ |
| #endif /* NOLOCAL */ |
| m = maclvl; /* Current macro stack level */ |
| x = addmac(name, def); /* Define a new macro */ |
| if (x > -1) { /* If successful, */ |
| dodo(x,NULL,flags); /* start it (increments maclvl). */ |
| while (maclvl > m) { /* Keep going till done with it, */ |
| debug(F101,"domac loop maclvl 1","",maclvl); |
| sstate = (CHAR) parser(1); /* parsing & executing each command, */ |
| debug(F101,"domac loop maclvl 2","",maclvl); |
| if (sstate) proto(); /* including protocol commands. */ |
| } |
| debug(F101,"domac loop exit maclvl","",maclvl); |
| } |
| #ifndef NOLOCAL |
| #ifdef OS2 |
| term_io = term_io_sav; |
| #endif /* OS2 */ |
| #endif /* NOLOCAL */ |
| return(success); |
| } |
| #endif /* NOSPL */ |
| |
| /* |
| G E T N C T |
| |
| Get next command from TAKE (command) file. |
| |
| Call with: |
| s Pointer to buffer to read into |
| n Length of buffer |
| f File descriptor of file to read from |
| flag 0 == keep line terminator on and allow continuation |
| 1 == discard line terminator and don't allow continuation |
| |
| Call with flag == 0 to read a command from a TAKE file; |
| Call with flag != 0 to read a line from a dialing or network directory. |
| |
| In both cases, trailing comments and/or trailing whitespace is/are stripped. |
| If flag == 0, continued lines are combined into one line. A continued line |
| is one that ends in hypen, or any line in a "block", which starts with "{" |
| at the end of a line and ends with a matching "}" at the beginning of a |
| subsequent line; blocks may be nested. |
| |
| Returns: |
| 0 if a string was copied, |
| -1 on EOF, |
| -2 on malloc failure |
| -3 if line is not properly terminated |
| -4 if (possibly continued) line is too long. |
| */ |
| static int lpxlen = 0; |
| |
| int |
| getnct(s,n,f,flag) char *s; int n; FILE *f; int flag; { |
| int i = 0, len = 0, buflen = 0; |
| char c = NUL, cc = NUL, ccl = NUL, ccx = NUL, *s2 = NULL; |
| char *lp = NULL, *lpx = NULL, *lp2 = NULL, *lp3 = NULL, *lastcomma = NULL; |
| char * prev = NULL; |
| int bc = 0; /* Block counter */ |
| |
| s2 = s; /* Remember original pointer */ |
| prev = s2; |
| buflen = n; /* Remember original buffer length */ |
| |
| if (n < 0) |
| return(-2); |
| |
| /* Allocate a line buffer only if we don't have one that's big enough */ |
| |
| debug(F111,"getnct",ckitoa(lpxlen),n); |
| |
| if (lpx && (n > lpxlen)) { /* Have one already */ |
| debug(F101,"getnct new buffer","",lpxlen); |
| free(lpx); /* But it's not big enough */ |
| lpx = NULL; /* Free current one */ |
| lpxlen = 0; |
| } |
| if (!lpx) { /* Get new one */ |
| if (!(lpx = (char *) malloc(n))) { |
| debug(F101,"getnct malloc failure","",0); |
| printf("?Memory allocation failure [getnct]\n"); |
| return(-2); |
| } |
| lpxlen = n; |
| } |
| lp2 = lpx; |
| #ifdef KLUDGE |
| /* NOTE: No longer used as of 14 Aug 2000 */ |
| lp2++; |
| #endif /* KLUDGE */ |
| |
| while (1) { /* Loop to read lines from file */ |
| debug(F101,"getnct while (1)","",n); |
| if (fgets(lp2,n,f) == NULL) { /* Read a line into lp2 */ |
| debug(F110,"getnct EOF",s2,0); /* EOF */ |
| free(lpx); /* Free temporary storage */ |
| lpx = NULL; |
| *s = NUL; /* Make destination be empty */ |
| return(-1); /* Return failure code */ |
| } |
| #ifndef NODIAL |
| if (flag) /* Count this line */ |
| dirline++; |
| else |
| #endif /* NODIAL */ |
| tfline[tlevel]++; |
| len = strlen(lp2) - 1; /* Position of line terminator */ |
| if (len == 0 && lp2[0] != '\n') { /* Last line in file has one char */ |
| lp2[++len] = '\n'; /* that is not a newline */ |
| lp2[len] = NUL; |
| } |
| debug(F010,"getnct",lp2,0); |
| if (len < 0) |
| len = 0; |
| if (techo && pflag) /* If TAKE ECHO ON, */ |
| printf("%3d. %s", /* echo it this line. */ |
| #ifndef NODIAL |
| flag ? dirline : |
| #endif /* NODIAL */ |
| tfline[tlevel], |
| lp2 |
| ); |
| lp3 = lp2; /* Working pointer */ |
| i = len; /* Get first nonwhitespace character */ |
| while (i > 0 && (*lp3 == SP || *lp3 == HT)) { |
| i--; |
| lp3++; |
| } |
| if (i == 0 && bc > 0) /* Blank line in {...} block */ |
| continue; |
| |
| /* Isolate, remove, and check terminator */ |
| |
| c = lp2[len]; /* Value of line terminator */ |
| /* debug(F101,"getnct terminator","",c); */ |
| if (c < LF || c > CR) { /* It's not a terminator */ |
| /* debug(F111,"getnct bad line",lp2,c); */ |
| if (feof(f) && len > 0 && len < n) { |
| /* Kludge Alert... */ |
| if (!quiet) |
| printf("WARNING: Last line of %s lacks terminator\n", |
| s2 == cmdbuf ? "command file" : "directory file"); |
| c = lp2[++len] = '\n'; /* No big deal - supply one. */ |
| } else { /* Something's wrong, fail. */ |
| free(lpx); |
| lpx = NULL; |
| return(-3); |
| } |
| } |
| /* Trim trailing whitespace */ |
| |
| for (i = len - 1; i > -1 && lp2[i] <= SP; i--) /* Trim */ |
| ; |
| /* debug(F101,"getnct i","",i); */ |
| lp2[i+1] = NUL; /* Terminate the string */ |
| /* debug(F110,"getnct lp2",lp2,0); */ |
| lp = lp2; /* Make a working pointer */ |
| |
| /* Remove trailing or full-line comment */ |
| |
| while ((cc = *lp)) { |
| if (cc == ';' || cc == '#') { /* Comment introducer? */ |
| if (lp == lp2) { /* First char on line */ |
| *lp = NUL; |
| break; |
| } else if (*(lp - 1) == SP || *(lp - 1) == HT) { |
| lp--; |
| *lp = NUL; /* Or preceded by whitespace */ |
| break; |
| } |
| } |
| lp++; |
| } |
| if (lp > lp2) |
| lp--; /* Back up over the NUL */ |
| |
| /* Now trim any space that preceded the comment */ |
| |
| while ((*lp == SP || *lp == HT) && lp >= lp2) { |
| *lp = NUL; |
| if (lp <= lp2) |
| break; |
| lp--; |
| } |
| /* debug(F110,"getnct comment trimmed",lp2,0); */ |
| |
| len = strlen(lp2); /* Length after trimming */ |
| |
| if (n - len < 2) { /* Check remaining space */ |
| debug(F111,"getnct command too long",s2,buflen); |
| printf("?Line too long, maximum length: %d.\n",buflen); |
| free(lpx); |
| return(-4); |
| } |
| ccl = (len > 0) ? lp2[len-1] : 0; /* Last character in line */ |
| ccx = (len > 1) ? lp2[len-2] : 0; /* Penultimate char in line */ |
| |
| #ifdef COMMENT |
| /* Line containing only whitespace and ,- */ |
| if ((len > 1) && (lp3 == lp2+len-2) && (ccl == '-') && (ccx == ',')) |
| continue; |
| #endif /* COMMENT */ |
| |
| #ifdef KLUDGE |
| /* |
| If it is a command and it begins with a token (like ! or .) that is not |
| followed by a space, insert a space now; otherwise cmkey() can get mighty |
| confused. |
| */ |
| if (s == s2 && !flag) { |
| char *p = toktab; |
| while (*p) { |
| if (*p == *lp3 && *(p+1) != SP) { |
| debug(F110,"getnct token",p,0); |
| *lp3-- = SP; |
| *lp3 = *p; |
| if (lp3 < lp2) { |
| lp2--; |
| len++; |
| } |
| break; |
| } else |
| p++; |
| } |
| } |
| #endif /* KLUDGE */ |
| lp = lp2; |
| |
| while ((*s++ = *lp++)) /* Copy result to target buffer */ |
| n--; /* accounting for length */ |
| s--; /* Back up over the NUL */ |
| |
| /* Check whether this line is continued */ |
| |
| if (flag) /* No line continuation when flag=1 */ |
| break; /* So break out of read-lines loop */ |
| |
| #ifdef COMMENT |
| debug(F000,"getnct first char","",*lp3); |
| debug(F000,"getnct last char","",ccl); |
| debug(F000,"getnct next-to-last char","",ccx); |
| #endif /* COMMENT */ |
| |
| if (bc > 0 && *lp3 == '}') { /* First char on line is '}' */ |
| bc--; /* Decrement block counter */ |
| } |
| |
| if (bc == 0 && /* Line is continued if bc > 0 */ |
| #ifdef COMMENT |
| /* Not supported as of C-Kermit 6.0 */ |
| ccl != CMDQ && /* or line ends with CMDQ */ |
| #endif /* COMMENT */ |
| ccl != '-' && /* or line ends with dash */ |
| ccl != '{') /* or line ends with opening brace */ |
| break; /* None of those, we're done. */ |
| |
| if (ccl == '-' || ccl == '{') /* Continuation character */ |
| if (ccx == CMDQ) /* But it's quoted */ |
| break; /* so ignore it */ |
| |
| if (ccl == '{') { /* Last char on line is '{'? */ |
| bc++; /* Count the block opener. */ |
| } else if (ccl == '-') { /* Explicit continue? */ |
| char c, * ss; |
| int state = 0, nn; |
| s--; /* Yes, back up over terminators */ |
| n++; /* and over continuation character */ |
| nn = n; /* Save current count */ |
| ss = s; /* and pointer */ |
| s--; /* Back up over dash */ |
| n++; |
| while (state < 2 && s >= prev) { /* Check for "{,-" */ |
| n++; |
| c = *s--; |
| if (c <= SP) |
| continue; |
| if (c != ',' && c != '{') |
| break; |
| switch (state) { |
| case 0: /* Looking for comma */ |
| if (c == ',') |
| state = 1; |
| break; |
| case 1: /* Looking for left brace */ |
| if (c == '{') { |
| state = 2; |
| s += 2; |
| *s = NUL; |
| bc++; |
| } |
| break; |
| } |
| } |
| if (state != 2) { s = ss; n = nn; } |
| *s = NUL; |
| } else { /* None of those but (bc > 0) */ |
| lastcomma = s; |
| *s++ = ','; /* and insert a comma */ |
| n--; |
| } |
| #ifdef COMMENT |
| debug(F101,"getnct bc","",bc); |
| debug(F100,"getnct continued","",0); |
| #endif /* COMMENT */ |
| |
| *s = NUL; |
| prev = s; |
| |
| } /* read-lines while loop */ |
| |
| if (lastcomma) |
| *lastcomma = SP; |
| if (!flag) /* Tack line terminator back on */ |
| *s++ = c; |
| *s++ = NUL; /* Terminate the string */ |
| untab(s2); /* Done, convert tabs to spaces */ |
| #ifdef DEBUG |
| if (!flag) { |
| debug(F010,"CMD(F)",s2,0); |
| } |
| #endif /* DEBUG */ |
| free(lpx); /* Free temporary storage */ |
| return(0); /* Return success */ |
| } |
| |
| VOID |
| shostack() { /* Dump the command stack */ |
| int i; |
| char *p; |
| #ifndef NOSPL |
| for (i = cmdlvl; i > 0; i--) { |
| if (cmdstk[i].src == CMD_TF) { |
| p = tfnam[cmdstk[i].lvl]; |
| if (zfnqfp(p,TMPBUFSIZ,tmpbuf)) |
| p = tmpbuf; |
| printf(" %2d. File : %s (line %d)\n", |
| i, |
| p, |
| tfline[cmdstk[i].lvl] |
| ); |
| } else if (cmdstk[i].src == CMD_MD) { |
| char * m; |
| m = m_arg[cmdstk[i].lvl][0]; /* Name of this macro */ |
| if (i > 0) { /* Special handling for 2-level */ |
| char *s; /* built-in macros... */ |
| s = m_arg[cmdstk[i-1].lvl][0]; /* Name next level up */ |
| if (s && cmdstk[i-1].src == CMD_MD) { |
| if (!strcmp(s,"_forx")) |
| m = "FOR"; |
| else if (!strcmp(s,"_xif")) |
| m = "XIF"; |
| else if (!strcmp(s,"_while")) |
| m = "WHILE"; |
| else if (!strcmp(s,"_switx")) |
| m = "SWITCH"; |
| } |
| } |
| printf(" %2d. Macro : %s\n",i,m); |
| } else if (cmdstk[i].src == CMD_KB) { |
| printf(" %2d. Prompt:\n",i); |
| } else { |
| printf(" %2d. ERROR : Command source unknown\n",i); |
| } |
| } |
| #else |
| for (i = tlevel; i > -1; i--) { |
| p = tfnam[i]; |
| if (zfnqfp(p,TMPBUFSIZ,tmpbuf)) |
| p = tmpbuf; |
| printf(" %2d. File : %s (line %d)\n", |
| i, |
| p, |
| tfline[i] |
| ); |
| } |
| #endif /* NOSPL */ |
| if (i == 0) |
| printf(" %2d. Prompt: (top level)\n",0); |
| } |
| |
| |
| /* P A R S E R -- Top-level interactive command parser. */ |
| |
| /* |
| Call with: |
| m = 0 for normal behavior: keep parsing and executing commands |
| until an action command is parsed, then return with a |
| Kermit start-state as the value of this function. |
| m = 1 to parse only one command, can also be used to call parser() |
| recursively. |
| m = 2 to read but do not execute one command. |
| In all cases, parser() returns: |
| 0 if no Kermit protocol action required |
| > 0 with a Kermit protocol start-state. |
| < 0 upon error. |
| */ |
| int |
| parser(m) int m; { |
| int tfcode, xx, yy, zz; /* Workers */ |
| int is_tn = 0; |
| int cdlost = 0; |
| |
| #ifndef NOSPL |
| int inlevel; /* Level we were called at */ |
| extern int askflag; |
| #endif /* NOSPL */ |
| char *cbp; /* Command buffer pointer */ |
| #ifdef MAC |
| extern char *lfiles; /* Fake extern cast */ |
| #endif /* MAC */ |
| extern int interrupted; |
| #ifndef NOXFER |
| extern int sndcmd, getcmd, fatalio, clearrq; |
| #endif /* NOXFER */ |
| |
| debok = 1; /* Undisable debugging */ |
| |
| #ifdef AMIGA |
| reqres(); /* Restore AmigaDOS requestors */ |
| #endif /* AMIGA */ |
| |
| #ifdef OS2 |
| if (cursor_save > -1) { /* Restore cursor if it was */ |
| cursorena[VCMD] = cursor_save; /* turned off during file transfer */ |
| cursor_save = -1; |
| } |
| #endif /* OS2 */ |
| |
| #ifdef IKSDB |
| if (ikdbopen) slotstate(what,"COMMAND PROMPT","",""); /* IKSD database */ |
| #endif /* IKSDB */ |
| |
| is_tn = (local && network && IS_TELNET()) || |
| (!local && sstelnet); |
| |
| if (!xcmdsrc) /* If at top (interactive) level ... */ |
| concb((char)escape); /* put console in 'cbreak' mode. */ |
| |
| #ifdef CK_TMPDIR |
| /* If we were cd'd temporarily to another device or directory ... */ |
| if (f_tmpdir) { |
| int x; |
| x = zchdir((char *) savdir); /* ... restore previous directory */ |
| f_tmpdir = 0; /* and remember we did it. */ |
| debug(F111,"parser tmpdir restoring",savdir,x); |
| } |
| #endif /* CK_TMPDIR */ |
| |
| #ifndef NOSPL |
| inlevel = cmdlvl; /* Current macro level */ |
| #ifdef DEBUG |
| if (deblog) { |
| debug(F101,"&parser entry maclvl","",maclvl); |
| debug(F101,"&parser entry inlevel","",inlevel); |
| debug(F101,"&parser entry tlevel","",tlevel); |
| debug(F101,"&parser entry cmdlvl","",cmdlvl); |
| debug(F101,"&parser entry m","",m); |
| } |
| #endif /* DEBUG */ |
| #endif /* NOSPL */ |
| |
| #ifndef NOXFER |
| ftreset(); /* Reset global file settings */ |
| #endif /* NOXFER */ |
| /* |
| sstate becomes nonzero when a command has been parsed that requires some |
| action from the protocol module. Any non-protocol actions, such as local |
| directory listing or terminal emulation, are invoked directly from below. |
| */ |
| sstate = 0; /* Start with no start state. */ |
| |
| #ifndef NOXFER |
| #ifndef NOSPL |
| query = 0; /* QUERY not active */ |
| #endif /* NOSPL */ |
| #ifndef NOHINTS |
| if (!success) { |
| if (local && !network && carrier != CAR_OFF) { |
| int x; /* Serial connection */ |
| x = ttgmdm(); /* with carrier checking */ |
| if (x > -1) { |
| if (!(x & BM_DCD)) { |
| cdlost = 1; |
| fatalio = 1; |
| } |
| } |
| } |
| } |
| #ifdef DEBUG |
| if (deblog) { |
| debug(F101,"parser top what","",what); |
| debug(F101,"parser top interrupted","",interrupted); |
| debug(F101,"parser top cdlost","",cdlost); |
| debug(F101,"parser top sndcmd","",sndcmd); |
| debug(F101,"parser top getcmd","",getcmd); |
| } |
| #endif /* DEBUG */ |
| if (cdlost && !interrupted && (sndcmd || getcmd)) { |
| printf("?Connection broken (carrier signal lost)\n"); |
| } |
| if (sndcmd && !success && hints && !interrupted && !fatalio && !xcmdsrc) { |
| int x = 0, n = 0; |
| printf("\n*************************\n"); |
| printf("SEND-class command failed.\n"); |
| printf(" Packets sent: %d\n", spackets); |
| printf(" Retransmissions: %d\n",retrans); |
| printf(" Timeouts: %d\n", timeouts); |
| printf(" Damaged packets: %d\n", crunched); |
| if (epktrcvd) { |
| printf(" Transfer canceled by receiver.\n"); |
| printf(" Receiver's message: \"%s\"\n",(char *)epktmsg); |
| n++; |
| } else { |
| if (epktmsg) if (*epktmsg) { |
| printf(" Fatal Kermit Protocol Error: %s\n",epktmsg); |
| n++; |
| } |
| } |
| if (local && !network && carrier != CAR_OFF) { |
| int xx; /* Serial connection */ |
| xx = ttgmdm(); /* with carrier checking */ |
| if (xx > -1) { |
| if (!(xx & BM_DCD)) |
| cdlost = 1; |
| } |
| } |
| |
| #ifdef UNIX |
| if (errno != 0) |
| #endif /* UNIX */ |
| { |
| printf(" Most recent local OS error: \"%s\"\n",ck_errstr()); |
| n++; |
| } |
| printf( |
| "\nHINTS... If the preceding error message%s not explain the failure:\n", |
| (n > 1) ? "s do" : " does" |
| ); |
| #ifndef NOLOCAL |
| if (local) { |
| if (rpackets == 0) { |
| printf(" . Did you start a Kermit receiver on the far end?\n"); |
| } else { |
| printf( |
| " . Try changing the remote Kermit's FLOW-CONTROL setting.\n"); |
| if (!network && mdmtyp > 0) |
| if ((3 * crunched) > spackets) |
| printf( |
| " . Try placing a new call to get a cleaner connection.\n"); |
| } |
| } else if (rpackets > 0) { |
| if (flow == FLO_NONE) |
| printf(" . Give me a SET FLOW XON/XOFF command and try again.\n"); |
| else |
| printf(" . Give me a SET FLOW NONE command and try again.\n"); |
| } |
| x++; |
| #endif /* NOLOCAL */ |
| |
| if ((3 * timeouts) > spackets) |
| printf(" . Adjust the timeout method (see HELP SET SEND).\n"); |
| if ((3 * retrans) > spackets) |
| printf(" . Increase the retry limit (see HELP SET RETRY).\n"); |
| |
| #ifdef CK_SPEED |
| if (prefixing != PX_ALL && rpackets > 2) { |
| printf(" . Try it again with SET PREFIXING ALL.\n"); |
| x++; |
| } |
| #endif /* CK_SPEED */ |
| #ifdef STREAMING |
| if (streamed) { |
| printf(" . Try it again with SET STREAMING OFF.\n"); |
| x++; |
| } else if (reliable) { |
| printf(" . Try it again with SET RELIABLE OFF.\n"); |
| x++; |
| } |
| #endif /* STREAMING */ |
| |
| #ifdef CK_SPEED |
| if (clearrq > 0 && prefixing == PX_NON) { |
| printf(" . Try it again with SET CLEAR-CHANNEL OFF.\n"); |
| x++; |
| } |
| #endif /* CK_SPEED */ |
| if (!parity) { |
| printf(" . Try it again with SET PARITY SPACE.\n"); |
| x++; |
| } |
| printf(" . %sive a ROBUST command and try again.\n", |
| (x > 0) ? "As a last resort, g" : "G" |
| ); |
| printf("Also:\n"); |
| printf(" . Be sure the source file has read permission.\n"); |
| printf(" . Be sure the target directory has write permission.\n"); |
| printf("(Use SET HINTS OFF to suppress hints.)\n"); |
| printf("*************************\n\n"); |
| } |
| debug(F101,"topcmd","",topcmd); |
| if (getcmd && !success && hints && !interrupted && !fatalio && !xcmdsrc) { |
| int x = 0; |
| extern int urpsiz, wslotr; |
| printf("\n*************************\n"); |
| printf("RECEIVE- or GET-class command failed.\n"); |
| printf(" Packets received: %d\n", rpackets); |
| printf(" Damaged packets: %d\n", crunched); |
| printf(" Timeouts: %d\n", timeouts); |
| if (rpackets > 0) |
| printf(" Packet length: %d\n", urpsiz); |
| if (epktrcvd) { |
| printf(" Transfer canceled by sender.\n"); |
| printf(" Sender's message: \"%s\"\n",(char *)epktmsg); |
| } |
| #ifdef UNIX |
| if (errno != 0) |
| #endif /* UNIX */ |
| printf(" Most recent local error: \"%s\"\n",ck_errstr()); |
| printf( |
| "\nHINTS... If the preceding error message%s not explain the failure:\n", |
| epktrcvd ? "s do" : " does" |
| ); |
| #ifndef NOLOCAL |
| if (local) { |
| if (topcmd == XXGET) |
| printf(" . Did you start a Kermit SERVER on the far end?\n"); |
| if (rpackets == 0) { |
| if (topcmd != XXGET) |
| printf(" . Did you start a Kermit SENDer on the far end?\n"); |
| } else { |
| printf( |
| " . Choose a different FLOW-CONTROL setting and try again.\n"); |
| } |
| } else if (topcmd == XXGET) |
| printf(" . Is the other Kermit in (or does it have) SERVER mode?\n"); |
| if (rpackets > 0 && urpsiz > 90) |
| printf(" . Try smaller packets (SET RECEIVE PACKET-LENGTH).\n"); |
| if (rpackets > 0 && wslotr > 1 && !streamed) |
| printf(" . Try a smaller window size (SET WINDOW).\n"); |
| if (!local && rpackets > 0) { |
| if (flow == FLO_NONE) |
| printf(" . Give me a SET FLOW XON/XOFF command and try again.\n"); |
| else |
| printf(" . Give me a SET FLOW NONE command and try again.\n"); |
| } |
| x++; |
| #endif /* NOLOCAL */ |
| #ifdef STREAMING |
| if (streamed) { |
| printf(" . Try it again with SET STREAMING OFF.\n"); |
| x++; |
| } else if (reliable && local) { |
| printf(" . Try it again with SET RELIABLE OFF.\n"); |
| x++; |
| } else |
| #endif /* STREAMING */ |
| if (!parity) { |
| printf(" . Try it again with SET PARITY SPACE.\n"); |
| x++; |
| } |
| printf((x > 0) ? |
| " . As a last resort, give a ROBUST command and try again.\n" : |
| " . Give a ROBUST command and try again.\n" |
| ); |
| printf("Also:\n"); |
| printf(" . Be sure the target directory has write permission.\n"); |
| printf(" . Try telling the %s to SET PREFIXING ALL.\n", |
| topcmd == XXGET ? "server" : "sender" |
| ); |
| printf(" . Try giving a ROBUST command to the %s.\n", |
| topcmd == XXGET ? "server" : "sender" |
| ); |
| printf("(Use SET HINTS OFF to suppress hints.)\n"); |
| printf("*************************\n\n"); |
| } |
| #endif /* NOHINTS */ |
| getcmd = 0; |
| sndcmd = 0; |
| interrupted = 0; |
| #endif /* NOXFER */ |
| |
| while (sstate == 0) { /* Parse cmds until action requested */ |
| debug(F100,"parse top","",0); |
| what = W_COMMAND; /* Now we're parsing commands. */ |
| rcdactive = 0; /* REMOTE CD not active */ |
| keepallchars = 0; /* MINPUT not active */ |
| |
| #ifdef OS2 |
| if (apcactive == APC_INACTIVE) |
| WaitCommandModeSem(-1); |
| #endif /* OS2 */ |
| #ifdef IKS_OPTION |
| if ((local && |
| !xcmdsrc && |
| is_tn && |
| TELOPT_ME(TELOPT_KERMIT) && |
| TELOPT_SB(TELOPT_KERMIT).kermit.me_start) || |
| (!local && |
| !cmdadl && |
| TELOPT_ME(TELOPT_KERMIT) && |
| TELOPT_SB(TELOPT_KERMIT).kermit.me_start) |
| ) { |
| tn_siks(KERMIT_STOP); |
| } |
| #endif /* IKS_OPTION */ |
| |
| #ifndef NOXFER |
| if (autopath) { |
| fnrpath = PATH_AUTO; |
| autopath = 0; |
| } |
| remfile = 0; /* Clear these in case REMOTE */ |
| remappd = 0; /* command was interrupted... */ |
| rempipe = 0; |
| makestr(&snd_move,g_snd_move); /* Restore these */ |
| makestr(&rcv_move,g_rcv_move); |
| makestr(&snd_rename,g_snd_rename); |
| makestr(&rcv_rename,g_rcv_rename); |
| #endif /* NOXFER */ |
| xaskmore = saveask; /* Restore global more-prompting */ |
| diractive = 0; |
| cdactive = 0; |
| |
| #ifndef NOSPL |
| askflag = 0; |
| #endif /* NOSPL */ |
| |
| /* Take requested action if there was an error in the previous command */ |
| |
| setint(); |
| debug(F101,"parser tlevel","",tlevel); |
| debug(F101,"parser cmd_rows","",cmd_rows); |
| |
| #ifndef NOLOCAL |
| debug(F101,"parser wasclosed","",wasclosed); |
| if (wasclosed) { /* If connection was just closed */ |
| #ifndef NOSPL |
| int k; |
| k = mlook(mactab,"on_close",nmac); /* Look up "on_close" */ |
| if (k >= 0) { /* If found, */ |
| /* printf("ON_CLOSE CMD LOOP\n"); */ |
| dodo(k,ckitoa(whyclosed),0); /* Set it up */ |
| } |
| #endif /* NOSPL */ |
| whyclosed = WC_REMO; |
| wasclosed = 0; |
| } |
| #endif /* NOLOCAL */ |
| |
| #ifndef NOSPL |
| xxdot = 0; /* Clear this... */ |
| |
| debug(F101,"parser success","",success); |
| if (success == 0) { |
| if (cmdstk[cmdlvl].src == CMD_TF && takerr[cmdlvl]) { |
| printf("Command file terminated by error.\n"); |
| popclvl(); |
| if (cmdlvl == 0) return(0); |
| } |
| if (cmdstk[cmdlvl].src == CMD_MD && merror[cmdlvl]) { |
| printf("Command error: macro terminated.\n"); |
| popclvl(); |
| if (m && (cmdlvl < inlevel)) |
| return((int) sstate); |
| } |
| } |
| nulcmd = (m == 2); |
| debug(F101,"parser nulcmd","",nulcmd); |
| #else |
| if (success == 0 && tlevel > -1 && takerr[tlevel]) { |
| printf("Command file terminated by error.\n"); |
| popclvl(); |
| cmini(ckxech); /* Clear the cmd buffer. */ |
| if (tlevel < 0) /* Just popped out of cmd files? */ |
| return(0); /* End of init file or whatever. */ |
| } |
| #endif /* NOSPL */ |
| |
| #ifdef MAC |
| /* Check for TAKE initiated by menu. */ |
| if ((tlevel == -1) && lfiles) |
| startlfile(); |
| #endif /* MAC */ |
| |
| /* If in TAKE file, check for EOF */ |
| #ifndef NOSPL |
| #ifdef MAC |
| if |
| #else |
| while |
| #endif /* MAC */ |
| ((cmdstk[cmdlvl].src == CMD_TF) /* If end of take file */ |
| && (tlevel > -1) |
| && feof(tfile[tlevel])) { |
| popclvl(); /* pop command level */ |
| cmini(ckxech); /* and clear the cmd buffer. */ |
| if (cmdlvl == 0) { /* Just popped out of all cmd files? */ |
| return(0); /* End of init file or whatever. */ |
| } |
| } |
| #ifdef MAC |
| miniparser(1); |
| if (sstate == 'a') { /* if cmd-. cancel */ |
| debug(F100, "parser: cancel take due to sstate", "", sstate); |
| sstate = '\0'; |
| dostop(); |
| return(0); /* End of init file or whatever. */ |
| } |
| #endif /* MAC */ |
| |
| #else /* NOSPL */ |
| if ((tlevel > -1) && feof(tfile[tlevel])) { /* If end of take */ |
| popclvl(); /* Pop up one level. */ |
| cmini(ckxech); /* and clear the cmd buffer. */ |
| if (tlevel < 0) /* Just popped out of cmd files? */ |
| return(0); /* End of init file or whatever. */ |
| } |
| #endif /* NOSPL */ |
| |
| |
| #ifndef NOSPL |
| debug(F101,"parser cmdlvl","",cmdlvl); |
| debug(F101,"parser cmdsrc","",cmdstk[cmdlvl].src); |
| |
| if (cmdstk[cmdlvl].src == CMD_MD) { /* Executing a macro? */ |
| debug(F100,"parser macro","",0); |
| maclvl = cmdstk[cmdlvl].lvl; /* Get current level */ |
| debug(F101,"parser maclvl","",maclvl); |
| cbp = cmdbuf; /* Copy next cmd to command buffer. */ |
| *cbp = NUL; |
| if (*savbuf) { /* In case then-part of 'if' command */ |
| ckstrncpy(cbp,savbuf,CMDBL); /* was saved, restore it. */ |
| *savbuf = '\0'; |
| } else { /* Else get next cmd from macro def */ |
| if (getncm(cbp,CMDBL) < 0) { |
| #ifdef DEBUG |
| if (deblog) { |
| debug(F101,"parser end of macro m","",m); |
| debug(F101,"parser end of macro cmdlvl","",cmdlvl); |
| debug(F101,"parser end of macro inlevel","",inlevel); |
| } |
| #endif /* DEBUG */ |
| if (m && (cmdlvl < inlevel)) |
| return((int) sstate); |
| else /* if (!m) */ continue; |
| } |
| } |
| debug(F010,"CMD(M)",cmdbuf,0); |
| |
| } else if (cmdstk[cmdlvl].src == CMD_TF) |
| #else |
| if (tlevel > -1) |
| #endif /* NOSPL */ |
| { |
| #ifndef NOSPL |
| debug(F111,"parser savbuf",savbuf,tlevel); |
| if (*savbuf) { /* In case THEN-part of IF command */ |
| ckstrncpy(cmdbuf,savbuf,CMDBL); /* was saved, restore it. */ |
| *savbuf = '\0'; |
| } else |
| #endif /* NOSPL */ |
| |
| /* Get next line from TAKE file */ |
| |
| if ((tfcode = getnct(cmdbuf,CMDBL,tfile[tlevel],0)) < 0) { |
| debug(F111,"parser tfcode",tfile[tlevel],tfcode); |
| if (tfcode < -1) { /* Error */ |
| printf("?Error in TAKE command file: %s\n", |
| (tfcode == -2) ? "Memory allocation failure" : |
| "Line too long or contains NUL characters" |
| ); |
| dostop(); |
| } |
| continue; /* -1 means EOF */ |
| } |
| |
| /* If interactive, get next command from user. */ |
| |
| } else { /* User types it in. */ |
| if (pflag) prompt(xxstring); |
| cmini(ckxech); |
| } |
| |
| /* Now we know where next command is coming from. Parse and execute it. */ |
| |