/***************************************************************************
 *                                                                         *
 *   BBSIGNUP.C                                                            *
 *                                                                         *
 *   Copyright (c) 1993 Consensus Systems, Inc.  All rights reserved.      *
 *   Copyright (c) 1993-1997 Galacticomm, Inc.   All rights reserved.      *
 *                                                                         *
 *   This is the Galacticomm Client/Server signup agent.                   *
 *                                                                         *
 *                                              - T. Stryker 11/26/93      *
 *                                                C. Robert                *
 *                                                B. Love                  *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "majorbbs.h"
#include "gcspsrv.h"
#include "wgsignup.h"
#include "wgssup.h"

#define FILREV "$Revision: 25 $"

#define  NMQSTS    10              /* # of possible addtn'l signup ques    */
#define  ANSSIZ    80              /* size of each free-form signup answer */
#define  MXASLN    (NMQSTS*(ANSSIZ-1)) /* max len of add sup ans stg fm cli*/
#define  QSFXSZ    4               /* sz of suffix info on sup ques stg    */
#define  MXPRT1    8               /* max # of ques can fit into 1 dpk     */

struct supcfg {                    /* signup config info                   */
     GBOOL asknam;                 /*   ask name?                          */
     GBOOL askcom;                 /*   ask company?                       */
     GBOOL askadr;                 /*   ask address?                       */
     GBOOL askpho;                 /*   ask phone number?                  */
     GBOOL asksys;                 /*   ask system type?                   */
     GBOOL askbdy;                 /*   ask birthday?                      */
     GBOOL asksex;                 /*   ask sex?                           */
     SHORT nmasup;                 /*   # of addtn'l signup ques. (0=none) */
     SHORT sgnusz;                 /*   max size of userids                */
     GBOOL digalw;                 /*   allow digits in userids?           */
     GBOOL fulalw;                 /*   allow space and punc in userids?   */
     SHORT namdft;                 /*   how do we handle signups?          */
} supcfg;                          /* info to send to client               */

struct flddef supcfgFDA[] = {
     { CVTFLD_SHORT,12,fldoff(supcfg,asknam),NULL },
     { CVTFLD_END  ,0 ,0                    ,NULL }
};

struct supdat {                    /* new user signup data sent by client  */
     CHAR userid[UIDSIZ-1];        /*   userid                             */
     CHAR psword[PSWSIZ-1];        /*   password                           */
     CHAR usrnam[NADSIZ-1];        /*   name                               */
     CHAR usrad1[NADSIZ-1];        /*   address line 1 (company)           */
     CHAR usrad2[NADSIZ-1];        /*   address line 2                     */
     CHAR usrad3[NADSIZ-1];        /*   address line 3                     */
     CHAR usrad4[NADSIZ-1];        /*   address line 4                     */
     CHAR usrpho[PHOSIZ-1];        /*   phone number                       */
     SHORT systyp;                 /*   system type code                   */
     SHORT sex;                    /*   sex                                */
     CHAR birthd[DATSIZ-1];        /*   birthdate (string or double)       */
};

struct flddef supdatFDA[]={
     {CVTFLD_RTEXT,UIDSIZ-1+PSWSIZ-1+(NADSIZ-1)*5+PHOSIZ-1,0,NULL},
     {CVTFLD_SHORT,2       ,fldoff(supdat,systyp),           NULL},
     {CVTFLD_CHAR ,DATSIZ-1,fldoff(supdat,birthd),           NULL},
     {CVTFLD_END  ,0       ,0,                               NULL}
};

static VOID supread(INT direction,struct saunam *dpknam);
static VOID supwrite(struct saunam *dpknam,USHORT length,VOID *value);
static VOID supxdone(VOID);
static VOID supabort(VOID);

VOID savusr(CHAR *answers0);

struct agent supagt={              /* agent information structure          */
     "WGSIGNUP",                   /*   appid                              */
     supread,                      /*   read-dynapak function pointer      */
     supwrite,                     /*   write-dynapak function pointer     */
     supxdone,                     /*   file xfer-done function pointer    */
     supabort                      /*   abort-request function pointer     */
};

