/***************************************************************************
 *                                                                         *
 *   GALPNQA.C                                                             *
 *                                                                         *
 *   Copyright (c) 1994-1997 Galacticomm, Inc.   All rights reserved.      *
 *                                                                         *
 *   This is the Galacticomm Client/Server Polls and Questionnaires        *
 *   agent.                                                                *
 *                                                                         *
 *                                                - T. Stark 07/14/94      *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "majorbbs.h"
#include "gme.h"
#include "gcspsrv.h"
#include "galpnq.h"
#include "galpnqh.h"

#define FILREV "$Revision: 15 $"

#define RDPCYC   2                 /* disk accesses/cycle                  */
#define GENQREAD 0                 /* get question, taking poll            */
#define GENQRES  1                 /* get question, view results           */
#define STRTW0   "00/"             /* dir'nl ques reads, start w/ ques 0   */

VOID (*oldModified)(const struct polldata);

struct vbplist *plptr;
struct vbqlist *qlptr;
struct quesdata *qrptr;
struct ansrdata *ansptr;
struct pollstat *statptr;
struct rstat *rsptr;
struct vbpdata *vbpptr;
extern struct cupacomp acompcup;

extern struct polltally tally;

extern HMCVFILE polmb;      /* message block file handle            */

extern DFAFILE* sbb;       /* user stat file pointer               */
extern DFAFILE* pbb;       /* master data file pointer             */
extern DFAFILE* qbb;       /* question data file pointer           */
extern DFAFILE* abb;       /* answer data file pointer             */
extern DFAFILE* tbb;       /* tally data file buffer pointer       */
extern struct ansrcomp acomp;  /* answer composite key structure       */
extern struct statcomp scomp;  /* user stat composite key structure    */
extern struct quescomp qcomp;  /* question data structure              */
extern struct gcspoll* gcsp;   /* poll tracking information structure  */

extern CHAR* poledit;

LONG *apolpos=NULL;    /* array of file positions of polls to be announced */

INT *annoidx,                      /* per-user index for announcing polls  */
    nanno=0;                       /* number of polls to be announced      */

struct polldata curpdata;          /* current poll data being worked with  */

static VOID polannou(VOID);

VOID                               /* NOTE: called from GALP&Q.C           */
inicspq(VOID)                      /* initialize C/S P&Qs                  */
{
     annoidx=(INT *)alczer(nterms*sizeof(INT));
     dfaSetBlk(pbb);
     setmem(&curpdata,sizeof(struct polldata),0);
     while (dfaAcqGT(&curpdata,curpdata.pname,0)) {
          if (curpdata.priority != SKIP) {
               addpanno(dfaAbs());
          }
     }
}

VOID
addpanno(         /* record poll's position, create announce vector for it */
LONG pollpos)                      /*   poll's data file position          */
                                   /* implicit outputs: nanno, apolpos[]   */
{
     INT i;
     GBOOL alrdyin=FALSE;

     for (i=0 ; i < nanno ; i++) {
          if (apolpos[i] == pollpos) {
               alrdyin=TRUE;
               break;
          }
     }
     if (!alrdyin) {
          apolpos=(LONG *)alcrsz(apolpos,nanno*sizeof(LONG),
                                         (nanno+1)*sizeof(LONG));
          apolpos[nanno++]=pollpos;
          hook_announce(polannou);
     }
}

static VOID
polannou(VOID)                     /* P&Q announcement routine             */
{
     CHAR cmdstg[PNAMELEN+5];

     cmdstg[0]='\0';
     dfaSetBlk(pbb);
     setmem(&curpdata,sizeof(struct polldata),0);
     if (dfaAcqAbs(&curpdata,apolpos[annoidx[usrnum]],0)
      && curpdata.priority != SKIP        // just in case was updated online
      && !(curpdata.flags&(EDITP|ADDP|DELETEP))
      && !(cofdat(curpdata.closedate) < cofdat(today()))
      && haskey(curpdata.logon_key)) {
          stlcpy(scomp.uid,usaptr->userid,UIDSIZ);
          stlcpy(scomp.pname,curpdata.pname,PNAMELEN);
          dfaSetBlk(sbb);
          if (!dfaQueryEQ(&scomp,0)) {
               sprintf(cmdstg,"TAKE %s",curpdata.pname);
          }
     }
     if (cmdstg[0] != '\0') {
          setmbk(polmb);
          prfmsg(CSPOLANC,curpdata.polltype == POLL ? "poll" : "questionnaire",
                          curpdata.pname);
          addannom(prfbuf,PQAPPID,cmdstg);
     }
     else {
          addanno("");
     }
     if (++annoidx[usrnum] == nanno) {
          annoidx[usrnum]=0;
     }
}

VOID
polread(
INT direction,
struct saunam *dpknam)             /* dynapak read routines                */
{
     SHORT find;

     setmbk(polmb);
     if (stdmchk(MAINKEY)) {
          if (sameto("plist",dpknam->suffix)) {
               if (plist(direction,dpknam)) {
                    return;
               }
          }
          else if (sameto("qread",dpknam->suffix)) {
               if (direction != -1) {
                    if (rdques(GENQREAD,direction,dpknam)) {
                         return;
                    }
               }
          }
          else if (sameto("aread",dpknam->suffix)) {
               if (direction != -1) {
                    if (aread(direction,dpknam)) {
                         return;
                    }
               }
          }
          else if (sameto("sread",dpknam->suffix)) {
               sread(dpknam);
               return;
          }
          else if (sameto("qcheck",dpknam->suffix)) {
               qcheck(direction,dpknam);
               return;
          }
          else if (sameto("chk4dup",dpknam->suffix)) {
               chk4dups(dpknam);
               return;
          }
          else if (sameto("modacc",dpknam->suffix)) {
               chkmodacc(dpknam);
               return;
          }
          else if (sameto("level",dpknam->suffix)) {
               find=0;
               if (ispollop()) {
                    find|=UACPO;
               }
               if (isysop()) {
                    find|=UACSYS;
               }
               rsp2read(dpknam,sizeof(SHORT),&find,shortFDA);
               return;
          }
          else if (sameto("plstat",dpknam->suffix)) {
               rqiptr->idx=0;
               dfaSetBlk(pbb);
               if (dfaAcqLO(NULL,0)) {
                    rqiptr->abs=dfaAbs();
                    rqiptr->idx++;
                    cycleme(plstat);
               }
          }
          else if (sameto("qlist",dpknam->suffix)) {
               if (qlist(dpknam)) {
                    return;
               }
          }
          else if (sameto("pedit",dpknam->suffix)) {
               if (pedit(direction,dpknam)) {
                    return;
               }
          }
          else if (sameto("qresstat",dpknam->suffix)) {
               if (qresstat(dpknam)) {
                    return;
               }
          }
          else if (sameto("qresacc",dpknam->suffix)) {
               qresacc(dpknam);
               return;
          }
          else if (sameto("mresult",dpknam->suffix)) {
               if (mresult(direction,dpknam)) {
                    return;
               }
          }
          else if (sameto("qresult",dpknam->suffix)) {
               if (direction == 1) {
                    if (rdques(GENQRES,direction,dpknam)) {
                         return;
                    }
               }
          }
          else if (sameto("uidpoll",dpknam->suffix)) {
               if (direction == 1) {
                    if (uidpoll(dpknam)) {
                         return;
                    }
               }
          }
          else if (sameto("whynot",dpknam->suffix)) {
               if (direction == 1) {
                    if (!uidpoll(dpknam)) {
                         rsp2read(namtmp,strlen(rsptmp),rsptmp,rtextFDA);
                         return;
                    }
               }
          }
     }
     rejectreq();
}

