/***************************************************************************
 *                                                                         *
 *   MENUING.C                                                             *
 *                                                                         *
 *   Copyright (c) 1991-1997 Galacticomm, Inc.    All Rights Reserved.     *
 *                                                                         *
 *   This is the Worldgroup suite of main menuing routines.                *
 *                                                                         *
 *                                                - C. Robert  10/1/91     *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "majorbbs.h"
#include "wgsmajor.h"
#undef   LEVEL3
#undef   LEVEL4
#undef   LEVEL6
#include "wgsrip.h"
#include "phasedbg.h"

#define FILREV "$Revision: 15 $"

HMCVFILE ripmb;               /* WGSRIP.MSG                                */

INT mnudnl=-1;                /* user # downloading wgsmenu2.dat (or -1)   */

GBOOL globgo=FALSE;           /* doing a global /go exit chain?            */

DFAFILE *mnubb;               /* menu information btrieve file pointer     */

static VOID *muusrs;          /* pointer for use with ptrblok()            */

struct usrmnu *mnuusr;        /* global pointer to menu user in effect     */
struct mnupag *menupg;        /* gen purp menupg pointer for btrieve gets  */

CHAR *dfllin;                 /* default line of main menu (from CNF opt)  */

CHAR ***autscns;              /* button cmds for auto-RIP menus            */

CHAR defcrds[MAXSEL][MAXSEL][5]={  /* def button coords for auto-RIP scns  */
          {"593V"},
          {"592R","5950"},
          {"5927","593V","595J"},
          {"591U","5936","594I","595U"},
          {"591M","592Q","593U","594Y","5962"},
          {"591J","592I","593H","594G","595F","596E"},
          {"591F","5929","5933","593X","594R","595L","596F"},
          {"591C","5922","592T","593K","594B","5952","595T","596K"},
          {"131M","9I1M","132Q","9I2Q","133U","9I3U","134Y","9I4Y","5962"},
          {"131M","9I1M","132Q","9I2Q","133U","9I3U","134Y","9I4Y","1362",
           "9I62"},
          {"131J","9I1J","132I","9I2I","133H","9I3H","134G","9I4G","135F",
           "9I5F","596E"},
          {"131J","9I1J","132I","9I2I","133H","9I3H","134G","9I4G","135F",
           "9I5F","136E","9I6E"},
          {"131F","9I1F","1329","9I29","1333","9I33","133X","9I3X","134R",
           "9I4R","135L","9I5L","596F"},
          {"131F","9I1F","1329","9I29","1333","9I33","133X","9I3X","134R",
           "9I4R","135L","9I5L","136F","9I6F"},
          {"131B","9I1B","1322","9I22","132T","9I2T","133K","9I3K","134B",
           "9I4B","1352","9I52","135T","9I5T","596K"},
          {"131B","9I1B","1322","9I22","132T","9I2T","133K","9I3K","134B",
           "9I4B","1352","9I52","135T","9I5T","136K","9I6K"},
          {"0H1J","6A1J","C31J","0H2I","6A2I","C32I","0H3H","6A3H","C33H",
           "0H4G","6A4G","C34G","0H5F","6A5F","C35F","3E6E","966E"},
          {"0H1J","6A1J","C31J","0H2I","6A2I","C32I","0H3H","6A3H","C33H",
           "0H4G","6A4G","C34G","0H5F","6A5F","C35F","0H6E","6A6E","C36E"},
          {"0H1F","6A1F","C31F","0H29","6A29","C329","0H33","6A33","C333",
           "0H3X","6A3X","C33X","0H4R","6A4R","C34R","0H5L","6A5L","C35L",
           "6A6F"},
          {"0H1F","6A1F","C31F","0H29","6A29","C329","0H33","6A33","C333",
           "0H3X","6A3X","C33X","0H4R","6A4R","C34R","0H5L","6A5L","C35L",
           "3E6F","966F"},
          {"0H1F","6A1F","C31F","0H29","6A29","C329","0H33","6A33","C333",
           "0H3X","6A3X","C33X","0H4R","6A4R","C34R","0H5L","6A5L","C35L",
           "0H6F","6A6F","C36F"},
          {"0H1B","6A1B","C31B","0H22","6A22","C322","0H2T","6A2T","C32T",
           "0H3K","6A3K","C33K","0H4B","6A4B","C34B","0H52","6A52","C352",
           "0H5T","6A5T","C35T","6A6K"},
          {"0H1B","6A1B","C31B","0H22","6A22","C322","0H2T","6A2T","C32T",
           "0H3K","6A3K","C33K","0H4B","6A4B","C34B","0H52","6A52","C352",
           "0H5T","6A5T","3E6K","C35T","966K"},
          {"0H1B","6A1B","C31B","0H22","6A22","C322","0H2T","6A2T","C32T",
           "0H3K","6A3K","C33K","0H4B","6A4B","C34B","0H52","6A52","C352",
           "0H5T","6A5T","C35T","0H6K","6A6K","C36K"},
          {"0H19","6A19","C319","0H1X","6A1X","C31X","0H2L","6A2L","C32L",
           "0H39","6A39","C339","0H3X","6A3X","C33X","0H4L","6A4L","C34L",
           "0H59","6A59","C359","0H5X","6A5X","C35X","6A6L"}
};
CHAR *lgrfnt[]={"|Y00000100",/* def button label font style, large/enabled */
                "|Y00000100"},/* def button label font sytle, large/dimmed */
     *lgrsty[]={"|1B770F0207QQ020E000F080700000F07000077",
                              /* def button style, large/enabled           */
                "|1B770F0207QO0207000F070800000F07000077"},
                              /* def button style, large/dimmed            */

     *smrfnt[]={"|Y02000400", /* def button label font style, small/enabled*/
                "|Y02000400"},/* def button label font sytle, small/dimmed */
     *smrsty[]={"|1B580F0207QQ020E000F080700000F07000058",
                              /* def button style, small/enabled           */
                "|1B580F0207QO0207000F070800000F07000058"};
                              /* def button style, small/dimmed            */

