/***************************************************************************
 *                                                                         *
 *   GCSASYS.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 "System Agent".                 *
 *                                                                         *
 *                                                - T. Stryker 8/5/93      *
 *                                                  C. Robert              *
 *                                                  B. Love                *
 *                                                                         *
 *   - Added standard system dynapak read/write support.                   *
 *   - Added support for C/S version of userid x-ref list.                 *
 *                                                                         *
 *                                                - Bill Hyatt 7/15/94     *
 *                                                                         *
 *   Added support for Remote System Console agent.                        *
 *                                                                         *
 *                                                - Joe Delekto 1/10/96    *
 *                                                                         *
 ***************************************************************************/
#include "gcomm.h"
#include "majorbbs.h"
#include "gcspsrv.h"
#include "gcsasys.h"
#include "wgserver.h"
#include "wgssup.h"
#include "phasedbg.h"

#define FILREV "$Revision: 64 $"

#define   LOKDLY    32768L         /* delay for locking/unlocking datalink */
#define   w4atck    (*((ULONG *)mrqptr))
                                   /* ticker for C/S-A/A mode swiches      */
#define   XRFPCY    10             /* # of uid's to cross-ref per cycle    */
#define   FREE2U    -1             /* chan's req free to use uid x-ref     */
#define   XSFXSZ    5              /* size of suffix info in uid x-ref list*/
#define   STDNSZ    14             /* size of std dpk/field names (w/ NULL)*/
#define   NSYSEL    4              /* #elems in sysstg[] array             */
#define   NANSEL    4              /* #elems in ansstg[] array             */
#define   UIDISZ    14+1           /* size of ret stg for "useridinfo" dpk */
#define   UIDDLM    ';'            /* delim chr for uids in dpk names/vals */
#define   LSFXSZ    4              /* size of suffix info in lnglst stg    */
#define   LNGSEP    9              /* delimiter for langs in lnglst        */
#define   MXGCDI    20             /* max len for "gcditype" chaninfo fld  */
#define   MINSWD    40             /* minimum ANSI screen width allowed    */
#define   MAXSWD    136            /* maximum ANSI screen width allowed    */
#define   MINSLN    3              /* minimum ANSI screen length allowed   */
#define   MAXSLN    254            /* maximum ANSI screen length allowed   */
#define   UINAID    "GALUIE"       /* acc disp/edit appid used by uintfy() */

/* types of possible parameters in "chaninfo" std dpk suffix */
#define   ISNULL    0              /* parm is '\0'                         */
#define   ISCNUM    1              /* parm is channel number (c=nn)        */
#define   ISUID     2              /* parm is user-id (u=xxx)              */
#define   ISUNUM    3              /* parm is a usrnum (n=nn)              */
#define   ISFLD     4              /* parm is possibly a field name        */

/* possible actions for write of language dpks */
#define   CHGNON    0              /* no change                            */
#define   CHGAUT    1              /* change preference to AUTO            */
#define   CHGONL    2              /* change online for this session only  */
#define   CHGOND    3              /* change permanently on disk           */

/* length of return values for dynapak fields */
#define   CHRLEN    sizeof(CHAR)   /* used for CHAR return values          */
#define   INTLEN    sizeof(SHORT)  /* used for int return values           */
#define   LNGLEN    sizeof(LONG)   /* used for long return values          */
#define   DBLLEN    sizeof(DOUBLE) /* used for double return values        */
#define   AXSLEN    (sizeof(SHORT)*7)/* used for array of access flags     */

                          /* note: unsigned values are cast as longs for VB*/

#define   cdr(vp,t) (*((t *)vp))   /* cast and dereference void pointer    */
#define   cvp(vp,t) ((t *)vp)      /* cast a void pointer                  */

#define   NCLSSZ    ((4*(KEYSIZ-1))+11) /* len of stg from "nextclass" fld */

/* length of return values for "sysinfo" fields */
#define   TTLSIZ    50             /* sysname (same as CNF opt BBSTTL)     */
#define   CMPSIZ    46             /* syscompnay (same as CNF opt COMPANY) */
#define   ADDRSZ    44             /* sysaddr1/2 (sam as CNF opt ADDRES1/2)*/
#define   DTPHSZ    32             /* sysphone (same as CNF opt DATAPH)    */
#define   LVPHSZ    31             /* restpho (same as CNF opt LIVEPH)     */
#define   CGHRSZ    22             /* chghour ( "   "   "   "  CHGHOUR)    */
#define   CGMNSZ    31             /* mincharge (same as CNF opt CHGMIN)   */
#define   RNOSIZ    8              /* regnumber                            */

#define   cpyrsp(s) stlcpy(rsptmp,(s),MAXDPKV)    /* start new response str*/
#define   delimiter() stlcat(rsptmp,"\t",MAXDPKV) /* add delimiter to rsp  */
#define   catrsp(s) stlcat(rsptmp,(s),MAXDPKV)    /* add to response str   */

#define HASHPRIM (859433L)         /* prime number for hashing             */

static VOID sysread(INT direction,struct saunam *dpknam);
static VOID syswrite(struct saunam *dpknam,USHORT length,VOID *value);
static VOID sysxdone(VOID);
static VOID sysabort(VOID);

struct agent sysagt={              /* agent information structure           */
     "",                           /*   appid                               */
     sysread,                      /*   read-dynapak function pointer       */
     syswrite,                     /*   write-dynapak function pointer      */
     sysxdone,                     /*   file xfer-done function pointer     */
     sysabort                      /*   abort-request function pointer      */
};

struct srchdat {                   /* per-channel user-id x-ref data       */
     CHAR begxrf[XRFSIZ];          /*   x-ref string to start with         */
     INT usingid;                  /*   FREE2U, or id of req using x-ref   */
     ULONG curpos;                 /*   current pos in xrf data file       */
     INT nsofar;                   /*   # of userids sent so far           */
     CHAR *uidlst;                 /*   list of uids to send to client     */
} *srchdat,                        /* array of user-id x-ref data          */
  *sdatptr;                        /* ptr to current channel's x-ref data  */

struct pndreq {                    /* per-req area for pending x-ref req's */
     CHAR begxrf[XRFSIZ];          /*   x-ref string to start with         */
};

#define spndptr ((struct pndreq *)mrqptr) /* ptr to pending req mem area   */

struct ncicrdvb {                  /* for uintfy(): new cls info if shwcrd */
     CHAR clname[KEYSIZ-1];        /*   class name                         */
     SHORT limcal;                 /*   time limit per call                */
     SHORT limday;                 /*   time limit per day                 */
     LONG dbtlmt;                  /*   debt limit                         */
     CHAR exempt;                  /*   exempt from credit charges? (Y/N)  */
};

struct flddef ncicrdvbFDA[]={
     { CVTFLD_CHAR  ,KEYSIZ-1 ,fldoff(ncicrdvb,clname) ,NULL },
     { CVTFLD_SHORT ,2        ,fldoff(ncicrdvb,limcal) ,NULL },
     { CVTFLD_LONG  ,1        ,fldoff(ncicrdvb,dbtlmt) ,NULL },
     { CVTFLD_CHAR  ,1        ,fldoff(ncicrdvb,exempt) ,NULL },
     { CVTFLD_END   ,0        ,0                       ,NULL }
};

struct ncivb {                     /* for uintfy(): new cls info, no shwcrd*/
     CHAR clname[KEYSIZ-1];        /*   class name                         */
     SHORT limcal;                 /*   time limit per call                */
     SHORT limday;                 /*   time limit per day                 */
};

struct flddef ncivbFDA[]={         /* subset of struct ncicrdvb (not used) */
     { CVTFLD_CHAR  ,KEYSIZ-1 ,fldoff(ncivb,clname)    ,NULL },
     { CVTFLD_SHORT ,2        ,fldoff(ncivb,limcal)    ,NULL },
     { CVTFLD_END   ,0        ,0                       ,NULL }
};

CHAR dpkrvchr,                     /* used for type CHAR dpk read resp's   */
      nilrvchr='\0',               /* used to ret "nil" for CHAR read rsp's*/
      *supappid,                   /* signup agent's appid                 */
      *mmappid,                    /* main menu agent's appid              */
      *stakey;                     /* key required to read "sysstat" dpk   */

SHORT dpkrvint,                    /* used for type int dpk read resp's    */
      dpkusn,                      /* std dpk: req'd uid's usrnum          */
      csnumxrf,                    /* max userid x-refs for C/S users      */
      chglngt,                     /* action for "su:userinfo language" wrt*/
      nwlingot,                    /* new lingo for "su:userinfo language" */
      chglngp,                     /* action for "su:userinfo permlang" wrt*/
      nwlingop;                    /* new lingo for "su:userinfo permlang" */

SHORT nilrvint=-GCMAXSHORT;        /* used to ret "nil" for int read resp's*/

GBOOL usron,                       /* std dpk: req'd uid currently online? */
      uidsame,                     /* std dpk: is req'd uid current user?  */
      invldres,                    /* reason that vlduid() rejected userid */
      alwknock;                    /* allow users to knock themselves off  */

LONG dpkrvlng;                     /* used for type long dpk read resp's   */
ULONG dpkrvulng;                   /* used for type unsigned long dpk rsp's*/

LONG nilrvlng=-GCMAXLONG;          /* used to ret "nil" for long read rsp's*/

DOUBLE dpkrvdbl;                   /* used for type double dpk read resp's */

HMCVFILE gcsmb;                    /* GCSP message block pointer           */

INT jumpflags;                     /* controls plugin main menu execution  */

struct user *dpkusp;               /* std dpk: req'd uid's user struct     */

struct usracc *dpkuap,             /* std dpk: req'd uid's in-mem usracc   */
              accrec;              /* std dpk: req'd uid's on-disk usracc  */

GBOOL (*swtcls_hook)(struct usracc *usract,CHAR *usrclass,INT days)=NULL;

extern UINT maxpol;                /* system polling rate                  */

extern DFAFILE* keysbb;            /* keys database pointer                */
extern DFAFILE* clsbb;             /* class database pointer               */
extern DFAFILE* xrfbb;             /* user-id x-ref database pointer       */

CHAR *uiekytbl[UIEKYTSZ];          /* table of user information edit keys  */

ULONG *hashvals;                   /* per-user returned hashing keys       */

struct epw {                       /* structure for crypto-logon           */
     LONG nullval;                 /*   null-key                           */
     LONG hashval;                 /*   hashed password                    */
} epwt;                            /* one instance                         */

static VOID wt2srch(VOID);
static VOID gtuids(CHAR *begxrf);
static VOID bldlst(VOID);
static VOID snduids(CHAR *uidlst);
static struct clstab *getctp(VOID);
static GBOOL wrtlng(SHORT newlang,GBOOL wrtonl);
static SHORT *rdlng(GBOOL rdonl);
static INT adjlgo(INT ilingo);
static GBOOL vlduid(CHAR *dpkuid);
static VOID gtkrng(CHAR *ringid,GBOOL clsrng,struct saunam *dpknam);
static VOID ptkrng(CHAR *ringid,CHAR *rings,GBOOL clsrng);
VOID uintfy(INT chan,CHAR *uid,struct clstab *cltptr);
static VOID wt4lok(VOID);
static VOID knockem(VOID);
static VOID w4ldly(VOID);
static VOID w4udly(VOID);
static VOID retwgmvr(VOID);
static VOID retfilist(VOID);
static VOID dontzap(VOID);
static VOID retfile(CHAR *filname);
static VOID retupdfile(CHAR *filname,INT direction);
static VOID sysfin(VOID);
static ULONG hash(CHAR *stg,ULONG initial);
static VOID regdpk(VOID);

/* dynapak/field read routines and aux. functions */
static VOID dpkr_agentver(struct saunam *dpknam);
static VOID dpkr_chaninfo(struct saunam *dpknam);
static GBOOL prssfx(CHAR *suffix,CHAR **fldnam);
static INT  prmtyp(CHAR *parm);
static VOID dpkra_chaninfo(struct chninfvb *chninfvb);
static VOID *fldr_useridc(VOID), *fldr_channel(VOID),
            *fldr_chantype(VOID),  *fldr_gcditype(VOID),
            *fldr_usernumber(VOID),*fldr_baud(VOID),
            *fldr_mode(VOID);
static VOID dpkr_classinfo(struct saunam *dpknam);
static VOID dpkra_classinfo(struct clsinfvb *clsinfvb);
static VOID *fldr_nextclass(VOID),*fldr_limpercall(VOID),
            *fldr_limperday(VOID),*fldr_defdayexp(VOID),
            *fldr_debtlimtc(VOID),*fldr_forgivdays(VOID),
            *fldr_idledays(VOID), *fldr_flags(VOID),
            *fldr_seconds(VOID),  *fldr_usersin(VOID);
static VOID dpkr_classkeys(struct saunam *dpknam);
static VOID dpkr_classmsgs(struct saunam *dpknam);
static VOID dpkr_classlist(struct saunam *dpknam);
static VOID dpkr_langlist(struct saunam *dpknam);
static VOID dpkr_rsptime(struct saunam *dpknam);
static VOID dpkr_sysinfo(struct saunam *dpknam);
static VOID dpkra_sysinfo(struct sysinfvb *sysinfvb);
static VOID *fldr_sysname(VOID),  *fldr_syscompany(VOID),
            *fldr_sysaddr1(VOID), *fldr_sysaddr2(VOID),
            *fldr_sysphone(VOID), *fldr_restpho(VOID),
            *fldr_chgperhr(VOID), *fldr_mincharge(VOID),
            *fldr_regnumber(VOID);
static VOID dpkr_sysloading(struct saunam *dpknam);
static VOID dpkr_syspolrate(struct saunam *dpknam);
static VOID dpkr_sysstat(struct saunam *dpknam);
static VOID dpkra_sysstat(struct stainfvb *stainfvb);
static VOID *fldr_numlines(VOID),   *fldr_othonline(VOID),
            *fldr_totalcalls(VOID), *fldr_downloads(VOID),
            *fldr_uploads(VOID),    *fldr_totalmsgs(VOID),
            *fldr_totalaccts(VOID), *fldr_totalmale(VOID),
            *fldr_totalfemale(VOID),*fldr_totalcorp(VOID),
            *fldr_totalansi(VOID);
static VOID dpkr_useridinfo(struct saunam *dpknam);
static VOID dpkr_userinfo(struct saunam *dpknam);
static VOID dpkra_userinfo(struct usrinfvb *usrinfvb);
static VOID *fldr_userid(VOID),    *fldr_password(VOID),
            *fldr_name(VOID),      *fldr_company(VOID),
            *fldr_address1(VOID),  *fldr_address2(VOID),
            *fldr_address3(VOID),  *fldr_phone(VOID),
            *fldr_systemtype(VOID),*fldr_ansi(VOID),
            *fldr_scnwidth(VOID),  *fldr_scnlength(VOID),
            *fldr_fsescnlen(VOID), *fldr_editorprf(VOID),
            *fldr_age(VOID),       *fldr_sex(VOID),
            *fldr_birthdate(VOID), *fldr_createdate(VOID),
            *fldr_laston(VOID),    *fldr_class(VOID),
            *fldr_retclass(VOID),  *fldr_creditrate(VOID),
            *fldr_credits(VOID),   *fldr_credever(VOID),
            *fldr_paidever(VOID),  *fldr_timeonline(VOID),
            *fldr_calltimlim(VOID),*fldr_daytimlim(VOID),
            *fldr_timetoday(VOID), *fldr_daysleft(VOID),
            *fldr_debtlimit(VOID), *fldr_exempt(VOID),
            *fldr_language(VOID),  *fldr_permlang(VOID),
            *fldr_acctflags(VOID), *fldr_secondstt(VOID),
            *fldr_access(VOID);
static VOID dpkr_usrclskeys(struct saunam *dpknam);
static VOID dpkr_usrpslkeys(struct saunam *dpknam);