VOID
polwrite(
struct saunam *dpknam,
USHORT length,
VOID *value)                       /* dynapak write routines               */
{
     INT i,mode,opriority;
     CHAR *cp,*pp;
     LONG polpos;

     (VOID)length;
     setmbk(polmb);
     if (stdmchk(MAINKEY)) {
          if (sameto("answer",dpknam->suffix)) {
               if ((cp=strchr(dpknam->suffix,' ')) == NULL
                || (pp=strrchr(++cp,':')) == NULL || strlen(pp+1) != 3) {
                    pqerror("Bad dynapak suffix in ANSWER!  suffix='%s'",
                            dpknam->suffix);
                    rejectreq();
                    return;
               }
               *pp++='\0';
               stlcpy(rqiptr->pname,cp,PNAMELEN);
               dfaSetBlk(pbb);
               if (!dfaAcqEQ(NULL,rqiptr->pname,0)) {
                    rejectreq();
                    return;
               }
               if (!haskey(pptr->acc_key)) {
                    rejectreq();
                    return;
               }
               if (pptr->flags&(EDITP|ADDP|DELETEP)) {
                    rejectreq();
                    return;
               }
               ansptr=(struct ansrdata *)rsptmp;
               ansptr->qnum=atoi(pp);
               if (ansptr->qnum < 0 || ansptr->qnum >= MAXQUES) {
                    rejectreq();
                    return;
               }
               qcomp.qnum=ansptr->qnum;
               stlcpy(qcomp.pollname,rqiptr->pname,PNAMELEN);
               dfaSetBlk(qbb);
               if (!dfaAcqEQ(NULL,&qcomp,0)) {
                    rejectreq();
                    return;
               }
               stlcpy(ansptr->pollname,rqiptr->pname,PNAMELEN);
               stlcpy(ansptr->uid,usaptr->userid,UIDSIZ);
               stlcpy(ansptr->answer,(CHAR *)value,ANSSIZ);
               if (qptr->qtype == OPEN_ENDED) {
                    cfrmtb(ansptr->answer);
               }
               dfaSetBlk(abb);
               stlcpy(acomp.pollname,ansptr->pollname,PNAMELEN);
               stlcpy(acomp.uid,ansptr->uid,UIDSIZ);
               acomp.qnum=ansptr->qnum;
               if (pptr->answer == ACCUMULATE || !dfaAcqEQ(NULL,&acomp,0)) {
                    dfaInsertV(ansptr,fldoff(ansrdata,answer)+
                                      strlen(ansptr->answer)+1);
               }
               else {
                    dfaUpdateV(ansptr,fldoff(ansrdata,answer)+
                    strlen(ansptr->answer)+1);
                    if (!csremtally()) {
                         return;
                    }
               }
               qcomp.qnum=ansptr->qnum;
               stlcpy(qcomp.pollname,ansptr->pollname,PNAMELEN);
               dfaSetBlk(qbb);
               if (dfaAcqEQ(NULL,&qcomp,0) && qptr->qtype == USERACCT) {
                    upaccfld(qptr->field,ansptr->answer);
               }
               dfaSetBlk(pbb);
               if (dfaAcqEQ(NULL,ansptr->pollname,0)) {
                    if (pptr->data == ASCII || pptr->data == BOTH) {
                         apendasc(qptr->qnum,pptr->pname,ansptr->answer);
                    }
                    if (pptr->polltype != QUEST && strlen(ansptr->answer) > 0
                     && OK2TALLY(qptr->qtype)) {
                         add_tally(qptr->qnum,pptr->pname,ansptr->answer);
                    }
               }
               rsp2write(TRUE,STGLEN,"Answer written to disk.",rtextFDA);
               return;
          }
          else if (sameto("status ",dpknam->suffix)) {
               statptr=(struct pollstat *)rsptmp;
               if ((cp=strchr(dpknam->suffix,' ')) == NULL) {
                    pqerror("Bad dynapak in STATUS! suffix='%s'",
                            dpknam->suffix);
                    rejectreq();
                    return;
               }
               stlcpy(rqiptr->pname,++cp,PNAMELEN);
               dfaSetBlk(pbb);
               if (!dfaAcqEQ(NULL,rqiptr->pname,0)) {
                    rejectreq();
                    return;
               }
               if (!haskey(pptr->acc_key)) {
                    rejectreq();
                    return;
               }
               if (pptr->flags&(EDITP|ADDP|DELETEP)) {
                    rejectreq();
                    return;
               }
               stlcpy(statptr->pname,rqiptr->pname,PNAMELEN);
               stlcpy(statptr->uid,usaptr->userid,UIDSIZ);
               stlcpy(scomp.pname,statptr->pname,PNAMELEN);
               stlcpy(scomp.uid,statptr->uid,UIDSIZ);
               dfaSetBlk(sbb);
               if (!dfaAcqEQ(NULL,&scomp,0)) {
                    if (sameas(value,"DONE")) {
                         dfaInsert(statptr);
                         dfaSetBlk(pbb);
                         dfaGetEQ(NULL,statptr->pname,0);
                         csgrantstf();
                    }
               }
               else {
                    if (sameas(value,"DONE")) {
                         dfaUpdate(statptr);
                    }
                    else if (sameas(value,"OPEN")) {
                         dfaDelete();
                    }
               }
               rsp2write(TRUE,STGLEN,"Status written to disk.",rtextFDA);
               return;
          }
          else if (sameto("reserve",dpknam->suffix)) {
               if ((cp=strchr(dpknam->suffix,' ')) == NULL
                || (pp=strchr(++cp,' ')) == NULL) {
                    pqerror("Bad dynapak in RESERVE! suffix='%s'",
                            dpknam->suffix);
                    rejectreq();
                    return;
               }
               *pp++='\0';
               if (sameas(cp,"set")) {
                    dfaSetBlk(pbb);
                    if (dfaAcqEQ(NULL,pp,0) && !(pptr->flags&DELETEP)
                     && haskey(pptr->acc_key) && !(pptr->flags&EDITP)) {
                         stzcpy(gcsp[usrnum].pname,pp,PNAMELEN);
                         rsp2write(TRUE,STGLEN,spr("Poll %s reserved.",pp),
                                   rtextFDA);
                         return;
                    }
               }
               else if (sameas(cp,"clear")) {
                    setmem(gcsp[usrnum].pname,PNAMELEN,0);
                    rsp2write(TRUE,STGLEN,spr("Poll %s unreserved.",pp),rtextFDA);
                    return;
               }
          }
          else if (sameto("pedit",dpknam->suffix)) {
               if ((cp=strchr(dpknam->suffix,' ')) == NULL) {
                    pqerror("Bad dynapack in PEDIT write! suffix='%s'",
                            dpknam->suffix);
                    rejectreq();
                    return;
               }
               else {
                    cp++;
                    dfaSetBlk(pbb);
                    if (sameas(gcsp[usrnum].pname,cp)
               && dfaAcqEQ(NULL,cp,0)) {
                         pptr->flags&=~(EDITP+ADDP);
                         dfaUpdate(NULL);
                         poledit[usrnum]=0;
                         setmem(gcsp[usrnum].pname,PNAMELEN,0);
                         gcsudca(pptr);
                         rsp2write(TRUE,STGLEN,spr("Poll %s unlocked.",cp),
                                   rtextFDA);
                         return;
                    }
               }
          }
          else if (sameto("psave",dpknam->suffix)) {
               if ((cp=strchr(dpknam->suffix,' ')) == NULL) {
                    pqerror("Bad dynapack in PSAVE write! suffix='%s'",
                            dpknam->suffix);
                    rejectreq();
                    return;
               }
               else {
                    if (!ispollop()) {
                         rejectreq();
                         return;
                    }
                    cp++;
                    dfaSetBlk(pbb);
                    mode=-1;
                    if (dfaAcqEQ(NULL,cp,0)) {
                         if (sameas(gcsp[usrnum].pname,cp)
                          && pptr->flags&(EDITP|ADDP)) {
                              mode=0;
                              opriority=pptr->priority;
                              polpos=dfaAbs();
                         }
                    }
                    else {
                         mode=1;
                    }
                    vbpptr=(struct vbpdata *)rsptmp;
                    movmem((struct vbpdata *)value,vbpptr,
                           sizeof(struct vbpdata));
                    if (mode == 1) {
                         b2ccpy(pptr->pname,vbpptr->pname,PNAMELEN);
                    }
                    b2ccpy(pptr->pdesc,vbpptr->pdesc,PDESCLEN);
                    pptr->polltype=vbpptr->polltype;
                    pptr->priority=vbpptr->priority;
                    pptr->data=vbpptr->data;
                    pptr->answer=vbpptr->answer;
                    if (mode == 1) {
                         pptr->createdate=v2ddat(vbpptr->createdate);
                         if (pptr->createdate == 0) {
                              prfmsg(INVCRDAT);
                              r2wprf(FALSE);
                              return;
                         }
                    }
                    pptr->closedate=v2ddat(vbpptr->closedate);
                    if (pptr->closedate == 0
                     || pptr->closedate < pptr->createdate) {
                         prfmsg(INVCLDAT);
                         r2wprf(FALSE);
                         return;
                    }
                    b2ccpy(pptr->lookup_key,vbpptr->lookup_key,KEYLEN);
                    strupr(pptr->lookup_key);
                    b2ccpy(pptr->logon_key,vbpptr->logon_key,KEYLEN);
                    strupr(pptr->logon_key);
                    b2ccpy(pptr->acc_key,vbpptr->acc_key,KEYLEN);
                    strupr(pptr->acc_key);
                    pptr->acc_attr=vbpptr->acc_attr+1;
                    b2ccpy(pptr->res_key,vbpptr->res_key,KEYLEN);
                    strupr(pptr->res_key);
                    if (isysop()) {
                         b2ccpy(pptr->grant_key,vbpptr->grant_key,KEYLEN);
                         strupr(pptr->grant_key);
                         b2ccpy(pptr->grant_class,vbpptr->grant_class,KEYLEN);
                         strupr(pptr->grant_class);
                         pptr->grant_crd=vbpptr->grant_crd;
                         b2ccpy(pptr->grant_file,vbpptr->grant_file,PTHFILSIZ);
                    }
                    else if (mode == 1) {
                         pptr->grant_key[0]='\0';
                         pptr->grant_class[0]='\0';
                         pptr->grant_crd=0L;
                         pptr->grant_file[0]='\0';
                    }
                    pptr->flags=vbpptr->flags;
                    dfaSetBlk(pbb);
                    if (mode == 1) {
                         dfaInsert(NULL);
                         if (pptr->priority != SKIP) {
                              addpanno(dfaAbs());
                         }
                         if (pollModified != NULL) {
                              (*pollModified)(*pptr);
                         }
                         gcsudca(pptr);
                         shocst("PNQ POLL ADDED","Poll %s has been added by %s",
                           cp,usaptr->userid);
                         rsp2write(TRUE,STGLEN,spr("Poll %s inserted.",cp),
                                   rtextFDA);
                         return;
                    }
                    else if (mode == 0) {
                         dfaUpdate(NULL);
                         if (pptr->priority != SKIP && opriority == SKIP) {
                              addpanno(polpos);
                         }
                         if (pollModified != NULL) {
                              (*pollModified)(*pptr);
                         }
                         gcsudca(pptr);
                         shocst("PNQ POLL UPDATED","Poll %s has been updated by %s",
                           cp,usaptr->userid);
                         rsp2write(TRUE,STGLEN,spr("Poll %s updated.",cp),
                                   rtextFDA);
                         return;
                    }
               }
          }
          else if (sameto("qsave",dpknam->suffix)) {
               if ((cp=strchr(dpknam->suffix,' ')) == NULL
             || (pp=strrchr(++cp,':')) == NULL) {
                    pqerror("Bad dynapak in QSAVE! suffix='%s'",
                   dpknam->suffix);
                    rejectreq();
                    return;
               }
               if (!ispollop()) {
                    rejectreq();
                    return;
               }
               *pp++='\0';
               dfaSetBlk(pbb);
               qrptr=(struct quesdata *)rsptmp;
               movmem((struct quesdata *)value,qrptr,sizeof(struct quesdata));
               stzcpy(qrptr->pollname,cp,PNAMELEN);
               for (i=0 ; i < MAXASTGS ; i++) {
                    b2ccvt(qrptr->ansstg[i],ANSSTGLEN);
               }
               b2ccvt(qrptr->txtmsg,TXTSIZ);
               cfrmtb(qrptr->txtmsg);
               qcomp.qnum=atoi(pp);
               stzcpy(qcomp.pollname,cp,PNAMELEN);
               oldModified=pollModified;
               pollModified=NULL;
               timeup();
               pollModified=oldModified;
               dfaSetBlk(qbb);
               if (!dfaAcqEQ(NULL,&qcomp,0)) {
                    dfaInsertV(qrptr,fldoff(quesdata,txtmsg)+
                  strlen(qrptr->txtmsg)+1);
               }
               else {
                    dfaUpdateV(qrptr,fldoff(quesdata,txtmsg)+
                  strlen(qrptr->txtmsg)+1);
               }
               rsp2write(TRUE,STGLEN,"Question written to disk.",rtextFDA);
               return;
          }
          else if (sameto("qdel",dpknam->suffix)) {
               if ((cp=strchr(dpknam->suffix,' ')) == NULL
                || (pp=strrchr(++cp,':')) == NULL) {
                    pqerror("Bad dynapak in QDEL! suffix='%s'",dpknam->suffix);
                    rejectreq();
                    return;
               }
               if (!ispollop()) {
                    rejectreq();
                    return;
               }
               *pp++='\0';
               if (!sameas(gcsp[usrnum].pname,cp)) {
                    rejectreq();
                    return;
               }
               qcomp.qnum=atoi(pp);
               stzcpy(qcomp.pollname,cp,PNAMELEN);
               dfaSetBlk(qbb);
               if (dfaAcqEQ(NULL,&qcomp,0)) {
                    dfaDelete();
                    rsp2write(TRUE,STGLEN,"Question deleted.",rtextFDA);
                    return;
               }
          }
          else if (sameto("pdel",dpknam->suffix)) {
               if ((cp=strchr(dpknam->suffix,' ')) == NULL) {
                    pqerror("Bad dynapak in PDEL! suffix='%s'",dpknam->suffix);
               }
               else if (ispollop()) {
                    cp++;
                    for (i=0 ; i < nterms ; i++) {
                         if (i != usrnum && usrinpoll(i,cp)) {
                              rejectreq();
                              return;
                         }
                    }
                    dfaSetBlk(pbb);
                    if (dfaAcqEQ(NULL,cp,0) && !(pptr->flags&DELETEP)
               && !(pptr->flags&(EDITP|ADDP))) {
                         shocst("P&Q POLL TAGGED FOR DELETE",
                                "Poll %s tagged by %s for delete.",
                                pptr->pname,usaptr->userid);
                         pptr->flags|=DELETEP;
                         dfaUpdate(NULL);
                         gcsdel(pptr);
                         rsp2write(TRUE,STGLEN,
                                   spr("Poll %s deleted.",pptr->pname),
                                   rtextFDA);
                         return;
                    }
               }
          }
          else if (sameto("preset",dpknam->suffix)) {
               if ((cp=strchr(dpknam->suffix,' ')) == NULL) {
                    pqerror("Bad dynapak in PRESET!  suffix='%s'",
                            dpknam->suffix);
               }
               else if (ispollop()) {
                    cp++;
                    dfaSetBlk(pbb);
                    if (dfaAcqEQ(NULL,cp,0) && !(pptr->flags&DELETEP)
                     && !(pptr->flags&(EDITP|ADDP))) {
                         stzcpy(gcsp[usrnum].pname,pptr->pname,PNAMELEN);
                         pptr->flags|=EDITP;
                         poledit[usrnum]=1;
                         dfaUpdate(NULL);
                         gcsudca(pptr);
                         rqiptr->idx=0;
                         stzcpy(rqiptr->pname,pptr->pname,PNAMELEN);
                         cycleme(cscycres);
                         return;
                    }
               }
          }
     }
     rejectreq();
}