CHAR *xitpge;                 /* name of "Logoff (End Session)" module page*/
INT dspxit,                   /* display button for main menu logoff?      */
    maxlge,                   /* max. # of options for large button style  */
    dspoext;                  /* disp .IBM/.ANS/.ASC menu files to RIP usrs?*/

INT (*gomvec)(VOID)=gomutl;   /* vector for cmd stg handling in gomodl()   */

INT glostt;                    /* menu-ize global command state            */

static CHAR *extold;               /* globals between opnans() & tryfnd()  */
static CHAR *tryfil;               /* globals between opnans() & tryfnd()  */

static INT tryfnd(CHAR *ext);
static VOID eodpag(CHAR *pagnam,INT enable);

static VOID iniglo(VOID);
static GBOOL cs2glo(VOID);
static VOID getbuts(CHAR **butlst,INT scnno);
static VOID getsty(CHAR *fntsty,CHAR *butsty,INT optno);
static VOID ansdsp(INT lngmnu);
static VOID ripdsp(INT lngmnu);

struct module doglobal={           /* module interface block               */
     "",                           /*    name used to refer to this module */
     NULL,                         /*    user logon supplemental routine   */
     cs2glo,                       /*    input routine if selected         */
     dfsthn,                       /*    status-input routine if selected  */
     NULL,                         /*    "injoth" routine for this module  */
     NULL,                         /*    user logoff supplemental routine  */
     NULL,                         /*    hangup (lost carrier) routine     */
     NULL,                         /*    midnight cleanup routine          */
     NULL,                         /*    delete-account routine            */
     NULL                          /*    finish-up (sys shutdown) routine  */
};

VOID
inimnu(VOID)                  /* initialize Menuing system                 */
{
     muusrs=(struct usrmnu *)alcblok(nterms,sizeof(struct usrmnu));
     menupg=(struct mnupag *)alczer(sizeof(struct mnupag));
     mnubb=dfaOpen("wgsmenu2.dat",sizeof(struct mnupag),NULL);
     setmbk(mjrmb);
     dfllin=stgopt(DFLLIN);
     rstmbk();
     rtkick(1,iniglo);
}

static VOID
iniglo(VOID)
{
     if (isfile("galglo.mdf")) {
          stzcpy(doglobal.descrp,gmdnam("galglo.mdf"),MNMSIZ);
          glostt=register_module(&doglobal);
     }
}


INT
iniarip(VOID)                 /* initialize auto-RIP menuing system        */
{
     INT scnno,svcl;

     for (ripidx=0 ; ripidx < nlingo
       && !samend(languages[ripidx]->name,RIPSFX) ; ripidx++) {
     }
     if (ripidx == nlingo) {
          return(0);
     }
     ripmb=opnmsg("wgsrip.mcv");
     svcl=clingo;
     clingo=ripidx;
     autscns=(CHAR ***)alczer(MAXSEL*sizeof(CHAR **));
     for (scnno=0 ; scnno < MAXSEL ; scnno++) {
          getbuts(autscns[scnno]=(CHAR **)alczer((scnno+1)*sizeof(CHAR *)),
                  scnno);
     }
     getsty(lgrfnt[0],lgrsty[0],ENALGE);
     getsty(lgrfnt[1],lgrsty[1],DIMLGE);
     getsty(smrfnt[0],smrsty[0],ENASML);
     getsty(smrfnt[1],smrsty[1],DIMSML);
     maxlge=numopt(MAXLGE,0,25);
     if ((dspxit=ynopt(DSPXIT)) == 0) {
          xitpge=stgopt(XITPGE);
     }
     dspoext=ynopt(DSPOEXT);
     rstmbk();
     clingo=svcl;
     return(1);
}

static GBOOL
cs2glo(VOID)                       /* command string -> global command     */
{
     INT i,rc,goret=0;

     if ((usrptr->flags&WSGCSU) && usrptr->entstt == glostt) {
          usrptr->entstt=0; /* if used from c/s, from a tmode module page */
     }
     rstrin();
     movmem(input+1,input,strlen(input));
     if (*input != '\0') {
          parsin();
          if (!(usrptr->flags&NOGLOB)) {
               if (sameto("/go",input)) {
                    usrptr->state=0;
                    goret=1;
               }
               for (i=0 ; i < nglobs ; i++) {
                    if ((rc=(*globs[i])()) == -2) {
                         outprf(usrnum);
                    }
                    if (rc != 0) {
                         break;
                    }
               }
               if (goret && rc != -1) {
                    usrptr->state=glostt;
                    goret=0;
               }
          }
     }
     clrprf();
     return(goret || !(usrptr->state == glostt));
}

static VOID
getbuts(butlst,scnno)         /* read in button cmds for auto-RIP menus    */
CHAR **butlst;                /*     ptr to area in autscns to store cmds  */
INT scnno;                    /*     how many buttons for this screen?     */
{
     INT nbuts,nfnd=0,len;
     CHAR *cp,*cp2;

     cp=rawmsg(DEF1+scnno);
     nbuts=scnno+1;
     while (*cp != '\0' && strlen(cp) >= RBUTSZ && nfnd < nbuts) {
          if (strncmp(cp,RIP_BUTTON,BCSIZ) == 0) {
               if ((cp2=strstr(cp,"<>")) == NULL) {
                    break;
               }
               len=((INT)(cp2-cp));
               butlst[nfnd]=alczer(len+1);
               stzcpy(butlst[nfnd],cp,len+1);
               nfnd++;
               cp=*cp2 == '\r' ? cp2+1 : cp2;
          }
          else {
               cp++;
          }
     }
     if (nfnd < nbuts) {
          for ( ; nfnd < nbuts ; nfnd++) {
               butlst[nfnd]=alczer(RBUTSZ+1);
               sprintf(butlst[nfnd],"%s%s%s",RIP_BUTTON,defcrds[scnno][nfnd],
                                             BCLST8);
          }
     }
}