/* dynapak/field write routines and aux. functions */
static VOID dpkw_reqgenagt(struct saunam *dpknam,UINT length,VOID *value);
static VOID dpkw_userinfo(struct saunam *dpknam,UINT length,VOID *value);
static VOID dpkw_usrpslkeys(struct saunam *dpknam,UINT length,VOID *value);
static VOID dpkw_classinfo(struct saunam *dpknam,UINT length,VOID *value);
static VOID dpkw_classkeys(struct saunam *dpknam,UINT length,VOID *value);
static VOID dpkw_classmsgs(struct saunam *dpknam,UINT length,VOID *value);
static VOID dpkw_classkill(struct saunam *dpknam,UINT length,VOID *value);
static VOID dpkw_copyuser(struct saunam *dpknam,UINT length,VOID *value);
static GBOOL dpkwa_classinfo(struct clsinfvb *clsinfvb,struct acclass *clsdat);
static GBOOL fldw_nextclass(CHAR *clsstg,struct acclass *clsdat);
static GBOOL fldw_limpercall(SHORT *newlim,struct acclass *clsdat);
static GBOOL fldw_limperday(SHORT *newlim, struct acclass *clsdat);
static GBOOL fldw_defdayexp(SHORT *newexp, struct acclass *clsdat);
static GBOOL fldw_debtlimtc(LONG *newlim, struct acclass *clsdat);
static GBOOL fldw_forgivdays(SHORT *newday,struct acclass *clsdat);
static GBOOL fldw_idledays(SHORT *newday,struct acclass *clsdat);
static GBOOL fldw_flags(SHORT *newflg,struct acclass *clsdat);
static GBOOL fldw_seconds(LONG *newsec,struct acclass *clsdat);
static GBOOL fldw_usersin(LONG *newusr,struct acclass *clsdat);
static VOID chglng(INT lngact,INT newlingo);
static GBOOL dpkwa_userinfo(struct usrinfvb *usrinfvb, struct usracc *accrec);
static INT  valinf(CHAR *infstg,UINT minlen,GBOOL chkpfn);
static GBOOL fldw_password(CHAR *newpsw, struct usracc *accrec),
             fldw_name(CHAR *newname,struct usracc *accrec),
             fldw_company(CHAR *newcomp,struct usracc *accrec),
             fldw_address1(CHAR *newaddr,struct usracc *accrec),
             fldw_address2(CHAR *newaddr,struct usracc *accrec),
             fldw_address3(CHAR *newaddr,struct usracc *accrec),
             fldw_phone(CHAR *newpho,struct usracc *accrec),
             fldw_systemtype(SHORT *newstyp,struct usracc *accrec),
             fldw_ansi(SHORT *newansi,struct usracc *accrec),
             fldw_daysleft(LONG *newdays,struct usracc *accrec),
             fldw_scnwidth(SHORT *newwid,struct usracc *accrec),
             fldw_scnlength(SHORT *newlen,struct usracc *accrec),
             fldw_fsescnlen(SHORT *newlen,struct usracc *accrec),
             fldw_editorprf(CHAR *newprf,struct usracc *accrec),
             fldw_birthdate(DOUBLE *newbdy,struct usracc *accrec),
             fldw_acctflags(SHORT *newflags,struct usracc *accrec),
             fldw_sex(CHAR *newsex,struct usracc *accrec),
             fldw_class(CHAR *newclass,LONG daysleft,struct usracc *accrec),
             fldw_language(SHORT *newlang),
             fldw_permlang(SHORT *newlang),
             fldw_access(SHORT *flags,struct usracc *accrec);

struct sdpkinf {                   /* standard dynapak info structure      */
     CHAR dpknam[STDNSZ];          /*   dynapak name                       */
     VOID (*dpkrrou)(struct saunam *dpknam);/*   dynapak read routine      */
     VOID (*dpkwrou)(struct saunam *dpknam,UINT length,VOID *value);
                                   /*   dynapak write routine              */
} stdpks[]={                       /* array of standard dynapak info       */
     {"s:agentver",   dpkr_agentver,  NULL},
     {"s:chaninfo",   dpkr_chaninfo,  NULL},
     {"s:classinfo",  dpkr_classinfo, dpkw_classinfo},
     {"s:classkeys",  dpkr_classkeys, dpkw_classkeys},
     {"s:classlist",  dpkr_classlist, NULL},
     {"s:classmsgs",  dpkr_classmsgs, dpkw_classmsgs},
     {"s:classkill",  NULL,           dpkw_classkill},
     {"s:copyuser",   NULL,           dpkw_copyuser},
     {"s:langlist",   dpkr_langlist,  NULL},
     {"s:reqgenagt",  NULL,           dpkw_reqgenagt},
     {"s:rsptime",    dpkr_rsptime,   NULL},
     {"s:sysinfo",    dpkr_sysinfo,   NULL},
     {"s:sysloading", dpkr_sysloading,NULL},
     {"s:syspolrate", dpkr_syspolrate,NULL},
     {"s:sysstat",    dpkr_sysstat,   NULL},
     {"s:useridinfo", dpkr_useridinfo,NULL},
     {"su:userinfo",  dpkr_userinfo,  dpkw_userinfo},
     {"su:usrclskeys",dpkr_usrclskeys,NULL},
     {"su:usrpslkeys",dpkr_usrpslkeys,dpkw_usrpslkeys}
};

typedef GBOOL (*FLDWROU)(VOID *value,VOID *clsnfo);// to avoid compiler errs*/

struct fldinf {                    /* std dpk field info structure         */
     CHAR fldnam[STDNSZ];          /*   field name                         */
     VOID *(*fldrrou)(VOID);       /*   field read routine                 */
     UINT retlen;                  /*   length of reads' returned info     */
     FLDWROU fldwrou;              /*   field write rou                    */
     struct flddef *flddef;        /*   field definition array for convert */
};

struct fldinf cinflds[]={          /* fields for "chaninfo" std dpk        */
     {"userid",    fldr_useridc,   STGLEN,NULL,charsFDA},
     {"channel",   fldr_channel,   INTLEN,NULL,shortFDA},
     {"chantype",  fldr_chantype,  INTLEN,NULL,shortFDA},
     {"gcditype",  fldr_gcditype,  STGLEN,NULL,charsFDA},
     {"usernumber",fldr_usernumber,INTLEN,NULL,shortFDA},
     {"baud",      fldr_baud,      LNGLEN,NULL,longFDA },
     {"mode",      fldr_mode,      INTLEN,NULL,shortFDA}
};

struct chninfvb {                  /* VB structure form of "chaninfo"      */
     CHAR userid[UIDSIZ-1];        /*   userid on channel                  */
     SHORT channel;                /*   user's channel number              */
     SHORT chantype;               /*   type of channel (modem,lan,etc.)   */
     CHAR gcditype[MXGCDI];        /*   type of chan if GCDI, or all ' '   */
     SHORT usernumber;             /*   user number (ie. usrnum)           */
     LONG baud;                    /*   user's baud rate                   */
     SHORT mode;                   /*   -1=C/S, 0-99=A/A language number   */
};

struct flddef chninfvbFDA[] = {
     { CVTFLD_CHAR  ,UIDSIZ-1 ,fldoff(chninfvb,userid)      ,NULL },
     { CVTFLD_SHORT ,2        ,fldoff(chninfvb,channel)     ,NULL },
     { CVTFLD_CHAR  ,MXGCDI   ,fldoff(chninfvb,gcditype)    ,NULL },
     { CVTFLD_SHORT ,1        ,fldoff(chninfvb,usernumber)  ,NULL },
     { CVTFLD_LONG  ,1        ,fldoff(chninfvb,baud)        ,NULL },
     { CVTFLD_SHORT ,1        ,fldoff(chninfvb,mode)        ,NULL },
     { CVTFLD_END   ,0        ,0                            ,NULL }
};

struct fldinf clsflds[]={          /* fields for "classinfo" std dpk       */
     {"nextclass", fldr_nextclass, STGLEN,(FLDWROU)fldw_nextclass,charsFDA},
     {"limpercall",fldr_limpercall,INTLEN,(FLDWROU)fldw_limpercall,shortFDA},
     {"limperday", fldr_limperday, INTLEN,(FLDWROU)fldw_limperday,shortFDA},
     {"defdayexp", fldr_defdayexp, INTLEN,(FLDWROU)fldw_defdayexp,shortFDA},
     {"debtlimit", fldr_debtlimtc, LNGLEN,(FLDWROU)fldw_debtlimtc,longFDA},
     {"forgivdays",fldr_forgivdays,INTLEN,(FLDWROU)fldw_forgivdays,shortFDA},
     {"idledays",  fldr_idledays,  INTLEN,(FLDWROU)fldw_idledays,shortFDA},
     {"flags",     fldr_flags,     INTLEN,(FLDWROU)fldw_flags,shortFDA},
     {"seconds",   fldr_seconds,   LNGLEN,(FLDWROU)fldw_seconds,longFDA},
     {"usersin",   fldr_usersin,   LNGLEN,(FLDWROU)fldw_usersin,longFDA}
};

struct clsinfvb {                  /* VB structure form of "classinfo"     */
     CHAR nextclass[NCLSSZ];       /*   class to return to when expires    */
     SHORT limpercall;             /*   limit per call                     */
     SHORT limperday;              /*   limit per day                      */
     SHORT defdayexp;              /*   default days before expiring       */
     LONG debtlimit;               /*   debt limit                         */
     SHORT forgivdays;             /*   days to wait before "forgiving"    */
     SHORT idledays;               /*   inactive days before delete        */
     SHORT flags;                  /*   general bit flags                  */
     LONG seconds;                 /*   seconds used so far this month     */
     LONG usersin;                 /*   total # of users in this class     */
};

struct flddef clsinfvbFDA[] = {
     { CVTFLD_CHAR  ,NCLSSZ   ,fldoff(clsinfvb,nextclass)   ,NULL },
     { CVTFLD_SHORT ,3        ,fldoff(clsinfvb,limpercall)  ,NULL },
     { CVTFLD_LONG  ,1        ,fldoff(clsinfvb,debtlimit)   ,NULL },
     { CVTFLD_SHORT ,3        ,fldoff(clsinfvb,forgivdays)  ,NULL },
     { CVTFLD_LONG  ,2        ,fldoff(clsinfvb,seconds)     ,NULL },
     { CVTFLD_END   ,0        ,0                            ,NULL }
};

struct fldinf sinflds[]={          /* fields for "sysinfo" std dpk         */
     { "sysname",   fldr_sysname,   STGLEN,NULL,charsFDA },
     { "syscompany",fldr_syscompany,STGLEN,NULL,charsFDA },
     { "sysaddr1",  fldr_sysaddr1,  STGLEN,NULL,charsFDA },
     { "sysaddr2",  fldr_sysaddr2,  STGLEN,NULL,charsFDA },
     { "sysphone",  fldr_sysphone,  STGLEN,NULL,charsFDA },
     { "restpho",   fldr_restpho,   STGLEN,NULL,charsFDA },
     { "chgperhr",  fldr_chgperhr,  STGLEN,NULL,charsFDA },
     { "mincharge", fldr_mincharge, STGLEN,NULL,charsFDA },
     { "regnumber", fldr_regnumber, STGLEN,NULL,charsFDA }
};

struct sysinfvb {                  /* VB structure form of "sysinfo"       */
     CHAR sysname[TTLSIZ];         /*   system name                        */
     CHAR syscompany[CMPSIZ];      /*   system company                     */
     CHAR sysaddr1[ADDRSZ];        /*   system address line 1              */
     CHAR sysaddr2[ADDRSZ];        /*   system address line 2              */
     CHAR sysphone[DTPHSZ];        /*   system phone number                */
     CHAR restpho[LVPHSZ];         /*   system restricted phone number     */
     CHAR chgperhr[CGHRSZ];        /*   charge per hour                    */
     CHAR mincharge[CGMNSZ];       /*   minimum charge                     */
     CHAR regnumber[RNOSIZ];       /*   registration number                */
};

struct flddef sysinfvbFDA[] = {
     { CVTFLD_CHAR  ,TTLSIZ+CMPSIZ+(ADDRSZ*2)+DTPHSZ+LVPHSZ+CGHRSZ+CGMNSZ+RNOSIZ
                                   ,fldoff(sysinfvb,sysname) ,NULL },
     { CVTFLD_END   ,0             ,0                       ,NULL }
};

struct fldinf staflds[]={          /* fields for "sysstat" std dpk         */
     { "numlines",   fldr_numlines,   INTLEN,NULL,shortFDA  },
     { "othonline",  fldr_othonline,  INTLEN,NULL,shortFDA  },
     { "totalcalls", fldr_totalcalls, LNGLEN,NULL,longFDA },
     { "downloads",  fldr_downloads,  LNGLEN,NULL,longFDA },
     { "uploads",    fldr_uploads,    LNGLEN,NULL,longFDA },
     { "totalmsgs",  fldr_totalmsgs,  LNGLEN,NULL,longFDA },
     { "totalaccts", fldr_totalaccts, LNGLEN,NULL,longFDA },
     { "totalmale",  fldr_totalmale,  LNGLEN,NULL,longFDA },
     { "totalfemale",fldr_totalfemale,LNGLEN,NULL,longFDA },
     { "totalcorp",  fldr_totalcorp,  LNGLEN,NULL,longFDA },
     { "totalansi",  fldr_totalansi,  LNGLEN,NULL,longFDA }
};

struct stainfvb {                  /* VB structure form of "sysstat"       */
     SHORT numlines;               /*   number channels defined on server  */
     SHORT othonline;              /*     "    of channels in use          */
     LONG totalcalls;              /*   total calls to date                */
     LONG downloads;               /*     "   downloads to date            */
     LONG uploads;                 /*     "   uploads to date              */
     LONG totalmsgs;               /*     "   messages to date             */
     LONG totalaccts;              /*   number of accounts                 */
     LONG totalmale;               /*     "    "  male accounts            */
     LONG totalfemale;             /*     "    "  female accounts          */
     LONG totalcorp;               /*     "    "  corporate accounts       */
     LONG totalansi;               /*     "    "  ansi accounts            */
};

struct flddef stainfvbFDA[]={
     { CVTFLD_SHORT ,2   ,fldoff(stainfvb,numlines)    ,NULL },
     { CVTFLD_LONG  ,9   ,fldoff(stainfvb,totalcalls)  ,NULL },
     { CVTFLD_END   ,0   ,0                            ,NULL }
};

struct fldinf uinflds[]={          /* fields for "userinfo" std dpk        */
     { "userid",    fldr_userid,    STGLEN,NULL                    ,charsFDA},
     { "password",  fldr_password,  STGLEN,(FLDWROU)fldw_password  ,charsFDA},
     { "name",      fldr_name,      STGLEN,(FLDWROU)fldw_name      ,charsFDA},
     { "company",   fldr_company,   STGLEN,(FLDWROU)fldw_company   ,charsFDA},
     { "address1",  fldr_address1,  STGLEN,(FLDWROU)fldw_address1  ,charsFDA},
     { "address2",  fldr_address2,  STGLEN,(FLDWROU)fldw_address2  ,charsFDA},
     { "address3",  fldr_address3,  STGLEN,(FLDWROU)fldw_address3  ,charsFDA},
     { "phone",     fldr_phone,     STGLEN,(FLDWROU)fldw_phone     ,charsFDA},
     { "systemtype",fldr_systemtype,INTLEN,(FLDWROU)fldw_systemtype,shortFDA},
     { "ansi",      fldr_ansi,      INTLEN,(FLDWROU)fldw_ansi      ,shortFDA},
     { "scnwidth",  fldr_scnwidth,  INTLEN,(FLDWROU)fldw_scnwidth  ,shortFDA},
     { "scnlength", fldr_scnlength, INTLEN,(FLDWROU)fldw_scnlength ,shortFDA},
     { "fsescnlen", fldr_fsescnlen, INTLEN,(FLDWROU)fldw_fsescnlen ,shortFDA},
     { "editorprf", fldr_editorprf, CHRLEN,(FLDWROU)fldw_editorprf ,charFDA},
     { "age",       fldr_age,       INTLEN,NULL                    ,shortFDA},
     { "birthdate", fldr_birthdate, DBLLEN,(FLDWROU)fldw_birthdate ,doubleFDA},
     { "sex",       fldr_sex,       CHRLEN,(FLDWROU)fldw_sex       ,charFDA},
     { "createdate",fldr_createdate,DBLLEN,NULL                    ,doubleFDA},
     { "laston",    fldr_laston,    DBLLEN,NULL                    ,doubleFDA},
     { "class",     fldr_class,     STGLEN,(FLDWROU)fldw_class     ,charsFDA},
     { "retclass",  fldr_retclass,  STGLEN,NULL                    ,charsFDA},
     { "creditrate",fldr_creditrate,INTLEN,NULL                    ,shortFDA},
     { "credits",   fldr_credits,   LNGLEN,NULL                    ,longFDA},
     { "credever",  fldr_credever,  LNGLEN,NULL                    ,longFDA},
     { "paidever",  fldr_paidever,  LNGLEN,NULL                    ,longFDA},
     { "timeonline",fldr_timeonline,INTLEN,NULL                    ,shortFDA},
     { "calltimlim",fldr_calltimlim,INTLEN,NULL                    ,shortFDA},
     { "daytimlim", fldr_daytimlim, INTLEN,NULL                    ,shortFDA},
     { "timetoday", fldr_timetoday, LNGLEN,NULL                    ,longFDA},
     { "seconds",   fldr_secondstt, LNGLEN,NULL                    ,longFDA},
     { "daysleft",  fldr_daysleft,  INTLEN,(FLDWROU)fldw_daysleft  ,longFDA},
     { "debtlimit", fldr_debtlimit, LNGLEN,NULL                    ,longFDA},
     { "exempt",    fldr_exempt,    CHRLEN,NULL                    ,charFDA},
     { "language",  fldr_language,  INTLEN,(FLDWROU)fldw_language  ,shortFDA},
     { "permlang",  fldr_permlang,  INTLEN,(FLDWROU)fldw_permlang  ,shortFDA},
     { "acctflags", fldr_acctflags, INTLEN,(FLDWROU)fldw_acctflags ,shortFDA},
     { "access",    fldr_access,    AXSLEN,(FLDWROU)fldw_access    ,shortsFDA}
};

