/***************************************************************************
 *                                                                         *
 *   SIGNUP.C                                                              *
 *                                                                         *
 *   Copyright (c) 1987-1997 Galacticomm, Inc.    All Rights Reserved.     *
 *                                                                         *
 *   This is the Worldgroup signup module.                                 *
 *                                                                         *
 *                                            - T. Stryker 6/24/86         *
 *                                                                         *
 ***************************************************************************/
   
#include "gcomm.h"
#include "majorbbs.h"
#include "phasedbg.h"
#include "wgssup.h"
#include "fsd.h"

#define FILREV "$Revision: 22 $"

#define  NMQSTS    10         /* #/free-form questions sysop can ask@signup*/
#define  ANSSIZ    80         /* size of each free-form signup answer      */

                              /* morsup() state codes                      */
#define   SUPKEYS   1         /*   create user keyring                     */
#define   SUPACCT   2         /*   insert account record into database     */
#define   SUPXREF   3         /*   add User-ID cross-reference             */
#define   SUPCLASS  4         /*   set up user's class                     */
#define   SUPMAIL   5         /*   send new-user mail message              */
#define   SUPHOOKS  1000      /*   base state for create-acct hooks        */

HMCVFILE supmb;               /* signup named-message file handle          */
FILE *suptxt;                 /* pointer to the signup ASCII text file     */

extern struct module module00;/* main svr module for supplemental stuff    */

                              /*--- OPTIONS FROM WGSSUP.MSG ---*/
INT sgnusz,                   /* maximum size of user-ids for new signups  */
    sgnaud,                   /* make audit trail entry for new signups?   */
    sgnbel,                   /* period and duration of new-signup beep    */
    safpsw,                   /* can a User-ID or "password" be a password */
    savinf,                   /* save standard information to file?        */
    supfrm,                   /* format output in fixed-length ASCII?      */
    digalw,                   /* digits allowed in User-IDs?               */
    fulalw,                   /* full names allowed as User-IDs?           */
    namdft,                   /* how do you handle user-ids?               */
    shwcrd,                   /* show user how many credits they have?     */
    dftedt,                   /* default editor? 1=LINE 0=FSE              */
    sndrst,                   /* snd RIP_RESET_WINDOWS after sw to non-RIP?*/
    minuid,                   /* minimum allowable User-ID size            */
    minpwd;                   /* minimum allowable user password size      */
LONG fresup;                  /* free credits given upon signup            */
CHAR *asupq[NMQSTS],          /* ptrs to addtn'l signup questions          */
     *suphdr,                 /* addtn'l signup questions header           */
     *supend,                 /* clsing thanks for additonal signup ques's */
     *langchg;                /* key required to change language pref      */

INT detflg=0;                 /* shwusr(): called frm REMSYS.C, DETAIL cmd?*/

static INT newstt;

struct supvda {               /* signup vda structure definition           */
     INT insstt;                   /* state for inserting final records    */
     INT dunend;                   /* flag set if endsup() has been called */
     CHAR answers[NMQSTS][ANSSIZ]; /* answers to sysop-defined free-form   */
};

/*** Signup questions answer table ***/

INT asktbl[ASTSIZ][3]={       /* table of questions new users are asked    */
   {0,0,0},                        /* blank (place-holder)                 */
   {0,LAFOOT,LNGSIZ-1},            /* language preference                  */
   {0,GASKANS,3},                  /* can you display ANSI graphics?       */
   {0,GUSRNAM,NADSIZ-1},           /* what's your real name?               */
   {0,GUSRAD1,NADSIZ-1},           /* what's your address? (line 1)        */
   {0,GUSRAD2,NADSIZ-1},           /* what's your address? (line 2)        */
   {0,GUSRAD3,NADSIZ-1},           /* what's your address? (line 3)        */
   {0,GUSRAD4,NADSIZ-1},           /* what's your address? (line 4)        */
   {0,GUSRPHO,PHOSIZ-1},           /* what's your phone number?            */
   {0,GSYSTYP2,1},                 /* what's your system type?             */
   {0,GBDAY2,LDATSIZ-1},           /* what is your birthday?               */
   {0,GSEX,1},                     /* are you male or female?              */
   {0,SUPQS1,ANSSIZ-1},            /* sysop-configurable signup questions  */
   {0,GUSENAM,3},                  /* use your real name as your User-ID?  */
   {1,PREUID,UIDSIZ-1}             /* what User-ID do you want to use?     */
};
/*** NOTE: update asktbl[][] and the TBLxxx constants in MAJORBBS.H in sync ***/

#define supptr ((struct supvda *)vdaptr)

CHAR *sysstg[]={             /* strings corresponding to sys type codes   */
     "OTHER",
     "IBM-PC",
     "Macintosh",
     "Apple/non-Mac",
};

CHAR *ansstg[]= {            /* strings corresponding to ANSI settings    */
     "non-ANSI","ANSI","ANSI OFF","ANSI ON"
};

static VOID nxtask(VOID);
static VOID tmabosup(INT supstt);
static VOID tmendsup(VOID);
static INT hdlok(CHAR *stg);
static INT supques(VOID);
VOID savusr(CHAR *answers0);
static VOID sndans(VOID);