static VOID
getsty(fntsty,butsty,optno)   /* get font and button style                 */
CHAR *fntsty;                 /*    where to put the font style            */
CHAR *butsty;                 /*    whete to put the button style          */
INT optno;                    /*    option to read info from               */
{
     CHAR *cp,*tbbuf;
     INT fndfs=0,fndbs=0;

     for (cp=tbbuf=rawmsg(optno)
          ; *cp != '\0' && strlen(cp) >= RBUTSZ
            && strncmp(cp,RIP_BUTTON,BCSIZ) != 0 ; cp++) {
     }
     while (!(cp == tbbuf || (fndfs && fndbs))) {
          if (!fndfs && strncmp(cp,RIP_FONT_STYLE,FSSIZ) == 0) {
               stzcpy(fntsty,cp,RFNTSZ+1);
               fndfs=1;
          }
          else if (!fndbs && strncmp(cp,RIP_BUTTON_STYLE,BSSIZ) == 0) {
               stzcpy(butsty,cp,RBSYSZ+1);
               fndbs=1;
          }
          cp--;
     }
}

INT
globalgo(VOID)                     /* global "go" command handler          */
{
     INT errmsg;
     CHAR pagnam[PNMSIZ];
     static CHAR prmbuf[INPSIZ];

     if (sameas(margv[0],"/go")) {
          setmbk(mjrmb);
          if (usrptr->usrcls != ACTUSR) {
               prfmsg(NGONOW);
               outprf(usrnum);
               rstmbk();
               return(1);
          }
          bgncnc();
          cncwrd();
          if (!morcnc()) {
               prfmsg(GOHELP);
               outprf(usrnum);
               rstmbk();
               return(1);
          }
          stzcpy(pagnam,strupr(cncwrd()),PNMSIZ);
          depad(pagnam);
          morcnc();
          strcpy(prmbuf,cncall());
          dfaSetBlk(mnubb);
          if (!dfaAcqEQ(menupg,spr("A%s",pagnam),0) || menupg->flags&DISABL) {
               errmsg=NOSUCH;
          }
          else if (!(menupg->flags&CNGOTO)) {
               errmsg=BADPAG;
          }
          else if (!haskey(menupg->golock)) {
               errmsg=NOGOPG;
          }
          else {
               errmsg=0;
               unpack(menupg);
          }
          dfaRstBlk();
          if (errmsg != 0) {
               prfmsg(errmsg);
               outprf(usrnum);
               rstmbk();
               return(1);
          }
          globgo=TRUE;
          if (!xitmod()) {
               globgo=FALSE;
               setmbk(mjrmb);
               prfmsg(NGONOW);
               outprf(usrnum);
               rstmbk();
               return(1);
          }
          globgo=FALSE;
          sprintf(input,"Z%s",prmbuf);
          parsin();
          bgncnc();
          mnuusr->curpag[0]='\0';
          if (!gopage(pagnam,1,0)) {
               clrprf();
               prfmsg(NOGOPG);
               gopage("TOP",1,0);
          }
          if (usrptr->state == 0) {
               outprf(usrnum);
          }
          return(-1);
     }
     return(0);
}

GBOOL
xitmod(VOID)                       /* exit out of the current module       */
{
     INT i;

     usrptr->flags&=~CONCEX;
     for (i=0 ; i < XTRIES  && usrptr->state != 0 ; i++) {
          strcpy(input,"x");
          margc=1;
          margv[0]=input;
          hdlinp();
          btuclo(usrnum);
     }
     return(usrptr->state == 0);
}

VOID
enapag(pagnam)                     /* enable a page or menu selection      */
CHAR *pagnam;                      /* page name or sel char to enable      */
{
     eodpag(pagnam,1);
}

VOID
dispag(pagnam)                     /* disable a page or menu selection     */
CHAR *pagnam;                      /* page name or sel char to disable     */
{
     eodpag(pagnam,0);
}

static VOID
eodpag(pagnam,enable)              /* enable or disable a page or sel char */
CHAR *pagnam;                      /* page name or sel char to e or d      */
INT enable;                        /* enable? (1=yes, 0=no)                */
{
     INT snum,ok=1;
     CHAR buffer[PNMSIZ];

     stzcpy(buffer,pagnam,PNMSIZ);
     depad(buffer);
     strupr(buffer);
     if (strlen(buffer) == 1 && (snum=selnum(*buffer)) != -1) {
          strcpy(buffer,mnuusr->pages[snum]);
     }
     dfaSetBlk(mnubb);
     if (mnudnl != -1) {
          prfmsg(CNTEOD,uacoff(mnudnl)->userid);
     }
     else if (!dfaAcqEQ(menupg,spr("A%s",buffer),0)) {
          prfmsg(NOSUCH);
     }
     else if (enable && !(menupg->flags&DISABL)) {
          prfmsg(NOENBL,buffer);
     }
     else if (!enable && menupg->flags&DISABL) {
          prfmsg(NODSBL,buffer);
     }
     else {
          unpack(menupg);
          if (enable) {
               menupg->flags&=~DISABL;
          }
          else {
               if (sameas(buffer,"TOP")) {
                    prfmsg(NODTOP);
                    ok=0;
               }
               else if (sameas(buffer,mnuusr->curpag)) {
                    prfmsg(NODCUR);
                    ok=0;
               }
               else {
                    menupg->flags|=DISABL;
               }
          }
          if (ok) {
               savepage(menupg,FALSE);
               prfmsg(enable ? OKENBL : OKDSBL,buffer);
          }
     }
     dfaRstBlk();
}