static
HMCVFILE bbsupmb;                  /* agent message block pointer          */

static
CHAR *supstg1=NULL,                /* stg to store add. signup questions   */
     *supstg2=NULL,                /* extra stg for add. signup questions  */
     answers[NMQSTS][ANSSIZ],      /* ans's to addtn'l signup questions    */
     quesep[]={9,'\0'};            /* ques delimiter in sup ques string    */

static
INT lsqlingo=-1;                   /* last lang used for signup ques stgs  */

IMPORT_VARIABLE(INT) supfrm;       /* format output in fixed-length ASCII? */

struct suprqi {                    /* signup per-request information       */
     SHORT insstt;                 /*   insacc() state for finalization    */
};

#define rqiptr ((struct suprqi *)mrqptr)

static VOID getsups(VOID);
static GBOOL goodsd(struct supdat *supdat);
static INT  valinf(CHAR *infstg,UINT minlen,GBOOL chkpfn);
static VOID insacc(VOID);
static VOID supfin(VOID);

VOID EXPORT
init__wgsignup(VOID)               /* agent initialization routine         */
{
     INT msgnum=SUPQS1;


     register_agent(&supagt);
     dclmrq(sizeof(struct suprqi));
     bbsupmb=opnmsg("wgsignup.mcv");
     register_dpkfda("WGSIGNUP","sa:supdat",supdatFDA);
     supcfg.asknam=(asktbl[TBLNAM][0] ? VBTRUE : FALSE);
     supcfg.askcom=(asktbl[TBLAD1][0] ? VBTRUE : FALSE);
     supcfg.askadr=(asktbl[TBLAD2][0] ? VBTRUE : FALSE);
     supcfg.askpho=(asktbl[TBLPHO][0] ? VBTRUE : FALSE);
     supcfg.asksys=(asktbl[TBLSYS][0] ? VBTRUE : FALSE);
     supcfg.askbdy=(asktbl[TBLBDY][0] ? VBTRUE : FALSE);
     supcfg.asksex=(asktbl[TBLSEX][0] ? VBTRUE : FALSE);
     setmbk(supmb);
     for (supcfg.nmasup=0 ; msgnum <= SUPQ10 ; supcfg.nmasup++,msgnum++) {
          if (*(getmsg(msgnum)) == '\0') {
               break;
          }
     }
     rstmbk();
     supcfg.sgnusz=sgnusz;
     supcfg.digalw=(digalw ? VBTRUE : FALSE);
     supcfg.fulalw=(fulalw ? VBTRUE : FALSE);
     supcfg.namdft=namdft;
     hook_shutdown(supfin);
}

VOID EXPORT
initwc__wgsignup(VOID)
{
     init__wgsignup();
}