VOID
inisup(VOID)                       /* initialize signup stuff              */
{
     supmb=opnmsg("wgssup.mcv");
     sgnusz=numopt(SGNUSZ,3,29);
     sgnaud=ynopt(SGNAUD);
     sgnbel=numopt(SGNBEL,0,2000);
     fresup=lngopt(FRESUP,0L,1000000000L);
     minuid=numopt(MINUID,3,29);
     minpwd=numopt(MINPWD,1,9);
     shwcrd=ynopt(SHWCRD);
     safpsw=ynopt(SAFPSW);
     namdft=tokopt(NAMDFT,"REAL","DFAULT","ASK",NULL);
     dftedt=tokopt(DFTEDT,"LINE",NULL);
     sndrst=ynopt(SNDRST);
     asktbl[TBLLNG][0]=(ynopt(LANGSUP) && nlingo > 1);
     langchg=stgopt(LANGCHG);
     asktbl[TBLANS][0]=ynopt(ANSASK);
     asktbl[TBLNAM][0]=ynopt(ASKNAM);
     if (!asktbl[TBLNAM][0]) {
          namdft=3;
     }
     asktbl[TBLAD1][0]=ynopt(ASKCOM);
     asktbl[TBLAD2][0]=ynopt(ASKADR);
     asktbl[TBLAD3][0]=ynopt(ASKADR);
     asktbl[TBLAD4][0]=ynopt(ASKADR);
     asktbl[TBLPHO][0]=ynopt(ASKPHO);
     asktbl[TBLSYS][0]=ynopt(ASKSYS);
     asktbl[TBLBDY][0]=ynopt(ASKBDY);
     asktbl[TBLSEX][0]=ynopt(ASKSEX);
     asktbl[TBLSUP][0]=(*(getmsg(SUPQS1)) != '\0');
     asktbl[TBLUSE][0]=(namdft == 2);
     savinf=ynopt(SAVINF);
     supfrm=ynopt(SUPFRM);
     digalw=ynopt(DIGALW);
     fulalw=ynopt(FULALW);
     setmem(&uiekytbl,UIEKYTSZ*sizeof(CHAR *),NULL);
     if (asktbl[TBLNAM][0]) {
          uiekytbl[UIEKYNAM]=stgopt(NAMCHGKY);
     }
     if (asktbl[TBLAD1][0]) {
          uiekytbl[UIEKYCOM]=stgopt(COMCHGKY);
     }
     if (asktbl[TBLAD2][0]) {
          uiekytbl[UIEKYADR]=stgopt(ADRCHGKY);
     }
     if (asktbl[TBLPHO][0]) {
          uiekytbl[UIEKYPHO]=stgopt(PHOCHGKY);
     }
     if (asktbl[TBLSYS][0]) {
          uiekytbl[UIEKYSYS]=stgopt(SYSCHGKY);
     }
     uiekytbl[UIEKYANS]=stgopt(ANSCHGKY);
     uiekytbl[UIEKYSCW]=stgopt(SCWCHGKY);
     uiekytbl[UIEKYSCL]=stgopt(SCLCHGKY);
     uiekytbl[UIEKYEDT]=stgopt(EDTCHGKY);
     uiekytbl[UIEKYPAU]=stgopt(PAUCHGKY);
     if (asktbl[TBLSEX][0]) {
          uiekytbl[UIEKYSEX]=stgopt(SEXCHGKY);
     }
     uiekytbl[UIEKYPSW]=stgopt(PSWCHGKY);
     dclvda(sizeof(struct supvda));
}

static VOID
nxtask(VOID)                       /* find next question to ask user       */
{
     INT i,foot=0;
     CHAR *savprf;

     for (i=0 ; i < ASTSIZ ; i++) {
          if (!foot) {
               foot=asktbl[i][1] == newstt;       /* Phase 1: where are we? */
          }
          else if (asktbl[i][0]) {            /* Phase 2: where to go next? */
               switch (newstt=asktbl[i][1]) {
               case SUPQS1:
                    setmem(supptr,sizeof(struct supvda),0);
                    prfmsg(SUPHDR);
                    prfmsg(SUPQS1);
                    break;
               case GUSENAM:
                    savprf=prfptr;
                    if (!hdlok(usaptr->usrnam)) {
                         *(prfptr=savprf)='\0';
                         nxtask();
                    }
                    else {
                         prfmsg(newstt,usaptr->userid);
                    }
                    break;
               case PREUID:
                    if (namdft == 1) {
                         prfmsg(PSWIRON,usaptr->userid);
                         prfmsg(newstt=GPSWORD1);
                         btumil(usrnum,PSWSIZ-1);
                         echsec(secchr,PSWSIZ-1);
                         return;
                    }
                    prfmsg(digalw ? PREDID : newstt);
                    break;
               case GASKANS:
                    btuclo(usrnum);
                    prf("");
                    outprf(usrnum);
                    prfmsg(newstt);
                    sndans();
                    break;
               case LAFOOT:
                    prfmsg(LAHEAD);
                    lnglist(1);
                    lngfoot(1);
                    break;
               default:
                    prfmsg(newstt);
               }
               btumil(usrnum,newstt == PREUID ? sgnusz : asktbl[i][2]);
               return;
          }
     }
}