VOID
bgnfnd(VOID)                       /* begin a "find" command search        */
{
     strlwr(margv[1]);
     stzcpy(mnuusr->pages[0],margv[1],SHDSIZ);
     cncall();      /* ^^ use pages for storing search stg  */
     depad(mnuusr->pages[0]);
     setmbk(mjrmb);
     prfmsg(BGNFND);
     rstmbk();
     dfaSetBlk(mnubb);
     dfaAcqLO(menupg,0);
     unpack(menupg);
     chk4mtch();
     dfaRstBlk();
     strcpy(mnuusr->parpag,menupg->pagnam); /* cur srch pos */
     usrptr->substt=4;
     usrptr->flags|=NOGLOB;
     begin_polling(usrnum,cntfnd);
}

VOID
cntfnd(VOID)                       /* continue a "find" command search     */
{
     dfaSetBlk(mnubb);
     setmbk(mjrmb);
     dfaGetEQ(menupg,spr("A%s",mnuusr->parpag),0);
     prf("");
     if (!dfaAcqGT(menupg,spr("A%s",mnuusr->parpag),0)
        || menupg->menutype[0] != 'A') {
          abtfnd();
     }
     else {
          unpack(menupg);
          strcpy(mnuusr->parpag,menupg->pagnam); /* cur srch pos */
          chk4mtch();
     }
     dfaRstBlk();
     rstmbk();
     outprf(usrnum);
}

VOID
chk4mtch(VOID)                     /* look for "find" command match in page*/
{                                       /* implicit input:  menupg         */
     INT i;
     CHAR buf[SHDSIZ];
     static struct mnupag mpag;

     if (menupg->flags&CNGOTO) {
          if (menupg->golock[0] == '\0' || haskey(menupg->golock)) {
               if (dfaAcqEQ(&mpag,spr("A%s",menupg->parpag),0)) {
                    unpack(&mpag);
                    for (i=0 ; i < MAXSEL ; i++) {
                         if (sameas(menupg->pagnam,mpag.page[i].destpage)) {
                              strcpy(buf,mpag.page[i].shortd);
                              strlwr(mpag.page[i].shortd);
                              if (strstr(mpag.page[i].shortd,
                                             mnuusr->pages[0])) {
                                   prfmsg(FNDLIN,menupg->pagnam,buf);
                              }
                              break;
                         }
                    }
               }
          }
     }
}

VOID
abtfnd(VOID)                       /* abort a "find" command search        */
{
     usrptr->flags&=~NOGLOB;
     stop_polling(usrnum);
     setmbk(mjrmb);
     prfmsg(ENDFND);
     rstmbk();
     gopage(mnuusr->curpag,isripu(),0);
}

INT
gopage(pagnam,lngmnu,reting)       /* jump to a specific page              */
CHAR *pagnam;                      /* page (or file) name to jump to       */
INT lngmnu;                        /* display the long menu (1 or 0)       */
INT reting;                        /* returning from page? (1 or 0)        */
{
     INT tmpret,reject=0;
     CHAR camfrm[PNMSIZ],paghld[PNMSIZ+1];
     static INT autotp=0;

     setmbk(mjrmb);
     dfaSetBlk(mnubb);
     usrptr->state=0;
     usrptr->substt=1;
     stzcpy(paghld,spr("A%s",strupr(pagnam)),PNMSIZ+1);
     if (sameas(menupg->menutype,paghld)) {
          if (menupg->flags&DISABL) {
               reject=1;
          }
     }
     else if (!dfaAcqEQ(menupg,paghld,0)) {
          reject=1;
     }
     else {
          unpack(menupg);
          if (menupg->flags&DISABL) {
               reject=1;
          }
     }
     if (reject) {
          if (sameas(paghld,"ATOP")) {
               shocst("AUTOSELECT TOP MENU PAGE ERROR",
                      "CP:%s U:%s",
                      mnuusr->curpag,usaptr->userid);
               byenow(NO_MESSAGE);
               return(1);
          }
          prfmsg(NOPAGE);
          if (mnuusr->curpag[0] != '\0') {
               if (sameas(menupg->menutype,paghld) && menupg->flags&DISABL) {
                    tmpret=gopage(menupg->parpag,(isripu() ? 1 : shortm),1);
               }
               else {
                    tmpret=gopage(sameas(mnuusr->curpag,&paghld[1])
                      ? "TOP" : mnuusr->curpag,
                      (isripu() ? 1 : shortm),1);
               }
          }
          else {
               tmpret=0;
          }
          dfaRstBlk();
          rstmbk();
          return(tmpret);
     }
     strcpy(camfrm,mnuusr->curpag);
     strcpy(mnuusr->curpag,menupg->pagnam);
     strcpy(mnuusr->parpag,menupg->parpag);
     if (menupg->flags&AUTPAG) {
          if (sameas(paghld,"ATOP")) {
               if (autotp) {
                    shocst("AUTOSELECT TOP MENU PAGE ERROR",
                           "CF:%s CP:%s U:%s",
                           camfrm,mnuusr->curpag,usaptr->userid);
                    byenow(NO_MESSAGE);
                    return(1);
               }
               autotp=1;
               tmpret=gocond();
               autotp=0;
          }
          else if (reting) {
               tmpret=gopage(mnuusr->parpag,(isripu() ? 1 : shortm),1);
          }
          else {
               tmpret=gocond();
          }
     }
     else if (menupg->flags&MDLPAG) {
          tmpret=gomodl();
     }
     else if (menupg->flags&FILPAG) {
          tmpret=gofile();
     }
     else {
          tmpret=gomenu(lngmnu);
     }
     dfaRstBlk();
     rstmbk();
     if (!tmpret) {
          if (sameas(paghld,"ATOP")) {
               shocst("AUTOSELECT TOP MENU PAGE ERROR",
                      "CP:%s U:%s",
                      mnuusr->curpag,usaptr->userid);
               byenow(NO_MESSAGE);
               return(1);
          }
          else {
               cncall();
               if (*camfrm != '\0') {
                    return(gopage(camfrm,(isripu() ? 1 : shortm),1));
               }
               if (menupg->flags&MDLPAG) {
                    return(gopage(mnuusr->parpag,1,1));
               }
          }
     }
     return(tmpret);
}