static VOID
getsups(VOID)                      /* assemble add. sup. ques. stgs        */
{
     INT i,lenall=0,len1=0,len2=0,msgnum;
     CHAR *cssuphdr,*cssupend,*csasupq[NMQSTS];

     if (supcfg.nmasup > 0) {
          if (supstg1 != NULL) {
               free(supstg1);
          }
          if (supstg2 != NULL) {
               free(supstg2);
          }
          setmbk(supmb);
          for (i=0,msgnum=SUPQS1 ; i < supcfg.nmasup ; i++,msgnum++) {
               csasupq[i]=stgopt(msgnum);
               stp4cs(csasupq[i]);
               lenall+=strlen(csasupq[i])+1;
          }
          cssuphdr=stgopt(SUPHDR);
          stp4cs(cssuphdr);
          cssupend=stgopt(SUPEND);
          stp4cs(cssupend);
          lenall+=strlen(cssuphdr)+1+strlen(cssupend)+1+QSFXSZ+1;
          if (lenall <= MAXDPKV) {
               supstg1=alczer(lenall);
               strcat(supstg1,cssuphdr);
               strcat(supstg1,quesep);
               for (i=0 ; i < supcfg.nmasup ; i++) {
                    strcat(supstg1,csasupq[i]);
                    strcat(supstg1,quesep);
               }
               strcat(supstg1,cssupend);
               strcat(supstg1,spr("%sn=%d",quesep,supcfg.nmasup));
               supstg2=NULL;
          }
          else {
               for (i=0 ; i < MXPRT1 ; i++) {
                    len1+=strlen(csasupq[i])+1;
               }
               len1+=strlen(cssuphdr)+1+QSFXSZ+1;
               supstg1=alczer(len1);
               strcat(supstg1,cssuphdr);
               strcat(supstg1,quesep);
               for (i=0 ; i < MXPRT1 ; i++) {
                    strcat(supstg1,csasupq[i]);
                    strcat(supstg1,quesep);
               }
               strcat(supstg1,spr("n=%d",MXPRT1));
               for (i=MXPRT1 ; i < supcfg.nmasup ; i++) {
                    len2+=strlen(csasupq[i])+1;
               }
               len2+=strlen(cssupend)+1+QSFXSZ+1;
               supstg2=alczer(len2);
               for (i=MXPRT1 ; i < supcfg.nmasup ; i++) {
                    strcat(supstg2,csasupq[i]);
                    strcat(supstg2,quesep);
               }
               strcat(supstg2,cssupend);
               strcat(supstg2,spr("%sn=%d",quesep,supcfg.nmasup-MXPRT1));
          }
          for (i=0 ; i < supcfg.nmasup ; i++) {
               free(csasupq[i]);
          }
          free(cssuphdr);
          free(cssupend);
          lsqlingo=clingo;
          rstmbk();
     }
}

static VOID
supread(                           /* read-dynapak handler                 */
INT direction,                     /*   read direction: 0=eq, 1=gt, -1=lt  */
struct saunam *dpknam)             /*   dynapak name to read               */
{
     CHAR *dpkstg;

     if (sameas(dpknam->sysid,msysid) && direction == 0 && (*hdlsmp)()) {
          dpkstg=cnvs2d(dpknam);
          if (sameas(dpkstg,"sa:supcfg") && usaptr->userid[0] == '\0') {
#ifdef STARTER
               dfaSetBlk(accbb);
               if (dfaCountRec() == MAXSUSER) {
                    shocst("MAXIMUM USER COUNT REACHED","Delete a user and"
                           " run a cleanup before new users can sign-on");
                    othusn=usrnum;
                    prf("Worldgroup Starter cannot support additional"
                        " users at this time.");
                    injoth();
                    byenow(NO_MESSAGE);
                    rejectreq();
                    dfaRstBlk();
                    return;
               }
               dfaRstBlk();
#endif // STARTER
               rsp2read(NULL,sizeof(struct supcfg),&supcfg,supcfgFDA);
               usrptr->usrcls=SUPIPG;
               usrptr->usetmr=0;
               shochl("Client/server new user logon",'‡',baudat(usrptr->baud,0));
               return;
          }
          if (sameas(dpkstg,"sa:supques1")) {
               if (supcfg.nmasup > 0 && lsqlingo != clingo) {
                    getsups();
               }
               rsp2read(NULL,STGLEN,supstg1,rtextFDA);
               return;
          }
          if (sameas(dpkstg,"sa:supques2")) {
               if (supcfg.nmasup > 0 && lsqlingo != clingo) {
                    getsups();
               }
               rsp2read(NULL,STGLEN,supstg2,rtextFDA);
               return;
          }
     }
     rejectreq();
}

