/***************************************************************************
 *                                                                         *
 *   OPT.CPP                                                               *
 *                                                                         *
 *   Copyright (c) 1999 Galacticomm, Inc.         All rights reserved.     *
 *                                                                         *
 *   Active HTML Kernel configuration options manager.                     *
 *                                                                         *
 *                                           - J. Alvrus    02/01/1999     *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "galacth.h"
#include "opt.h"

#define FILREV "$Revision: 2 $"
MARKSOURCE(opt);

ACTHOPTCODE                        //   result code
GetAuthTypes(                      // get allowed authentication types option
size_t * pBufSize,                 //   size of buffer (updated)
CHAR * pBuffer);                   //   buffer to receive option value

ACTHOPTCODE                        //   result code
SetAuthTypes(                      // set allowed authentication types option
CHAR const * Value);               //   new value for option

ACTHOPTCODE                        //   result code
GetAuthCookie(                     // get authentication cookie name option
size_t * pBufSize,                 //   size of buffer (updated)
CHAR * pBuffer);                   //   buffer to receive option value

ACTHOPTCODE                        //   result code
SetAuthCookie(                     // set authentication cookie name option
CHAR const * Value);               //   new value for option

ACTHOPTCODE                        //   result code
GetAuthDefault(                    // get default authentication type option
size_t * pBufSize,                 //   size of buffer (updated)
CHAR * pBuffer);                   //   buffer to receive option value

ACTHOPTCODE                        //   result code
SetAuthDefault(                    // set default authentication type option
CHAR const * Value);               //   new value for option

ACTHOPTCODE                        //   result code
GetAuthRealm(                      // get authentication realm option
size_t * pBufSize,                 //   size of buffer (updated)
CHAR * pBuffer);                   //   buffer to receive option value

ACTHOPTCODE                        //   result code
SetAuthRealm(                      // set authentication realm option
CHAR const * Value);               //   new value for option

ACTHOPTCODE                        //   result code
GetParmSlice(                      // get parameter parsing time slice option
size_t * pBufSize,                 //   size of buffer (updated)
CHAR * pBuffer);                   //   buffer to receive option value

ACTHOPTCODE                        //   result code
SetParmSlice(                      // set parameter parsing time slice option
CHAR const * Value);               //   new value for option

ACTHOPTCODE                        //   result code
FillBuffer(                        // fill in buffer or size
CHAR const * Data,                 //   data to place in buffer
size_t * pBufSize,                 //   size of buffer (updated)
CHAR * pBuffer);                   //   buffer to receive data

bool
WordEqual(                         // are first words of strings equal?
CHAR const * s1,                   //   first string
CHAR const * s2);                  //   second string

typedef
ACTHOPTCODE                        //   result code
(*OptGetFunc)(                     // get an option function pointer
size_t * pBufSize,                 //   size of buffer (updated)
CHAR * Buffer);                    //   buffer to receive option value

typedef
ACTHOPTCODE                        //   result code
(*OptSetFunc)(                     // set an option function pointer
CHAR const * Value);               //   new value for option

struct KernelOption {              // kernel option holder
     CHAR * Name;                  //   name of option
     INT Flags;                    //   Boolean characteristics of option
     OptGetFunc GetOpt;            //   get-option function
     OptSetFunc SetOpt;            //   set-option function
} OptionArray[]={                  // array of option holders (alphabetical)
     {"Authentication Allowed Types",0,GetAuthTypes,SetAuthTypes},
     {"Authentication Cookie Name",0,GetAuthCookie,SetAuthCookie},
     {"Authentication Default Type",0,GetAuthDefault,SetAuthDefault},
     {"Authentication Realm",0,GetAuthRealm,SetAuthRealm},
     {"Parameter Parsing Time Slice",0,GetParmSlice,SetParmSlice}
};

                                   // option flag masks
#define OPT_DENYRD  1              //   deny attempts to get this option
#define OPT_DENYWR  2              //   deny attempts to set this option

///////////////////////////////////////////////////////////////////////////
// Option Management Functions

INT                                //   > 0 = target > test, etc.
OptCompFunc(                       // option name comparison function
const VOID *target,                //   target object
const VOID *array,                 //   array object
ULONG index)                       //   index of array element to test
{
     ASSERT(array == OptionArray);
     (VOID)array;
     return(stricmp(static_cast<CHAR const *>(target),OptionArray[index].Name));
}

INT                                //   returns < 0 if not found
FindOption(                        // find an option by name
CHAR const * Name)                 //   name of option to retrieve
{
     ULONG ulIndex=binSearch(static_cast<VOID const *>(Name)
                            ,static_cast<VOID const *>(OptionArray)
                            ,nelems(OptionArray),OptCompFunc);
     if (ulIndex == nelems(OptionArray)) {
          return(-1);
     }
     return(static_cast<INT>(ulIndex));
}

ACTHOPTCODE                        //   result code
acthGetOption(                     // get an Active HTML Kernel option
CHAR const * Name,                 //   name of option to retrieve
size_t * pBufSize,                 //   size of buffer (updated)
CHAR * pBuffer)                    //   buffer to receive option value
{
     INT i=FindOption(Name);
     if (i < 0) {
          return(AHOPT_NOTFOUND);
     }
     if (OptionArray[i].Flags&OPT_DENYRD) {
          return(AHOPT_WRITEONLY);
     }
     return(OptionArray[i].GetOpt(pBufSize,pBuffer));
}

ACTHOPTCODE                        //   result code
acthSetOption(                     // set an Active HTML Kernel option
CHAR const * Name,                 //   name of option to set
CHAR const * Value)                //   new value for option
{
     INT i=FindOption(Name);
     if (i < 0) {
          return(AHOPT_NOTFOUND);
     }
     if (OptionArray[i].Flags&OPT_DENYWR) {
          return(AHOPT_READONLY);
     }
     return(OptionArray[i].SetOpt(Value));
}

INT
acthNumOptions()                   // number of Active HTML Kernel options
{
     return(nelems(OptionArray));
}

ACTHOPTCODE                        //   result code
acthGetOptionName(                 // get an an Active HTML Kernel option name
INT Index,                         //   index of option to get name of
size_t * pBufSize,                 //   size of buffer (updated)
CHAR * pBuffer)                    //   buffer to receive option name
{
     if (Index < 0 || nelems(OptionArray) <= Index) {
          return(AHOPT_OUTOFRANGE);
     }
     return(FillBuffer(OptionArray[Index].Name,pBufSize,pBuffer));
}

///////////////////////////////////////////////////////////////////////////
// Specific Option Get/Set Functions

ACTHOPTCODE                        //   result code
GetAuthTypes(                      // get allowed authentication types option
size_t * pBufSize,                 //   size of buffer (updated)
CHAR * pBuffer)                    //   buffer to receive option value
{
     CHAR atstr[sizeof("Browser Cookie")]="";
     if (AuthTypeFlags&ATF_BROWSER) {
          strcpy(atstr,"Browser");
     }
     if (AuthTypeFlags&ATF_COOKIE) {
          if (*atstr != '\0') {
               strcat(atstr," ");
          }
          strcat(atstr,"Cookie");
     }
     return(FillBuffer(atstr,pBufSize,pBuffer));
}

ACTHOPTCODE                        //   result code
SetAuthTypes(                      // set allowed authentication types option
CHAR const * Value)                //   new value for option
{
     // make sure something is specified
     if (*Value == '\0') {
          return(AHOPT_EMPTY);
     }

     // parse value string
     INT tmpflg=0;
     CHAR const * pBeg=Value;
     while (true) {

          // compare to expected values
          if (WordEqual(pBeg,"Browser")) {
               tmpflg|=ATF_BROWSER;
          }
          else if (WordEqual(pBeg,"Cookie")) {
               tmpflg|=ATF_COOKIE;
          }
          else {
               return(AHOPT_INVALID);
          }

          // find next word
          CHAR const * pEnd=strchr(pBeg,' ');
          if (pEnd == NULL) {
               break;
          }
          pBeg=pEnd+1;
     }

     // update options
     if ((AuthDefault&tmpflg) == 0) {   // make sure default is still valid
          AuthDefault=tmpflg;
     }
     AuthTypeFlags=tmpflg;

     return(AHOPT_SUCCESS);
}

ACTHOPTCODE                        //   result code
GetAuthCookie(                     // get authentication cookie name option
size_t * pBufSize,                 //   size of buffer (updated)
CHAR * pBuffer)                    //   buffer to receive option value
{
     return(FillBuffer(AuthCookie,pBufSize,pBuffer));
}

ACTHOPTCODE                        //   result code
SetAuthCookie(                     // set authentication cookie name option
CHAR const * Value)                //   new value for option
{
     if (*Value == '\0') {
          return(AHOPT_EMPTY);
     }
     if (strlen(Value) >= MAXCOOKIE) {
          return(AHOPT_TOOLARGE);
     }

     // check validity of cookie name per cookie draft/RFC 2068
     if (Value[0] == '$') {             // names starting w/'$' are reserved
          return(AHOPT_INVRESERVED);
     }
     for (CHAR const * cp=Value ; *cp != '\0' ; ++cp) {
          CHAR c=*cp;
          if (c <= ' ' || c > '~'                      // SP, CTL, non-ASCII
           || strchr("()<>@,;:\\\"/[]?={}",c) != NULL) {        // tspecials
               return(AHOPT_INVALID);
          }
     }

     strcpy(AuthCookie,Value);
     return(AHOPT_SUCCESS);
}

ACTHOPTCODE                        //   result code
GetAuthDefault(                    // get default authentication type option
size_t * pBufSize,                 //   size of buffer (updated)
CHAR * pBuffer)                    //   buffer to receive option value
{
     CHAR atstr[max(sizeof("Browser"),sizeof("Cookie"))]="";
     if (AuthDefault == ATF_BROWSER) {
          strcpy(atstr,"Browser");
     }
     else if (AuthDefault == ATF_COOKIE) {
          strcpy(atstr,"Cookie");
     }
     return(FillBuffer(atstr,pBufSize,pBuffer));
}

ACTHOPTCODE                        //   result code
SetAuthDefault(                    // set default authentication type option
CHAR const * Value)                //   new value for option
{
     if (*Value == '\0') {
          return(AHOPT_EMPTY);
     }
     INT tmpflg=0;
     if (sameas("Browser",Value)) {
          tmpflg|=ATF_BROWSER;
     }
     else if (sameas("Cookie",Value)) {
          tmpflg|=ATF_COOKIE;
     }
     else {
          return(AHOPT_INVALID);
     }
     if ((tmpflg&AuthTypeFlags) == 0) {
          return(AHOPT_INVFORBID);
     }
     AuthDefault=tmpflg;
     return(AHOPT_SUCCESS);
}

ACTHOPTCODE                        //   result code
GetAuthRealm(                      // get authentication realm option
size_t * pBufSize,                 //   size of buffer (updated)
CHAR * pBuffer)                    //   buffer to receive option value
{
     return(FillBuffer(AuthRealm,pBufSize,pBuffer));
}

ACTHOPTCODE                        //   result code
SetAuthRealm(                      // set authentication realm option
CHAR const * Value)                //   new value for option
{
     if (*Value == '\0') {
          return(AHOPT_EMPTY);
     }
     if (strlen(Value) >= MAXREALM) {
          return(AHOPT_TOOLARGE);
     }
     strcpy(AuthRealm,Value);
     return(AHOPT_SUCCESS);
}

ACTHOPTCODE                        //   result code
GetParmSlice(                      // get parameter parsing time slice option
size_t * pBufSize,                 //   size of buffer (updated)
CHAR * pBuffer)                    //   buffer to receive option value
{
     CHAR buf[sizeof("1234567890")];

     sprintf(buf,"%d",ParmParseSlice);
     return(FillBuffer(buf,pBufSize,pBuffer));
}

ACTHOPTCODE                        //   result code
SetParmSlice(                      // set parameter parsing time slice option
CHAR const * Value)                //   new value for option
{
     if (*Value == '\0') {
          return(AHOPT_EMPTY);
     }
     if (!alldgs(Value)) {
          return(AHOPT_INVSYNTAX);
     }
     INT n=atoi(Value);
     if (n < MINPARMSLICE || MAXPARMSLICE < n) {
          return(AHOPT_OUTOFRANGE);
     }
     ParmParseSlice=n;
     return(AHOPT_SUCCESS);
}

///////////////////////////////////////////////////////////////////////////
// Miscellaneous Utility Functions

ACTHOPTCODE                        //   result code
FillBuffer(                        // fill in buffer or size
CHAR const * Data,                 //   data to place in buffer
size_t * pBufSize,                 //   size of buffer (updated)
CHAR * pBuffer)                    //   buffer to receive data
{
     ACTHOPTCODE rc=AHOPT_SUCCESS;
     size_t SizeNeeded=strlen(Data)+1;
     if (SizeNeeded > *pBufSize) {
          rc=AHOPT_BUFFERSIZE;
     }
     else {
          strcpy(pBuffer,Data);
     }
     *pBufSize=SizeNeeded;
     return(rc);
}

bool
WordEqual(                         // are first words of strings equal?
CHAR const * s1,                   //   first string
CHAR const * s2)                   //   second string
{
     bool end1=false;
     bool end2=false;
     while (true) {
          end1=(*s1 == '\0' || isspace(*s1));
          end2=(*s2 == '\0' || isspace(*s2));
          if (end1 || end2) {
               break;
          }
          if (toupper(*s1) != toupper(*s2)) {
               return(false);
          }
          ++s1;
          ++s2;
     }
     return(end1 && end2);
}