INT
gomodl(VOID)                       /* go to a module page                  */
{
     INT modnum;

     if ((modnum=findmod(menupg->modnam)) < 0) {
          prfmsg(NOPAGE);
          return(0);
     }
     if (!(menupg->flags&NOMPHD)) {
          prfmsg(MPGHDR);
          outprf(usrnum);
     }
     return(entmdl(modnum,menupg->cmdstg));
}

INT
entmdl(                            /* enter a module now                   */
INT modnum,                        /*   module number to enter             */
CHAR *cmdstg)                      /*   command string to use              */
{
     CHAR c;
     extern INT exicnc;
     static CHAR prmbuf[INPSIZ];

     usrptr->state=modnum;
     usrptr->substt=0;
     usrptr->flags|=X2MAIN;
     c=cncchr();       /* save the useless select char (modules expect it) */
     c=(c == '\0' ? 'Z' : c);      /* make sure it's a valid one           */
     strcpy(prmbuf,cncall());
     sprintf(input,"%c%s %-.*s",c,cmdstg,(INT)(INPSIZ-strlen(cmdstg)-3),
             prmbuf);
     parsin();
     if (exicnc && (margc > 1 || strlen(margv[0]) > 1)) {
          usrptr->flags|=CONCEX;
     }
     else {
          usrptr->flags&=~CONCEX;
     }
     btuoes(usrnum,0);
     usrptr->flags&=~INJOIP;
     setmem(vdaptr,vdasiz,0);
     clrprf();
     return((*gomvec)());
}

INT
gomutl(VOID)                       /* standard cmd stg hdlr for gomodl()   */
{
     return((*(module[usrptr->state]->sttrou))());
}

INT
gocond(VOID)                       /* go to a conditional page and branch  */
{
     INT i;

     for (i=0 ; i < MAXSEL ; i++) {
          if (menupg->page[i].selchr != '\0'
              && haskey(menupg->page[i].keyreq)) {
               gopage(menupg->page[i].destpage,1,0);
               return(1);
          }
     }
     prfmsg(NOAXSS,toupper(margv[0][0]));
     return(0);
}

INT
gomenu(lngmnu)                     /* go to a new menu page                */
INT lngmnu;                        /* display the long menu? (1 or 0)      */
{
     INT i;

     cncchr();
     usrptr->state=0;
     usrptr->substt=1;
     for (i=0 ; i < MAXSEL ; i++) {
          if (menupg->page[i].keyreq[0] == '\0') {
               mnuusr->keyreq[i]=-1;
          }
          else {
               switch (scnpsk(usrnum,menupg->page[i].keyreq)) {
               case -1:
                    if (usrptr->flags&MASTER) {
                         mnuusr->keyreq[i]=-1;
                    }
                    else {
                         mnuusr->keyreq[i]=lockbit(menupg->page[i].keyreq,1);
                    }
                    break;
               case 0:
                    mnuusr->keyreq[i]=-2;
                    break;
               case 1:
                    mnuusr->keyreq[i]=-1;
                    break;
               }
          }
     }
     for (i=0 ; i < MAXSEL ; i++) {
          mnuusr->selchrs[i]=menupg->page[i].selchr;
          stzcpy(mnuusr->pages[i],menupg->page[i].destpage,PNMSIZ);
          mnuusr->optdsp[i]=menupg->page[i].optdsp;
     }
     strcpy(mnuusr->mnuttl,menupg->mnuttl);
     if (!morcnc() || numcat+1 >= maxcat) {
          cncall();
          dspmnu(lngmnu);
     }
     return(1);
}

INT
gofile(VOID)                       /* go to a file page (display the file) */
{
     if (!(menupg->flags&NOFPHD)) {
          prfmsg(FPGHDR);
          outprf(usrnum);
     }
     cncall();
     usrptr->substt=3;
     return(opfile(menupg->fname));
}

VOID
dspmnu(                            /* display a menu (long or short)       */
INT lngmnu)                             /* long menu? (1=long 0=short)     */
{
     if (globgo) {
          return;
     }
     if (lngmnu && !(menupg->flags&DFTDSP) && menupg->fname[0] != '\0'
         && opnans(menupg->fname)) {
          usrptr->substt=2;
          return;
     }
     if (!isripu()) {
          ansdsp(lngmnu);
     }
     else {
          ripdsp(lngmnu);
     }
     return;
}