struct usrinfvb {                  /* VB structure form of "userinfo"      */
     CHAR userid[UIDSIZ-1];        /*   userid                             */
     CHAR password[PSWSIZ-1];      /*   password                           */
     CHAR name[NADSIZ-1];          /*   user name                          */
     CHAR company[NADSIZ-1];       /*   address line 1                     */
     CHAR address1[NADSIZ-1];      /*      "     "   2                     */
     CHAR address2[NADSIZ-1];      /*      "     "   3                     */
     CHAR address3[NADSIZ-1];      /*      "     "   4                     */
     CHAR phone[PHOSIZ-1];         /*   user phone number                  */
     SHORT systemtype;             /*   system type                        */
     SHORT ansi;                   /*   ansi preference                    */
     SHORT scnwidth;               /*   screen width                       */
     SHORT scnlength;              /*   screen len                         */
     SHORT fsescnlen;              /*   screen length for FSE              */
     CHAR editorprf;               /*   editor preference                  */
     SHORT age;                    /*   user age                           */
     DOUBLE birthdate;             /*   user birthdate                     */
     CHAR sex;                     /*   user sex                           */
     DOUBLE createdate;            /*   account creation date              */
     DOUBLE laston;                /*   last logged on date                */
     CHAR acctcls[KEYSIZ-1];       /*   current user class                 */
     CHAR retclass[KEYSIZ-1];      /*   class to return to if necc.        */
     SHORT creditrate;             /*   current credit rate                */
     LONG credits;                 /*   current number of credits          */
     LONG credever;                /*   credits to user ever               */
     LONG paidever;                /*   paid credits to user ever          */
     SHORT timeonline;             /*   time online this call              */
     SHORT calltimlim;             /*   time limit per call                */
     SHORT daytimlim;              /*    "     "    "  day                 */
     LONG timetoday;               /*   time online today                  */
     LONG daysleft;                /*   days left in class                 */
     LONG debtlimit;               /*   debt limit                         */
     CHAR exempt;                  /*   exempt from credit charges?        */
     SHORT language;               /*   index of current language          */
     SHORT permlang;               /*   index of permanent (on disk) lang  */
     SHORT acctflags;              /*   account flags                      */
     SHORT access[AXSSIZ];         /*   remote administrator access flags  */
};

struct flddef usrinfvbFDA[]={
     { CVTFLD_CHAR  ,UIDSIZ-1+PSWSIZ-1+(5*(NADSIZ-1))+PHOSIZ-1
                                   ,fldoff(usrinfvb,userid)      ,NULL },
     { CVTFLD_SHORT ,5             ,fldoff(usrinfvb,systemtype)  ,NULL },
     { CVTFLD_CHAR  ,1             ,fldoff(usrinfvb,editorprf)   ,NULL },
     { CVTFLD_SHORT ,1             ,fldoff(usrinfvb,age)         ,NULL },
     { CVTFLD_DOUBLE,1             ,fldoff(usrinfvb,birthdate)   ,NULL },
     { CVTFLD_CHAR  ,1             ,fldoff(usrinfvb,sex)         ,NULL },
     { CVTFLD_DOUBLE,2             ,fldoff(usrinfvb,createdate)  ,NULL },
     { CVTFLD_CHAR  ,2*(KEYSIZ-1)  ,fldoff(usrinfvb,acctcls)     ,NULL },
     { CVTFLD_SHORT ,1             ,fldoff(usrinfvb,creditrate)  ,NULL },
     { CVTFLD_LONG  ,3             ,fldoff(usrinfvb,credits)     ,NULL },
     { CVTFLD_SHORT ,3             ,fldoff(usrinfvb,timeonline)  ,NULL },
     { CVTFLD_LONG  ,3             ,fldoff(usrinfvb,timetoday)   ,NULL },
     { CVTFLD_CHAR  ,1             ,fldoff(usrinfvb,exempt)      ,NULL },
     { CVTFLD_SHORT ,3+AXSSIZ      ,fldoff(usrinfvb,language)    ,NULL },
     { CVTFLD_END   ,0             ,0                            ,NULL }
};

VOID
inisysagt(VOID)                    /* initialize the system agent          */
{
     INT i;

     register_agent(&sysagt);
     gcsmb=opnmsg("wgserver.mcv");
     hashvals=alczer(nterms*sizeof(ULONG));
     alwknock=ynopt(ALWKNOCK);
     supappid=stgopt(SUPAID1);
     mmappid=stgopt(MMAID1);
     stakey=stgopt(STAKEY);
     csnumxrf=numopt(CSNUMXRF,0,100);
     jumpflags=0;
     if (ynopt(JFLAGOFF)) {
          jumpflags|=1;
          if (ynopt(JFLAGRUN)) {
               jumpflags|=2;
          }
          else if (ynopt(JFLAGADV)) {
               jumpflags|=4;
          }
     }
     srchdat=(struct srchdat *)alczer(nterms*sizeof(struct srchdat));
     for (i=0 ; i < nterms ; i++) {
          srchdat[i].usingid=FREE2U;
          srchdat[i].uidlst=alczer(csnumxrf*(sgnusz+1)+XSFXSZ+1);
     }
     dclmrq(max(sizeof(ULONG),sizeof(struct pndreq)));
     inigenagt();
     regdpk();
     hook_shutdown(sysfin);
}

static VOID
sysread(                           /* read-dynapak handler                 */
INT direction,                     /*   read direction: 0=eq, 1=gt, -1=lt  */
struct saunam *dpknam)             /*   dynapak name to read               */
{
     CHAR *dpkstg,*begxrf,fptmp[GCMAXFNM];
     INT i;

     if (sameas(dpknam->sysid,msysid)) {
          setmbk(gcsmb);
          dpkstg=cnvs2d(dpknam);
          if (sameto("sf:osmupdfile ",dpkstg)) {
               *namtmp=*dpknam;
               retupdfile(fileparts(GCPART_FNAM,strchr(dpkstg,' ')+1,
                        fptmp,GCMAXFNM),
                 direction);
               return;
          }
          if (direction != 0) {    /* ALL AFTER HERE ARE NONDIRECTIONAL */
               rejectreq();
               return;
          }
          if (sameas(dpkstg,"s:supappid")) {
               if ((*hdlsmp)()) {
                    rsp2read(dpknam,STGLEN,spr("Y%s",supappid),NULL);
               }
               else {
                    prf("N");
                    prfmsg((*alwsup)() ? NONEWU : NONEWA);
                    r2rprf(dpknam);
                    byenow(NO_MESSAGE);
               }
               return;
          }
          else if (sameas(dpkstg,"s:jumpflags")) {
               sprintf(rsptmp,"%d",jumpflags);
               rsp2read(dpknam,STGLEN,rsptmp,NULL);
               return;
          }
          else if (sameas(dpkstg,"s:wgmversion")) {
               retwgmvr();
               return;
          }
          else if (sameas(dpkstg,"s:osmversion")) {
               rsp2read(dpknam,STGLEN,"32767",NULL); // old clients need update
               return;
          }
          else if (sameas(dpkstg,"s:osmfilelist")) {
               retfilist();
               return;
          }
          else if (sameto("sf:osmfile ",dpkstg)) {
               retfile(fileparts(GCPART_FNAM,strchr(dpkstg,' ')+1,fptmp,
                     GCMAXFNM));
               return;
          }
          else if (haskey("")) {
               if (sameto("s:useridxrf",dpkstg)) {
                    if ((begxrf=skpwht(skpwrd(dpknam->suffix))) != '\0') {
                         if (srchdat[usrnum].usingid == FREE2U) {
                              gtuids(begxrf);
                         }
                         else {
                              stzcpy(spndptr->begxrf,begxrf,XRFSIZ);
                              cycleme(wt2srch);
                         }
                         return;
                    }
               }
               else {
                    for (i=0 ; i < nelems(stdpks) ; i++) {
                         if (samepato(stdpks[i].dpknam,dpkstg)) {
                              if (stdpks[i].dpkrrou != NULL) {
                                   (*stdpks[i].dpkrrou)(dpknam);
                                   return;
                              }
                              break;
                         }
                    }
               }
          }
     }
     rejectreq();
}

static VOID
wt2srch(VOID)                      /* cycle while waiting to use x-ref fac */
{
     if (srchdat[usrnum].usingid == FREE2U) {
          cycleme(NULL);
          gtuids(spndptr->begxrf);
     }
}

static VOID
gtuids(                            /* get userids for userid x-ref list    */
CHAR *begxrf)                      /*   beginning search string            */
{
     CHAR xrf[XRFSIZ+1];

     sdatptr=&srchdat[usrnum];
     sdatptr->usingid=greqid;
     stzcpy(xrf,begxrf,XRFSIZ);
     xrf[XRFSIZ]='\0';
     dfaSetBlk(xrfbb);
     if (!dfaAcqGE(&uidxrf,xrf,0)) {
          snduids(NULL);
     }
     else {
          if (csnumxrf == 0) {
               snduids(sameas(uidxrf.userid,begxrf)
                       ? spr("%s;n=1",uidxrf.userid) : NULL);
          }
          else if (csnumxrf == 1) {
               snduids(spr("%s;n=1",uidxrf.userid));
          }
          else {
               stzcpy(sdatptr->begxrf,xrf,XRFSIZ);
               sdatptr->curpos=dfaAbs();
               sdatptr->nsofar=0;
               sdatptr->uidlst[0]='\0';
               cycleme(bldlst);
          }
     }
}

static VOID
bldlst(VOID)                       /* build user-id x-ref list             */
{
     struct uidxrf tmpxrf;
     INT i;

     dfaSetBlk(xrfbb);
     dfaGetAbs(&uidxrf,(sdatptr=&srchdat[usrnum])->curpos,0);
     for (i=0 ; i < XRFPCY ; i++) {
          if (!sameto(sdatptr->begxrf,uidxrf.xrfstg)) {
               break;
          }
          if (!sameas(uidxrf.userid,tmpxrf.userid)) {
               strcat(sdatptr->uidlst,spr("%s;",uidxrf.userid));
               if (++sdatptr->nsofar == csnumxrf) {
                    break;
               }
          }
          if (!dfaQueryNX()) {
               break;
          }
          movmem(&uidxrf,&tmpxrf,sizeof(struct uidxrf));
          movmem(xrfbb->data,&uidxrf,sizeof(struct uidxrf));
     }
     if (i < XRFPCY) {
          strcat(sdatptr->uidlst,spr("n=%d",sdatptr->nsofar));
          snduids(sdatptr->uidlst);
     }
     else {
          sdatptr->curpos=dfaAbs();
     }
}

static VOID
snduids(                           /* send userid x-ref list to client     */
CHAR *uidlst)                      /*   list to send (NULL to reject req)  */
{
     sdatptr->usingid=FREE2U;
     if (uidlst != NULL) {
          rsp2read(&rqdptr->saunam,STGLEN,uidlst,NULL);
     }
     else {
          rejectreq();
     }
}

static VOID
dpkr_agentver(                     /* "agentver" std dpk read rtn          */
struct saunam *dpknam)             /*   dynapak to read                    */
{
     CHAR mdfnam[FNEXSZ],*appid;

     appid=skpwht(skpwrd(dpknam->suffix));
     stlcpy(mdfnam,spr("%s.mdf",appid),FNEXSZ);
     if (isfile(mdfnam)) {
          rsp2read(NULL,STGLEN,scnmdf(mdfnam,"Agent version:"),NULL);
     }
     else {
          rsp2read(NULL,0,NULL,NULL);
     }
}

static VOID
dpkr_chaninfo(                     /* "chaninfo" std dpk read rtn          */
struct saunam *dpknam)             /*   dynapak to read                    */
{
     CHAR suffix[SFXSIZ],*fldnam;
     INT i;
     static struct chninfvb chninfvb;

     stlcpy(suffix,dpknam->suffix,SFXSIZ);
     if (ISMASTER() && prssfx(suffix,&fldnam)) {
          if (fldnam == NULL) {
               dpkra_chaninfo(&chninfvb);
               rsp2read(dpknam,sizeof(struct chninfvb),&chninfvb,chninfvbFDA);
               return;
          }
          for (i=0 ; i < nelems(cinflds) ; i++) {
               if (sameas(cinflds[i].fldnam,fldnam)) {
                    if (cinflds[i].fldrrou != NULL) {
                         rsp2read(dpknam,cinflds[i].retlen,
                                  (*cinflds[i].fldrrou)(),cinflds[i].flddef);
                         return;
                    }
                    break;
               }
          }
     }
     rejectreq();
}

static GBOOL
prssfx(                            /* parse "chaninfo" std dpk suffix      */
CHAR *suffix,                      /*   chaninfo dpk suffix                */
CHAR **fldnam)                     /*   ptr to set to fld name (or NULL)   */
{
     CHAR *parm,uid[UIDSIZ],*enduid;
     INT cnum,unum,ptype;

     parm=skpwht(skpwrd(suffix));
     if ((ptype=prmtyp(parm)) == ISFLD) {
          *fldnam=parm;
          parm=skpwht(skpwrd(parm));
          *skpwrd(*fldnam)='\0';
          ptype=prmtyp(parm);
     }
     else {
          *fldnam=NULL;
     }
     parm+=2;
     switch (ptype) {
     case ISNULL:
          dpkusn=usrnum;
          dpkusp=usrptr;
          dpkuap=usaptr;
          return(TRUE);
     case ISCNUM:
          sscanf(parm,"%x",&cnum);
          if ((unum=usridx(cnum)) >= 0) {
               dpkusn=unum;
               dpkusp=usroff(unum);
               dpkuap=uacoff(unum);
               return(TRUE);
          }
          break;
     case ISUID:
          if ((enduid=strchr(parm,UIDDLM)) != NULL) {
               stlcpy(uid,parm,(INT)(enduid-parm)+1);
               if (onsysn(uid,TRUE)) {
                    dpkusn=othusn;
                    dpkusp=othusp;
                    dpkuap=othuap;
                    return(TRUE);
               }
          }
          break;
     case ISUNUM:
          sscanf(parm,"%d",&unum);
          if (unum >=0 && unum < nterms) {
               dpkusn=unum;
               dpkusp=usroff(unum);
               dpkuap=uacoff(unum);
               return(TRUE);
          }
          break;
     case ISFLD:                   /* can only happen if 1st parm is a fld */
          break;
     }
     return(FALSE);
}

static INT
prmtyp(                            /* det. type of parm in dpk suffix      */
CHAR *parm)                        /*   parm to check                      */
{
     if (*parm == '\0') {
          return(ISNULL);
     }
     if (sameto("c=",parm)) {
          return(ISCNUM);
     }
     if (sameto("u=",parm)) {
          return(ISUID);
     }
     if (sameto("n=",parm)) {
          return(ISUNUM);
     }
     return(ISFLD);
}

static VOID
dpkra_chaninfo(                    /* read all "chaninfo" into structure   */
struct chninfvb *chninfvb)         /*   where to put the information       */
{
     c2bcpy(chninfvb->userid,fldr_useridc(),UIDSIZ-1);
     chninfvb->channel=cdr(fldr_channel(),SHORT);
     chninfvb->chantype=cdr(fldr_chantype(),SHORT);
     c2bcpy(chninfvb->gcditype,fldr_gcditype(),MXGCDI);
     chninfvb->usernumber=cdr(fldr_usernumber(),SHORT);
     chninfvb->baud=cdr(fldr_baud(),LONG);
     chninfvb->mode=cdr(fldr_mode(),SHORT);
}

static VOID *
fldr_useridc(VOID)                 /* chaninfo "userid" fld read rtn       */
{
     switch(dpkusp->usrcls) {
     case VACANT:
          return("");
     case ONLINE:
          return("<logging on>");
     case SUPIPG:
          return("<sign up>");
     default:
          return(dpkuap->userid);
     }
}