VOID
polxdone(VOID)                     /* transfer done routine                */
{
}

VOID
polabort(VOID)                     /* request abort handler                */
{
}

VOID
cscycres(VOID)                     /* reset users cycle routine            */
{
     if (rqiptr->idx >= MAXQUES) {
          dfaSetBlk(sbb);
          rqiptr->abs=dfaAcqEQ(statptr,rqiptr->pname,2) ? dfaAbs() : 0L;
          cycleme(NULL);
          cycleme(cscycres2);
          dfaRstBlk();
     }
     else {
          acompcup.qnum=rqiptr->idx;
          stzcpy(acompcup.pollname,rqiptr->pname,PNAMELEN);
          dfaSetBlk(abb);
          if (dfaAcqEQ(NULL,&acompcup,1)) {
               dfaDelete();
          }
          else {
               rqiptr->idx++;
          }
     }
     dfaRstBlk();
}

VOID
cscycres2(VOID)                    /* reset-2 users cycle routine          */
{
     dfaSetBlk(sbb);
     if (dfaAcqAbsLock(statptr,rqiptr->abs,2,0)) {
          dfaDelete();
          if (dfaAcqNX(statptr)) {
               rqiptr->abs=dfaAbs();
          }
     }
     else {
          dfaRstBlk();
          dfaSetBlk(tbb);
          if (dfaAcqEQ(NULL,rqiptr->pname,0)) {
               dfaDelete();
          }
          dfaRstBlk();
          dfaSetBlk(pbb);
          dfaGetEQ(NULL,rqiptr->pname,0);
          pptr->flags&=~EDITP;
          dfaUpdate(NULL);
          setmem(gcsp[usrnum].pname,PNAMELEN,0);
          poledit[usrnum]=0;
          shocst("P&Q POLL ANSWERS RESET","Poll %s has been reset by %s.",
                 pptr->pname,usaptr->userid);
          gcsrst(pptr);
          rsp2write(TRUE,STGLEN,"Poll reset.",rtextFDA);
          cycleme(NULL);
     }
     dfaRstBlk();
}

VOID
poldsc(VOID)                  /* C/S hangup/disconnect routine             */
{
     if (strlen(gcsp[usrnum].pname) > 0) {
          if (poledit[usrnum]) {
               dfaSetBlk(pbb);
               if (dfaAcqEQ(NULL,gcsp[usrnum].pname,0)) {
                    if (pptr->flags&(EDITP|ADDP)) {
                         pptr->flags&=~(EDITP+ADDP);
                         dfaUpdate(NULL);
                    }
               }
               poledit[usrnum]=0;
          }
          setmem(gcsp[usrnum].pname,PNAMELEN,0);
     }
     annoidx[usrnum]=0;
}

GBOOL
plist(
INT direction,
struct saunam *dpknam)             /* poll list routine                    */
{
     GBOOL found=FALSE;
     CHAR *cp,pname[PNAMELEN];