static VOID
ansdsp(lngmnu)                     /* display ANSI version of auto-menu    */
INT lngmnu;                        /*      long menu? (1=long 0=short)     */
{
     INT i;

     prfmsg(lngmnu ? DFLHDR : DFSBGN2);
     prf(mmuatr);
     for (i=0 ; i < MAXSEL ; i++) {
          if (mnuusr->selchrs[i] != '\0') {
               if (mnuusr->keyreq[i] == -1 || haskno(mnuusr->keyreq[i]) ||
                   mnuusr->optdsp[i] > 1) {
                    if (lngmnu) {
                         prf(dfllin,
                            mnuusr->selchrs[i],menupg->page[i].shortd);
                    }
                    else if (mnuusr->selchrs[i] != 'X') {
                         prf("%c,",mnuusr->selchrs[i]);
                    }
               }
               else if (mnuusr->optdsp[i] == 1) {
                    prf(ansdim);
                    if (lngmnu) {
                         strcpy(vdatmp,dfllin);
                         stpans(vdatmp);
                         prf(ansdim);
                         prf(vdatmp,
                            mnuusr->selchrs[i],menupg->page[i].shortd);
                    }
                    else {
                         prf(ansdim);
                         prf("%c,",mnuusr->selchrs[i]);
                    }
                    prf(mmuatr);
               }
          }
     }
     if (lngmnu) {
          ansdsp(0);
     }
     else {
          prfmsg(DFSEND);
     }
}

static VOID
ripdsp(lngmnu)                     /* display RIP version of auto-menu     */
INT lngmnu;                        /*      long menu? (1=long 0=short)     */
{
     INT i,j,mode[MAXSEL],optno[MAXSEL],curmde,dsp;
     CHAR **mnufnt,**mnusty,**butlst;

     if (!lngmnu) {
          prfmsg(DFSEND);
          return;
     }
     prfmsg(DFLHDR);
     for (i=0,j=0 ; i < MAXSEL ; i++) {
          dsp=1;
          if (menupg->page[i].selchr != '\0'
              && (mnuusr->keyreq[i] == -1
                  || (dsp=haskno(mnuusr->keyreq[i])) == 1
                  || mnuusr->optdsp[i] > 0)
              && (dspxit || !sameas(mnuusr->pages[i],xitpge))) {
               optno[j]=i;
               mode[j++]=(dsp || menupg->page[i].optdsp > 1 ? 0 : 1);
          }
     }
     if (j > 0) {
          butlst=autscns[j-1];
          for (i=0,curmde=-1,mnufnt=(j <= maxlge ? lgrfnt : smrfnt),
               mnusty=(j <= maxlge ? lgrsty : smrsty) ; i < j ; i++) {
               if (mode[i] != curmde) {
                    prf("\r!%s",mnufnt[curmde=mode[i]]);
                    prf("\r!%s",mnusty[curmde]);
               }
               prf("\r!%s<>%s<>%c`M",butlst[i],menupg->page[optno[i]].shortd,
                                    menupg->page[optno[i]].selchr);
          }
     }
     prfmsg(DFSEND);
}

struct usrmnu *
mnuoff(                            /* get pointer to user's menu info      */
INT unum)                          /*   user number to grab                */
{
     return((struct usrmnu *)ptrblok(muusrs,(USHORT)unum));
}

VOID
redolocks(inserted)                /* re-do the in-memory lock #'s for usrs*/
INT inserted;                           /* number at which new lock was put*/
{
     INT i,j;

     for (i=0 ; i < nterms ; i++) {
          if (usroff(i)->usrcls >= ACTUSR) {
               mnuusr=mnuoff(i);
               for (j=0 ; j < MAXSEL ; j++) {
                    if (mnuusr->keyreq[j] >= inserted) {
                         mnuusr->keyreq[j]+=1;
                    }
               }
          }
     }
     mnuusr=mnuoff(usrnum);
}

INT
opnans(filnam)                     /* open file w/ .EXT based on lang/prot */
CHAR *filnam;                      /* root file name to try to open        */
{
     INT lng,extfnd,isripu;
     struct lingo *lptr;

     tryfil=filnam;
     extold=NULL;
     if (strchr(filnam,'.')) {
          return(tryfnd(""));
     }
     for (isripu=isripu(),alg1st(lng=clingo) ; 1 ; lng=algnxt()) {
          lptr=languages[lng];
          if (isripu && !samend(lptr->name,RIPSFX)) {
               extfnd=dspoext && (tryfnd(lptr->extibm)
                               || tryfnd(lptr->extans)
                               || tryfnd(lptr->extasc));
          }
          else if (usaptr->ansifl&ANSON) {
               if (usaptr->systyp == 1) {
                    extfnd=tryfnd(lptr->extibm)
                        || tryfnd(lptr->extans)
                        || tryfnd(lptr->extasc);
               }
               else {
                    extfnd=tryfnd(lptr->extans)
                        || tryfnd(lptr->extibm)
                        || tryfnd(lptr->extasc);
               }
          }
          else {
               extfnd=tryfnd(lptr->extasc)
                   || tryfnd(lptr->extans)
                   || tryfnd(lptr->extibm);
          }
          if (lng == 0 || extfnd) {
               break;
          }
     }
     return(extfnd);
}

static INT
tryfnd(ext)                        /* try finding a menu file              */
CHAR *ext;                         /* proposed extension                   */
{                                  /* (file name comes from tryfil)        */
     INT n,rc=0;

     if (extold == NULL || !sameas(ext,extold)) {
          n=strlen(tryfil);
          strcat(tryfil,extold=ext);
          rc=opfile(tryfil);
          tryfil[n]='\0';
     }
     return(rc);
}