static VOID *
fldr_channel(VOID)                 /* chaninfo "channel" fld read rtn      */
{
     return(&channel[dpkusn]);
}

static VOID *
fldr_chantype(VOID)                /* chaninfo "chantype" fld read rtn     */
{
     dpkrvint=grtype[grpnum[dpkusn]];
     return(&dpkrvint);
}

static VOID *
fldr_gcditype(VOID)                /* chaninfo "gcditype" fld read rtn     */
{
     return(dpkusp->flags&ISGCDI ? grtsub[grpnum[dpkusn]] : "");
}

static VOID *
fldr_usernumber(VOID)              /* chaninfo "usernumber" fld read rtn   */
{
     return(&dpkusn);
}

static VOID *
fldr_baud(VOID)                    /* chaninfo "baud" fld read rtn         */
{
     dpkrvlng=(grtype[grpnum[dpkusn]] <= GTSERIAL ? dpkusp->baud
            : nilrvlng);
     return(&dpkrvlng);
}

static VOID *
fldr_mode(VOID)                    /* chaninfo "mode" fld read rtn         */
{
     if (dpkusp->usrcls == VACANT) {
          dpkrvint=nilrvint;
     }
     else {
          dpkrvint=(dpkusp->flags&ISGCSU ? -1 : dpkusp->lingo);
     }
     return(&dpkrvint);
}

static VOID
dpkr_classinfo(                    /* "classinfo" std dpk read rtn         */
struct saunam *dpknam)             /*   dynapak to read                    */
{
     CHAR *clsnam,*fldnam,suffix[SFXSIZ];
     INT i;
     static struct clsinfvb clsinfvb;

     if (ISMASTER() || ACCESS(OPACCT)) {
          stlcpy(suffix,dpknam->suffix,SFXSIZ);
          clsnam=skpwht(skpwrd(suffix));
          fldnam=skpwht(skpwrd(clsnam));
          *(skpwrd(clsnam))='\0';
          if ((clsptr=fndcls(clsnam)) != NULL) {
               if (*fldnam == '\0') {
                    dpkra_classinfo(&clsinfvb);
                    rsp2read(dpknam,sizeof(struct clsinfvb),&clsinfvb,clsinfvbFDA);
                    return;
               }
               for (i=0 ; i < nelems(clsflds) ; i++) {
                    if (sameas(clsflds[i].fldnam,fldnam)) {
                         if (clsflds[i].fldrrou != NULL) {
                              rsp2read(dpknam,clsflds[i].retlen,
                                       (*clsflds[i].fldrrou)(),clsflds[i].flddef);
                              return;
                         }
                         break;
                    }
               }
          }
     }
     rejectreq();
}

static VOID
dpkw_classkill(                    /* "classkill" std dpk write rtn        */
struct saunam *dpknam,             /*   dynapak to write                   */
UINT length,                       /*   length of dynapak value            */
VOID *value)                       /*   dynapak value                      */
{
     CHAR *clsnam,suffix[SFXSIZ];

     (VOID)length;
     (VOID)value;
     if (ISMASTER() || ACCESS(OPACCT)) {
          clrprf();
          stlcpy(suffix,dpknam->suffix,SFXSIZ);
          clsnam=skpwht(skpwrd(suffix));
          *(skpwrd(clsnam))='\0';
          if ((clsptr=fndcls(clsnam)) != NULL) {
               dltcls(clsptr);
               r2wprf(TRUE);
               return;
          }
          else {
               prf("NOTFND");
               r2wprf(FALSE);
               return;
          }
     }
     rejectreq();
}

static VOID
dpkw_copyuser(                     /* "copyuser" std dpk write rtn         */
struct saunam *dpknam,             /*   dynapak to write                   */
UINT length,                       /*   length of dynapak value            */
VOID *value)                       /*   dynapak value                      */
{
     CHAR *retval="No Access";
     CHAR uid[UIDSIZ];
     CHAR psw[PSWSIZ];

     clrprf();
     if ((length > 0) && ISMASTER()) {
          stzcpy(uid,itemidx(value,0),UIDSIZ);
          stzcpy(psw,itemidx(value,1),PSWSIZ);
          retval=copyuser(skpwht(skpwrd(dpknam->suffix)),uid,psw,NULL);
          if (retval == NULL) {
               rsp2write(TRUE,STGLEN,uid,NULL);
               return;
          }
     }
     prf("%s",retval);
     r2wprf(FALSE);
}

static VOID
dpkw_classinfo(                    /* "classinfo" std dpk write rtn        */
struct saunam *dpknam,             /*   dynapak to write                   */
UINT length,                       /*   length of dynapak information      */
VOID *value)                       /*   dynapak value (VB structure)       */
{
     GBOOL vldreq;
     struct acclass clsnfo;
     struct clstab *clptr;
     CHAR *clsnam,*fldnam,suffix[SFXSIZ],id[UIDSIZ];
     INT i;

     if (ISMASTER() || ACCESS(OPACCT)) {
          clrprf();
          stlcpy(suffix,dpknam->suffix,SFXSIZ);
          clsnam=skpwht(skpwrd(suffix));
          fldnam=skpwht(skpwrd(clsnam));
          *(skpwrd(clsnam))='\0';
          setmem(&clsnfo,sizeof(struct clstab),0);
          dfaSetBlk(clsbb);
          if ((clptr=fndcls(clsnam)) != NULL) {
               dfaGetEQ(&clsnfo,clsnam,0);
          }
          else {
               stlcpy(clsnfo.clname,strupr(clsnam),KEYSIZ);
          }
          if (*fldnam == '\0') {
               if (length == sizeof(struct clsinfvb)) {
                    vldreq=dpkwa_classinfo((struct clsinfvb *)value,&clsnfo);
               }
               else {
                    vldreq=FALSE;
               }
          }
          else {
               vldreq=FALSE;
               for (i=0 ; i < nelems(clsflds) ; i++) {
                    if (sameas(clsflds[i].fldnam,fldnam)) {
                         if (uinflds[i].fldwrou != NULL) {
                              vldreq=(*clsflds[i].fldwrou)(value,&clsnfo);
                         }
                         break;
                    }
               }
          }
          if (vldreq == TRUE) {
               if (clptr != NULL) {
                    movmem(&clsnfo,clptr,
                           sizeof(struct clstab)-sizeof(struct clstab *));
                    dfaUpdate(&clsnfo);
               }
               else {
                    dfaRstBlk();
                    if (crtclass(&clsnfo)) {
                         id[0]=RINGID;
                         stlcpy(id+1,clsnfo.clname,KEYSIZ);
                         nkyrec(id);
                         r2wprf(TRUE);
                         return;
                    }
                    else {
                         prf("NOMEM");
                         r2wprf(FALSE);
                         return;
                    }
               }
          }
          else {
               dfaRstBlk();
               prf("NOTVLD");
               r2wprf(FALSE);
               return;
          }
     }
     dfaRstBlk();
     rejectreq();
}

static GBOOL
dpkwa_classinfo(                   /* write all "classinfo" to memory/file */
struct clsinfvb *clsinfvb,         /*   where to get the information       */
struct acclass *clsdat)            /*   where to put the information       */
{
     return(fldw_nextclass(clsinfvb->nextclass,clsdat)
         && fldw_limpercall(&clsinfvb->limpercall,clsdat)
         && fldw_limperday(&clsinfvb->limperday,clsdat)
         && fldw_defdayexp(&clsinfvb->defdayexp,clsdat)
         && fldw_debtlimtc(&clsinfvb->debtlimit,clsdat)
         && fldw_forgivdays(&clsinfvb->forgivdays,clsdat)
         && fldw_idledays(&clsinfvb->idledays,clsdat)
         && fldw_flags(&clsinfvb->flags,clsdat)
         && fldw_seconds(&clsinfvb->seconds,clsdat)
         && fldw_usersin(&clsinfvb->usersin,clsdat));
}

static GBOOL
fldw_nextclass(                    /* classinfo "nextclass" write routine  */
CHAR *clsstg,
struct acclass *clsdat)
{
     INT i,cnt;
     CHAR *wrkstr,*sptr;

     wrkstr=strupr(b2ccvt(clsstg,NCLSSZ));
     cnt=itemcntd(wrkstr,";");
     for (i=0 ; i < cnt ; i++) {
          sptr=itemidxd(wrkstr,i,";");
          switch(*sptr) {
          case 'O':
               stlcpy(clsdat->nxtcls[DOUTTIM],sptr+2,KEYSIZ);
               break;
          case 'L':
               stlcpy(clsdat->nxtcls[DLOAFER],sptr+2,KEYSIZ);
               break;
          case 'E':
               stlcpy(clsdat->nxtcls[DEXPIRE],sptr+2,KEYSIZ);
               break;
          case 'C':
               stlcpy(clsdat->nxtcls[DCREDIT],sptr+2,KEYSIZ);
               break;
          default:
               break;
          }
     }
     return(TRUE);
}

static GBOOL
fldw_limpercall(                   /* classinfo "limpercall" write routine */
SHORT *newlim,
struct acclass *clsdat)
{
     if ((*newlim >= -1 && *newlim <= 1440) || (*newlim == -1)) {
          clsdat->limcal=*newlim;
          return(TRUE);
     }
     return(FALSE);
}

static GBOOL
fldw_limperday(                    /* classinfo "limperday" write routine  */
SHORT *newlim,
struct acclass *clsdat)
{
     if ((*newlim >= -1 && *newlim <= 1440)) {
          clsdat->limday=*newlim;
          return(TRUE);
     }
     return(FALSE);
}


static GBOOL
fldw_defdayexp(                    /* classinfo "defdayexp" write routine  */
SHORT *newexp,
struct acclass *clsdat)
{
     if (*newexp >= -1) {
          clsdat->dftday=*newexp;
          return(TRUE);
     }
     return(FALSE);
}

static GBOOL
fldw_debtlimtc(                    /* classinfo "debtlimtc" write routine  */
LONG *newlim,
struct acclass *clsdat)
{
     if ((*newlim >= -1 && *newlim <= 9999999L)) {
          clsdat->dbtlmt=*newlim;
          return(TRUE);
     }
     return(FALSE);
}

static GBOOL
fldw_forgivdays(                   /* classinfo "forgivdays" write routine */
SHORT *newday,
struct acclass *clsdat)
{
     if (*newday >= -1) {
          clsdat->fgvday=*newday;
          return(TRUE);
     }
     return(FALSE);
}

static GBOOL                       /* classinfo "idledays" write routine   */
fldw_idledays(
SHORT *newday,
struct acclass *clsdat)
{
     if (*newday >= -1) {
          clsdat->idlday=*newday;
          return(TRUE);
     }
     return(FALSE);
}

static GBOOL
fldw_flags(                        /* classinfo "flags" write routine      */
SHORT *newflg,
struct acclass *clsdat)
{
     clsdat->flags=*newflg;
     return(TRUE);
}

static GBOOL
fldw_seconds(                      /* classinfo "seconds" write routine    */
LONG *newsec,
struct acclass *clsdat)
{
     clsdat->seconds=*newsec;
     return(TRUE);
}

static GBOOL
fldw_usersin(                      /* classinfo "usersin" write routine    */
LONG *newusr,
struct acclass *clsdat)
{
     clsdat->users=(USHORT)*newusr;
     return(TRUE);
}

static VOID
dpkra_classinfo(                   /* read all "classinfo" into structure  */
struct clsinfvb *clsinfvb)         /*   where to put the information       */
{
     c2bcpy(clsinfvb->nextclass,fldr_nextclass(),NCLSSZ);
     clsinfvb->limpercall=cdr(fldr_limpercall(),SHORT);
     clsinfvb->limperday=cdr(fldr_limperday(),SHORT);
     clsinfvb->defdayexp=cdr(fldr_defdayexp(),SHORT);
     clsinfvb->debtlimit=cdr(fldr_debtlimtc(),LONG);
     clsinfvb->forgivdays=cdr(fldr_forgivdays(),SHORT);
     clsinfvb->idledays=cdr(fldr_idledays(),SHORT);
     clsinfvb->flags=cdr(fldr_flags(),SHORT);
     clsinfvb->seconds=cdr(fldr_seconds(),LONG);
     clsinfvb->usersin=cdr(fldr_usersin(),LONG);
}

static VOID *
fldr_nextclass(VOID)               /* classinfo "nextclass" fld read rtn   */
{
     static CHAR clsstg[NCLSSZ+1];

     setmem(clsstg,NCLSSZ+1,0);
     sprintf(clsstg,"O:%s;L:%s;E:%s;C:%s",
             clsptr->nxtcls[DOUTTIM],clsptr->nxtcls[DLOAFER],
             clsptr->nxtcls[DEXPIRE],clsptr->nxtcls[DCREDIT]);
     return(clsstg);
}

static VOID *
fldr_limpercall(VOID)              /* classinfo "limpercall" fld read rtn  */
{
     return(&clsptr->limcal);
}

static VOID *
fldr_limperday(VOID)               /* classinfo "limperday" fld read rtn   */
{
     return(&clsptr->limday);
}

static VOID *
fldr_defdayexp(VOID)               /* classinfo "defdayexp" fld read rtn   */
{
     return(&clsptr->dftday);
}

static VOID *
fldr_debtlimtc(VOID)               /* classinfo "debtlimit" fld read rtn   */
{
     return(&clsptr->dbtlmt);
}

static VOID *
fldr_forgivdays(VOID)              /* classinfo "forgivdays" fld read rtn  */
{
     return(&clsptr->fgvday);
}

static VOID *
fldr_idledays(VOID)                /* classinfo "idledays" fld read rtn    */
{
     return(&clsptr->idlday);
}

static VOID *
fldr_flags(VOID)                   /* classinfo "flags" fld read rtn       */
{
     return(&clsptr->flags);
}

static VOID *
fldr_seconds(VOID)                 /* classinfo "seconds" fld read rtn     */
{
     return(&clsptr->seconds);
}

static VOID *
fldr_usersin(VOID)                 /* classinfo "usersin" fld read rtn     */
{
     dpkrvlng=(LONG)clsptr->users;
     return(&dpkrvlng);
}

static VOID
dpkr_classkeys(                    /* "classkeys" std dpk read rtn         */
struct saunam *dpknam)             /*   dynapak to read                    */
{
     if (ISMASTER() || ACCESS(OPACCT) || ACCESS(OPDETL)) {
          gtkrng(skpwht(skpwrd(dpknam->suffix)),TRUE,dpknam);
          return;
     }
     rejectreq();
}

static VOID
dpkw_classkeys(                    /* "classkeys" std dpk write rtn        */
struct saunam *dpknam,             /*   dynapak to read                    */
UINT length,                       /*   length of keyring list             */
VOID *value)                       /*   lists of all the keys              */
{
     if (ISMASTER() || ACCESS(OPACCT)) {
          if (length < RINGSZ+32) {
               ptkrng(skpwht(skpwrd(dpknam->suffix)),(CHAR *)value,TRUE);
               return;
          }
          else {
               prf("TOOLNG");
               r2wprf(FALSE);
               return;
          }
     }
     rejectreq();
}

static VOID
dpkr_classmsgs(                    /* "classmsgs" std dpk read rtn         */
struct saunam *dpknam)             /*   dynapak to read                    */
{
     struct acclass clsrec;
     CHAR id[KEYSIZ],*clsnam;

     if (ISMASTER() || ACCESS(OPACCT)) {
          clsnam=skpwht(skpwrd(dpknam->suffix));
          stlcpy(id,clsnam,KEYSIZ);
          dfaSetBlk(clsbb);
          setmem(&clsrec,sizeof(struct acclass),0);
          if (dfaAcqEQ(&clsrec,id,0)) {
               cpyrsp(clsrec.msgs[0]);
               delimiter();
               catrsp(clsrec.msgs[1]);
               rsp2read(dpknam,STGLEN,rsptmp,NULL);
               dfaRstBlk();
               return;
          }
     }
     dfaRstBlk();
     rejectreq();
}

static VOID
dpkw_classmsgs(                    /* "classmsgs" std write dpk routine    */
struct saunam *dpknam,             /*   dynapak name                       */
UINT length,                   /*   length of dynapak value            */
VOID *value)                       /*   dynapak value                      */
{
     struct acclass clsrec;
     CHAR *clsnam,*fstmsg,*secmsg,id[KEYSIZ];

     (VOID)length;
     if (ISMASTER() || ACCESS(OPACCT)) {
          clrprf();
          fstmsg=(CHAR *)value;
          clsnam=skpwht(skpwrd(dpknam->suffix));
          stlcpy(id,clsnam,KEYSIZ);
          dfaSetBlk(clsbb);
          setmem(&clsrec,sizeof(struct acclass),0);
          if (dfaAcqEQ(&clsrec,id,0)) {
               if ((secmsg=strchr((const CHAR *)fstmsg,9)) != NULL) {
                    *secmsg++='\0';
                    stlcpy(clsrec.msgs[0],fstmsg,XMSGSZ);
                    stlcpy(clsrec.msgs[1],secmsg,XMSGSZ);
               }
               dfaUpdate(&clsrec);
               r2wprf(TRUE);
               dfaRstBlk();
               return;
          }
          else {
               dfaRstBlk();
               prf("NOTFND");
               r2wprf(FALSE);
               return;
          }
     }
     dfaRstBlk();
     rejectreq();
}