     if ((cp=strchr(dpknam->suffix,' ')) == NULL) {
          pqerror("Bad dynapak suffix in PLIST!  suffix='%s'",dpknam->suffix);
          return(FALSE);
     }
     plptr=(struct vbplist *)rsptmp;
     dfaSetBlk(pbb);
     stzcpy(pname,++cp,PNAMELEN);
     switch (direction) {
     case -1:
          found=dfaAcqLT(NULL,pname,0);
          break;
     case 0:
          found=dfaAcqEQ(NULL,pname,0);
          break;
     case 1:
          found=dfaAcqGT(NULL,pname,0);
     }
     if (found) {
          if (pollvis(pptr,usrnum,FALSE)) {
               c2bcpy(plptr->pname,pptr->pname,PNAMELEN);
               c2bcpy(plptr->pdesc,pptr->pdesc,PDESCLEN);
               plptr->polltype=pptr->polltype;
               plptr->data=pptr->data;
               plptr->answer=pptr->answer;
               plptr->flags=pptr->polltype == 1 ? POLLTYPE : QUESTYPE;
               if (!haskey(pptr->acc_key)) {
                    plptr->flags|=REDX;
               }
               else {
                    if (pptr->flags&EDITP) {
                         plptr->flags|=REDM;
                    }
                    stzcpy(scomp.uid,usaptr->userid,UIDSIZ);
                    stzcpy(scomp.pname,pptr->pname,PNAMELEN);
                    dfaSetBlk(sbb);
                    if (dfaQueryEQ(&scomp,0)) {
                         plptr->flags|=GRNCHK;
                    }
                    else {
                         acomp.qnum=0;
                         stzcpy(acomp.pollname,pptr->pname,PNAMELEN);
                         stzcpy(acomp.uid,usaptr->userid,UIDSIZ);
                         dfaSetBlk(abb);
                         if (dfaQueryEQ(&acomp,0)) {
                              plptr->flags|=YELCHK;
                         }
                         else {
                              plptr->flags|=BLUEBOX;
                         }
                    }
               }
               movmem(dpknam,namtmp,sizeof(struct saunam));
               stzcpy(namtmp->suffix,spr("PLIST %s",pptr->pname),SFXSIZ);
               rsp2read(namtmp,sizeof(struct vbplist),plptr,vbplistFDA);
               return(TRUE);
          }
          else if (direction != 0) {
               movmem(dpknam,&rqiptr->dpknam,sizeof(struct saunam));
               stzcpy(rqiptr->dpknam.suffix,
                spr("PLIST %s",pptr->pname),SFXSIZ);
               rqiptr->idx=direction;
               cycleme(cycplist);
               return(TRUE);
          }
     }
     return(FALSE);
}

VOID
cycplist(VOID)                     /* cycled poll list routine             */
{
     if (!plist(rqiptr->idx,&rqiptr->dpknam)) {
          rejectreq();
     }
}

INT
qlist(
struct saunam *dpknam)             /* question list routine                */
{
     CHAR *pp,*np;

     qlptr=(struct vbqlist *)rsptmp;
     if ((pp=strchr(dpknam->suffix,' ')) == NULL
      || (np=strrchr(++pp,':')) == NULL || strlen(np+1) != 3) {
          pqerror("Bad dynapak suffix in QLIST! suffix='%s'",dpknam->suffix);
          return(0);
     }
     *np++='\0';
     qcomp.qnum=atoi(np);
     stzcpy(qcomp.pollname,pp,PNAMELEN);
     dfaSetBlk(pbb);
     if (!dfaAcqEQ(NULL,qcomp.pollname,0)
      || (!haskey(pptr->acc_key) && !ispollop())) {
          return(0);
     }
     dfaSetBlk(qbb);
     if (dfaAcqEQ(NULL,&qcomp,0)) {
          qlptr->qnum=qptr->qnum;
          qlptr->qtype=qptr->qtype;
          qlptr->prev=qptr->prev;
          qlptr->next=qptr->next;
          if (qptr->flags&BRANCH) {
               qlptr->branch=VBTRUE;
          }
          else {
               qlptr->branch=FALSE;
          }
          stzcpy(qlptr->ques,qptr->txtmsg,PDESCLEN);
          cvt4tb(qlptr->ques);
          c2bcvt(qlptr->ques,PDESCLEN);
          rsp2read(dpknam,sizeof(struct vbqlist),qlptr,vbqlistFDA);
          return(1);
     }
     return(0);
}

GBOOL                              /*   return TRUE if read req is ok      */
rdques(                            /* read a question (dir or non-dir)     */
INT type,                          /*   read type (for taking or results?) */
INT direction,                     /*   direction of read                  */
struct saunam *dpknam)             /*   read request dynapak               */
{
     CHAR *cp,*pp,tmpsuf[SFXSIZ];
     GBOOL found;

     stlcpy(tmpsuf,dpknam->suffix,SFXSIZ);
     if ((cp=strchr(tmpsuf,' ')) == NULL || (pp=strrchr(++cp,':')) == NULL
         || strlen(pp+1) != 3) {
          pqerror("Bad dynapak suffix in %s! suffix='%s'",
                  type == GENQREAD ? "QREAD" : "QRESULT",tmpsuf);
          return(FALSE);
     }
     *pp++='\0';
     setmem(rqiptr,sizeof(struct rqinfo),0);
     stzcpy(rqiptr->qcomp.pollname,cp,PNAMELEN);
     dfaSetBlk(pbb);
     if (!dfaAcqEQ(NULL,rqiptr->qcomp.pollname,0)
      || (!haskey(pptr->acc_key) && !ispollop())) {
          return(FALSE);
     }
     qrptr=(struct quesdata *)rsptmp;
     if (direction == 1 && sameas(pp,STRTW0)) {
          rqiptr->qcomp.qnum=0;
     }
     else {
          rqiptr->qcomp.qnum=atoi(pp);
     }
     if (rqiptr->qcomp.qnum < 0 || rqiptr->qcomp.qnum > MAXQUES) {
          return(FALSE);
     }
     dfaSetBlk(qbb);
     if (direction == 0) {
          found=dfaAcqEQ(qrptr,&rqiptr->qcomp,0);
     }
     else {
          if (rqiptr->qcomp.qnum == 0 && sameas(pp,STRTW0)) {
               found=dfaAcqGE(qrptr,&rqiptr->qcomp,0);
          }
          else {
               found=dfaAcqGT(qrptr,&rqiptr->qcomp,0);
          }
     }
     if (found && sameas(qrptr->pollname,rqiptr->qcomp.pollname)) {
          if (type == GENQREAD || qrptr->qtype != DISONLY) {
               sndqdpk(dpknam,type,qrptr);
               return(TRUE);
          }
          else {
               movmem(dpknam,&rqiptr->dpknam,sizeof(struct saunam));
               cycleme(skpdonly);
               return(TRUE);
          }
     }
     return(FALSE);
}

VOID
skpdonly(VOID)                     /* skp disp-only ques, when viewing res */
{
     INT i;

     dfaSetBlk(qbb);
     qrptr=(struct quesdata *)rsptmp;
     for (i=0 ; i < RDPCYC*2 ; i++) {
          if (dfaAcqGT(qrptr,&rqiptr->qcomp,0)
              && sameas(qrptr->pollname,rqiptr->qcomp.pollname)) {
               if (qrptr->qtype != DISONLY) {
                    sndqdpk(&rqiptr->dpknam,GENQRES,qrptr);
                    break;
               }
               else {
                    rqiptr->qcomp.qnum=qrptr->qnum;
               }
          }
          else {
               rejectreq();
               break;
          }
     }
}

VOID
sndqdpk(                           /* send a question-info dynapak         */
struct saunam *dpknam,             /*   orig read-request dpk              */
INT type,                          /*   read type (for taking or results?) */
struct quesdata *qdata)            /*   question data to send              */
{
     INT i;

     movmem(dpknam,namtmp,sizeof(struct saunam));
     stzcpy(namtmp->suffix,
            spr("%s %s:%03d",type == GENQREAD ? "QREAD" : "QRESULT",
                qdata->pollname,qdata->qnum),
            SFXSIZ);
     c2bcvt(qdata->pollname,PNAMELEN);
     for (i=0 ; i < MAXASTGS ; i++) {
          c2bcvt(qdata->ansstg[i],ANSSTGLEN);
     }
     cvt4tb(qdata->txtmsg);
     c2bcvt(qdata->txtmsg,TXTSIZ);
     rsp2read(namtmp,sizeof(struct quesdata),qdata,quesdataFDA);
}

GBOOL                              /*   return TRUE if read req is ok      */
aread(                             /* read answer data (dir or non-dir)    */
INT direction,                     /*   direction of read                  */
struct saunam *dpknam)             /*   read request dynapak               */
{
     CHAR *cp,*pp,tmpsuf[SFXSIZ];
     GBOOL found;