INT
signup(VOID)                       /* signup main input handler            */
{
     CHAR c;
     INT intguy;
     INT savit;
     CHAR temp[PSWSIZ];
     CHAR *cp;
     INT minID;

     if (usrptr->flags&BYEBYE) {   /* if status(es) leaked in after caling */
          return(1);               /* byenow(), just ignore them...        */
     }
     setmbk(supmb);
     if (!(*alwsup)()) { // oops, we're full - someone beat user to last seat
          byenow(OOPSFUL);
          return(1);
     }
     bgncnc();
     switch (newstt=usrptr->substt) {
     case 0:
#ifdef STARTER
          dfaSetBlk(accbb);
          if (dfaCountRec() >= MAXSUSER) {
               catastro("Worldgroup Starter permits only %d user accounts.\n"
                        "If you would like to upgrade and take full advantage of\n"
                        "Worldgroup's capabilities, call 1-800-328-1128.",MAXSUSER);
          }
          dfaRstBlk();
#endif // STARTER
          supdfts();
          btutsw(usrnum,usaptr->scnwid);
          setmem(usaptr->userid,UIDSIZ,0);
          setmem(supptr,sizeof(struct supvda),0);
          rstrxf();
          prfmsg(INTRO2);
          if (strlen(prfbuf) < 40) {
               stpans(prfbuf);
               depad(cp=skpwht(prfbuf));
               if (*cp == '$' && opnans(cp+1)) {
                    newstt=1;
                    clrprf();
                    break;
               }
               clrprf();
               prfmsg(INTRO2);
          }
          nxtask();
          break;
     case 1:                       /* aborting the displayed intro file    */
          clfile();
          cntsup();
          if (*nxtcmd == '\0' || usrptr->substt != GASKANS) {
               break;
          }
     case LAFOOT:
          if (morcnc() == '?') {
               prfmsg(LAHEAD);
               lnglist(1);
               lngfoot(1);
          }
          else if ((intguy=cnclng()) != -1) {
               if (isripu() && !samend(languages[intguy]->name,RIPSFX)
                   && sndrst) {
                    prf("\r!%s%s\r",RIP_RESET_WINDOWS,RNMOR3);
               }
               clingo=usrptr->lingo=intguy;
               rstrxf();
               savit=asktbl[TBLANS][0];
               if (!samend(languages[clingo]->name,"/ANSI")) {
                    asktbl[TBLANS][0]=0;
               }
               nxtask();
               asktbl[TBLANS][0]=savit;
          }
          else {
               lngfoot(1);
          }
          break;
     case GASKANS:
          if ((c=cncyesno()) != 'Y' && c != 'N') {
               btuclo(usrnum);
               prfmsg(GASKANS);
               sndans();
               cncall();
               break;
          }
          else if (c == 'Y' && !(usaptr->ansifl&ANSON)) {
               usaptr->ansifl=ANSON+ANSMAN;
               stansi();
          }
          else if (c == 'N' && usaptr->ansifl&ANSON) {
               usaptr->ansifl=ANSMAN;
               stansi();
          }
          cncall();
          prfmsg(ANSDEP);
          nxtask();
          break;
     case GUSRNAM:
          minID=(namdft == 1 || namdft == 2 ? minuid : 5);
          if (uinfok(GUSRNAM,minID,NADSIZ,usaptr->usrnam)) {
               if (namdft == 1 && !hdlok(usaptr->usrnam)) {
                    clrprf();
                    prfmsg(BADNAM);
                    prfmsg(GUSRNAM);
               }
               else {
                    clrprf();
                    nxtask();
               }
          }
          break;
     case GUSRAD1:
          if (uinfok(GUSRAD1,0,NADSIZ,usaptr->usrad1)) {
               nxtask();
          }
          break;
     case GUSRAD2:
          if (uinfok(GUSRAD2,5,NADSIZ,usaptr->usrad2)) {
               nxtask();
          }
          break;
     case GUSRAD3:
          if (uinfok(GUSRAD3,5,NADSIZ,usaptr->usrad3)) {
               nxtask();
          }
          break;
     case GUSRAD4:
          if (uinfok(GUSRAD4,0,NADSIZ,usaptr->usrad4)) {
               nxtask();
          }
          break;
     case GUSRPHO:
          if (uinfok(GUSRPHO,7,PHOSIZ,usaptr->usrpho)) {
               nxtask();
          }
          break;
     case GSYSTYP2:
          if (unumok(GSYSTYP2,0,3,&intguy)) {
               usaptr->systyp=intguy;
               nxtask();
          }
          break;
     case GBDAY2:
          if (udatok(GBDAY2,usaptr->birthd)) {
               usaptr->age=calcage(usaptr->birthd);
               nxtask();
          }
          break;
     case GSEX:
          if (usexok()) {
               nxtask();
          }
          break;
     case GUSENAM:
          if (cncyesno() == 'Y') {
               prfmsg(PSWIRON,usaptr->userid);
               prfmsg(newstt=GPSWORD1);
               btumil(usrnum,PSWSIZ-1);
               echsec(secchr,PSWSIZ-1);
          }
          else {
               nxtask();
          }
          cncall();
          break;
     case PREUID:
     case GUSERID:
          if (hdlok(input)) {
               prfmsg(newstt=UIDOK,usaptr->userid);
               btumil(usrnum,3);
          }
          break;
     case UIDOK:
          if (cncyesno() == 'Y') {
               prfmsg(PSWIRON,usaptr->userid);
               prfmsg(newstt=GPSWORD1);
               btumil(usrnum,PSWSIZ-1);
               echsec(secchr,PSWSIZ-1);
          }
          else {
               prfmsg(newstt=GUSERID);
               btumil(usrnum,sgnusz);
          }
          cncall();
          break;
     case GPSWORD1:
          if (uinfok(GPSWORD1,minpwd,PSWSIZ,usaptr->psword)) {
               if (safpsw || valpsw(usaptr->psword)) {
                    prfmsg(newstt=GPSWORD2);
               }
               else {
                    prfmsg(BADPSW1);
                    prfmsg(GPSWORD1);
               }
          }
          break;
     case GPSWORD2:
          if (uinfok(GPSWORD2,minpwd,PSWSIZ,temp)) {
               if (sameas(usaptr->psword,temp)) {
                    prfmsg(newstt=PSWEPI3);
                    echon();
                    btuech(usrnum,0);
               }
               else {
                    prfmsg(BADPSW2);
                    prfmsg(newstt=GPSWORD1);
               }
          }
          break;
     case PSWEPI3:
          echon();
          savusr(supptr->answers[0]);
          prfmsg(newstt=WELCOME);
          supptr->insstt=0;
          btuinj(usrnum,CYCLE);
          break;
     case WELCOME:
          if (supptr->insstt == DUNINS) {
               usrptr->usetmr=0;
               usrptr->usrcls=ACTUSR;
               tmendsup();
               if (imbump(0)) {
                    usrptr->usrcls=SUPIPG;
                    return(1);
               }
               btumil(usrnum,DFTIMX);
               return(0);
          }
          return(1);
     default:
          if (!supques()) {
               newstt=SUPQS1;
               nxtask();
          }
     }
     if (newstt != GASKANS) {
          btuclo(usrnum);
     }
     outprf(usrnum);
     usrptr->substt=newstt;
     return(1);
}