static VOID
dpkr_classlist(                    /* "classlist" std dpk read rtn         */
struct saunam *dpknam)             /*   dynapak to read                    */
{
     struct clstab *clmptr;

     if (ISMASTER() || ACCESS(OPACCT) || ACCESS(OPDETL)) {
          *rsptmp='\0';
          clmptr=clshead;
          while (clmptr != NULL) {
               if (!(clmptr->flags&HASCRD && clmptr->flags&NOCRED)) {
                    if (*rsptmp != '\0') {
                         delimiter();
                    }
                    catrsp(clmptr->clname);
               }
               clmptr=clmptr->next;
          }
          rsp2read(dpknam,STGLEN,rsptmp,NULL);
          return;
     }
     rejectreq();
}

static VOID
dpkr_langlist(                     /* "langlist" std dpk read rtn          */
struct saunam *dpknam)             /*   dynapak to read                    */
{
     INT i;

     rsptmp[0]='\0';
     for (i=0 ; i < nlingo ; i++) {
          strcat(rsptmp,spr("%-15s %-50s%c",languages[i]->name,
                            languages[i]->desc,LNGSEP));
     }
     strcat(rsptmp,spr("n=%d",nlingo));
     rsp2read(dpknam,(LNGSIZ+LNGDSC)*nlingo+LSFXSZ,rsptmp,NULL);
}

static VOID
dpkr_rsptime(                      /* "rsptime" std dpk read rtn           */
struct saunam *dpknam)             /*   dynapak to read                    */
{
     if (ISMASTER()) {
          rsp2read(dpknam,LNGLEN,&rsptim,longFDA);
          return;
     }
     rejectreq();
}

static VOID
dpkr_sysinfo(                      /* "sysinfo" std dpk read rtn           */
struct saunam *dpknam)             /*   dynapak to read                    */
{
     CHAR *fldnam;
     INT i;
     static struct sysinfvb sysinfvb;

     fldnam=skpwht(skpwrd(dpknam->suffix));
     if (*fldnam == '\0') {
          dpkra_sysinfo(&sysinfvb);
          rsp2read(dpknam,sizeof(struct sysinfvb),&sysinfvb,sysinfvbFDA);
          return;
     }
     for (i=0 ; i < nelems(sinflds) ; i++) {
          if (sameas(sinflds[i].fldnam,fldnam)) {
               if (sinflds[i].fldrrou != NULL) {
                    rsp2read(dpknam,sinflds[i].retlen,(*sinflds[i].fldrrou)(),
                             sinflds[i].flddef);
                    return;
               }
               break;
          }
     }
     rejectreq();
}

static VOID
dpkra_sysinfo(                     /* read all "sysinfo" into structure    */
struct sysinfvb *sysinfvb)         /*   where to put the information       */
{
     c2bcpy(sysinfvb->sysname,fldr_sysname(),TTLSIZ);
     c2bcpy(sysinfvb->syscompany,fldr_syscompany(),CMPSIZ);
     c2bcpy(sysinfvb->sysaddr1,fldr_sysaddr1(),ADDRSZ);
     c2bcpy(sysinfvb->sysaddr2,fldr_sysaddr2(),ADDRSZ);
     c2bcpy(sysinfvb->sysphone,fldr_sysphone(),DTPHSZ);
     c2bcpy(sysinfvb->restpho,fldr_restpho(),LVPHSZ);
     c2bcpy(sysinfvb->chgperhr,fldr_chgperhr(),CGHRSZ);
     c2bcpy(sysinfvb->mincharge,fldr_mincharge(),CGMNSZ);
     c2bcpy(sysinfvb->regnumber,fldr_regnumber(),RNOSIZ);
}

static VOID *
fldr_sysname(VOID)                 /* sysinfo "sysname" fld read rtn       */
{
     return(bbsttl);
}

static VOID *
fldr_syscompany(VOID)              /* sysinfo "syscompany" fld read rtn    */
{
     return(company);
}

static VOID *
fldr_sysaddr1(VOID)                /* sysinfo "sysaddr1" fld read rtn      */
{
     return(addres1);
}

static VOID *
fldr_sysaddr2(VOID)                /* sysinfo "sysaddr2" fld read rtn      */
{
     return(addres2);
}

static VOID *
fldr_sysphone(VOID)                /* sysinfo "sysphone" fld read rtn      */
{
     return(dataph);
}

static VOID *
fldr_restpho(VOID)                 /* sysinfo "restpho" fld read rtn       */
{
     return(liveph);
}

static VOID *
fldr_chgperhr(VOID)                /* sysinfo "chgperhr" fld read rtn      */
{
     return(chghour);
}

static VOID *
fldr_mincharge(VOID)               /* sysinfo "mincharge" fld read rtn     */
{
     return(chgmin);
}

static VOID *
fldr_regnumber(VOID)               /* sysinfo "regnumber" fld read rtn     */
{
     return(bturno);
}

static VOID
dpkr_sysloading(                   /* "sysloading" std dpk read rtn        */
struct saunam *dpknam)             /*   dynapak to read                    */
{
     if (ISMASTER()) {
          rsp2read(dpknam,INTLEN,&syslod,shortFDA);
          return;
     }
     rejectreq();
}

static VOID
dpkr_syspolrate(                   /* "syspolrate" std dpk read rtn        */
struct saunam *dpknam)             /*   dynapak to read                    */
{
     if (ISMASTER()) {
          rsp2read(dpknam,INTLEN,&maxpol,shortFDA);
          return;
     }
     rejectreq();
}

static VOID
dpkr_sysstat(                      /* "sysstat" std dpk read rtn           */
struct saunam *dpknam)             /*   dynapak to read                    */
{
     CHAR *fldnam;
     INT i;
     static struct stainfvb stainfvb;

     if (haskey(stakey) || ACCESS(OPSYSS)) {
          fldnam=skpwht(skpwrd(dpknam->suffix));
          if (*fldnam == '\0') {
               dpkra_sysstat(&stainfvb);
               rsp2read(dpknam,sizeof(struct stainfvb),&stainfvb,stainfvbFDA);
               return;
          }
          for (i=0 ; i < nelems(staflds) ; i++) {
               if (sameas(staflds[i].fldnam,fldnam)) {
                    if (staflds[i].fldrrou != NULL) {
                         rsp2read(dpknam,staflds[i].retlen,
                                  (*staflds[i].fldrrou)(),staflds[i].flddef);
                         return;
                    }
                    break;
               }
          }
     }
     rejectreq();
}

static VOID
dpkra_sysstat(                     /* read all "sysstat" into structure    */
struct stainfvb *stainfvb)         /*   where to put the information       */
{
     stainfvb->numlines=cdr(fldr_numlines(),SHORT);
     stainfvb->othonline=cdr(fldr_othonline(),SHORT);
     stainfvb->totalcalls=cdr(fldr_totalcalls(),LONG);
     stainfvb->downloads=cdr(fldr_downloads(),LONG);
     stainfvb->uploads=cdr(fldr_uploads(),LONG);
     stainfvb->totalmsgs=cdr(fldr_totalmsgs(),LONG);
     stainfvb->totalaccts=cdr(fldr_totalaccts(),LONG);
     stainfvb->totalmale=cdr(fldr_totalmale(),LONG);
     stainfvb->totalfemale=cdr(fldr_totalfemale(),LONG);
     stainfvb->totalcorp=cdr(fldr_totalcorp(),LONG);
     stainfvb->totalansi=cdr(fldr_totalansi(),LONG);
}

static VOID *
fldr_numlines(VOID)                /* sysstat "numlines" fld read rtn      */
{
     return(&nterms);
}

static VOID *
fldr_othonline(VOID)               /* sysstat "othonline" fld read rtn     */
{
     INT othusn;
     GBOOL iginv;

     dpkrvint=0;
     iginv=ISMASTER();
     for (othusn=0 ; othusn < nterms ; othusn++) {
          if (incusr(othusn,FALSE,iginv) > VACANT) {
               dpkrvint++;
          }
     }
     return(&dpkrvint);
}

static VOID *
fldr_totalcalls(VOID)              /* sysstat "totalcalls" fld read rtn    */
{
     return(&sv2.totcalls);
}

static VOID *
fldr_downloads(VOID)               /* sysstat "downloads" fld read rtn     */
{
     return(&sv.dwnlds);
}

static VOID *
fldr_uploads(VOID)                 /* sysstat "uploads" fld read rtn       */
{
     return(&sv.uplds);
}

static VOID *
fldr_totalmsgs(VOID)               /* sysstat "totalmsgs" fld read rtn     */
{
     return(&sv.msgtot);
}

static VOID *
fldr_totalaccts(VOID)              /* sysstat "totalaccts" fld read rtn    */
{
     dpkrvulng=sv2.numact;
     return(&dpkrvulng);
}

static VOID *
fldr_totalmale(VOID)               /* sysstat "totalmale" fld read rtn     */
{
     dpkrvulng=sv2.numact-sv2.numfem;
     return(&dpkrvulng);
}

static VOID *
fldr_totalfemale(VOID)             /* sysstat "totalfemale" fld read rtn   */
{
     dpkrvulng=sv2.numfem;
     return(&dpkrvulng);
}

static VOID *
fldr_totalcorp(VOID)               /* sysstat "totalcorp" fld read rtn     */
{
     dpkrvulng=sv2.numcor;
     return(&dpkrvulng);
}

static VOID *
fldr_totalansi(VOID)               /* sysstat "totalansi" fld read rtn     */
{
     dpkrvulng=sv2.numans;
     return(&dpkrvulng);
}

static VOID
dpkr_useridinfo(                   /* "useridinfo" std dpk read rtn        */
struct saunam *dpknam)             /*   dynapak to read                    */
{
     CHAR *namdef[]={"REAL","DEFAULT","ASK"};
     CHAR retstg[UIDISZ];

     setmem(retstg,UIDISZ,0);
     sprintf(retstg,"%d %c %c %s",sgnusz,digalw ? 'Y' : 'N',
          fulalw ? 'Y' : 'N',namdef[namdft-1]);
     rsp2read(dpknam,STGLEN,retstg,NULL);
}

static VOID
dpkr_userinfo(                     /* "userinfo" std dpk read rtn          */
struct saunam *dpknam)             /*   dynapak to read                    */
{
     CHAR *fldnam;
     INT i;
     static struct usrinfvb usrinfvb;
     GBOOL vldreq;

     vldreq=vlduid(dpknam->usrid);
     if (!vldreq && invldres == CANTALTR) {
          vldreq=ACCESS(OPDETL) || ACCESS(OPACCT) || haskey(glbkey);
     }
     if (vldreq) {
          fldnam=skpwht(skpwrd(dpknam->suffix));
          if (*fldnam == '\0') {
               dpkra_userinfo(&usrinfvb);
               rsp2read(dpknam,sizeof(struct usrinfvb),&usrinfvb,usrinfvbFDA);
               return;
          }
          for (i=0 ; i < nelems(uinflds) ; i++) {
               if (sameas(uinflds[i].fldnam,fldnam)) {
                    if (uinflds[i].fldrrou != NULL) {
                         rsp2read(dpknam,uinflds[i].retlen,
                                  (*uinflds[i].fldrrou)(),uinflds[i].flddef);
                         return;
                    }
                    break;
               }
          }
     }
     else if (accrec.userid[0] != '\0') {
          rsp2read(dpknam,STGLEN,accrec.userid,NULL);
          return;
     }
     rejectreq();
}

static VOID
dpkra_userinfo(                    /* read all "userinfo" into structure   */
struct usrinfvb *usrinfvb)         /*   where to put the information       */
{
     SHORT i,*iptr;

     c2bcpy(usrinfvb->userid,fldr_userid(),UIDSIZ-1);
     c2bcpy(usrinfvb->password,fldr_password(),PSWSIZ-1);
     c2bcpy(usrinfvb->name,fldr_name(),NADSIZ-1);
     c2bcpy(usrinfvb->company,fldr_company(),NADSIZ-1);
     c2bcpy(usrinfvb->address1,fldr_address1(),NADSIZ-1);
     c2bcpy(usrinfvb->address2,fldr_address2(),NADSIZ-1);
     c2bcpy(usrinfvb->address3,fldr_address3(),NADSIZ-1);
     c2bcpy(usrinfvb->phone,fldr_phone(),PHOSIZ-1);
     usrinfvb->systemtype=cdr(fldr_systemtype(),SHORT);
     usrinfvb->ansi=cdr(fldr_ansi(),SHORT);
     usrinfvb->scnwidth=cdr(fldr_scnwidth(),SHORT);
     usrinfvb->scnlength=cdr(fldr_scnlength(),SHORT);
     usrinfvb->fsescnlen=cdr(fldr_fsescnlen(),SHORT);
     usrinfvb->editorprf=cdr(fldr_editorprf(),CHAR);
     usrinfvb->age=cdr(fldr_age(),SHORT);
     usrinfvb->birthdate=cdr(fldr_birthdate(),DOUBLE);
     usrinfvb->sex=cdr(fldr_sex(),CHAR);
     usrinfvb->createdate=cdr(fldr_createdate(),DOUBLE);
     usrinfvb->laston=cdr(fldr_laston(),DOUBLE);
     c2bcpy(usrinfvb->acctcls,fldr_class(),KEYSIZ-1);
     c2bcpy(usrinfvb->retclass,fldr_retclass(),KEYSIZ-1);
     usrinfvb->creditrate=cdr(fldr_creditrate(),SHORT);
     usrinfvb->credits=cdr(fldr_credits(),LONG);
     usrinfvb->credever=cdr(fldr_credever(),LONG);
     usrinfvb->paidever=cdr(fldr_paidever(),LONG);
     usrinfvb->timeonline=cdr(fldr_timeonline(),SHORT);
     usrinfvb->calltimlim=cdr(fldr_calltimlim(),SHORT);
     usrinfvb->daytimlim=cdr(fldr_daytimlim(),SHORT);
     usrinfvb->timetoday=cdr(fldr_timetoday(),LONG);
     usrinfvb->daysleft=cdr(fldr_daysleft(),SHORT);
     usrinfvb->debtlimit=cdr(fldr_debtlimit(),LONG);
     usrinfvb->exempt=cdr(fldr_exempt(),CHAR);
     usrinfvb->language=cdr(fldr_language(),SHORT);
     usrinfvb->permlang=cdr(fldr_permlang(),SHORT);
     usrinfvb->acctflags=cdr(fldr_acctflags(),SHORT);
     iptr=cvp(fldr_access(),SHORT);
     for (i=0 ; i < AXSSIZ ; i++) {
          usrinfvb->access[i]=*iptr++;
     }
}

static VOID *
fldr_secondstt(VOID)               /* userinfo "secondstt" fld read rtn    */
{
     dpkrvlng=(dpkuap->timtdy);
     return(&dpkrvlng);
}

static VOID *
fldr_userid(VOID)                  /* userinfo "userid" fld read rtn       */
{
     return(dpkuap->userid);
}

static VOID *
fldr_password(VOID)                /* userinfo "password" fld read rtn     */
{
     return(uidsame || vispsw ? dpkuap->psword : "");
}

static VOID *
fldr_name(VOID)                    /* userinfo "name" fld read rtn         */
{
     return(dpkuap->usrnam);
}

static VOID *
fldr_company(VOID)                 /* userinfo "company" fld read rtn      */
{
     return(dpkuap->usrad1);
}

static VOID *
fldr_address1(VOID)                /* userinfo "address1" fld read rtn     */
{
     return(dpkuap->usrad2);
}

static VOID *
fldr_address2(VOID)                /* userinfo "address2" fld read rtn     */
{
     return(dpkuap->usrad3);
}

static VOID *
fldr_address3(VOID)                /* userinfo "address3" fld read rtn     */
{
     return(dpkuap->usrad4);
}

static VOID *
fldr_phone(VOID)                   /* userinfo "phone" fld read rtn        */
{
     return(dpkuap->usrpho);
}

static VOID *
fldr_systemtype(VOID)              /* userinfo "systemtype" fld read rtn   */
{
     dpkrvint=dpkuap->systyp;
     return(&dpkrvint);
}