     stlcpy(tmpsuf,dpknam->suffix,SFXSIZ);
     ansptr=(struct ansrdata *)rsptmp;
     if ((cp=strchr(tmpsuf,' ')) == NULL|| (pp=strrchr(++cp,':')) == NULL
         || strlen(pp+1) != 3) {
          pqerror("Bad dynapak suffix in AREAD!  suffix='%s'",tmpsuf);
          return(FALSE);
     }
     *pp++='\0';
     dfaSetBlk(pbb);
     if (dfaAcqEQ(NULL,cp,0) && (pptr->data == DISCARD || pptr->data == ASCII)) {
          return(FALSE);
     }
     if (!haskey(pptr->acc_key) && !ispollop()) {
          return(FALSE);
     }
     setmem(rqiptr,sizeof(struct rqinfo),0);
     if (direction == 1 && sameas(pp,STRTW0)) {
          rqiptr->acomp.qnum=0;
     }
     else {
          rqiptr->acomp.qnum=atoi(pp);
     }
     if (rqiptr->acomp.qnum < 0 || rqiptr->acomp.qnum > MAXQUES) {
          return(FALSE);
     }
     stzcpy(rqiptr->acomp.pollname,cp,PNAMELEN);
     stzcpy(rqiptr->acomp.uid,usaptr->userid,UIDSIZ);
     dfaSetBlk(abb);
     if (direction == 0) {
          found=dfaAcqEQ(ansptr,&rqiptr->acomp,0);
     }
     else {
          if (rqiptr->acomp.qnum == 0 && sameas(pp,STRTW0)) {
               found=dfaAcqGE(ansptr,&rqiptr->acomp,0);
          }
          else {
               found=dfaAcqGT(ansptr,&rqiptr->acomp,0);
          }
     }
     if (found && sameas(ansptr->pollname,rqiptr->acomp.pollname)
         && sameas(ansptr->uid,rqiptr->acomp.uid)) {
          if (strlen(ansptr->answer) > 0) {
               sndadpk(dpknam,ansptr);
               return(TRUE);
          }
          else if (direction == 1) {
               movmem(dpknam,&rqiptr->dpknam,sizeof(struct saunam));
               cycleme(findans);
               return(TRUE);
          }
     }
     return(FALSE);
}

VOID
findans(VOID)                      /* find non-0 len answer string         */
{
     INT i;

     dfaSetBlk(abb);
     ansptr=(struct ansrdata *)rsptmp;
     for (i=0 ; i < RDPCYC*2 ; i++) {
          if (dfaAcqGT(ansptr,&rqiptr->acomp,0)
              && sameas(ansptr->pollname,rqiptr->acomp.pollname)
              && sameas(ansptr->uid,rqiptr->acomp.uid)) {
               if (strlen(ansptr->answer) > 0) {
                    sndadpk(&rqiptr->dpknam,ansptr);
                    break;
               }
               else {
                    rqiptr->acomp.qnum=ansptr->qnum;
               }
          }
          else {
               rejectreq();
               break;
          }
     }
}

VOID
sndadpk(                           /* send answer string dynapak           */
struct saunam *dpknam,             /*   orig read-request dpk              */
struct ansrdata *adata)            /*   answer data                        */
{
     CHAR *txtp;

     movmem(dpknam,namtmp,sizeof(struct saunam));
     stzcpy(namtmp->suffix,spr("AREAD %s:%03d",adata->pollname,adata->qnum),
            SFXSIZ);
     txtp=adata->answer;
     cvt4tb(txtp);
     movmem(txtp,adata->answer,strlen(txtp)+1);
     rsp2read(namtmp,STGLEN,adata->answer,rtextFDA);
}

VOID
sread(
struct saunam *dpknam)             /* poll status routine                  */
{
     CHAR *cp;

     if ((cp=strchr(dpknam->suffix,' ')) == NULL) {
          pqerror("Bad dynapak suffix in SREAD!  suffix='%s'",dpknam->suffix);
          rejectreq();
          return;
     }
     setmem(rqiptr,sizeof(struct rqinfo),0);
     stlcpy(rqiptr->pname,++cp,PNAMELEN);
     dfaSetBlk(pbb);
     if (dfaAcqEQ(NULL,rqiptr->pname,0)
      && (haskey(pptr->acc_key) || ispollop())) {
          dfaSetBlk(qbb);
          stlcpy(rqiptr->qcomp.pollname,rqiptr->pname,PNAMELEN);
          if (dfaAcqGE(NULL,&rqiptr->qcomp,0)
              && sameas(qptr->pollname,rqiptr->pname)) {
               rqiptr->highques=qptr->qnum;
               rqiptr->totques++;
               rqiptr->qcomp.qnum=qptr->qnum;
          }
          else {
               rqiptr->cycflgs|=QUESDN;
          }
          dfaSetBlk(abb);
          stlcpy(rqiptr->acomp.pollname,rqiptr->pname,PNAMELEN);
          stlcpy(rqiptr->acomp.uid,usaptr->userid,UIDSIZ);
          if (dfaAcqGE(NULL,&rqiptr->acomp,0)
              && sameas(aptr->pollname,rqiptr->pname)
              && sameas(aptr->uid,rqiptr->acomp.uid)) {
               rqiptr->highansr=aptr->qnum;
               rqiptr->totansr++;
               rqiptr->acomp.qnum=aptr->qnum;
          }
          else {
               rqiptr->cycflgs|=ANSRDN;
          }
          movmem(dpknam,&rqiptr->dpknam,sizeof(struct saunam));
          cycleme(cycsread);
     }
     else {
          rejectreq();
     }
}

VOID
cycsread(VOID)                     /* cycle to compute poll status info    */
{
     INT i;

     for (i=0 ; i < RDPCYC ; i++) {
          if (!(rqiptr->cycflgs&QUESDN)) {
               dfaSetBlk(qbb);
               if (dfaAcqGT(NULL,&rqiptr->qcomp,0)
                   && sameas(qptr->pollname,rqiptr->pname)) {
                    rqiptr->highques=qptr->qnum;
                    rqiptr->totques++;
                    rqiptr->qcomp.qnum=qptr->qnum;
               }
               else {
                    rqiptr->cycflgs|=QUESDN;
               }
          }
          if (!(rqiptr->cycflgs&ANSRDN)) {
               dfaSetBlk(abb);
               if (dfaAcqGT(NULL,&rqiptr->acomp,0)
                   && sameas(aptr->pollname,rqiptr->pname)
                   && sameas(aptr->uid,rqiptr->acomp.uid)) {
                    rqiptr->highansr=aptr->qnum;
                    rqiptr->totansr++;
                    rqiptr->acomp.qnum=aptr->qnum;
               }
               else {
                    rqiptr->cycflgs|=ANSRDN;
               }
          }
          if ((rqiptr->cycflgs&QUESDN) && (rqiptr->cycflgs&ANSRDN)) {
               break;
          }
     }
     if ((rqiptr->cycflgs&QUESDN) && (rqiptr->cycflgs&ANSRDN)) {
          dfaSetBlk(pbb);
          if (dfaAcqEQ(NULL,rqiptr->pname,0)) {
               if (!(pptr->flags&DELETEP)
             && (haskey(pptr->acc_key) || pptr->acc_attr == SHOW
                 || pptr->acc_attr == DIM)) {
                    if (!haskey(pptr->acc_key)) {
                         pptr->flags|=REDX;
                    }
                    else {
                         if (pptr->flags&EDITP) {
                              pptr->flags|=REDM;
                         }
                         stlcpy(scomp.uid,usaptr->userid,UIDSIZ);
                         stlcpy(scomp.pname,rqiptr->pname,PNAMELEN);
                         dfaSetBlk(sbb);
                         if (dfaQueryEQ(&scomp,0)) {
                              pptr->flags|=GRNCHK;
                         }
                         else if (rqiptr->totansr > 0) {
                              pptr->flags|=YELCHK;
                         }
                         else {
                              pptr->flags|=BLUEBOX;
                         }
                    }
                    rqiptr->status=pptr->flags;
               }
          }
          rsptr=(struct rstat *)rsptmp;
          rsptr->status=rqiptr->status;
          rsptr->highques=rqiptr->highques;
          rsptr->totques=rqiptr->totques;
          rsptr->highansr=rqiptr->highansr;
          rsptr->totansr=rqiptr->totansr;
          rsp2read(&rqiptr->dpknam,sizeof(struct rstat),rsptr,rstatFDA);
     }
}

VOID
qcheck(
INT direction,
struct saunam *dpknam)        /* question check routine                    */
{
     SHORT find;
     CHAR *cp,*pp;