INT
opfile(filnam)                /* initiate "ASCII download" of a text file  */
CHAR *filnam;
{
     if (mnuusr->fp != NULL) {
          fclose(mnuusr->fp);
     }
     if ((mnuusr->fp=fopen(filnam,FOPRB)) != NULL) {
          if ((usaptr->ansifl&ANSON) && (samend(filnam,".ans")
                                      || samend(filnam,".ibm"))) {
               btutsw(usrnum,0);
               btuxnf(usrnum,0,19);
          }
          prf("\r");
          btuinj(usrnum,CYCLE);
          return(1);
     }
     return(0);
}

INT
rdfile(VOID)                       /* ongoing file-read processing         */
{
     INT oba;

     clrprf();
     oba=min(btuoba(usrnum),4096);
     while (oba > 1024) {
          if (feof(mnuusr->fp) || mdfgets(vdatmp,512,mnuusr->fp) == NULL) {
               if (btuoba(usrnum) == outbsz-1 && prfbuf[0] == '\0') {
                    clfile();
                    return(0);
               }
               break;
          }
          xltmnu(vdatmp);
          prf("%s",vdatmp);
          if (prfptr != prfbuf && *(prfptr-1) != '\r') {
               break;
          }
          oba-=strlen(vdatmp);
     }
     if (prfbuf[0] != '\0') {
          xltctls(prfbuf);    /* translate ^'s into control characters     */
          outprf(usrnum);
     }
     else {
          actdet=0;
     }
     btuinj(usrnum,CYCLE);
     return(1);
}

VOID
clfile(VOID)                  /* file-read operation complete, finish up   */
{
     if (mnuusr->fp != NULL) {
          fclose(mnuusr->fp);
          mnuusr->fp=NULL;
          btutsw(usrnum,usaptr->scnwid);
          if (usaptr->scnbrk != CTNUOS) {
               rstrxf();
          }
          if (btuoba(usrnum) != outbsz-1) {
               btuclo(usrnum);
               prf("\r");
          }
     }
}

VOID
xltmnu(buffer)                     /* alter menu output (macros and hidden)*/
CHAR *buffer;
{
     CHAR *ptr;
     INT sav,len,num,c,pos=0,spcout;

     while ((c=buffer[pos]) != '\0') {
          if (c == 255) {
               sav=pos;
               num=selnum(toupper(buffer[pos+1]));
               if (num == -1 || mnuusr->optdsp[num] > 1 ||
                    mnuusr->keyreq[num] == -1 || haskno(mnuusr->keyreq[num])) {
                    movmem(&buffer[pos+2],&buffer[pos],strlen(&buffer[pos+2])+1);
                    spcout=0;
               }
               else if (mnuusr->optdsp[num] == 1) {
                    movmem(&buffer[pos+2],&buffer[pos+strlen(ansdim)],
                           strlen(&buffer[pos+2])+1);
                    movmem(ansdim,&buffer[pos],strlen(ansdim));
                    pos+=(strlen(ansdim)-1);
                    spcout=-1;
               }
               else {
                    movmem(&buffer[pos+2],&buffer[pos],strlen(&buffer[pos+2])+1);
                    spcout=1;
                    pos--;
               }
               while ((c=buffer[++pos]) != 255 && c != '\0') {
                    if (spcout == 1) {
                         if (sameto("[",&buffer[pos])) {
                              ptr=&buffer[pos]+2;
                              while (isdigit(*ptr) || *ptr == ';') {
                                   ptr++;
                              }
                              if (*ptr++ == 'C') {
                                   sscanf(&buffer[pos],"[%dC",&len);
                                   if ((num=(INT)(ptr-&buffer[pos])) > len) {
                                        movmem(ptr,&buffer[pos+len],
                                               strlen(ptr)+1);
                                   }
                                   else if (num < len) {
                                        movmem(ptr,ptr+len-num,strlen(ptr)+1);
                                   }
                                   setmem(&buffer[pos],len,' ');
                                   pos+=len-1;
                              }
                              else {
                                   movmem(ptr,&buffer[pos],strlen(ptr)+1);
                                   pos--;
                              }
                         }
                         else if (c == 1) {
                              len=buffer[c=pos+2]-32;
                              do {
                              } while (buffer[c++] != 1);
                              if ((num=c-pos) != len) {
                                   movmem(&buffer[c],&buffer[pos+len],
                                          strlen(&buffer[c])+1);
                              }
                              setmem(&buffer[pos],len,' ');
                              pos+=(len-1);
                         }
                         buffer[pos]=' ';
                    }
                    else if (spcout < 0 && sameto("[",&buffer[pos])) {
                         ptr=&buffer[pos]+2;
                         while (isdigit(*ptr) || *ptr == ';') {
                              ptr++;
                         }
                         if (*ptr++ == 'm') {
                              movmem(ptr,&buffer[pos],strlen(ptr)+1);
                              pos--;
                         }
                    }
               }
               if (buffer[pos] == 255) {     /* zap final 255 char    */
                    movmem(&buffer[pos+1],&buffer[pos],
                           strlen(&buffer[pos+1])+1);
               }
               else if (spcout > 0) {
                    buffer[0]='\0';
                    return;
               }
               if (spcout < 1) {
                    pos=sav-1;
               }
               else {
                    pos--;
               }
          }
          else if (c == 1) {
               pos+=(grbtxv(&buffer[pos])-1);
          }
          pos++;
     }
}

CHAR *
xlttxv(buffer,size)                /* translate buffer (possible tvars)    */
CHAR *buffer;                      /* buffer to look through               */
INT size;                          /* size of buffer (maximum)             */
{
     CHAR *ptr;

     ptr=buffer;
     while (*ptr != '\0') {
          if (*ptr == 1 && strlen(buffer)+80 < size) {
               ptr+=grbtxv(ptr);
          }
          else if (*ptr == 1) {
               *ptr='\0';
               break;
          }
          else {
               ptr++;
          }
     }
     return(buffer);
}