VOID
supdfts(VOID)
{
     usaptr->scnwid=80;
     usaptr->scnfse=usaptr->scnbrk=24;
     if (dftedt) {
          usaptr->usrprf|=PRFLIN;
     }
}

VOID
supcyc(VOID)                       /* handle a CYCLE while signing up      */
{
     switch (usrptr->substt) {
     case 1:
          if (!rdfile()) {
               cntsup();
          }
          break;
     case WELCOME:
          supptr->insstt=morsup(supptr->insstt);
          btuinj(usrnum,supptr->insstt == DUNINS ? CRSTG : CYCLE);
          break;
     }
}

static VOID
tmabosup(                          /* terminal-mode abort-signup           */
INT supstt)
{
     while (supstt != DUNINS) {
          supstt=morsup(supstt);
     }
     tmendsup();
}

static VOID
tmendsup(VOID)                     /* terminal-mode end-of-signup          */
{
     if (supptr->dunend) {
          return;
     }
     supptr->dunend=1;
     endsup();
}

VOID
suphup(VOID)                       /* hdl a lost carrier while signing up  */
{
     switch (usrptr->substt) {
     case 1:
          clfile();
          break;
     case WELCOME:
          tmabosup(supptr->insstt);
          break;
     }
}

static INT
hdlok(                             /* is inputted handle ok?               */
CHAR *stg)
{
     INT errn;
     static INT baduid[]={NAAUID,PL1UID,PL2UID,PL3UID,SMLUID2,BIGUID,UIDINU};

     switch (errn=valuid(stg)) {
     case 0:
          stzcpy(usaptr->userid,stg,UIDSIZ);
          return(1);
     case 1:
     case 2:
     case 3:
     case 4:
          prfmsg(baduid[errn-1]);
          break;
     case 5:
          prfmsg(baduid[errn-1],minuid);
          break;
     case 6:
          prfmsg(baduid[errn-1],sgnusz);
          break;
     case 7:
          prfmsg(baduid[errn-1],stg);
          break;
     }
     prfmsg(GUSERID);
     return(0);
}

INT
valuid(
CHAR *stg)
{
     CHAR *inpptr;
     INT space=0,len,retval;

     len=strlen(stg);
     for (inpptr=stg ; issupc(*inpptr) ; inpptr++) {
          if (*inpptr == ' ') {
               if (space) {
                    break;
               }
               space=1;
          }
          else {
               space=0;
          }
     }
     if (*inpptr != '\0' || isspace(stg[0]) || ispunct(stg[0])) {
          retval=1;
     }
     else if (pfnlvl != 0) {
          retval=1+pfnlvl;
     }
     else if (sameas(stg,"new") || sameas(stg,"the")
      || sameas(stg,"off") || sameas(stg,"all")) {
          retval=2;
     }
     else if (len < minuid) {
          retval=5;
     }
     else if (len > sgnusz) {
          retval=6;
     }
     else {
          makhdl(stg);
          dfaSetBlk(accbb);
          if (!(*chkauid)(stg) || dfaQueryEQ(stg,0) || onbbs(stg,1)) {
               retval=7;
          }
          else {
               retval=0;
          }
     }
     return(retval);
}

