/***************************************************************************
 *                                                                         *
 *   WGSUSER.CPP                                                           *
 *                                                                         *
 *   Copyright (c) 1996-1997 Galacticomm, Inc.    All Rights Reserved.     *
 *                                                                         *
 *   Worldgroup implementation of User-ID's, derived from Active HTML's    *
 *   acthUserID class.                                                     *
 *                                                                         *
 *                                              - R. Stein  8/7/96         *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "galacth.h"
#include "majorbbs.h"

#define FILREV "$Revision: 12 $"

class wgUserID : public acthUserID {

public:
     wgUserID(                     // constructor
     const CHAR *userid);          //   User-ID, as user-typed, case ignored
     virtual
     ~wgUserID();                  // destructor

private:
     wgUserID(                     // no copy constructor
     wgUserID&);
     VOID operator=(               // no assignment operator
     wgUserID&);

public:
     virtual
     const CHAR *
     userid() const;               // database-formatted User-ID

#ifdef WEBCAST
     virtual
     GBOOL                         //   ret TRUE=pass, FALSE=fail
     pswAuthentic(                 // authenticate user based on his password
     const CHAR *password);        //   user-typed password
#else
     virtual
     AUTHSTAT                      //   ret TRUE=pass, FALSE=fail
     pswAuthentic(                 // authenticate user based on his password
     const CHAR *password);        //   user-typed password
#endif // WEBCAST

     virtual
     GBOOL                         //   ret TRUE=pass, FALSE=fail
     digAuthentic(                 // authenticate user via digest of uid:psw
     const CHAR *digest,           //   32-digit digest, Digest Access Auth.
     const CHAR *typedUID=NULL);   //   User-ID as typed (if differs from ctor)

     virtual
     VOID
     unAuthentic();                // remove authenticated status

     virtual
     GBOOL                         //   TRUE=acceptable
     okSyntax() const;             // is syntax of typed User-ID acceptable?

     virtual
     GBOOL                         //   TRUE=in database FALSE=not
     isOnFile();                   // is User-ID on file?
#ifdef WEBCAST
     virtual
     GBOOL
     authentic();                  // has user been authenticated?
#else
     virtual
     AUTHSTAT
     authentic();                  // has user been authenticated?
#endif // WEBCAST

public:                            // must be authenticated to use these:
     virtual
     GBOOL                         //   TRUE=granted, FALSE=denied
     hasKey(                       // access check, ala haskey("NORMAL")
     const CHAR *key);             //   name of key

public:                            // can use these if user simply on file:
     virtual
     GBOOL                         //   TRUE=has enough, FALSE=doesn't
     afford(                       // can user afford this charge?
     LONG credits);                //   so many credits

     virtual
     GBOOL                         //   TRUE=had enough, FALSE=didn't
     charge(                       // deduct credits from user's account
     LONG credits,                 //   so many credits
     GBOOL asmuch=TRUE);           //   if short, take as much as possible?

private:                           // internal data:

     CHAR *useridTyped;            // User-ID as user typed it in
     CHAR *useridOnFile;           // database-formatted User-ID (NULL=unk)
     LONG uacAbs;                  // pointer to database record
#ifdef WEBCAST
     GBOOL _authentic;             // has user been authenticated?
#else
     AUTHSTAT _authentic;          // has user been authenticated?
#endif // WEBCAST

private:                           // internal functions:
     const struct usracc *         //   ptr to user info (short lived)
     userLookup();                 // look up database record for user

     VOID
     delUOF();                     // delete useridOnFile string

     virtual
     CHAR *
     useridnc();                   // database-formatted User-ID (mutable)
};

UIDFACTORY wgnewActhUserID;        // User-ID factory, Worldgroup-specific

class wgsuser {                    // wgsuser.cpp initialization
public:                            // (maybe one day, we think of better way)
     wgsuser()
     {
          acthUserID::setUIDfactory(wgnewActhUserID);
     }
};
wgsuser init__wgsuser;

acthUserID *                       //   base ptr to implemented derived class
wgnewActhUserID(                   // User-ID factory, Worldgroup-specific
const CHAR *userid)                //   User-ID, as user-typed, case ignored
{
     return(new wgUserID(userid));
}

wgUserID::wgUserID(                // wgUserID constructor
const CHAR *userid) :
     useridOnFile(NULL),
     uacAbs(0L),
#ifdef WEBCAST
     _authentic(FALSE)
#else
     _authentic(USERUNKNOWN)
#endif // WEBCAST
{
     ASSERT(userid != NULL);
     useridTyped=strcpy(new CHAR[max(UIDSIZ,strlen(userid)+1)],userid);
}

wgUserID::~wgUserID()              // wgUserID destructor
{
     // record this session
     if (authentic() == USERAUTHENTIC && !onbbs(useridnc(),TRUE)) {
          struct usracc uacbuf;
          USHORT tdy=today();
          dfaSetBlk(accbb);
          if (dfaAcqEQ(&uacbuf,useridnc(),0) && uacbuf.usedat != tdy)  {
               uacbuf.usedat=tdy;
               dfaUpdate(&uacbuf);
          }
          dfaRstBlk();
     }

     delUOF();
     if (useridTyped != NULL) {
          delete[] useridTyped;
          useridTyped=NULL;
     }
}

const CHAR *
wgUserID::userid() const           // database-formatted User-ID
{
     return(useridOnFile == NULL ? useridTyped : useridOnFile);
}

#ifndef WEBCAST
AUTHSTAT                           //   ret TRUE=pass, FALSE=fail
wgUserID::pswAuthentic(            // authenticate user based on his password
const CHAR *password)              //   user-typed password
{
     const struct usracc* uptr;

     if (!isOnFile()) {
          return(authentic());
     }
     uptr=userLookup();
     if (sameas(uptr->psword,password)) {
          if (uptr->flags&SUSPEN) {
               _authentic=USERSUSPENDED;
          }
          else {
               _authentic=USERAUTHENTIC;
          }
     }
     else {
          _authentic=USERBADPASSWORD;
     }
     if (authentic() == USERAUTHENTIC) {
          strcpy(usaptr->userid,"(");                  // Warning, this code
          stzcat(usaptr->userid,userid(),UIDSIZ);      // section assumes
          if (strlen(usaptr->userid) < UIDSIZ-1) {     // usaptr is available.
               strcat(usaptr->userid,")");
          }
          else {
               strcpy(usaptr->userid+UIDSIZ-3,"*)");
          }
          shochl(usaptr->userid,'W',0x1F);
     }
     return(authentic());
}
#else
GBOOL                              //   ret TRUE=pass, FALSE=fail
wgUserID::pswAuthentic(            // authenticate user based on his password
const CHAR *password)              //   user-typed password
{
     if (!isOnFile()) {
          return(FALSE);
     }
     _authentic=sameas(userLookup()->psword,password);
     if (authentic()) {
          strcpy(usaptr->userid,"(");                  // Warning, this code
          stzcat(usaptr->userid,userid(),UIDSIZ);      // section assumes
          if (strlen(usaptr->userid) < UIDSIZ-1) {     // usaptr is available.
               strcat(usaptr->userid,")");
          }
          else {
               strcpy(usaptr->userid+UIDSIZ-3,"*)");
          }
          shochl(usaptr->userid,'W',0x1F);
     }
     return(authentic());
}
#endif // WEBCAST

GBOOL                              //   ret TRUE=pass, FALSE=fail
wgUserID::digAuthentic(            // authenticate user via digest of uid:psw
const CHAR *digest,                //   32-digit digest, Digest Access Auth.
const CHAR *typedUID)              //   User-ID as typed (if differs from ctor)
{
     (VOID)digest;  // HACK
     (VOID)typedUID; // HACK
     return(FALSE); // HACK
}

VOID
wgUserID::unAuthentic()            // remove authentication status
{
#ifdef WEBCAST
     _authentic=FALSE;
#else
     _authentic=USERUNKNOWN;
#endif // WEBCAST
}

GBOOL                              //   TRUE=acceptable
wgUserID::okSyntax() const         // is syntax of typed User-ID acceptable?
{
     (*setpfn)(useridTyped);
     INT rc=valuid(useridTyped);
     return(rc == 0 || rc == 7);
}

GBOOL                              //   TRUE=in database FALSE=not
wgUserID::isOnFile()               // is User-ID on file?
{
     const struct usracc *uap=userLookup();
     if (uap == NULL) {
          delUOF();
          return(FALSE);
     }
     delUOF();
     useridOnFile=strcpy(new CHAR[max(UIDSIZ,strlen(uap->userid)+1)],
                         uap->userid);
     return(TRUE);
}

#ifdef WEBCAST
GBOOL                              //   TRUE=xxx Authentic() passed
wgUserID::authentic()              // has user been authenticated?
{
     return(_authentic);
}
#else
AUTHSTAT                           //   TRUE=xxxAuthentic() passed
wgUserID::authentic()              // has user been authenticated?
{
     return(_authentic);
}
#endif // WEBCAST

GBOOL                              //   TRUE=granted, FALSE=denied
wgUserID::hasKey(                  // access check, ala haskey()
const CHAR *key)                   //   name of key
{
     return(authentic() == USERAUTHENTIC
         && uhskey(useridnc(),const_cast<CHAR *>(key)));
}

GBOOL                              //   TRUE=has enough, FALSE=doesn't
wgUserID::afford(                  // can user afford this charge?
LONG credits)                      //   so many credits
{
     return(isOnFile()
         && gtstcrd(useridnc(),credits,0));
}

GBOOL                              //   TRUE=had enough, FALSE=didn't
wgUserID::charge(                  // deduct credits from user's account
LONG credits,                      //   so many credits
GBOOL asmuch)                      //   if short, take as much as possible?
{
     return(isOnFile()
         && gdedcrd(useridnc(),credits,0,asmuch));
}

const struct usracc *              //   pointer to static internal data
wgUserID::userLookup()             // look up database record for user
{
     static struct usracc uacbuf;
     const struct usracc *retval=NULL;

     ASSERT(useridTyped != NULL);
     dfaSetBlk(accbb);
     if (uacAbs != 0L) {
          if (dfaAcqAbs(&uacbuf,uacAbs,0)
           && useridOnFile != NULL
           && sameas(uacbuf.userid,useridOnFile)
           && !(uacbuf.flags&DELTAG)) {
               retval=&uacbuf;
          }
          else {
               uacAbs=0L;
#ifdef WEBCAST
               unAuthentic();
#endif // WEBCAST
#ifndef WEBCAST
               if (uacbuf.flags&DELTAG) {
                    _authentic=USERDELETED;
               }
               else {
                    unAuthentic();
               }
#endif // WEBCAST
          }
     }
     if (retval == NULL && dfaAcqEQ(&uacbuf,useridTyped,0))  {
#if ! defined( WEBCAST )
          if (uacbuf.flags&DELTAG) {
               _authentic=USERDELETED;
          }
          else {
               uacAbs=dfaAbs();
               retval=&uacbuf;
          }
#else
          uacAbs=dfaAbs();
          retval=&uacbuf;
#endif
     }
     dfaRstBlk();
     return(retval);
}

VOID
wgUserID::delUOF()                 // delete useridOnFile string
{
     if (useridOnFile != NULL) {
          delete[] useridOnFile;
          useridOnFile=NULL;
     }
}

CHAR *
wgUserID::useridnc()               // database-formatted User-ID (mutable)
{
     return(useridOnFile == NULL ? useridTyped : useridOnFile);
}