INT
trulen(                            /* return maximum text variable length  */
CHAR *stg,                         /* or -1 if '%' symbol is embedded      */
INT length)
{
     INT ctr;

     for (ctr=0 ; *stg != '\0' ; ctr++,stg++) {
          if (*stg == '%' && *(stg+1) != '%'
             && (ctr == 0 || *(stg-1) != '%')) {
               return(-1);
          }
     }
     return(ctr > length ? length : ctr);
}

CHAR *
pctvar(                            /* return a printable text variable by  */
CHAR *stg,                         /* translating single % to %%           */
INT len)                           /* ... len=(max prfable size)           */
{
     static CHAR retval[161];
     INT ctr,pct=0;

     setmem(retval,161,0);
     for (ctr=0 ; *stg != '\0' && ctr < len && ctr+pct < 160 ; ctr++,stg++) {
          retval[ctr+pct]=stg[0];
          if (*stg == '%' && *(stg+1) != '%'
             && (ctr == 0 || *(stg-1) != '%')) {
               retval[++pct+ctr]='%';
          }
     }
     return(retval);
}

INT
grbtxv(buffer)                     /* translate text variable in buffer    */
CHAR *buffer;                      /* buffer that hold text variable       */
{
     CHAR just,*ptr,*txtptr;
     INT num,len,actlen,pos=0;

     just=toupper(buffer[++pos]);
     len=buffer[++pos]-32;
     ptr=&buffer[++pos];
     while (*ptr != 1) {
          if (*(ptr++) == '\0') {
               buffer[pos-3]='\0';
               return(0);
          }
     }
     *ptr='\0';
     if (len > 79 || (just != 'R' && just != 'L' && just != 'C' &&
         just != 'N') || (num=findtvar(&buffer[pos])) == -1) {
          movmem(ptr+1,&buffer[pos-3],strlen(ptr+1)+1);
          return(0);
     }
     else {
          BEG_PHASE("Text variable",txtvars[num].varrou);
          txtptr=(*(txtvars[num].varrou))();
          END_PHASE("Text variable",strlen(txtptr));
          if (just == 'N') {
               len=strlen(txtptr);
               if (len > 79 && strchr(txtptr,'%') != NULL) {
                    movmem(ptr+1,&buffer[pos-3],strlen(ptr+1)+1);
                    return(0);
               }
          }
          if (len < (num=(INT)(ptr-&buffer[pos-3]))) {
               movmem(ptr+1,&buffer[pos-3]+len,strlen(ptr+1)+1);
          }
          else {
               movmem(ptr+1,ptr+(len-num),strlen(ptr+1)+1);
          }
          ptr=&buffer[pos-3];
          setmem(ptr,len,' ');
          actlen=trulen(txtptr,len);
          if (actlen < 0) {
               num=strlen(txtptr);
               num=min(num,len);
               txtptr=pctvar(txtptr,len);
               num=strlen(txtptr)-num;
               movmem(ptr,ptr+num,strlen(ptr)+1);
               setmem(ptr,num,' ');
               len+=num;
               actlen=strlen(txtptr);
          }
          if (just != 'N' && actlen != len) {
               if (just == 'R') {
                    movmem(txtptr,ptr+(len-actlen),actlen);
               }
               else if (just == 'L') {
                    movmem(txtptr,ptr,actlen);
               }
               else {
                    movmem(txtptr,ptr+((len/2)-(actlen/2)),actlen);
               }
          }
          else {
               movmem(txtptr,ptr,actlen);
          }
          return(len);
     }
}

INT
selnum(                            /* get the selection number from a char */
CHAR selchr)
{
     INT i;

     selchr=toupper(selchr);
     for (i=0 ; i < MAXSEL ; i++) {
          if (mnuusr->selchrs[i] == selchr) {
               return(i);
          }
     }
     return(-1);
}

INT                                /*   state code (or 0 if problem)       */
pagstt(                            /* get A/A mod state for C/S user       */
CHAR *pagnam)                      /*   for this page name                 */
{
     GBOOL accessok=TRUE;
     INT retstt=0,i;
     CHAR *key;

     dfaSetBlk(mnubb);
     key=spr("C%s",pagnam);
     if (sameas(menupg->menutype,key) || dfaAcqEQ(menupg,key,0)) {
          if (!(menupg->flags&DISABL)
           && (menupg->flags&MDLPAG)
           && !(menupg->flags&CSMPAG)) {
               if (!(menupg->flags&CNGOTO) || !haskey(menupg->golock)) {
                    accessok=FALSE;
                    if (dfaAcqEQ(menupg,spr("C%s",menupg->parpag),0)) {
                         for (i=0 ; i < menupg->npages ; i++) {
                              if (sameas(menupg->page[i].destpage,pagnam)) {
                                   if (haskey(menupg->page[i].keyreq)) {
                                        accessok=TRUE;
                                        dfaAcqEQ(menupg,key,0);
                                   }
                                   break;
                              }
                         }
                    }
               }
               if (accessok) {
                    for (i=0 ; i < nmods ; i++) {
                         if (sameas(menupg->modnam,module[i]->descrp)) {
                              retstt=i;
                              break;
                         }
                    }
               }
          }
     }
     dfaRstBlk();
     return(retstt);
}

CHAR *                             /*   command string (or "" if problem)  */
pagcstg(                           /* get A/A mod command stg for C/S user */
CHAR *pagnam)                      /*   for this page name                 */
{
     return(pagstt(pagnam) > 0 ? (CHAR *)menupg->cmdstg : "");
}

VOID
clsmnu(VOID)                       /* close down The Major Menuing system  */
{
     dfaClose(mnubb);
}