static VOID *
fldr_ansi(VOID)                    /* userinfo "ansi" fld read rtn         */
{
     dpkrvint=dpkuap->ansifl;
     return(&dpkrvint);
}

static VOID *
fldr_scnwidth(VOID)                /* userinfo "scnwidth" fld read rtn     */
{
     dpkrvint=dpkuap->scnwid;
     return(&dpkrvint);
}

static VOID *
fldr_scnlength(VOID)               /* userinfo "scnlength" fld read rtn    */
{
     dpkrvint=dpkuap->scnbrk;
     return(&dpkrvint);
}

static VOID *
fldr_fsescnlen(VOID)               /* userinfo "fsescnlen" fld read rtn    */
{
     dpkrvint=dpkuap->scnfse;
     return(&dpkrvint);
}

static VOID *
fldr_editorprf(VOID)               /* userinfo "editorprf" fld read rtn    */
{
     dpkrvchr=dpkuap->usrprf&PRFLIN ? 'L' : 'F';
     return(&dpkrvchr);
}

static VOID *
fldr_age(VOID)                     /* userinfo "age" fld read rtn          */
{
     dpkrvint=dpkuap->age > 0 ? (INT)dpkuap->age : nilrvint;
     return(&dpkrvint);
}

static VOID *
fldr_birthdate(VOID)
{
     dpkrvdbl=s2vdat(strBirthdate(dpkuap->birthd),"");
     return(&dpkrvdbl);
}

static VOID *
fldr_sex(VOID)                     /* userinfo "sex" fld read rtn          */
{
     dpkrvchr=(dpkuap->sex == 'M' || dpkuap->sex == 'F' ? dpkuap->sex : 'U');
     return(&dpkrvchr);
}

static VOID *
fldr_createdate(VOID)              /* userinfo "createdate" fld read rtn   */
{
     dpkrvdbl=d2vdat(dpkuap->credat,0.0);
     return(&dpkrvdbl);
}

static VOID *
fldr_laston(VOID)                  /* userinfo "laston" fld read rtn       */
{
     if (dpkuap->usedat == 0) {
          dpkrvdbl=0.0;
     }
     else {
          dpkrvdbl=d2vdat(dpkuap->usedat,0.0);
     }
     return(&dpkrvdbl);
}

static VOID *
fldr_class(VOID)                   /* userinfo "class" fld read rtn        */
{
     return(dpkuap->curcls);
}

static VOID *
fldr_retclass(VOID)                /* userinfo "retclass" fld read rtn     */
{
     return(dpkuap->prmcls);
}

static VOID *
fldr_creditrate(VOID)              /* userinfo "creditrate" fld read rtn   */
{
     return(usron ? &dpkusp->crdrat : &nilrvint);
}

static VOID *
fldr_credits(VOID)                 /* userinfo "credits" fld read rtn      */
{
     return(&dpkuap->creds);
}

static VOID *
fldr_credever(VOID)                /* userinfo "credever" fld read rtn     */
{
     return(&dpkuap->totcreds);
}

static VOID *
fldr_paidever(VOID)                /* userinfo "paidever" fld read rtn     */
{
     return(&dpkuap->totpaid);
}

static VOID *
fldr_timeonline(VOID)              /* userinfo "timeonline" fld read rtn   */
{
     dpkrvint=usron ? (dpkusp->minut4+2)/4 : nilrvint;
     return(&dpkrvint);
}

static VOID *
fldr_calltimlim(VOID)              /* userinfo "calltimlim" fld read rtn   */
{
     return((clsptr=getctp()) != NULL ? &clsptr->limcal : &nilrvint);
}

static VOID *
fldr_daytimlim(VOID)               /* userinfo "daytimlim" fld read rtn    */
{
     return((clsptr=getctp()) != NULL ? &clsptr->limday : &nilrvint);
}

static VOID *
fldr_timetoday(VOID)               /* userinfo "timetoday" fld read rtn    */
{
     dpkrvlng=(dpkuap->timtdy+30L)/60L;
     return(&dpkrvlng);
}

static VOID *
fldr_daysleft(VOID)                /* userinfo "daysleft" fld read rtn     */
{
     if ((clsptr=getctp()) == NULL) {
          return(&nilrvlng);
     }
     dpkrvlng=clsptr->flags&DAYEXP ? (LONG)dpkuap->daystt : -1L;
     return(&dpkrvlng);
}

static VOID *
fldr_debtlimit(VOID)               /* userinfo "debtlimit" fld read rtn    */
{
     return((clsptr=getctp()) != NULL ? &clsptr->dbtlmt : &nilrvlng);
}

static VOID *
fldr_exempt(VOID)                  /* userinfo "exempt" fld read rtn       */
{
     if ((clsptr=getctp()) == NULL) {
          return(&nilrvchr);
     }
     dpkrvchr=clsptr->flags&CRDXMT ? 'Y' : 'N';
     return(&dpkrvchr);
}

static VOID *
fldr_language(VOID)                /* userinfo "language" fld read rtn     */
{
     return(rdlng(TRUE));
}

static VOID *
fldr_permlang(VOID)                /* userinfo "permlang" fld read rtn     */
{
     return(rdlng(FALSE));
}

static VOID *                      /* userinfo "acctflags" fld read rtn    */
fldr_acctflags(VOID)
{
     return(&dpkuap->flags);
}

static VOID *
fldr_access(VOID)                  /* userinfo "remote access" fld read rtn*/
{
     return(dpkuap->access);
}

static struct clstab *
getctp(VOID)                       /* get req'd uid's class table pointer  */
{
     return(usron ? dpkusp->cltptr : fndcls(dpkuap->curcls));
}

static VOID
dpkr_usrclskeys(                   /* "usrclskeys" std dpk read rtn        */
struct saunam *dpknam)             /*   dynapak to read                    */
{
     if (vlduid(dpknam->usrid)) {
          gtkrng((uidsame ? dpkusp->cltptr->clname : dpkuap->curcls),
                 TRUE,dpknam);
          return;
     }
     rejectreq();
}

static VOID
dpkw_usrpslkeys(                   /* "usrpslkeys" std dpk write rtn       */
struct saunam *dpknam,             /*   dynapak to read                    */
UINT length,                       /*   length of keyring list             */
VOID *value)                       /*   lists of all the keys              */
{
     if (ISMASTER() || ACCESS(OPACCT)) {
          if (length < RINGSZ+32) {
               ptkrng(skpwht(skpwrd(dpknam->suffix)),(char *)value,FALSE);
               return;
          }
          else {
               prf("TOOLNG");
               r2wprf(FALSE);
               return;
          }
     }
     rejectreq();
}

static VOID
dpkr_usrpslkeys(                   /* "usrpslkeys" std dpk read rtn        */
struct saunam *dpknam)             /*   dynapak to read                    */
{
     GBOOL vldreq;

     vldreq=vlduid(dpknam->usrid);
     if (!vldreq && invldres == CANTALTR) {
          vldreq=ACCESS(OPACCT);
     }
     if (vldreq) {
          gtkrng(dpknam->usrid,FALSE,dpknam);
          return;
     }
     rejectreq();
}

static VOID
syswrite(                          /* write-dynapak handler                */
struct saunam *dpknam,             /*   dynapak name to write              */
USHORT length,                     /*   length of dynapak value            */
VOID *value)                       /*   dynapak value to write             */
{
     INT ilingo,i;
     CHAR *dpkstg;

     dpkstg=cnvs2d(dpknam);
     setmbk(gcsmb);
     if (sameas(dpkstg,":sysid")) {
          hashvals[usrnum]=0L;
          sprintf(rsptmp,"%s;%s",msysid,mmappid);
          rsp2write(sameas(value,msysid),STGLEN,rsptmp,NULL);
     }
     else if (!sameas(dpknam->sysid,msysid)) {
          rejectreq();
     }
     else if (samepat(dpkstg,"s:epw")) {
          hashvals[usrnum]=rand()*65536L+rand()+1L;
          rsp2write(TRUE,sizeof(ULONG),&hashvals[usrnum],NULL);
     }
     else if (alwknock && samepat(dpkstg,"su:knock")) {
          if (onbbs(dpknam->usrid,1)) {
               if (!loadacc(dpknam->usrid)) {
                    prfmsg(UIDNOG1);
               }
               else if (!(*cschkpsw)(value)) {
                    prf("BYEPASS");
                    r2wprf(FALSE);
                    shochl("Invalid password attempt",'!',
                           baudat(usrptr->baud,0));
                    byenow(NO_MESSAGE);
                    shocst("INVALID PASSWORD ATTEMPT",
                           "C/S attempt on \"%s\"",usaptr->userid);
                    setmem(usaptr,sizeof(struct usracc),0);
               }
               else {
                    btuinj(uisusn,RING);
                    cycleme(knockem);
               }
          }
          else {
               rsp2write(TRUE,0,"",NULL);
          }
     }
     else if (samepat(dpkstg,"su:logon")) {
          if (usaptr->userid[0] == '\0'
           && sameas(dpknam->usrid,usdptr->usrid)) {
               if ((i=(*cschkuid)(dpknam->usrid,value)) == CSLONOK) {
                    switch ((*hdlbump)(TRUE)) {
                    case BMPAOK:
                         usrflags();
                         if ((*vallon)()) {
                              if (nlingo > 1 && getgen(&genbuf,usaptr->userid)
                               && (ilingo=lngfnd(genbuf.lngnam)) != -1) {
                                   usrptr->lingo=adjlgo(ilingo);
                              }
                              rsp2write(TRUE,0,NULL,NULL);
                              usrptr->usrcls=ACTUSR;
                              gcsplon();
                              return;
                         }
                         break;         /* FALSE vallon(): reason in prfbuf*/
                    case BMPDEL:
                         prfmsg(UIDNOG1);
                         break;
                    case BMPLNV:
                    case BMPSNV:        /* should never happen at logon    */
                         prfmsg(IMMEDL);
                         break;
                    case BMPTIM:
                         prfmsg(NOTIME);
                         break;
                    case BMPOTH:
                         break;
                    }
               }
               r2wprf(FALSE);
               setmem(usaptr,sizeof(struct usracc),0);
               if (i != CSLONBYE) {
                    return;             /* bypass byenow() to stay online  */
               }
          }
          byenow(NO_MESSAGE);
     }
     else if (!haskey("")) {
          rejectreq();
     }
     else if (samepat(dpkstg,"su:go ascii")) {
          stlcpy(mnuusr->curpag,value,PNMSIZ);
          dllock(usrnum);
          cycleme(wt4lok);
     }
     else {
          for (i=0 ; i < nelems(stdpks) ; i++) {
               if (samepato(stdpks[i].dpknam,dpkstg)) {
                    if (stdpks[i].dpkwrou != NULL) {
                         (*stdpks[i].dpkwrou)(dpknam,length,value);
                         return;
                    }
                    break;
               }
          }
          rejectreq();
     }
}

static VOID
dpkw_reqgenagt(                    /* "reqgenagt" std dpk write rtn        */
struct saunam *dpknam,             /*   dynapak name to write              */
UINT length,                       /*   length of dynapak value            */
VOID *value)                       /*   dynapak value to write             */
{
     (VOID)dpknam;
     if (length < AIDSIZ && newgenagt((CHAR*)value)) {
          rsp2write(TRUE,0,NULL,NULL);
          return;
     }
     rejectreq();
}

static VOID
dpkw_userinfo(                     /* "userinfo" std dpk write rtn         */
struct saunam *dpknam,             /*   dynapak name to write              */
UINT length,                       /*   length of dynapak value            */
VOID *value)                       /*   dynapak value to write             */
{
     CHAR *fldnam;
     INT i;
     GBOOL vldreq;

     vldreq=vlduid(dpknam->usrid);
     if (!vldreq && invldres == CANTALTR) {
          vldreq=ACCESS(OPACCT);
     }
     if (vldreq) {
          fldnam=skpwht(skpwrd(dpknam->suffix));
          if (*fldnam == '\0') {
               if (length <= sizeof(struct usrinfvb)) {
                    vldreq=dpkwa_userinfo((struct usrinfvb *)value,&accrec);
               }
          }
          else {
               vldreq=FALSE;
               for (i=0 ; i < nelems(uinflds) ; i++) {
                    if (sameas(uinflds[i].fldnam,fldnam)) {
                         if (uinflds[i].fldwrou != NULL) {
                              vldreq=(*uinflds[i].fldwrou)(value,&accrec);
                         }
                         break;
                    }
               }
          }
     }
     if (vldreq) {
          if (usron) {
               movmem(&accrec,dpkuap,sizeof(struct usracc));
          }
          else {
               dfaUpdate(&accrec);
          }
          chglng(chglngt,nwlingot);
          chglng(chglngp,nwlingop);
          rsp2write(TRUE,0,NULL,NULL);
          return;

     }
     r2wprf(FALSE);
}

static VOID
chglng(                            /* change req'd userid's language pref  */
INT lngact,                        /*   action to take to change language  */
INT newlingo)                      /*   language number to change to       */
{
     switch (lngact) {
     case CHGNON:
          break;
     case CHGAUT:
          if (genbuf.lngnam[0] != '\0') {
               genbuf.lngnam[0]='\0';
               setgen(&genbuf);
          }
          break;
     case CHGONL:
          dpkusp->lingo=adjlgo(newlingo);
          break;
     case CHGOND:
          strcpy(genbuf.lngnam,languages[newlingo]->name);
          setgen(&genbuf);
     }
}

static GBOOL
dpkwa_userinfo(                    /* write all userinfo from structure    */
struct usrinfvb *usrinfvb,         /*   info from client to write          */
struct usracc *accrec)             /*   in-memory usracc struct to write to*/
{
     return(fldw_password(usrinfvb->password,accrec)
         && fldw_name(usrinfvb->name,accrec)
         && fldw_company(usrinfvb->company,accrec)
         && fldw_address1(usrinfvb->address1,accrec)
         && fldw_address2(usrinfvb->address2,accrec)
         && fldw_address3(usrinfvb->address3,accrec)
         && fldw_phone(usrinfvb->phone,accrec)
         && fldw_systemtype(&usrinfvb->systemtype,accrec)
         && fldw_ansi(&usrinfvb->ansi,accrec)
         && fldw_daysleft(&usrinfvb->daysleft,accrec)
         && fldw_scnwidth(&usrinfvb->scnwidth,accrec)
         && fldw_scnlength(&usrinfvb->scnlength,accrec)
         && fldw_fsescnlen(&usrinfvb->fsescnlen,accrec)
         && fldw_editorprf(&usrinfvb->editorprf,accrec)
         && fldw_birthdate(&usrinfvb->birthdate,accrec)
         && fldw_sex(&usrinfvb->sex,accrec)
         && fldw_acctflags(&usrinfvb->acctflags,accrec)
         && fldw_access(usrinfvb->access,accrec)
         && fldw_language(&usrinfvb->language)
         && fldw_class(usrinfvb->acctcls,usrinfvb->daysleft,accrec)
         && fldw_permlang(&usrinfvb->permlang));
}

static GBOOL
fldw_password(                     /* userinfo "password" fld write rtn    */
CHAR *newpsw,                      /*   new info to write                  */
struct usracc *accrec)             /*   in-memory usracc struct to write to*/
{
     CHAR pass[PSWSIZ];

     b2ccpy(pass,newpsw,PSWSIZ);
     if (uidsame || vispsw) {
          if (pass[0] == '\0' || sameas(pass,accrec->psword)) {
               return(TRUE);
          }
          stlcpy(accrec->psword,pass,PSWSIZ);
          if (valinf(accrec->psword,minpwd,FALSE) != 0) {
               prf("PSW");
               prfmsg(PTOOSML);
               return(FALSE);
          }
          if (!(haskey(uiekytbl[UIEKYPSW]) || ACCESS(OPACCT)
             || ISMASTER())) {
               prf("PSW");
               prfmsg(NOTALWD,"password");
               return(FALSE);
          }
          if (!safpsw && !valupsw(accrec->userid,accrec->psword)) {
               prf("PSW");
               prfmsg(BADPSW);
               return(FALSE);
          }
          return(TRUE);
     }
     if (pass[0] == '\0' || sameas(pass,accrec->psword)) {
          return(TRUE);
     }
     prf("PSW");
     prfmsg(CANTCPSW);
     return(FALSE);
}

static GBOOL
fldw_name(                         /* userinfo "name" fld write rtn        */
CHAR *newname,                     /*   new info to write                  */
struct usracc *accrec)             /*   in-memory usracc struct to write to*/
{
     INT errn;
     CHAR tmpnam[NADSIZ];