INT
uinfok(                                 /* enter a user-information string */
INT pmtmsn,
INT minlen,
INT maxsiz,
CHAR *stgptr)
{
     INT len;

     stripb(nxtcmd);
     if ((len=strlen(nxtcmd)) >= minlen) {
          if (len >= maxsiz) {
               prfmsg(TOOBIG,maxsiz-1);
          }
          else if (pfnlvl > 1 && usrptr->substt != GPSWORD1
            && usrptr->substt != GPSWORD2) {
               prfmsg(UINPFN);
          }
          else {
               strcpy(stgptr,cncall());
               return(1);
          }
     }
     prfmsg(pmtmsn);
     return(0);
}

INT
unumok(pmtmsn,minnum,maxnum,number)     /* enter a user-information number */
INT pmtmsn,minnum,maxnum,*number;
{
     INT val;

     if (isdigit(*nxtcmd) && (val=atoi(cncall())) >= minnum && val <= maxnum) {
          *number=val;
          return(1);
     }
     prfmsg(NUMOOR,minnum,maxnum);
     prfmsg(pmtmsn);
     return(0);
}

INT
udatok(                                 /* check to make sure date is ok   */
INT pmtmsn,
CHAR *stgptr)
{

     stripb(nxtcmd);
     if (okbday(nxtcmd)) {
          strcpy(stgptr,cncall());
          return(1);
     }
     prfmsg(pmtmsn);
     return(0);
}

INT
okbday(                            /* is this a valid birthday?            */
CHAR *stg)                         /*   date str buffer (must be DATSIZ)   */
{
     CHAR *ptr;
     INT mon,day,year,i;
     CHAR strMonth[3],strDay[3],strYear[5];

     if (alldgs(stg)) {
          i=strlen(stg);
          if (i != CSTRLEN("MMDDYY") && i != CSTRLEN("MMDDYYYY")) {
               return(0);
          }
          ptr=stg;
          strMonth[0]=*ptr++;
          strMonth[1]=*ptr++;
          strMonth[2]='\0';
          strDay[0]=*ptr++;
          strDay[1]=*ptr++;
          strDay[2]='\0';
          stlcpy(strYear,ptr,sizeof(strYear));
          mon=atoi(strMonth);
          day=atoi(strDay);
          year=atoi(strYear);
     }
     else {
          for (i=0 ; stg[i] != '\0' ; ++i) {
               if (!isdigit(stg[i])) {
                    stg[i]='/';
               }
          }
          if (sscanf(stg,"%d/%d/%d",&mon,&day,&year) != 3) {
               return(0);
          }
     }
     if (year < 100) {
          year+=1900;
     }
     if (!validDate(year,mon,day) || year >= ddyear(today())) {
          return(0);
     }
     sDateEncode(year,mon,day,stg,DATSIZ);
     return(1);
}

INT
calcage(                           /* compute age (in years) as of today   */
const CHAR *birthd)                /*   birth date (YYYYMMDD or MM/DD/YY)  */
{
     INT m,d,y,age;
     USHORT dosDate;
     CHAR strDate[DATSIZ];

     stlcpy(strDate,birthd,DATSIZ);
     fixBirthdate(strDate);
     sDateDecode(strDate,&y,&m,&d);
     if (y < 0 || m < 0 || d < 0) {
          return(0);
     }
     dosDate=today();
     age=ddyear(dosDate)-y;
     if (ddmon(dosDate) < m || (ddmon(dosDate) == m && ddday(dosDate) < d)) {
          --age;
     }
     return(age);
}

GBOOL                              /*   returns TRUE if modified           */
fixBirthdate(                      /* fix date from MM/DD/YY to YYYYMMDD   */
CHAR *strDate)                     /*   birth date string (must be DATSIZ) */
{
     INT m,d,y;

     ASSERT(strDate != NULL);
     if (!alldgs(strDate)
      && sscanf(strDate,"%d/%d/%d",&m,&d,&y) == 3) {
          y+=1900;
          sDateEncode(y,m,d,strDate,DATSIZ);
          return(TRUE);
     }
     return(FALSE);
}

const CHAR *                       /*   returns pointer to static buffer   */
strBirthdate(                      /* format birthdate into "MM/DD/YYYY"   */
const CHAR *strDate)               /*   birth date string                  */
{
     INT y,m,d;
     static CHAR retBuf[LDATSIZ];

     ASSERT(strDate != NULL);
     fixBirthdate(stlcpy(retBuf,strDate,DATSIZ));
     sDateDecode(retBuf,&y,&m,&d);
     if (y < 0 || m < 0 || d < 0) {
          return("");
     }
     return(prnDate(y,m,d,retBuf,LDATSIZ,PRND_MDYY,'/'));
}

INT
usexok(VOID)                       /* check for "ok" sex                   */
{
     CHAR c;

     c=cncchr();
     cncall();
     if (margc != 0) {
          if (c == 'M' || c == 'F') {
               usaptr->sex=c;
               return(1);
          }
          prfmsg(MRFPLS);
     }
     prfmsg(GSEX);
     return(0);
}

VOID
lnglist(                /* show a numbered list of languages to choose from */
INT all)                     /* 1=all languages, 0=only top poslng[] values */
                                               /* 2=all languages plus AUTO */
{
     INT i,lngchc;

     setmbk(supmb);
     cntcand();
     for (i=lngchc=0 ; i < nlingo ; i++) {
          if (all != 0 || poslng[usrnum*nlingo+i] == maxcand) {
               prfmsg(LALINE,++lngchc,languages[i]->name,
                                      languages[i]->desc);
          }
     }
     if (all == 2) {
          prfmsg(LAAUTO);
     }
     rstmbk();
}