static VOID
supwrite(                          /* write-dynapak handler                */
struct saunam *dpknam,             /*   dynapak name to write              */
USHORT length,                     /*   length of dynapak value            */
VOID *value)                       /*   dynapak value to write             */
{
     CHAR *dpkstg;
     INT i;
     GBOOL vldreq=TRUE;

     setmbk(bbsupmb);
     if (sameas(dpknam->sysid,msysid) && !haskey("") && (*hdlsmp)()) {
          dpkstg=cnvs2d(dpknam);
          if (sameas(dpkstg,"sa:supdat") && length == sizeof(struct supdat)
           && !(usrptr->flags&GCSDUN)) {
               if (!goodsd(value)) {
                    setmem(usaptr,sizeof(struct usracc),0);
                    r2wprf(FALSE);
               }
               else {
                    rsp2write(TRUE,0,NULL,NULL);
               }
               return;
          }
          if (sameas(dpkstg,"sa:supdone") && usaptr->userid[0] != '\0'
           && !(usrptr->flags&GCSDUN)) {
               if (supcfg.nmasup > 0) {
                    if (length < 1 || length > MXASLN) {
                         vldreq=FALSE;
                    }
                    else {
                         for (i=0 ; i < supcfg.nmasup ; i++) {
                              b2ccpy(answers[i],(CHAR *)value+i*(ANSSIZ-1),
                                     ANSSIZ-1);
                         }
                    }
               }
               if (vldreq) {
#ifdef STARTER
                    dfaSetBlk(accbb);
                    if (dfaCountRec() >= MAXSUSER) {
                         rejectreq();
                         dfaRstBlk();
                         return;
                    }
                    dfaRstBlk();
#endif // STARTER
                    savusr(answers[0]);
                    usrptr->flags|=GCSDUN;
                    rqiptr->insstt=1;
                    cycleme(insacc);
                    return;
               }
          }
     }
     rejectreq();
}

static GBOOL
goodsd(                            /* chk signup info, record in usaptr    */
struct supdat *supdat)             /*   info to check                      */
{
     DOUBLE binbdy;
     CHAR *msgptr;
     INT errn,y,m,d;
     CHAR tmpbdy[LDATSIZ];
     static INT baduid[]={CSNAAUID,CSPL1UID,CSPL2UID,CSPL3UID,CSSMLID2,
                          CSBIGUID,CSUIDINU};
     static INT baduin[]={NAAUIN,PL1UIN,PL2UIN,PL3UIN,SMLUIN,BIGUIN,UININU};