     (VOID)direction;
     qrptr=(struct quesdata *)rsptmp;
     if ((cp=strchr(dpknam->suffix,' ')) == NULL
      || (pp=strrchr(++cp,':')) == NULL || strlen(pp+1) != 3) {
          pqerror("Bad dynapak suffix in QCHECK! suffix='%s'",dpknam->suffix);
          rejectreq();
          return;
     }
     *pp++='\0';
     if ((qcomp.qnum=atoi(pp)) == 0) {
          pqerror("Bad dynapak suffix qnum in QCHECK! qnum=%s",pp);
          rejectreq();
          return;
     }
     stzcpy(qcomp.pollname,cp,PNAMELEN);
     dfaSetBlk(pbb);
     if (dfaAcqEQ(NULL,qcomp.pollname,0)
      && (haskey(pptr->acc_key) || ispollop())) {
          dfaSetBlk(qbb);
          find=dfaQueryEQ(&qcomp,0) ? VBTRUE : 0;
          rsp2read(dpknam,sizeof(SHORT),&find,shortFDA);
     }
     else {
          rejectreq();
     }
}

VOID
chkmodacc(
struct saunam *dpknam)        /* check if user has module access           */
{
     SHORT find;

     if (!hasmkey(MAINKEY) || (!isysop && chk4poll() == 0)) {
          find=FALSE;
     }
     else {
          find=VBTRUE;
     }
     rsp2read(dpknam,sizeof(SHORT),&find,shortFDA);
}

VOID
plstat(VOID)                  /* count number of polls                     */
{
     dfaSetBlk(pbb);
     dfaGetAbs(NULL,rqiptr->abs,0);
     if (dfaQueryNX()) {
          rqiptr->abs=dfaAbs();
          rqiptr->idx++;
     }
     else {
          cycleme(NULL);
          rsp2read(&rqiptr->dpknam,sizeof(SHORT),&rqiptr->idx,shortFDA);
     }
}

VOID
gcsudca(
struct polldata *polptr)      /* update C/S poll listing                   */
{
     INT i;
     struct saunam dpknam;

     plptr=(struct vbplist *)rsptmp;
     setmem(&dpknam,sizeof(struct saunam),0);
     stzcpy(dpknam.sysid,msysid,SIDSIZ);
     stzcpy(dpknam.appid,PQAPPID,AIDSIZ);
     stzcpy(dpknam.suffix,"PLCHANGE",SFXSIZ);
     for (i=0 ; i < nterms ; i++) {
          if (usroff(i)->flags&ISGCSU) {
               if (pollvis(polptr,i,FALSE) && qroom(i,NORMAL)) {
                    senddpk(i,PQAPPID,NORMAL,&dpknam,strlen(polptr->pname),
                            polptr->pname,NULL);
               }
          }
     }
}

VOID
gcsrst(
struct polldata *pdp)         /* poll-op has reset this poll, update user  */
{
     INT i;
     struct saunam dpknam;

     setmem(&dpknam,sizeof(struct saunam),0);
     stzcpy(dpknam.sysid,msysid,SIDSIZ);
     stzcpy(dpknam.appid,PQAPPID,AIDSIZ);
     stzcpy(dpknam.suffix,"PLRESET",SFXSIZ);
     for (i=0 ; i < nterms ; i++) {
          if (usroff(i)->flags&ISGCSU) {
               if (pollvis(pdp,i,FALSE) && qroom(i,NORMAL)) {
                    senddpk(i,PQAPPID,NORMAL,&dpknam,strlen(pdp->pname),
                            pdp->pname,NULL);
               }
          }
     }
}

VOID
gcsdel(
struct polldata *pdp)         /* poll-op has deleted  poll, update user    */
{
     INT i;
     struct saunam dpknam;

     setmem(&dpknam,sizeof(struct saunam),0);
     stzcpy(dpknam.sysid,msysid,SIDSIZ);
     stzcpy(dpknam.appid,PQAPPID,AIDSIZ);
     stzcpy(dpknam.suffix,"PLDELETE",SFXSIZ);
     for (i=0 ; i < nterms ; i++) {
          if (usroff(i)->flags&ISGCSU) {
               if (pollvis(pdp,i,TRUE) && qroom(i,NORMAL)) {
                    senddpk(i,PQAPPID,NORMAL,&dpknam,strlen(pdp->pname),
                            pdp->pname,NULL);
               }
          }
     }
}

INT
pedit(
INT direction,
struct saunam *dpknam)        /* C/S poll-op editor interface              */
{
     INT i;
     CHAR *cp;

     vbpptr=(struct vbpdata *)rsptmp;
     if ((cp=strchr(dpknam->suffix,' ')) == NULL) {
          pqerror("Bad dynapak name in PEDIT! suffix='%s'",dpknam->suffix);
          return(0);
     }
     cp++;
     if (direction == 0) {
          dfaSetBlk(pbb);
          if (dfaAcqEQ(NULL,cp,0)) {
               if (!ispollop()) {
                    return(0);
               }
               if (pptr->flags&DELETEP) {
                    return(0);
               }
               if (pptr->flags&(EDITP|ADDP)) {
                    return(0);
               }
               for (i=0 ; i < nterms ; i++) {
                    if (i != usrnum && usrinpoll(i,pptr->pname)) {
                         return(0);
                    }
               }
               stzcpy(gcsp[usrnum].pname,pptr->pname,PNAMELEN);
               pptr->flags|=EDITP;
               poledit[usrnum]=1;
               dfaUpdate(NULL);
               gcsudca(pptr);
               c2bcpy(vbpptr->pname,pptr->pname,PNAMELEN);
               c2bcpy(vbpptr->pdesc,pptr->pdesc,PDESCLEN);
               vbpptr->polltype=pptr->polltype;
               vbpptr->priority=pptr->priority;
               vbpptr->data=pptr->data;
               vbpptr->answer=pptr->answer;
               vbpptr->createdate=d2vdat(pptr->createdate,0);
               vbpptr->closedate=d2vdat(pptr->closedate,0);
               c2bcpy(vbpptr->lookup_key,strupr(pptr->lookup_key),KEYLEN);
               c2bcpy(vbpptr->logon_key,strupr(pptr->logon_key),KEYLEN);
               c2bcpy(vbpptr->acc_key,strupr(pptr->acc_key),KEYLEN);
               vbpptr->acc_attr=pptr->acc_attr-1;
               c2bcpy(vbpptr->res_key,strupr(pptr->res_key),KEYLEN);
               c2bcpy(vbpptr->grant_key,strupr(pptr->grant_key),KEYLEN);
               c2bcpy(vbpptr->grant_class,strupr(pptr->grant_class),KEYLEN);
               vbpptr->grant_crd=pptr->grant_crd;
               c2bcpy(vbpptr->grant_file,pptr->grant_file,PTHFILSIZ);
               vbpptr->flags=pptr->flags;
               rsp2read(dpknam,sizeof(struct vbpdata),vbpptr,vbpdataFDA);
               return(1);
          }
     }
     return(0);
}

GBOOL                         /*   return TRUE if at least 1 valid ques    */
qresstat(                     /* determine # of valid questions in poll    */
struct saunam *dpknam)        /*   orignal read request dynapak            */
{
     CHAR *cp;

     if ((cp=strchr(dpknam->suffix,' ')) == NULL) {
          pqerror("Bad dynapak name in QRESSTAT! suffix='%s'",dpknam->suffix);
          return(FALSE);
     }
     setmem(rqiptr,sizeof(struct rqinfo),0);
     stlcpy(rqiptr->qcomp.pollname,++cp,PNAMELEN);
     dfaSetBlk(pbb);
     if (!dfaAcqEQ(NULL,rqiptr->qcomp.pollname,0)
      || (!haskey(pptr->acc_key) && !ispollop())) {
          return(FALSE);
     }
     dfaSetBlk(qbb);
     if (dfaAcqGE(NULL,&rqiptr->qcomp,0)
      && sameas(qptr->pollname,rqiptr->qcomp.pollname)) {
          if (qptr->qtype != DISONLY) {
               rqiptr->idx++;
          }
          rqiptr->qcomp.qnum=qptr->qnum;
          movmem(dpknam,&rqiptr->dpknam,sizeof(struct saunam));
          cycleme(cycqrs);
          return(TRUE);
     }
     return(FALSE);
}

VOID
cycqrs(VOID)                  /* cycle compute # valid questions in poll   */
{
     GBOOL atend=FALSE;
     INT i;

     dfaSetBlk(qbb);
     for (i=0 ; i < RDPCYC*2 && !atend ; i++) {
          if (dfaAcqGT(NULL,&rqiptr->qcomp,0)
           && sameas(qptr->pollname,rqiptr->qcomp.pollname)) {
               if (qptr->qtype != DISONLY) {
                    rqiptr->idx++;
               }
               rqiptr->qcomp.qnum=qptr->qnum;
          }
          else {
               atend=TRUE;
          }
     }
     if (atend) {
          if (rqiptr->idx > 0) {
               rsp2read(&rqiptr->dpknam,sizeof(rqiptr->idx),&rqiptr->idx,shortFDA);
          }
          else {
               rejectreq();
          }
     }
}