     b2ccpy(tmpnam,newname,NADSIZ);
     if (strcmp(tmpnam,accrec->usrnam) == 0) {
          return(TRUE);
     }
     if (!(HASUIEKEY(UIEKYNAM) || ACCESS(OPACCT) || ISMASTER())) {
          prf("NAM");
          prfmsg(NOTALWD,"name");
          return(FALSE);
     }
     if ((errn=valinf(tmpnam,5,TRUE)) != 0) {
          prf("NAM");
          prfmsg(errn == 1 ? NTOOSML : NPROFAN);
          return(FALSE);
     }
     stlcpy(accrec->usrnam,tmpnam,NADSIZ);
     return(TRUE);
}

static GBOOL
fldw_company(                      /* userinfo "company" fld write rtn     */
CHAR *newcomp,                     /*   new info to write                  */
struct usracc *accrec)             /*   in-memory usracc struct to write to*/
{
     CHAR tmpadr[NADSIZ];

     b2ccpy(tmpadr,newcomp,NADSIZ);
     if (strcmp(tmpadr,accrec->usrad1) == 0) {
          return(TRUE);
     }
     if (!(HASUIEKEY(UIEKYCOM) || ACCESS(OPACCT) || ISMASTER())) {
          prf("COM");
          prfmsg(NOTALWD,"company name");
          return(FALSE);
     }
     if (valinf(tmpadr,0,TRUE) != 0) {
          prf("COM");
          prfmsg(CPROFAN);
          return(FALSE);
     }
     stlcpy(accrec->usrad1,tmpadr,NADSIZ);
     return(TRUE);
}

static GBOOL
fldw_address1(                     /* userinfo "address1" fld write rtn    */
CHAR *newaddr,                     /*   new info to write                  */
struct usracc *accrec)             /*   in-memory usracc struct to write to*/
{
     INT errn;
     CHAR tmpadr[NADSIZ];

     b2ccpy(tmpadr,newaddr,NADSIZ);
     if (strcmp(tmpadr,accrec->usrad2) == 0) {
          return(TRUE);
     }
     if (!(HASUIEKEY(UIEKYADR) || ACCESS(OPACCT) || ISMASTER())) {
          prf("AD1");
          prfmsg(NOTALWD,"address");
          return(FALSE);
     }
     if ((errn=valinf(tmpadr,5,TRUE)) != 0) {
          prf("AD1");
          prfmsg(errn == 1 ? A1TOOSML : A1PROFAN);
          return(FALSE);
     }
     stlcpy(accrec->usrad2,tmpadr,NADSIZ);
     return(TRUE);
}

static GBOOL
fldw_address2(                     /* userinfo "address2" fld write rtn    */
CHAR *newaddr,                     /*   new info to write                  */
struct usracc *accrec)             /*   in-memory usracc struct to write to*/
{
     INT errn;
     CHAR tmpadr[NADSIZ];

     b2ccpy(tmpadr,newaddr,NADSIZ);
     if (strcmp(tmpadr,accrec->usrad3) == 0) {
          return(TRUE);
     }
     if (!(HASUIEKEY(UIEKYADR) || ACCESS(OPACCT) || ISMASTER())) {
          prf("AD2");
          prfmsg(NOTALWD,"address");
          return(FALSE);
     }
     if ((errn=valinf(tmpadr,5,TRUE)) != 0) {
          prf("AD2");
          prfmsg(errn == 1 ? A2TOOSML : A2PROFAN);
          return(FALSE);
     }
     stlcpy(accrec->usrad3,tmpadr,NADSIZ);
     return(TRUE);
}

static GBOOL
fldw_address3(                     /* userinfo "address3" fld write rtn    */
CHAR *newaddr,                     /*   new info to write                  */
struct usracc *accrec)             /*   in-memory usracc struct to write to*/
{
     CHAR tmpadr[NADSIZ];

     b2ccpy(tmpadr,newaddr,NADSIZ);
     if (strcmp(tmpadr,accrec->usrad4) == 0) {
          return(TRUE);
     }
     if (!(HASUIEKEY(UIEKYADR) || ACCESS(OPACCT) || ISMASTER())) {
          prf("AD3");
          prfmsg(NOTALWD,"country");
          return(FALSE);
     }
     if (valinf(tmpadr,0,TRUE) != 0) {
          prf("AD3");
          prfmsg(A3PROFAN);
          return(FALSE);
     }
     stlcpy(accrec->usrad4,tmpadr,NADSIZ);
     return(TRUE);
}

static GBOOL
fldw_phone(                        /* userinfo "phone" fld write rtn       */
CHAR *newpho,                      /*   new info to write                  */
struct usracc *accrec)             /*   in-memory usracc struct to write to*/
{
     INT errn;
     CHAR tmppho[PHOSIZ];

     b2ccpy(tmppho,newpho,PHOSIZ);
     if (strcmp(tmppho,accrec->usrpho) == 0) {
          return(TRUE);
     }
     if (!(HASUIEKEY(UIEKYPHO) || ACCESS(OPACCT) || ISMASTER())) {
          prf("PHO");
          prfmsg(NOTALWD,"phone number");
          return(FALSE);
     }
     if ((errn=valinf(tmppho,7,TRUE)) != 0) {
          prf("PHO");
          prfmsg(errn == 1 ? VTOOSML : VPROFAN);
          return(FALSE);
     }
     stlcpy(accrec->usrpho,tmppho,PHOSIZ);
     return(TRUE);
}

static GBOOL
fldw_systemtype(                   /* userinfo "systemtype" fld write rtn  */
SHORT *newstyp,                    /*   new info to write                  */
struct usracc *accrec)             /*   in-memory usracc struct to write to*/
{
     if (*newstyp == accrec->systyp) {
          return(TRUE);
     }
     if (!(HASUIEKEY(UIEKYSYS) || ACCESS(OPACCT) || ISMASTER())) {
          prf("SYS");
          prfmsg(NOTALWD,"system type");
          return(FALSE);
     }
     if (*newstyp >= 0 && *newstyp < NSYSEL) {
          accrec->systyp=*newstyp;
          return(TRUE);
     }
     prf("SYS");
     prfmsg(INVSYS);
     return(FALSE);
}

static GBOOL
fldw_acctflags(                    /* userinfo "acctflags" fld write rtn   */
SHORT *newflags,                   /*   new flags to write                 */
struct usracc *accrec)             /*   in-memory usracc struct to write   */
{
     if (ISMASTER()) {
          accrec->flags&=~(HASMST);
          accrec->flags|=(*newflags&(HASMST));
     }
     if (ISMASTER() || ACCESS(OPPROT)) {
          accrec->flags&=~(UNDAXS);
          accrec->flags|=(*newflags&(UNDAXS));
     }
     if (ISMASTER() || ACCESS(OPDELT)) {
          accrec->flags&=~(DELTAG);
          accrec->flags|=(*newflags&(DELTAG));
     }
     if (ISMASTER() || ACCESS(OPSUSP)) {
          accrec->flags&=~(SUSPEN);
          accrec->flags|=(*newflags&(SUSPEN));
     }
     return(TRUE);
}

static GBOOL
fldw_ansi(                         /* userinfo "ansi" fld write rtn        */
SHORT *newansi,                    /*   new info to write                  */
struct usracc *accrec)             /*   in-memory usracc struct to write to*/
{
     if (*newansi == accrec->ansifl) {
          return(TRUE);
     }
     if (!(haskey(uiekytbl[UIEKYANS]) || ACCESS(OPACCT) || ISMASTER())) {
          prf("ANS");
          prfmsg(NOTALWD,"terminal mode ANSI setting");
          return(FALSE);
     }
     if (*newansi >= 0 && *newansi < NANSEL) {
          accrec->ansifl=*newansi;
          return(TRUE);
     }
     prf("ANS");
     prfmsg(BADANSI);
     return(FALSE);
}

static GBOOL
fldw_daysleft(                     /* userinfo "daysleft" fld write rtn    */
LONG *newdays,                     /*   new info to write                  */
struct usracc *accrec)             /*   in-memory usracc struct to write to*/
{
     if ((*newdays >= -1L) && (*newdays <= 32767L)) {
          if (ISMASTER() || ACCESS(OPACCT)) {
               accrec->daystt=(USHORT)(*newdays);
          }
          return(TRUE);
     }
     prf("DAY");
     return(FALSE);
}

static GBOOL
fldw_scnwidth(                     /* userinfo "scnwidth" fld write rtn    */
SHORT *newwid,                     /*   new info to write                  */
struct usracc *accrec)             /*   in-memory usracc struct to write to*/
{
     if (*newwid == accrec->scnwid) {
          return(TRUE);
     }
     if (!(haskey(uiekytbl[UIEKYSCW]) || ACCESS(OPACCT) || ISMASTER())) {
          prf("SWD");
          prfmsg(NOTALWD,"terminal mode screen width");
          return(FALSE);
     }
     if (*newwid >= MINSWD && *newwid <= MAXSWD) {
          accrec->scnwid=*newwid;
          return(TRUE);
     }
     prf("SWD");
     prfmsg(BADSWD,MINSWD,MAXSWD);
     return(FALSE);
}

static GBOOL
fldw_scnlength(                    /* userinfo "scnlength" fld write rtn   */
SHORT *newlen,                     /*   new info to write                  */
struct usracc *accrec)             /*   in-memory usracc struct to write to*/
{
     GBOOL hasky;

     if (*newlen == accrec->scnbrk) {
          return(TRUE);
     }
     if (*newlen == CTNUOS) {
          hasky=haskey(uiekytbl[UIEKYPAU]);
     }
     else {
          hasky=haskey(uiekytbl[UIEKYSCL]);
     }
     if (!(hasky || ACCESS(OPACCT) || ISMASTER())) {
          prf("SLN");
          prfmsg(NOTALWD,"terminal mode screen length");
          return(FALSE);
     }
     if ((*newlen >= MINSLN && *newlen <= MAXSLN) || *newlen == CTNUOS) {
          accrec->scnbrk=*newlen;
          return(TRUE);
     }
     prf("SLN");
     prfmsg(BADSLN,MINSLN,MAXSLN);
     return(FALSE);
}

static GBOOL
fldw_fsescnlen(                    /* userinfo "fsescnlen" fld write rtn   */
SHORT *newlen,                     /*   new info to write                  */
struct usracc *accrec)             /*   in-memory usracc struct to write to*/
{
     if ((*newlen >= MINSLN && *newlen <= MAXSLN)
      || *newlen == accrec->scnfse) {
          accrec->scnfse=*newlen;
          return(TRUE);
     }
     prf("FLN");
     prfmsg(BADSLN,MINSLN,MAXSLN);
     return(FALSE);
}

static GBOOL
fldw_editorprf(                    /* userinfo "editorprf" fld write rtn   */
CHAR *newprf,                      /*   new info to write                  */
struct usracc *accrec)             /*   in-memory usracc struct to write to*/
{
     CHAR nprf;

     if ((nprf=toupper(*newprf)) == 'L' && (accrec->usrprf&PRFLIN)) {
          return(TRUE);
     }
     if (nprf == 'F' && !(accrec->usrprf&PRFLIN)) {
          return(TRUE);
     }
     if (!(haskey(uiekytbl[UIEKYEDT]) || ACCESS(OPACCT) || ISMASTER())) {
          prf("EDT");
          prfmsg(NOTALWD,"terminal mode editor preference");
          return(FALSE);
     }
     if (nprf == 'L') {
          accrec->usrprf|=PRFLIN;
          return(TRUE);
     }
     if (nprf == 'F') {
          accrec->usrprf&=~PRFLIN;
          return(TRUE);
     }
     prf("EPF");
     prfmsg(BADEPRF);
     return(FALSE);
}

static GBOOL
fldw_birthdate(                    /* userinfo "birthdate" fld write rtn   */
DOUBLE *newbdy,                    /*   new info to write                  */
struct usracc *accrec)             /*   in-memory usracc struct to write to*/
{
     GBOOL bAllowChange;
     CHAR birthd[LDATSIZ];

     setmbk(supmb);
     bAllowChange=ynopt(ASKBDY)
               && (*accrec->birthd == '\0' || ynopt(CHGBDY));
     rstmbk();

     stlcpy(birthd,v2sdatl(*newbdy),LDATSIZ);
     if (okbday(birthd) || sameas(birthd,accrec->birthd)) {
          if (ISMASTER() || ACCESS(OPACCT) || bAllowChange) {
               stlcpy(accrec->birthd,birthd,DATSIZ);
          }
          return(TRUE);
     }
     prf("BDY");
     prfmsg(INVBDY);
     return(FALSE);
}

static GBOOL
fldw_sex(                          /* userinfo "sex" fld write rtn         */
CHAR *newsex,                      /*   new info to write                  */
struct usracc *accrec)             /*   in-memory usracc struct to write to*/
{
     CHAR nsex;

     if ((nsex=toupper(*newsex)) == accrec->sex) {
          return(TRUE);
     }
     if (!(HASUIEKEY(UIEKYSEX) || ACCESS(OPACCT) || ISMASTER())) {
          prf("SEX");
          prfmsg(NOTALWD,"sex");
          return(FALSE);
     }
     if (nsex == 'M' || nsex == 'F' || nsex == 'U') {
          accrec->sex=nsex;
          return(TRUE);
     }
     prf("SEX");
     prfmsg(INVSEX);
     return(FALSE);
}

static GBOOL
fldw_class(                        /* userinfo "class" fld write rtn       */
CHAR *newclass,                    /*   new class to write                 */
LONG daysleft,                     /*   days to keep in if expiring tonight*/
struct usracc *accrec)             /*   in-memory usracc struct to write to*/
{
     CHAR id[KEYSIZ],oldclass[KEYSIZ];

     if (ISMASTER() || ACCESS(OPACCT)) {
          stlcpy(oldclass,accrec->curcls,KEYSIZ);
          b2ccpy(id,newclass,KEYSIZ);
          if (*skpwht(id) != NULL) {
               if (!sameas(oldclass,id)) {
                    if (swtcls_hook != NULL) {
                         return((*swtcls_hook)(accrec,id,(INT)daysleft));
                    }
               }
          }
     }
     return(TRUE);
}

static GBOOL
fldw_language(                     /* userinfo "language" fld write rtn    */
SHORT *newlang)                    /*   new info to write                  */
{
     return(wrtlng(*newlang,TRUE));
}

static GBOOL
fldw_access(                       /* user remote access fld write rtn     */
SHORT *flags,                      /*   new flags to set for user          */
struct usracc *accrec)             /*   in-memory usracc struct to write   */
{
     SHORT i,*iptr;

     if (ISMASTER() || ACCESS(OPSYSP)) {
          iptr=flags;
          for (i=0; i < AXSSIZ ; i++) {
               accrec->access[i]=*iptr++;
          }
     }
     return(TRUE);
}

static GBOOL
fldw_permlang(                     /* userinfo "permlang" fld write rtn    */
SHORT *newlang)                    /*   new info to write                  */
{
     return(wrtlng(*newlang,FALSE));
}

static GBOOL
wrtlng(                            /* record req'd uid's new language pref */
SHORT newlang,                     /*   index of new language              */
GBOOL wrtonl)                      /*   try to write online language 1st?  */
{
     INT lngchg;

     if (chglngt == CHGAUT || chglngt == CHGOND) {
          chglngp=CHGNON;          /* su:language takes precedence */
          return(TRUE);
     }
     if (newlang == *rdlng(wrtonl)) {
          lngchg=CHGNON;
     }
     else {
          if (ISMASTER() || ACCESS(OPACCT) || (uidsame && haskey(langchg))) {
               if (newlang == -1) {
                    lngchg=CHGAUT;
               }
               else if (newlang >= 0 && newlang < nlingo) {
                    lngchg=wrtonl && usron ? CHGONL : CHGOND;
               }
               else {
                    prf("LNG");
                    prfmsg(BADLANG);
                    return(FALSE);
               }
          }
          else {
               prf("LNG");
               prfmsg(CANTCLNG);
               return(FALSE);
          }
     }
     if (wrtonl) {
          chglngt=lngchg;
          nwlingot=newlang;
     }
     else {
          chglngp=lngchg;
          nwlingop=newlang;
     }
     return(TRUE);
}

static SHORT *                     /* rets lng idx, or -1 if bad ondisk lng*/
rdlng(                             /* read req'd userid's current language */
GBOOL rdonl)                       /*   try to read online language 1st?   */
{
     if (rdonl && usron) {
          dpkrvint=dpkusp->lingo;
     }
     else {
          getgen(&genbuf,dpkuap->userid);
          dpkrvint=lngfnd(genbuf.lngnam);
     }
     return(&dpkrvint);
}