     setmem(usaptr,sizeof(struct usracc),0);
     supdfts();
     b2ccpy(usaptr->userid,supdat->userid,UIDSIZ);
     setpfn(usaptr->userid);
     if ((errn=valuid(usaptr->userid)) != 0) {
          prf(namdft == 1 ? "NAM" : "UID");
          msgptr=(namdft != 1 && (errn-1) == 4 ? spr("%d",minuid)
                                               : usaptr->userid);
          prfmsg(namdft == 1 ? baduin[errn-1] : baduid[errn-1],msgptr);
          return(FALSE);
     }
     b2ccpy(usaptr->psword,supdat->psword,PSWSIZ);
     if ((errn=valinf(usaptr->psword,minpwd,FALSE)) != 0) {
          prf("PSW");
          prfmsg(PTOOSML);
          return(FALSE);
     }
     else if (!safpsw && !valpsw(usaptr->psword)) {
          prf("PSW");
          prfmsg(BADPSW);
          return(FALSE);
     }
     if (asktbl[TBLNAM][0]) {
          b2ccpy(usaptr->usrnam,supdat->usrnam,NADSIZ);
          if ((errn=valinf(usaptr->usrnam,minuid,TRUE)) != 0) {
               prf("NAM");
               prfmsg(errn == 1 ? NTOOSML : NPROFAN);
               return(FALSE);
          }
     }
     if (asktbl[TBLAD1][0]) {
          b2ccpy(usaptr->usrad1,supdat->usrad1,NADSIZ);
          if ((errn=valinf(usaptr->usrad1,0,TRUE)) != 0) {
               prf("COM");
               prfmsg(CPROFAN);
               return(FALSE);
          }
     }
     if (asktbl[TBLAD2][0]) {
          b2ccpy(usaptr->usrad2,supdat->usrad2,NADSIZ);
          if ((errn=valinf(usaptr->usrad2,5,TRUE)) != 0) {
               prf("AD1");
               prfmsg(errn == 1 ? A1TOOSML : A1PROFAN);
               return(FALSE);
          }
          b2ccpy(usaptr->usrad3,supdat->usrad3,NADSIZ);
          if ((errn=valinf(usaptr->usrad3,5,TRUE)) != 0) {
               prf("AD2");
               prfmsg(errn == 1 ? A2TOOSML : A2PROFAN);
               return(FALSE);
          }
          b2ccpy(usaptr->usrad4,supdat->usrad4,NADSIZ);
          if ((errn=valinf(usaptr->usrad4,0,TRUE)) != 0) {
               prf("AD3");
               prfmsg(A3PROFAN);
               return(FALSE);
          }
     }
     if (asktbl[TBLPHO][0]) {
          b2ccpy(usaptr->usrpho,supdat->usrpho,PHOSIZ);
          if ((errn=valinf(usaptr->usrpho,7,TRUE)) != 0) {
               prf("PHO");
               prfmsg(errn == 1 ? VTOOSML : VPROFAN);
               return(FALSE);
          }
     }
     if (asktbl[TBLSYS][0]) {
          usaptr->systyp=supdat->systyp;
          if (usaptr->systyp > 3) {
               prf("SYS");
               prfmsg(INVSYS);
               return(FALSE);
          }
     }
     if (asktbl[TBLSEX][0]) {
          usaptr->sex=supdat->sex;
          if (usaptr->sex != 'M' && usaptr->sex != 'F') {
               prf("SEX");
               prfmsg(INVSEX);
               return(FALSE);
          }
     }
     if (asktbl[TBLBDY][0]) {
          ASSERT(sizeof(DOUBLE) == DATSIZ-1);
          memcpy(tmpbdy,supdat->birthd,DATSIZ-1);
          tmpbdy[DATSIZ-1]='\0';
          if (sscanf(tmpbdy,"%d/%d/%d",&m,&d,&y) != 3 || !validDate(y,m,d)) {
               cvtData(tmpbdy,&binbdy,DATSIZ-1,doubleFDA,
                       CVTCLIENT,CVTSERVER,usrnum);
               stlcpy(tmpbdy,v2sdatl(binbdy),LDATSIZ);
          }
          if (!okbday(tmpbdy)) {
               prf("BDY");
               prfmsg(INVBDY);
               return(FALSE);
          }
          stlcpy(usaptr->birthd,tmpbdy,DATSIZ);
          usaptr->age=calcage(usaptr->birthd);
     }
     return(TRUE);
}

static INT
valinf(                            /* check a piece of info                */
CHAR *infstg,                      /*   info to check                      */
UINT minlen,                       /*   minimum required length            */
GBOOL chkpfn)                      /*   check profanity as well?           */
{
     if (strlen(infstg) < minlen) {
          return(1);
     }
     if (chkpfn) {
          setpfn(infstg);
          if (pfnlvl > 1) {
               return(2);
          }
     }
     return(0);
}

static VOID
insacc(VOID)                       /* cycle routine to record new usr info */
{
     INT rc;

     if ((rqiptr->insstt=morsup(rqiptr->insstt)) == DUNINS) {
          usrptr->usrcls=ACTUSR;
          endsup();
          if ((rc=(*hdlbump)(FALSE)) == BMPAOK) {
               usrflags();
               if ((*vallon)()) {
                    rsp2write(TRUE,STGLEN,"Y",NULL);
                    gcsplon();
               }
               else {
                    strins(prfbuf,"N",PFBSIZ);
                    r2wprf(TRUE);
                    setbbye();
               }
          }
          else {
               prf("N");
               setmbk(bbsupmb);
               if (rc != BMPOTH) {
                    prfmsg(IMMEDB);
               }
               r2wprf(TRUE);
               setbbye();
          }
     }
}

static VOID
supxdone(VOID)                     /* file transfer-done handler           */
{
}

static VOID
supabort(VOID)                     /* abort-request handler                */
{
     if (rqiptr->insstt != 0) {
          abosup(rqiptr->insstt);
          byenow(NO_MESSAGE);
     }
}

static VOID
supfin(VOID)                       /* system shutdown hook handler         */
{
     clsmsg(bbsupmb);
}