VOID
qresacc(
struct saunam *dpknam)        /* C/S does user have valid results access   */
{
     CHAR *cp;
     SHORT retval;

     if ((cp=strchr(dpknam->suffix,' ')) == NULL) {
          pqerror("Bad dynapak name in QRESACC! suffix='%s'",dpknam->suffix);
          rejectreq();
     }
     cp++;
     dfaSetBlk(pbb);
     if (dfaAcqEQ(NULL,cp,0) && !(pptr->flags&DELETEP)
      && (haskey(pptr->res_key) || ispollop())) {
          retval=VBTRUE;
          rsp2read(dpknam,sizeof(SHORT),&retval,shortFDA);
     }
     else {
          rejectreq();
     }
}

INT
mresult(
INT direction,
struct saunam *dpknam)        /* C/S get results data for a poll           */
{
     CHAR *cp;

     vbpptr=(struct vbpdata *)rsptmp;
     if ((cp=strchr(dpknam->suffix,' ')) == NULL) {
          return(0);
     }
     cp++;
     dfaSetBlk(pbb);
     if (!dfaAcqEQ(NULL,cp,0)
      || (!haskey(pptr->acc_key) && !ispollop())) {
          return(0);
     }
     if (direction == 0) {
          dfaSetBlk(tbb);
          if (dfaAcqEQ(&tally,cp,0)) {
               c2bcvt(tally.pollname,PNAMELEN);
               rsp2read(dpknam,sizeof(struct polltally),&tally,polltallyFDA);
               return(1);
          }
     }
     return(0);
}

GBOOL
uidpoll(
struct saunam *dpknam)        /* C/S check user-id/pollname/if taken       */
{
     INT i;
     CHAR *cp,*np,*ap;
     GBOOL ansrxst,found;

     if ((cp=strchr(dpknam->suffix,' ')) == NULL
      || (np=strrchr(++cp,':')) == NULL || strlen(np+1) != 3) {
          strcpy(rsptmp,"Bad dynapak name");
          return(FALSE);
     }
     movmem(dpknam,namtmp,sizeof(struct saunam));
     *np++='\0';
     if (sameas(np,STRTW0)) {
          rqiptr->qcomp.qnum=0;
     }
     else {
          rqiptr->qcomp.qnum=atoi(np);
     }
     if (rqiptr->qcomp.qnum < 0 || rqiptr->qcomp.qnum >= MAXQUES) {
          strcpy(rsptmp,"Bad question number");
          return(FALSE);
     }
     stzcpy(rqiptr->qcomp.pollname,cp,PNAMELEN);
     dfaSetBlk(pbb);
     if (dfaAcqEQ(NULL,cp,0) && !(pptr->flags&DELETEP)
      && (haskey(pptr->acc_key) || pptr->acc_attr == SHOW
          || pptr->acc_attr == DIM)) {
          if (!haskey(pptr->lookup_key)) {
               strcpy(rsptmp,"No access");
               return(FALSE);
          }
          dfaSetBlk(accbb);
          if (!dfaAcqEQ(NULL,dpknam->usrid,0)) {
               strcpy(rsptmp,"No such User-ID");
               return(FALSE);
          }
          stzcpy(scomp.uid,((struct usracc *)(accbb->data))->userid,UIDSIZ);
          stzcpy(scomp.pname,pptr->pname,PNAMELEN);
          dfaSetBlk(sbb);
          if (!dfaAcqEQ(NULL,&scomp,0)) {
               strcpy(rsptmp,"Poll not completed");
               return(FALSE);
          }
     }
     else {
          strcpy(rsptmp,"No such poll");
          return(FALSE);
     }
     dfaSetBlk(qbb);
     if (sameas(np,STRTW0)) {
          found=dfaAcqGE(NULL,&rqiptr->qcomp,0);
     }
     else {
          found=dfaAcqGT(NULL,&rqiptr->qcomp,0);
     }
     if (!(found && sameas(qptr->pollname,rqiptr->qcomp.pollname))) {
          strcpy(rsptmp,"Question not found");
          return(FALSE);
     }
     rqiptr->acomp.qnum=qptr->qnum;
     stzcpy(rqiptr->acomp.pollname,rqiptr->qcomp.pollname,PNAMELEN);
     stzcpy(rqiptr->acomp.uid,((struct usracc *)(accbb->data))->userid,UIDSIZ);
     dfaSetBlk(abb);
     ansrxst=dfaAcqEQ(NULL,&rqiptr->acomp,0);
     stzcpy(namtmp->suffix,spr("%s %s:%03d",
                      firstwd(dpknam->suffix),
                      qptr->pollname,qptr->qnum),SFXSIZ);
     cvt4tb(qptr->txtmsg);
     strcpy(rsptmp,qptr->txtmsg);
     if (ansrxst && strlen(aptr->answer) > 0) {
          switch (qptr->qtype) {
          case MULTICHC:
               setmem(vdatmp,vdasiz,0);
               if (aptr->answer != '\0'
             && itemcntd(aptr->answer,",") == qptr->ansparam) {
                    for (i=0 ; i < qptr->ansparam ; i++) {
                         ap=itemidxd(aptr->answer,i,",");
                         strcat(vdatmp,spr("%c:  %s\r",*ap,
                                           qptr->ansstg[(INT)(*ap)-65]));

                    }
               }
               cvt4tb(vdatmp);
               strcat(rsptmp,"\t");
               strcat(rsptmp,vdatmp);
               break;
          case TRUEFALSE:
               strcat(rsptmp,
                      spr("\t%s",aptr->answer[0] == 'A' ? "TRUE" : "FALSE"));
               break;
          case YESNO:
               strcat(rsptmp,
                spr("\t%s",aptr->answer[0] == 'A' ? "YES" : "NO"));
               break;
          case DISONLY:
               break;
          default:
               cvt4tb(aptr->answer);
               strcat(rsptmp,"\t");
               strcat(rsptmp,aptr->answer);
               break;
          }
     }
     rsp2read(namtmp,strlen(rsptmp),rsptmp,rtextFDA);
     return(TRUE);
}

CHAR *
cvt4tb(
CHAR *stg)                   /* prepare string for use with VB Textboxes */
{
     INT find=0,i;
     CHAR *cp, *op;

     strcpy(prfbuf,stg);
     stg[0]='\0';
     for (op=stg, cp=prfbuf, i=0 ; *cp != '\0' ; cp++, i++) {
          if (i == 0 && (*cp == '\r' || *cp == '\n')) {
               continue;
          }
          if (*cp == '\r') {
               if (*(cp+1) != '\n') {
                    *op++='\r';
                    *op++='\n';
               }
               else {
                    *op++=*cp;
                    find=2;
               }
          }
          else if (!find && *cp == '\n') {
               *op++='\r';
               *op++='\n';
          }
          else {
               *op++=*cp;
          }
          if (find > 0) {
               find--;
          }
     }
     *op='\0';
     return(stg);
}


CHAR *
cfrmtb(
CHAR *stg)                   /* convert VB Textbox string to AA */
{
     INT i;
     CHAR *cp, *op;

     strcpy(prfbuf,stg);
     stg[0]='\0';

     for (op=stg, cp=prfbuf, i=0 ; *cp != '\0' ; cp++, i++) {
          if (i == 0) {
               *op++='\r';
          }
          if (*cp == '\r' && *(cp+1) == '\n') {
               *op++='\r';
               cp++;
          }
          else {
               *op++=*cp;
          }
     }
     *op='\0';
     return(stg);
}

GBOOL
csremtally(VOID)                   /* remove tallied stats for ques # */
{
     INT i;

     qcomp.qnum=aptr->qnum;
     stlcpy(qcomp.pollname,aptr->pollname,PNAMELEN);
     dfaSetBlk(qbb);
     dfaGetEQ(NULL,&qcomp,0);
     if (!(qptr->qtype == TRUEFALSE || qptr->qtype == YESNO
        || qptr->qtype == MULTICHC)) {
          return(TRUE);
     }
     dfaSetBlk(tbb);
     if (!dfaAcqEQ(&tally,aptr->pollname,0)) {
          setmem(&tally,sizeof(struct polltally),0);
          stlcpy(tally.pollname,aptr->pollname,PNAMELEN);
          dfaInsertV(&tally,sizeof(struct polltally));
          return(TRUE);
     }
     if ((qptr->flags&BRANCH) && !sameas(aptr->answer,ansptr->answer)) {
          qcomp.qnum=qptr->branch[(INT)(aptr->answer[0])-65];
          if (tally.answer[qptr->qnum][(INT)(aptr->answer[0])-65] > 0) {
               tally.answer[qptr->qnum][(INT)(aptr->answer[0])-65]--;
          }
          tally.answer[qptr->qnum][(INT)(ansptr->answer[0])-65]++;
          dfaSetBlk(tbb);
          dfaAbsRec(NULL,0);
          dfaUpdateV(&tally,sizeof(struct polltally));
          dfaSetBlk(qbb);
          if (dfaAcqEQ(NULL,&qcomp,0)) {
               rqiptr->idx=qptr->qnum;
               rqiptr->abs=dfaAbs();
               stzcpy(rqiptr->pname,qptr->pollname,PNAMELEN);
               cycleme(cscyctally);
               return(FALSE);
          }
     }
     else {
          i=0;
          do {
               if (tally.answer[qptr->qnum][(INT)(aptr->answer[i])-65] > 0) {
                    tally.answer[qptr->qnum][(INT)(aptr->answer[i])-65]--;
               }
          } while (i < MAXASTGS && aptr->answer[i++] != '\0');
          dfaSetBlk(tbb);
          dfaAbsRec(NULL,0);
          dfaUpdateV(&tally,sizeof(struct polltally));
     }
     return(TRUE);
}