VOID
lngfoot(                                    /* show footer of language list */
INT all)                     /* 1=all languages, 0=only top poslng[] values */
                                               /* 2=all languages plus AUTO */
{
     setmbk(supmb);
     if (all != 0) {
          numcand=nlingo;
     }
     else {
          cntcand();
     }
     prfmsg(all == 2 ? LAFOOTA : LAFOOT,numcand);
     rstmbk();
}

VOID
stripb(                            /* "strip" blank spaces after input     */
CHAR *stg)
{
     depad(stg);
     if (stg == input) {
          inplen=strlen(input);
     }
}

VOID
makhdl(                            /* "make handle" for use w/ Btrieve     */
CHAR *stg)
{
     stripb(stg);
     zonkhl(stg);
}

VOID
zonkhl(                            /* "zonk" string for use w/ Btrieve     */
CHAR *stg)
{
     CHAR *inpptr;
     INT space=1,format;

     format=isuplo(stg);
     for (inpptr=stg ; *inpptr != '\0' ; inpptr++) {
          if (format) {
               if (*inpptr == ' ') {
                    space=1;
               }
               else if (space) {
                    *inpptr=toupper(*inpptr);
                    space=0;
               }
               else {
                    *inpptr=tolower(*inpptr);
               }
          }
     }
     while (++inpptr-stg < UIDSIZ) {
          *inpptr='\0';
     }
}

INT
isuplo(
CHAR *stg)
{
     CHAR *ptr;

     for (ptr=stg ; *ptr != '\0' ; ptr++) {
          if (isalpha(*ptr) && !islower(*ptr)) {
               break;
          }
     }
     if (*ptr == '\0') {
          return(1);
     }
     for (ptr=stg ; *ptr != '\0' ; ptr++) {
          if (isalpha(*ptr) && !isupper(*ptr)) {
               break;
          }
     }
     if (*ptr == '\0') {
          return(1);
     }
     return(0);
}

INT
loadup(VOID)                       /* load up an ASCII/ANSI user's account */
{
     CHAR temp;

     rstrin();
     makhdl(input);
     temp=usaptr->ansifl;
     if (loadacc(input)) {
          btutsw(usrnum,usaptr->scnwid);
          if (usaptr->scnbrk == 0) {
               usaptr->scnbrk=24;
          }
          dftans(temp);
          stansi();
          rstrxf();
          return(1);
     }
     setmem(usaptr,sizeof(struct usracc),0);
     usaptr->ansifl=temp;
     return(0);
}

VOID
dftans(                            /* default ANSI setting                 */
CHAR dft)                         /*   ...to this                         */
{
     if (!(usaptr->ansifl&ANSMAN)) {
          accacct(usaptr,-1);
          usaptr->ansifl=dft;
          accacct(usaptr,1);
     }
}

GBOOL
loadacc(                           /* load up a user's account record      */
const CHAR *userid)
{
     dfaSetBlk(accbb);
     if (dfaAcqEQ(usaptr,userid,0) && !(usaptr->flags&DELTAG)) {
          if ((usrptr->cltptr=fndcls(usaptr->curcls)) == NULL) {
               delacct(usaptr->userid);
          }
          else {
               if (usrptr->keys != NULL) {
                    free(usrptr->keys);
                    usrptr->keys=NULL;
               }
               loadkeys(usaptr->curcls);
               fixBirthdate(usaptr->birthd);
               return(TRUE);
          }
     }
     return(FALSE);
}

VOID
shwusr(                            /* display's a user's account info      */
struct usracc *usaptr)
{
     INT msgnum=SOPINFN5;
     CHAR buf[LDATSIZ];
     struct clstab *tabptr;

