/***************************************************************************
 *                                                                         *
 *   PARMMGR.CPP                                                           *
 *                                                                         *
 *   Copyright (c) 1998 Galacticomm, Inc.         All rights reserved.     *
 *                                                                         *
 *   Active HTML parameter manager class implementation.                   *
 *                                                                         *
 *                                           - J. Alvrus    06/16/1998     *
 *                                                                         *
 ***************************************************************************/

#pragma warn -par
#include "cyctimer.h"
#include "acthutl.h"
#include "parmmgr.h"
#include "parmurl.h"
#include "parmmlt.h"
#include "parmpurl.h"
#include "parmpmlt.h"
#include "parmsbuf.h"
#include "opt.h"

#define FILREV "$Revision: 2 $"

MARKSOURCE(parmmgr)

INT ParmParseSlice=PARSESLICE;     // parameter parsing time slice

acthParamMgr::acthParamMgr()       // default constructor
{
     ASSERTM(FALSE,"acthParamMgr: default constructor called");
}

acthParamMgr::acthParamMgr(        // standard constructor
acthRequest * req) :               //   associated request object
     m_req(req),
     m_parser(NULL),
     m_pst(NULL),
     m_timer(::ParmParseSlice),
     m_ready(false),
     m_enc(PENC_UNKNOWN)
{
}

acthParamMgr::~acthParamMgr()      // destructor
{
     if (m_parser != NULL) {
          delete m_parser;
          m_parser=NULL;
     }
     for (INT i=0 ; i < nparam() ; ++i) {
          delete m_vec[i];
     }
     if (m_pst != NULL) {
          delete m_pst;
          m_pst=NULL;
     }
}

bool
acthParamMgr::isReady(VOID)        // have parameters been fully parsed?
{
     // check if we're already ready
     if (m_ready) {
          return(true);
     }

     // determine encoding type
     if (m_enc == PENC_UNKNOWN) {
          m_enc=EncType();

          // if don't know encoding, just continue w/out parsing
          if (m_enc == PENC_UNKNOWN) {
               return(m_ready=true);
          }

          // construct parsing object
          ASSERT(m_parser == NULL);
          if (m_enc == PENC_URL) {
               m_parser=new acthParamParseURL(m_req,this);
          }
          if (m_enc == PENC_MULTIPART) {
               m_parser=new acthParamParseMulti(m_req,this);
          }
          ASSERT(m_parser != NULL);
     }

     // parse into names and positions
     for (bool cnt=m_timer.start() ; cnt ; cnt=m_timer.haveTime()) {
          m_ready=m_parser->process();
          if (m_ready) {
               delete m_parser;
               m_parser=NULL;
               break;              // out of timer loop
          }
     }
     return(m_ready);
}

VOID
acthParamMgr::TrackStream(         // keep ptr to param stream to delete
istream * pstParam)                //   parameter stream, deleted when done
{
     m_pst=pstParam;
}

PARAMENC
acthParamMgr::EncType(VOID)        // determine encoding type
{
     if (sameas(m_req->method(),"GET")
      || sameas(m_req->method(),"HEAD")) {
          return(PENC_URL);
     }
     if (sameas(m_req->method(),"POST")) {
          CHAR const * pHdr=ReadEncTypeHdr();
          // If Content-Type header not specified, we "guess" that the
          // encoding is URL encoded per RFC 2068 section 7.2.1.
          if (*pHdr == '\0'
           || sameas(pHdr,"application/x-www-form-urlencoded")) {
               return(PENC_URL);
          }
          if (sameas(pHdr,"multipart/form-data")) {
               return(PENC_MULTIPART);
          }
     }
     return(PENC_UNKNOWN);
}

CHAR const *                       //   returns content in static buffer
acthParamMgr::ReadEncTypeHdr(VOID) // read "Content-type" header
{
     static CHAR retbuf[100];      // ought to be big enough

     *retbuf='\0';
     ::ReadHeaderValue(m_req,"Content-type",sizeof(retbuf),retbuf);
     return(retbuf);
}

VOID
acthParamMgr::AddParam(            // add a parameter to list
acthParam * pParam)                //   allocated parameter to add
{
     m_vec.push_back(pParam);
}

PARAMENC                           //   returns encoding type code
acthParamMgr::paramEncoding() const// get type of encoding used for parameters
{
     return(m_enc);
}

INT
acthParamMgr::nparam() const       // number of parameters
{
     return(m_vec.size());
}

bool                               //   true=parameter specified, false=missing
acthParamMgr::param(               // get parameter by name (false=no such)
CHAR const * name,                 //   name of parameter (eg "parm")
CHAR * value,                      //   where to store value (NULL=don't)
INT size) const                    //   room for value (incl '\0')
{
     INT idx;
     if (paramIndex(name,idx)) {
          if (value != NULL && size > 0) {
               m_vec[idx]->getVal(value,size);
          }
          return(true);
     }
     if (value != NULL && size >= 1) {
          *value='\0';
     }
     return(false);
}