static INT
adjlgo(                            /* make sure lang num is one w/ DEFPRT  */
INT ilingo)                        /*   language number in question        */
{
     INT ilg;

     if (samend(languages[ilingo]->name,spr("/%s",DFTPRT))) {
          return(ilingo);
     }
     return((ilg=chgprt(ilingo,DFTPRT)) != -1 ? ilg : 0);
}

static GBOOL
vlduid(                            /* det. if req'd uid is valid, set vars */
CHAR *dpkuid)                      /*   key req'd if uid other than self   */
{
     dfaSetBlk(accbb);
     setmem(&accrec,sizeof(struct usracc),0);
     if (!dfaAcqEQ(&accrec,dpkuid,0)) {
          prf("UID");
          prfmsg(INVUID,dpkuid);
          invldres=INVUID;
          return(FALSE);
     }
     chglngt=chglngp=CHGNON;
     uidsame=sameas(dpkuid,usaptr->userid);
     if (uidsame) {
          usron=TRUE;
          dpkusn=usrnum;
          dpkusp=usrptr;
          dpkuap=usaptr;
          movmem(dpkuap,&accrec,sizeof(struct usracc));
          return(TRUE);
     }
     usron=onsysn(dpkuid,TRUE);
     if (usron) {
          dpkusn=othusn;
          dpkusp=othusp;
          dpkuap=othuap;
          movmem(dpkuap,&accrec,sizeof(struct usracc));
     }
     else {
          dpkusn=nterms;
          dpkusp=NULL;
          dpkuap=&accrec;
     }
     if (!ISMASTER()) {
          prf("UID");
          prfmsg(CANTALTR);
          invldres=CANTALTR;
          return(FALSE);
     }
     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
ptkrng(                            /* put a keyring                        */
CHAR *ringid,                      /*   ring id to update the keyring      */
CHAR *rings,                       /*   list of rings to update            */
GBOOL clsrng)                      /*   putting a class keyring?           */
{
     CHAR id[UIDSIZ];

     if (clsrng) {
          id[0]=RINGID;
          stlcpy(id+1,ringid,KEYSIZ);
     }
     else {
          stlcpy(id,ringid,UIDSIZ);
     }
     setmem(kysbuf,RINGSZ,0);
     dfaSetBlk(keysbb);
     if (dfaAcqEQ(kysbuf,id,0)) {
          stlcpy(&kysbuf[KLSTOF],rings,RINGSZ-32);
          dfaUpdateV((struct keyrec *)kysbuf,KLSTOF+strlen(&kysbuf[KLSTOF])+1);
          dfaRstBlk();
          r2wprf(TRUE);
          return;
     }
     else {
          dfaRstBlk();
          if (clsrng) {
               prf("INVCLS");
          }
          else {
               prf("INVUSR");
          }
          r2wprf(FALSE);
     }
}

static VOID
gtkrng(                            /* get a keyring                        */
CHAR *ringid,                      /*    ring id to get keyring for        */
GBOOL clsrng,                      /*    getting a class keyring?          */
struct saunam *dpknam)             /*    dpk name to respond with          */
{
     CHAR id[UIDSIZ];

     if (clsrng) {
          id[0]=RINGID;
          stlcpy(id+1,ringid,KEYSIZ);
     }
     else {
          stlcpy(id,ringid,UIDSIZ);
     }
     setmem(kysbuf,RINGSZ,0);
     dfaSetBlk(keysbb);
     if (dfaAcqEQ(kysbuf,id,0)) {
          rsp2read(dpknam,STGLEN,&kysbuf[KLSTOF],NULL);
          dfaRstBlk();
          return;
     }
     dfaRstBlk();
     rejectreq();
}

VOID
uintfy(                            /* notify C/S AD/E of class change      */
INT unum,                          /*   user number to notify              */
CHAR *uid,                         /*   userid switched                    */
struct clstab *cltptr)             /*   ptr to new class information       */
{
     struct saunam uinsau;
     struct ncicrdvb ncicrdvb;
     struct ncivb ncivb;

     stlcpy(uinsau.sysid,msysid,SIDSIZ);
     stlcpy(uinsau.appid,UINAID,AIDSIZ);
     stlcpy(uinsau.usrid,uid,UIDSIZ);
     uinsau.flags=0x00;
     stlcpy(uinsau.suffix,"class change",SFXSIZ);
     if (shwcrd) {
          c2bcpy(ncicrdvb.clname,cltptr->clname,KEYSIZ-1);
          ncicrdvb.limcal=cltptr->limcal;
          ncicrdvb.limday=cltptr->limday;
          ncicrdvb.dbtlmt=cltptr->dbtlmt;
          ncicrdvb.exempt=cltptr->flags&CRDXMT ? 'Y' : 'N';
          senddpk(unum,UINAID,NORMAL,&uinsau,sizeof(struct ncicrdvb),
             &ncicrdvb,ncicrdvbFDA);
     }
     else {
          c2bcpy(ncivb.clname,cltptr->clname,KEYSIZ-1);
          ncivb.limcal=cltptr->limcal;
          ncivb.limday=cltptr->limday;
          senddpk(unum,UINAID,NORMAL,&uinsau,sizeof(struct ncivb),&ncivb,
             ncivbFDA);
     }
}

static VOID
wt4lok(VOID)                       /* wait for datalink lock               */
{
     if (dllokd(usrnum)) {
          w4atck=hrtval();
          cycleme(w4ldly);
     }
}

static VOID
knockem(VOID)                      /* wait for other user to get knocked   */
{
     if (!onbbs(usaptr->userid,1)) {
          setmem(usaptr,sizeof(struct usracc),0);
          rsp2write(TRUE,0,"",NULL);
     }
}

static VOID
w4ldly(VOID)                       /* wait a bit before going to A/A mode  */
{
     if (!dllokd(usrnum)) {
          cycleme(wt4lok);
     }
     else if (hrtval()-w4atck > LOKDLY) {
          gcsasc();
          cycleme(w4udly); /* chgs cyc addr, but no cyc till ret to C/S */
     }
}

static VOID
w4udly(VOID)                       /* wait a bit before return to C/S mode */
{
     if (w4atck == 0L) {      /* freshly setmem()'d due to return from A/A */
          w4atck=hrtval();
     }
     else if (hrtval()-w4atck > LOKDLY) {
          dlunlk(usrnum);
          rejectreq();
     }
}

static VOID
retwgmvr(VOID)                     /* return WGM version to caller         */
{
     FILE *fp;
     INT sz;
     struct ffblk fb;
     CHAR *path;
     static CHAR *vercode=NULL;

     if (vercode == NULL) {
          path=spr("%s%s",OSMSUBDR,"WGM.VER");
          if (fndfile(&fb,path,0) && (fp=fopen(path,FOPRB)) != NULL) {
               if (fb.ff_fsize > 1024L) {
                    sz=1024;
               }
               else {
                    sz=(INT)fb.ff_fsize;
               }
               vercode=alczer(sz+1);
               fread(vercode,1,sz,fp);
               fclose(fp);
          }
          else {
               vercode="";
          }
     }
     rsp2read(NULL,STGLEN,vercode,NULL);
}

static VOID
retfilist(VOID)                    /* return OSM file list to caller       */
{
     struct ffblk fb;
     static CHAR *biglist=NULL;

     if (biglist == NULL) {
          *rsptmp='\0';
          if (tfsopn(OSMSUBDR"gcsvcman.lst") == 0) {
               rsp2read(NULL,0,"",NULL);
               return;
          }
          while (tfsrdl() != TFSDUN) {
               if (tfstate == TFSLIN) {
                    depad(tfsbuf);
                    if (fndfile(&fb,spr("%s%s",OSMSUBDR,tfsbuf),0)) {
                         sprintf(&rsptmp[strlen(rsptmp)],"%s\t%s\t%f\t",
                     fb.ff_name,l2as(fb.ff_fsize),
                     d2vdat(fb.ff_fdate,fb.ff_ftime));
                    }
               }
          }
          cntdir(OSMUPDDR STAR);
          strcat(rsptmp,l2as(numbyts));
          strcpy(biglist=alcmem(strlen(rsptmp)+1),rsptmp);
     }
     rsp2read(NULL,STGLEN,biglist,NULL);
}

static VOID
dontzap(VOID)                      /* prevent user from idling offline     */
{
     usrptr->usetmr=0;
}

static VOID
retfile(                           /* send OSM file to user                */
CHAR *filname)                     /*   the file name, security checked    */
{
     struct ffblk fb;
     CHAR *path;

     if (fndfile(&fb,path=spr("%s%s",OSMSUBDR,filname),0)) {
          cycleme(dontzap);
          rsp2read(NULL,STGLEN,spr("%s;%s",path,fb.ff_name),NULL);
     }
     else {
          rejectreq();
     }
}

static VOID
retupdfile(                        /* send OSM update file to user         */
CHAR *filname,                     /*   the file name, security checked    */
INT direction)                     /*   direction of read                  */
{
     struct ffblk fb;
     CHAR *path,best[FNEXSZ];

     if (direction == 0) {
          stlcpy(best,filname,FNEXSZ);
     }
     else {
          setmem(best,FNEXSZ,0);
          if (fnd1st(&fb,path=spr("%s"SLS STAR,OSMUPDDR),0)) {
               do {
                    if (direction > 0) {
                         if (*filname == '\0' ||
                              stricmp(fb.ff_name,filname) > 0) {
                              if (*best == '\0'
                               || stricmp(fb.ff_name,best) < 0) {
                                   stlcpy(best,fb.ff_name,FNEXSZ);
                              }
                         }
                    }
                    else {
                         if (stricmp(fb.ff_name,filname) < 0) {
                              if (*best == '\0'
                               || stricmp(fb.ff_name,best) > 0) {
                                   stlcpy(best,fb.ff_name,FNEXSZ);
                              }
                         }
                    }
               } while (fndnxt(&fb));
          }
     }
     if (*best != '\0') {
          strcpy(strchr(namtmp->suffix,' ')+1,best);
          if (fndfile(&fb,path=spr("%s%s",OSMUPDDR,best),0)) {
               cycleme(dontzap);
               rsp2read(namtmp,STGLEN,spr("%s;%s",path,fb.ff_name),NULL);
          }
          else {
               rejectreq();
          }
     }
     else {
          rejectreq();
     }
}

static VOID
sysxdone(VOID)                     /* system agent xfer done routine       */
{
}

static VOID
sysabort(VOID)                     /* system agent abort req routine       */
{
     if (srchdat[usrnum].usingid == greqid) {
          srchdat[usrnum].usingid=FREE2U;
     }
}

static VOID
sysfin(VOID)                       /* close down the system agent          */
{
     clsmsg(gcsmb);
}

INT                                /*   returns logon status code          */
csCheckUser(                       /* C/S default check User-ID function   */
const CHAR *userid,                /*   User-ID to check/load              */
const CHAR *password)              /*   password to check                  */
{
     if (!loadacc(userid)) {
          prfmsg(UIDNOG1);
     }
     else if (onbbs(userid,1)) {
          if (alwknock) {
               prf("ALRDONL");
               return(CSLONKNOCK);
          }
          else {
               prfmsg(ALRDON);
          }
     }
     else if (usaptr->flags&SUSPEN) {
          prfmsg(ACCSUS);
     }
     else if (!(*cschkpsw)(password)) {
          if (++(usrptr->countr) < 3) {
               prf("BADPASS");
               return(CSLONPASS);
          }
          else {
               prf("BYEPASS");
               shochl("Invalid password attempt",'!',baudat(usrptr->baud,0));
               shocst("INVALID PASSWORD ATTEMPT",
                      "C/S attempt on \"%s\"",usaptr->userid);
          }
     }
     else if (!(*hdlsmp)() && !haskey(sampky) && !(usaptr->flags&HASMST)) {
          prfmsg(MEMONL);
     }
     else {
          return(CSLONOK);
     }
     return(CSLONBYE);
}

GBOOL                              /*   returns whether password is good   */
csdftpsw(                          /* check password - client users        */
const CHAR *psword)                /*   proposed password                  */
{
     CHAR c,*psw;
     ULONG hashini;

     psw=usaptr->psword;
     if ((hashini=hashvals[usrnum]) != 0L) {
          hashvals[usrnum]=0L;
          movmem(psword,&epwt,sizeof(struct epw));
          if (epwt.nullval != 0L) {
               return(FALSE);
          }
          if (epwt.hashval != hash(psw,hashini)) {
               return(FALSE);
          }
     }
     else if (!sameas(psword,psw)) {
          return(FALSE);
     }
     do {
          c=*psw;
          if (c == '\0') {
               return(TRUE);
          }
          psw++;
     } while (!(c < ' ' && c > '\0')); /* less than 0x20, more than 0 */
     return(FALSE);
}

static ULONG                       /*   returns hashed value               */
hash(                              /* hash a short string                  */
CHAR *stg,                         /*   string to hash                     */
ULONG initial)                     /*   initial value of hash              */
{
     CHAR hashstg[PSWSIZ];

     stzcpy(hashstg,stg,PSWSIZ);
     strlwr(hashstg);
     stg=&hashstg[0];
     initial%=HASHPRIM;
     while (*stg != '\0') {
          initial=((256L*initial)+(*stg))%HASHPRIM;
          stg++;
     }
     return(initial);
}

GBOOL                              /*   based on axs4op() from REMSYS.C    */
hasaxs(                            /* does user have access to this op?    */
struct usracc *uacptr,             /*   pointer to user account to check   */
INT op)                            /*   operation to check access to       */
{
     if (sameas(uacptr->userid,"Sysop")
      || (op == 99 && (usrptr->flags&MASTER))) {
          return(TRUE);
     }
     return(uacptr->access[op>>4]&(1<<(op&15)));
}

static VOID
regdpk(VOID)
{
     register_dpkfda("","s:classinfo",clsinfvbFDA);
     register_dpkfda("","su:userinfo",usrinfvbFDA);
}

CHAR *                             /*   NULL on success, errmsg if fails   */
copyuser(                          /* copy a user                          */
CHAR *baseu,                       /*   base User-ID                       */
CHAR *newuid,                      /*   new User-ID (modifies)             */
CHAR *psword,                      /*   new User-ID's password (""=same)   */
struct usracc *uaptr)              /*   if online, from user's data        */
{
     struct usracc u;
     struct bbsgen gbuf;
     CHAR *keybuf;
     INT i,n;
     CREATEACCOUNT* vec;

     if (!(*alwsup)()) {
          return("New accounts can't be created right now");
     }
     switch (valuid(newuid)) {
     case 0:
          break;
     case 1:
          return("Target User-ID is invalid (bad character)");
     case 2:
     case 3:
     case 4:
          return("Target User-ID is invalid (profanity detected)");
     case 5:
          return("Target User-ID is invalid (too short)");
     case 6:
          return("Target User-ID is invalid (too long)");
     case 7:
          return("Target User-ID is invalid (already in use)");
     default:
          return("Target User-ID is invalid (undefined reason)");
     }
     if (psword != NULL && psword[0] != '\0' && strlen(psword) < minpwd) {
          return("Specified password is too short");
     }
     if (uaptr == NULL) {
          dfaSetBlk(accbb);
          if (!dfaAcqEQ(&u,baseu,0)) {
               return("Source user does not exist.");
          }
          dfaRstBlk();
     }
     else {
          u=*uaptr;
     }
     if (getgen(&gbuf,baseu)) {
          getgen(&genbuf,newuid); /* dependency exists in setgen() */
          stzcpy(gbuf.userid,newuid,UIDSIZ);
          setgen(&gbuf);
     }
     nkyrec(newuid);
     stzcpy(u.userid,newuid,UIDSIZ);
     if (psword != NULL && psword[0] != '\0') {
          stzcpy(u.psword,psword,PSWSIZ);
     }
     u.credat=today();
     u.usedat=0;
     setmem(u.birthd,DATSIZ,0);
     dfaSetBlk(accbb);
     dfaInsert(&u);
     dfaRstBlk();
     addxrf(newuid);
     keybuf=alczer(RINGSZ+1);
     getlst(baseu,keybuf);
     givkey(newuid,keybuf);
     free(keybuf);

     //  This was added to call all of the user signup vectors.  These vectors
     //   are used to create many things including aliases.  We looked at
     //   re-working this to use morsup(), however, there were a number of
     //   different issues as to why we decided not to.
     n=ninarr(hCreateAcctVecs);
     for (i=0; i < n; i++) {
          vec=*(CREATEACCOUNT **)arrelem(hCreateAcctVecs,i);
          BEG_PHASE("copyuser() Signup hook",vec);
          (*vec)(&u);
          END_PHASE("copyuser() Signup hook",0);
     }



     shocst("NEW USER CREATED","New User-ID: %s",newuid);
     accacct(&u,1);
     return(NULL);
}