     setmbk(supmb);
     strcpy(buf,ncdatel(usaptr->usedat));
     if (detflg) {
          msgnum=SOPINFN6;
          detflg=0;
     }
     if ((tabptr=fndcls(usaptr->curcls)) == NULL) {
          prfmsg(SOPINFN1,usaptr->userid,
                  ncdatel(usaptr->credat),
                  buf,
                  usaptr->curcls,
                  "<class deleted -- will be deleted at cleanup>",
                  "<class deleted -- will be deleted at cleanup>",
                  "<class deleted -- will be deleted at cleanup>",
                  usaptr->usrnam,usaptr->usrad1,usaptr->usrad2,usaptr->usrad3);
          prfmsg(msgnum,usaptr->usrad4,usaptr->usrpho,
                 sysstg[(SHORT)usaptr->systyp],ansstg[(SHORT)usaptr->ansifl],
                 usaptr->scnwid,usaptr->scnbrk == CTNUOS ? "(continuous)"
           : spr("%d",usaptr->scnbrk),
                 (usaptr->usrprf&PRFLIN) ? "LINE" : "FSE",
                 strBirthdate(usaptr->birthd),
                 usaptr->sex,
                 (vispsw ? usaptr->psword
            : "<not displayed, for security reasons>"),
                 spr(usaptr->creds > 0L ? "+%ld" : "%ld",usaptr->creds),
           "","");
     }
     else {
          prfmsg(SOPINFN1,usaptr->userid,
                 ncdatel(usaptr->credat),
                 buf,
                 usaptr->curcls,
                 tabptr->limcal != -1 ? spr("%d minutes",tabptr->limcal)
                                        : "UNLIMITED",
                 tabptr->limday != -1 ? spr("%d minutes",tabptr->limday)
                                        : "UNLIMITED",
                 (tabptr->flags&DAYEXP) ? spr("%d",usaptr->daystt)
                                          : "UNLIMITED",
                 usaptr->usrnam,usaptr->usrad1,usaptr->usrad2,usaptr->usrad3);
          prfmsg(msgnum,usaptr->usrad4,usaptr->usrpho,
                 sysstg[(SHORT)usaptr->systyp],ansstg[(SHORT)usaptr->ansifl],
                 usaptr->scnwid,usaptr->scnbrk == CTNUOS ? "(continuous)"
                                                           : spr("%d",usaptr->scnbrk),
                 (usaptr->usrprf&PRFLIN) ? "LINE" : "FSE",
                 strBirthdate(usaptr->birthd),
                 (usaptr->sex == '\0' ? ' ' : usaptr->sex),
                 (vispsw ? usaptr->psword : "<not displayed, for security reasons>"),
                 spr(usaptr->creds > 0L ? "+%ld" : "%ld",usaptr->creds),
                 tabptr->dbtlmt == -1L ? " (No bottom limit)"
                 : tabptr->dbtlmt > 0L ? spr(" (Bottom limit: -%ld)",
                              tabptr->dbtlmt) : "",
                 (tabptr->flags&CRDXMT) ?  " (Exempt from charges)" : "");
     }
     rstmbk();
}

VOID
finsup(VOID)                       /* close signup files for shutdown      */
{
     clsmsg(supmb);
}

static INT
supques(VOID)                 /* get answers for supplemental questions    */
{
     if (newstt >= SUPQS1 && newstt <= SUPQ10) {
          strcpy(supptr->answers[newstt-SUPQS1],cncall());
          if (supptr->answers[newstt-SUPQS1][0] != '\0'
           && (newstt == SUPQ10 || *(getmsg(++newstt)) == '\0')) {
               prfmsg(SUPEND);
               return(0);
          }
          prfmsg(newstt);
     }
     return(1);
}

VOID
savusr(                            /* save new user info to text file      */
CHAR *answers0)                    /*   pointer to first of add. ans. stgs */
{
     INT i;

     if (!savinf && *answers0 == '\0') {
          return;
     }
     if ((suptxt=fopen("wgssup.txt",FOPAA)) == NULL) {
          shocst("CAN'T EXPORT SIGNUPS TO TEXT!",
                 "(ERROR: Can't open \"WGSSUP.TXT\" for updating!)");
          return;
     }
     if (supfrm) {
          fprintf(suptxt,"%-11s",ncdatel(today()));
          fprintf(suptxt,"%-9s",nctime(now()));
          fprintf(suptxt,"%-29s",usaptr->userid);
          if (savinf) {
               fprintf(suptxt,"%-29s",usaptr->usrnam);
               fprintf(suptxt,"%-29s",usaptr->usrad1);
               fprintf(suptxt,"%-29s",usaptr->usrad2);
               fprintf(suptxt,"%-29s",usaptr->usrad3);
               fprintf(suptxt,"%-29s",usaptr->usrad4);
               fprintf(suptxt,"%-15s",usaptr->usrpho);
               fprintf(suptxt,"%-3d",usaptr->systyp);
               fprintf(suptxt,"%-3d",usaptr->scnwid);
               fprintf(suptxt,"%-3d",usaptr->scnbrk);
               fprintf(suptxt,"%-11s",strBirthdate(usaptr->birthd));
               fprintf(suptxt,"%c",usaptr->sex == '\0' ? ' ' : usaptr->sex);
          }
          if (*answers0 != '\0') {
               for (i=0 ; i < NMQSTS ; i++) {
                    fprintf(suptxt,"%-79s",answers0+ANSSIZ*i);
               }
          }
     }
     else {
          fprintf(suptxt,"------------------------------------------"
                         "-------------------------------------\n\n");
          fprintf(suptxt,"User-ID:  %-29s   Date:  %-10s  Time:  %-8s\n\n",
                         usaptr->userid,ncdatel(today()),nctime(now()));
          if (savinf) {
               fprintf(suptxt,"Address:  %-29s   Name:  %-29s\n",
                              usaptr->usrad1,usaptr->usrnam);

               fprintf(suptxt,"          %-29s  Phone:  %-15s\n",
                              usaptr->usrad2,usaptr->usrpho);
               fprintf(suptxt,"          %-29s   Born:  %-10s\n",
                              usaptr->usrad3,strBirthdate(usaptr->birthd));
               fprintf(suptxt,"          %-29s\n",usaptr->usrad4);
               fprintf(suptxt," System type:  %-24s    Sex:  %c\n",
                              sysstg[(SHORT)usaptr->systyp],
                              usaptr->sex == '\0' ? ' ' : usaptr->sex);
               fprintf(suptxt,"Screen width:  %-24d Length:  %-3d\n",
                              usaptr->scnwid,usaptr->scnbrk);
          }
          if (*answers0 != '\0') {
               if (savinf) {
                    fprintf(suptxt,"\n");
               }
               fprintf(suptxt,"Answers to additional signup questions:\n\n");
               for (i=0 ; i < NMQSTS ; i++) {
                    if (*(answers0+ANSSIZ*i) == '\0') {
                         break;
                    }
                    fprintf(suptxt,"%s\n",answers0+ANSSIZ*i);
               }
          }
     }
     fprintf(suptxt,"\n");
     fclose(suptxt);
}