INT                                //   returns length (not incl term)
acthParamMgr::param(               // get parameter by index
INT index,                         //   0 to nparam()-1
CHAR * name,                       //   where to put name (eg "parm")
INT namsiz,                        //   room for name (incl '\0')
CHAR * value,                      //   where to put value (eg "2")
INT valsiz) const                  //   room for value (incl '\0')
{
     ASSERT(0 <= index && index < nparam());
     if (0 > index || index >= nparam()) {
          return(0);
     }
     stlcpy(name,m_vec[index]->getName(),namsiz);
     return(m_vec[index]->getVal(value,valsiz));
}

bool                               //   true=parameter specified, false=missing
acthParamMgr::paramStreamOpen(     // get parameter input stream by name
CHAR const * name,                 //   name of parameter (case ignored)
istream ** ppstParam) const        //   buffer to receive stream pointer
{
     INT i;
     if (paramIndex(name,i)) {
          paramStreamOpen(i,ppstParam);
          return(true);
     }
     return(false);
}

VOID
acthParamMgr::paramStreamOpen(     // get parameter input stream by index
INT index,                         //   0 to nparam()-1
istream ** ppstParam) const        //   buffer to receive stream pointer
{
     ASSERT(0 <= index && index < nparam());
     if (0 > index || index >= nparam()) {
          *ppstParam=NULL;
          return;
     }
     *ppstParam=new istream(new acthParamStreamBuf(*(m_vec[index])));
}

VOID
acthParamMgr::paramStreamClose(    // finish up use of parameter stream
istream * pstParam) const          //   stream pointer from paramStreamOpen
{
     delete pstParam->rdbuf();
     delete pstParam;
}

bool                               //   TRUE=found, FALSE=none
acthParamMgr::paramIndex(          // get index of parameter name
CHAR const * name,                 //   name of parameter (eg "parm")
INT & idx) const                   //   answer, 0 to nparam()-1
{
     for (INT i=0 ; i < nparam() ; ++i) {
          if (*(m_vec[i]) == name) {
               idx=i;
               return(true);
          }
     }
     return(false);
}

INT                                //   room needed to store param (incl term)
acthParamMgr::paramRoom(           // room needed to decode entire param
CHAR const * name) const           //   name of parameter (eg "parm")
{
     INT idx;
     if (paramIndex(name,idx)) {
          return(paramRoom(idx));
     }
     return(1);
}

INT                                //   room needed to store param (incl term)
acthParamMgr::paramRoom(           // room needed to decode entire param
INT index) const                   //   0 to nparam()-1
{
     ASSERT(0 <= index && index < nparam());
     if (0 > index || index >= nparam()) {
          return(0);
     }
     return(m_vec[index]->sizVal());
}

INT
acthParamMgr::paramNumHeaders(     // get number of parameter headers
INT index) const                   //   0 to nparam()-1
{
     ASSERT(0 <= index && index < nparam());
     if (0 > index || index >= nparam()) {
          return(0);
     }
     return(m_vec[index]->numHeaders());
}

size_t                             //   returns length of value (less term.)
acthParamMgr::paramHeader(         // get a parameter header
INT index,                         //   index of parameter (0 to nparam()-1)
INT hdrIndex,                      //   index of header
CHAR * namBuf,                     //   buffer to receive name
size_t namSiz,                     //   size of name buffer
CHAR * valBuf,                     //   buffer to receive result
size_t valSiz) const               //   size of buffer
{
     ASSERT(0 <= index && index < nparam());
     if (0 > index || index >= nparam()) {
          return(0);
     }
     return(m_vec[index]->getHeader(hdrIndex,namBuf,namSiz,valBuf,valSiz));
}

bool                               //   returns true if header exists
acthParamMgr::paramHeader(         // get a parameter header
INT index,                         //   index of parameter (0 to nparam()-1)
CHAR const * hdrName,              //   name of header
CHAR * valBuf,                     //   buffer to receive result
size_t valSiz) const               //   size of buffer
{
     ASSERT(0 <= index && index < nparam());
     if (0 > index || index >= nparam()) {
          return(false);
     }
     return(m_vec[index]->getHeader(hdrName,valBuf,valSiz));
}

INT
acthParamMgr::paramNumHeaders(     // get number of parameter headers
CHAR const * name) const           //   name of parameter (eg "parm")
{
     INT idx;
     if (paramIndex(name,idx)) {
          return(m_vec[idx]->numHeaders());
     }
     return(0);
}

bool                               //   returns true if parameter exists
acthParamMgr::paramHeader(         // get a parameter header
CHAR const * name,                 //   name of parameter (case ignored)
INT hdrIndex,                      //   index of header
CHAR * namBuf,                     //   buffer to receive name
size_t namSiz,                     //   size of name buffer
CHAR * valBuf,                     //   buffer to receive result
size_t valSiz) const               //   size of buffer
{
     INT idx;
     if (paramIndex(name,idx)) {
          return(m_vec[idx]->getHeader(hdrIndex,namBuf,namSiz,valBuf,valSiz));
     }
     return(false);
}

bool                               //   returns true if parameter/header exist
acthParamMgr::paramHeader(         // get a parameter header
CHAR const * name,                 //   name of parameter (case ignored)
CHAR const * hdrName,              //   name of header
CHAR * valBuf,                     //   buffer to receive result
size_t valSiz) const               //   size of buffer
{
     INT idx;
     if (paramIndex(name,idx)) {
          return(m_vec[idx]->getHeader(hdrName,valBuf,valSiz));
     }
     return(false);
}