VOID
cscyctally(VOID)              /* tally user responses                      */
{
     INT done=0,nextq;

     setmbk(polmb);
     dfaSetBlk(qbb);
     dfaGetAbs(NULL,rqiptr->abs,0);
     acomp.qnum=qptr->qnum;
     stzcpy(acomp.pollname,qptr->pollname,PNAMELEN);
     stzcpy(acomp.uid,usaptr->userid,UIDSIZ);
     dfaSetBlk(abb);
     if (dfaAcqEQ(NULL,&acomp,0) && (qptr->flags&BRANCH)
      && isalpha(aptr->answer[0])) {
          dfaDelete();
          nextq=qptr->branch[(INT)(aptr->answer[0])-65];
          dfaSetBlk(tbb);
          if (dfaAcqEQ(&tally,qptr->pollname,0)) {
               tally.answer[qptr->qnum][(INT)(aptr->answer[0])-65]--;
               dfaUpdateV(&tally,sizeof(struct polltally));
          }
     }
     else {
          nextq=qptr->next;
     }
     qcomp.qnum=nextq;
     stzcpy(qcomp.pollname,qptr->pollname,PNAMELEN);
     dfaSetBlk(qbb);
     if (dfaAcqEQ(NULL,&qcomp,0)) {
          rqiptr->abs=dfaAbs();
     }
     else {
          done=1;
     }
     if (done) {
          qcomp.qnum=rqiptr->idx;
          /* qcomp.pollname is still valid from above code */
          dfaSetBlk(qbb);
          dfaGetEQ(NULL,&qcomp,0);
          dfaSetBlk(pbb);
          dfaGetEQ(NULL,qptr->pollname,0);
          acomp.qnum=qptr->qnum;
          stzcpy(acomp.pollname,pptr->pname,PNAMELEN);
          stzcpy(acomp.uid,usaptr->userid,UIDSIZ);
          dfaSetBlk(abb);
          if (!dfaAcqEQ(NULL,&acomp,0)) {
               pqerror("BAD AREA: anum=%d poll=%s uid=%s",
                       acomp.qnum,acomp.pollname,acomp.uid);
               rejectreq();
               return;
          }
          setmem(aptr->answer,ANSSIZ,0);
          aptr->answer[0]=(CHAR)rqiptr->highansr;
          dfaUpdateV(NULL,fldoff(ansrdata,answer)+strlen(aptr->answer)+1);
          if (qptr->qtype == USERACCT) {      /* user account field    */
               upaccfld(qptr->field,aptr->answer);
          }
          if (pptr->data == ASCII || pptr->data == BOTH) {
               apendasc(qptr->qnum,pptr->pname,aptr->answer);
          }
          if (pptr->polltype != QUEST && OK2TALLY(qptr->qtype)) {
               add_tally(qptr->qnum,pptr->pname,aptr->answer);
          }
          cycleme(NULL);
          rsp2write(TRUE,STGLEN,"Answer written to disk.",rtextFDA);
     }
     else {
          rqiptr->abs=dfaAbs();
     }
     dfaRstBlk();
}

VOID
csgrantstf(VOID)         /* after completion of poll/questionnaire handle  */
{                        /* granting user specifed key, credits and file   */
     LONG creds;
     CHAR fptmp[GCMAXFNM];
     struct clstab *tabptr;
     struct saunam dpknam;

     clrprf();
     setmem(&dpknam,sizeof(struct saunam),0);
     stzcpy(dpknam.sysid,msysid,SIDSIZ);
     stzcpy(dpknam.appid,PQAPPID,AIDSIZ);
     stzcpy(dpknam.suffix,"MESSAGE",SFXSIZ);
     tabptr=fndcls(usaptr->curcls);
     if (strlen(pptr->grant_key) > 0) {
          if (!haskey(pptr->grant_key)) {
               givkey(usaptr->userid,pptr->grant_key);
               prfmsg(GOTKEY,pptr->grant_key);
               stp4cs(prfbuf);
               senddpk(usrnum,PQAPPID,NORMAL,&dpknam,strlen(prfbuf),prfbuf,NULL);
               clrprf();
          }
     }
     if (pptr->grant_crd > 0L) {         /* post credits to user       */
          addcrd(usaptr->userid,l2as(pptr->grant_crd),0);
          prfmsg(CRDSPST,l2as(pptr->grant_crd));
          stp4cs(prfbuf);
          senddpk(usrnum,PQAPPID,NORMAL,&dpknam,strlen(prfbuf),prfbuf,NULL);
          clrprf();
     }
     else if (pptr->grant_crd < 0L && !(tabptr->flags&CRDXMT)) {
          creds=pptr->grant_crd*-1L;
          if (dedcrd(creds,0)) {
               prfmsg(CRDSDED,l2as(creds));
               stp4cs(prfbuf);
               senddpk(usrnum,PQAPPID,NORMAL,&dpknam,strlen(prfbuf),prfbuf,NULL);
               clrprf();
          }
     }
     if (strlen(pptr->grant_class) > 0) {/* data in class field?       */
          swtcls(usaptr,1,pptr->grant_class,3,0);
     }
     if (strlen(pptr->grant_file) > 0) { /* found something here       */
          setmem(&filmsg,sizeof(struct message),0);
          stlcpy(filmsg.to,usaptr->userid,MAXADR);
          stlcpy(filmsg.from,"Sysop",MAXADR);
          stlcpy(filmsg.topic,"Polls & Questionnaires File",TPCSIZ);
          stlcpy(filmsg.attname,
                 fileparts(GCPART_FNAM,pptr->grant_file,fptmp,GCMAXFNM),GCMAXFNM);
          fnmcse(filmsg.attname);
          filmsg.flags|=(FILATT+FILAPV+FILIND);
          clrprf();
          prfmsg(GRNTFIL,pptr->polltype == POLL ? "Poll" : "Questionnaire",
                 pptr->pname);
          prf2tx();
          simpsnd(&filmsg,vdatmp,pptr->grant_file);
          clrprf();
          prfmsg(MSGSNT,pptr->polltype == POLL ? "Poll" : "Questionnaire",
                 pptr->pname);
          stp4cs(prfbuf);
          senddpk(usrnum,PQAPPID,NORMAL,&dpknam,strlen(prfbuf),prfbuf,NULL);
          clrprf();
     }
}

GBOOL
pollvis(                      /* should this poll be shown to user?        */
struct polldata *polptr,      /*   data on poll in question                */
INT unum,                     /*   user number in question                 */
GBOOL igndel)                 /*   ignore DELETE flag?                     */
{
     if ((polptr->flags&DELETEP) && !igndel) {
          return(FALSE);
     }
     if (!(gen_haskey(polptr->acc_key,unum,usroff(unum))
        || polptr->acc_attr == SHOW || polptr->acc_attr == DIM)) {
          return(FALSE);
     }
     if (!(cofdat(polptr->closedate) > cofdat(today()) || ispollop())) {
          return(FALSE);
     }
     return(TRUE);
}

VOID
pqerror(
CHAR *pFormat,...)           /* error output routine                      */
{
     va_list pArguments;

     va_start(pArguments,pFormat);
     vsprintf(vdatmp,pFormat,pArguments);
     va_end(pArguments);
     shocst("P&Q ERROR","%s",vdatmp);
}

VOID
chk4dups(
struct saunam *dpknam)        /* check for duplicate poll names            */
{
     CHAR *cp;
     CHAR tmpstg[PNAMELEN];
     SHORT retval;

     if ((cp=strchr(dpknam->suffix,' ')) == NULL) {
          pqerror("Bad dynapak suffix in CHK4DUPS!  suffix='%s'",
                  dpknam->suffix);
          rejectreq();
          return;
     }
     stzcpy(tmpstg,++cp,PNAMELEN);
     dfaSetBlk(pbb);
     if (dfaQueryEQ(tmpstg,0)) {
          retval=VBTRUE;
          rsp2read(dpknam,sizeof(SHORT),&retval,shortFDA);
     }
     else {
          rejectreq();
     }
}