static VOID
sndans(VOID)                       /* send ANSI stuff (even if ANSI is off)*/
{
     CHAR *base,*ptr,savchr;

     base=ptr=prfbuf;
     while (*ptr != '\0') {
          if (*ptr == ESC) {
               savchr=*++ptr;
               *ptr='\0';
               btuxmt(usrnum,base);
               *(base=ptr)=savchr;
          }
          else {
               ptr++;
          }
     }
     btuxmt(usrnum,base);
     clrprf();
}

GBOOL                              /*   returns TRUE for good password     */
valpsw(                            /* check for valid password             */
CHAR *psw)                         /*   password to be checked             */
{
     return(valupsw(usaptr->userid,psw));
}

GBOOL                              /*   returns TRUE for good password     */
valupsw(                           /* check for valid password             */
CHAR *uid,                         /*   User-ID to check against           */
CHAR *psw)                         /*   password to be checked             */
{
     return(!sameas(uid,psw) && !sameas("PASSWORD",psw));
}

INT
issupc(                                 /* char is a valid signup uid char */
INT c)
{
     switch (c) {
     case '.':
     case ' ':
     case ',':
     case '-':
     case '\'':
          if (fulalw) {
               return(1);
          }
          break;
     default:
          if (isuidc(c) && (digalw || !isdigit(c))) {
               return(1);
          }
     }
     return(0);
}

VOID
cntsup(VOID)                       /* continue signup after intro message  */
{
     newstt=0;
     setmbk(supmb);
     nxtask();
     rstrxf();
     outprf(usrnum);
     usrptr->substt=newstt;
}

/*--- General-purpose signup utilities ---*/

INT
morsup(
INT supstt)
{
     CREATEACCOUNT *vec;
     INT i,n;

     setmbk(supmb);
     switch (supstt) {
     case SUPBEG:
          if (asktbl[TBLLNG][0]) {
               getgen(&genbuf,usaptr->userid);
               strcpy(genbuf.lngnam,languages[clingo]->name);
               setgen(&genbuf);
          }
          supstt=SUPKEYS;
          break;
     case SUPKEYS:
          nkyrec(usaptr->userid);
          supstt=SUPACCT;
          break;
     case SUPACCT:
          usaptr->usedat=usaptr->credat=today();
          strcpy(usaptr->curcls,getmsg(SUPCLS));
          if ((clsptr=fndcls(usaptr->curcls)) != NULL) {
               if (fresup > 0L && (clsptr->flags&HASCRD)) {
                    strcpy(usaptr->curcls,clsptr->nxtcls[DCREDIT]);
                    if ((clsptr=fndcls(usaptr->curcls)) != NULL) {
                         clsptr->users++;
                    }
               }
               else {
                    clsptr->users++;
               }
               if (clsptr != NULL && (clsptr->flags&DAYEXP)) {
                    usaptr->daystt=clsptr->dftday;
               }
          }
          usaptr->fgvdys=0;
          strcpy(usaptr->prmcls,usaptr->curcls);
          dfaSetBlk(accbb);
          dfaInsert(usaptr);
          usaptr->usedat=0;
          supstt=SUPXREF;
          break;
     case SUPXREF:
          addxrf(usaptr->userid);
          supstt=SUPCLASS;
          break;
     case SUPCLASS:
          if ((usrptr->cltptr=fndcls(usaptr->curcls)) == NULL) {
               catastro("BAD CLASS IN SIGNUP OPTION SUPCLS");
          }
          else {
               loadkeys(usaptr->prmcls);
          }
          if (sgnaud) {
               shocst("NEW USER SIGNUP","New User-ID: %s",usaptr->userid);
          }
          supstt=SUPMAIL;
          break;
     case SUPMAIL:
          if (emlsdrou != NULL) {
               (*emlsdrou)();
          }
          supstt=SUPHOOKS;
          break;
     default:
          if (supstt >= SUPHOOKS) {
               i=supstt-SUPHOOKS;
               n=ninarr(hCreateAcctVecs);
               if (i < n) {
                    vec=*(CREATEACCOUNT **)arrelem(hCreateAcctVecs,i);
                    BEG_PHASE("Signup hook",vec);
                    (*vec)(usaptr);
                    END_PHASE("Signup hook",0);
                    ++supstt;
                    if (supstt-SUPHOOKS < n) {
                         break;
                    }
               }
          }
          ASSERT(supstt-SUPHOOKS == ninarr(hCreateAcctVecs));
          supstt=DUNINS;
          break;
     }
     return(supstt);
}

VOID
abosup(
INT supstt)
{
     while (supstt != DUNINS) {
          supstt=morsup(supstt);
     }
     endsup();
}

VOID
endsup(VOID)
{
     belper(sgnbel);
     printf("\7");
     accacct(usaptr,1);
     if (fresup > 0L) {
          addcrd(usaptr->userid,l2as(fresup),0);
     }
     doaditbx();
}
