/*****************************************************************************/
/*
                                  DCL.h
*/     
/*****************************************************************************/

#ifndef DCL_H_LOADED
#define DCL_H_LOADED 1

#include "wasd.h"

/* number of times a 'not activated' script is retried */
#define DCL_MAX_SCRIPT_RETRY  5

/* number of times a script can output an ENDOFFILE */
#define DCL_SCRIPT_MAX_ENDOFFILE  50

/* location of script scratch area */
#define DCL_HTTPD_SCRATCH "WASD_SCRATCH:"

/* no world or group access */
#define DCL_PROCESS_MBX_PROT_MASK 0xff00

/* minimum/maximum size of buffer for DCL/CLI strings */
#define DCL_COMMAND_MIN_SIZE  256
#define DCL_COMMAND_MAX_SIZE 2048

#define DCL_TASK_TYPE_NONE              0
#define DCL_TASK_TYPE_CLI               1
#define DCL_TASK_TYPE_CGI_SCRIPT        2
#define DCL_TASK_TYPE_CGIPLUS_SCRIPT    3
#define DCL_TASK_TYPE_RTE_SCRIPT        4

#define DCL_FIND_SCRIPT_BEGIN    1
#define DCL_FIND_SCRIPT_COM      2
#define DCL_FIND_SCRIPT_CLD      3
#define DCL_FIND_SCRIPT_EXE      4
#define DCL_FIND_SCRIPT_RUNTIME  5

/* used as a lifetime sentinal */
#define DCL_DO_NOT_DISTURB -1
#define DCL_WEBSOCKET_DND  -2

/* if CGIplus/RTE idle life time not configured default to one hour */
#define DCL_CGIPLUS_LIFETIME 60 * 60

/* used to indicate a sys$delprc() has been queued against the process */
#define DCL_RUNDOWN_DELPRC -1

#define DCL_MAILBOX_DEVNAM_MAX 10

/* recover unused DCL resources after ten minutes */
#define DCL_RECOVERY_SECONDS 600

/* the proctor retry begins at this and multiplies by two each failure */
#define PROCTOR_RETRY_SECS 5

/* up to a maximim of one hour */
#define PROCTOR_RETRY_MAX_SECS 3600

/**************/
/* structures */
/**************/

#pragma __member_alignment __save
#pragma nomember_alignment

typedef struct DclCrePrcTermStruct DCL_CREPRC_TERM;

struct DclCrePrcTermStruct
{
    unsigned short int acc$w_msgtyp;
    unsigned short int acc$w_msgsiz;
    unsigned int acc$l_finalsts;
    unsigned int acc$l_pid;
    unsigned int acc$l_jobid;
    unsigned int acc$q_termtime [2];
    char acc$t_account [8];
    char acc$t_username [12];
    unsigned int acc$l_cputim;
    unsigned int acc$l_pageflts;
    unsigned int acc$l_pgflpeak;
    unsigned int acc$l_wspeak;
    unsigned int acc$l_biocnt;
    unsigned int acc$l_diocnt;
    unsigned int acc$l_volumes;
    unsigned int acc$q_login [2];
    unsigned int acc$l_owner;
};

typedef struct DclJpiItemStruct DCL_JPI_ITEM;

struct DclJpiItemStruct
{
   unsigned short  buf_len;
   unsigned short  item;
   unsigned char   *buf_addr;
   unsigned short  *short_ret_len;
};

#pragma member_alignment

typedef struct DclScriptNameCacheStruct DCL_SCRIPT_NAME_ENTRY;

struct DclScriptNameCacheStruct
{
   LIST_ENTRY  DclListEntry;

   int  /* number of times "hit" since last cache file name load */
        HitCount;

   int64  /* last time loaded/hit */
          LastTime64;

   char  /* the full searched-for script file name */
         ResFileName [ODS_MAX_FILE_NAME_LENGTH+1],
         /* the mapped script file name returned after mapping */
         ScriptFileName [ODS_MAX_FILE_NAME_LENGTH+1],
         /* the name of any run-time engine or RTE engine */
         ScriptRunTime [ODS_MAX_FILE_NAME_LENGTH+1];
};

typedef struct DclTaskStruct DCL_TASK;

struct DclTaskStruct
{
   LIST_ENTRY  DclListEntry;

   BOOL  /* add a newline to each record from a script process */
         AddNewline,
         /* record-by-record output from DCL, flush immediately */
         BufferRecords,
         /* build <LF> or <CR><LF> delimited records from single bytes */
         BuildRecords,
         /* script has indicated to send CGI variables in one structure */
         CgiPlusVarStruct,
         /* client-read: strip client I/O records of carriage-control */
         ClientReadStripCrLf,
         /* output is text (plain or html) */
         ContentTypeText,
         /* indicate it's a detached not process */
         CrePrcDetachProcess,
         /* absorb login meassages etc., with detached script processes */
         CrePrcDetachStarting,
         /* when the task completes the process is deleted */
         DeleteProcess,
         /* grant the identifier that marks this is a WASD script process */
         DetachedGrantId,
         /* DclFindScript() is currently using the structure */
         FindScript,
         /* use a $FORCEX to rundown the script */
         ForceImageExit,
         /* indicates a $FORCEX has been issued to the process */
         ForceImageExitIssued,
         /* indicates an asynchronous $GETJPI is still outstanding */
         ForceImageExitGetJpi,
         /* process has had /PARSE=EXTENDED set */
         ProcessParseExtended,
         /* there is an outstanding $GETJPI getting the CPU time consumed */
         ScriptCpuTimGetJpi,
         /* process read data/variables (i.e. became active) */
         ScriptProcessActivated,
         /* process provided response (i.e. sent some output) */
         ScriptProcessResponded,
         /* send script output to the bit-bucket while WATCHing */
         WatchNonCgiCompliant;
         
   int  /* */
        AgentUsageCount,
        /* set only by a CGI callout */
        BitBucketTimeout,
        /* number of times the CGIplus script has been used */
        CgiPlusUsageCount,
        /* size of storage when reading directly from client to HTTP$INPUT */
        ClientReadBufferSize,
        /* network write has returned an error status */
        ClientWriteErrorCount,
        /* remaining content in POST script */
        ContentLength,
        /* current length of DCL command */
        DclCommandLength,
        /* size of DCL command buffer */
        DclCommandSize,
        /* buffer the end of script output (end of file) sentinal */
        FindScriptRunTimeIdx,
        /* flag */
        FindScriptState,
        /* point at which we lose patience and $DELRPC it anyhow */
        ForceImageExitSecond,
        /* last time task was used as an HTTPd tick second */
        LastUsedSecond,
        /* used by the DclSupervisor() to time tasks out */
        LifeTimeSecond,
        /* non-zero indicates a proctored script */
        ProctorProcess,
        /* count of I/Os CGIplus variables reads still outstanding */
        QueuedCgiPlusIn,
        /* count of network/client->HTTP$INPUT reads still outstanding */
        QueuedClientRead,
        /* count of I/Os between HTTPd and client still outstanding */
        QueuedClientOutput,
        /* count of HTTP$INPUT reads still outstanding */
        QueuedHttpInput,
        /* count of I/Os between process and HTTPd still outstanding */
        QueuedSysCommand,
        /* when the count of I/Os is considered task finished */
        QueuedSysCommandAllowed,
        /* count of I/Os between process and HTTPd still outstanding */
        QueuedSysOutput,
        /* HTTPd tick second for resource recovery */
        RecoverySecond,
        /* when building records from single bytes */
        SysOutputBuildCount,
        /* SYS$OUTPUT end-of-files are ignored, ensure the script behaves */
        SysOutputEndOfFileCount,
        /* size of DCL process' SYS$OUTPUT buffer */
        SysOutputSize,
        /* whether it's a command, CGI script, agent, etc. */
        TaskType,
        /* non-zero then task is currently running-down */
        TaskRunDown,
        /* total number of times the task slot was used */
        TotalUsageCount,
        /* copied from request structure for WATCHing purposes */
        WatchItem,
        /* number of process has been a zombie */
        ZombieCount;

   unsigned short  /* channel to process' CGIPLUSIN mailbox */
                   CgiPlusInChannel,
                   /* channel to process' sys$creprc() termination mailbox */
                   CrePrcTermMbxChannel,
                   /* device unit of sys$creprc() termination mailbox */
                   CrePrcTermMbxUnit,
                   /* channel to process' HTTP$INPUT mailbox */
                   HttpInputChannel,
                   /* size of HTTP$INPUT mailbox */
                   HttpInputMbxSize,
                   /* channel to process' SYS$INPUT mailbox */
                   SysCommandChannel,
                   /* channel to process' SYS$OUTPUT mailbox */
                   SysOutputChannel,
                   /* some are easier :^) to report via sys$output status */
                   ViaSysOutputStatus;

   unsigned long  /* process name includes PID */
                  ProcessNamePid,
                  /* process' PID */
                  ScriptProcessPid;

   int64  /* last time CGIplus script was used */
          LastUsedTime64;

   char  /* storage for when reading directly from client to HTTP$INPUT */
         *ClientReadBufferPtr,
         /* content pointer in POST script */
         *ContentPtr,
         /* storage for DCL command */
         *DclCommandPtr,
         /* points to the file name being used in parse/search */
         *FindScriptFileNamePtr,
         /* points to a string denoting how the script is invoked */
         *ScriptRunTimePtr,
         /* heap storage for buffering process' SYS$OUTPUT */
         *SysOutputPtr;

   char  /* device name of process' CGIPLUSIN mailbox */
         CgiPlusInDevName [DCL_MAILBOX_DEVNAM_MAX+1],
         /* device name of sys$creprc() process termination mailbox */
         CrePrcTermMbxDevName [DCL_MAILBOX_DEVNAM_MAX+1],
         /* user name persona the sys$creprc() process created under */
         CrePrcUserName [13],
         /* device name of process' HTTP input mailbox */
         HttpInputDevName [DCL_MAILBOX_DEVNAM_MAX+1],
         /* process name when scripting */
         PrcNamActive [16],
         /* default process name */
         PrcNamDefault [16],
         /* the name of the script file being executed */
         ScriptFileName [ODS_MAX_FILE_NAME_LENGTH+1],
         /* script name (path) */
         ScriptName [SCRIPT_NAME_SIZE],
         /* the name of any run-time engine or RTE engine */
         ScriptRunTime [ODS_MAX_FILE_NAME_LENGTH+1],
         /* device name of process' input mailbox */
         SysCommandDevName [DCL_MAILBOX_DEVNAM_MAX+1],
         /* device name of process' output mailbox */
         SysOutputDevName [DCL_MAILBOX_DEVNAM_MAX+1];

   /* sentinal I/O sequences */

   int  /* length of the detached-script-output sequence */
        CgiBelLength,
        /* length of the end-of-file (output) sequence */
        CgiEofLength,
        /* length of the agent end-of-text sequence */
        CgiEotLength,
        /* length of the "escape" sequence */
        CgiEscLength;

   char  /* beginning of detached-script-output sequence */
         CgiBel [32],
         /* end-of-file (output) sequence */
         CgiEof [32],
         /* agent end-of-text sequence */
         CgiEot [32],
         /* CGI "escape" sequence */
         CgiEsc [32];

   IO_SB  CgiPlusInIOsb,
          CrePrcTermMbxIOsb,
          HttpInputIOsb,
          SysCommandIOsb,
          SysOutputIOsb;

   /* sys$creprc() process termination accounting record */
   struct DclCrePrcTermStruct  CrePrcTermRecord;

   /* string descriptors for the various mailbox device names */
   struct dsc$descriptor_s  CgiPlusInDevNameDsc;
   struct dsc$descriptor_s  CrePrcTermMbxDevNameDsc;
   struct dsc$descriptor_s  HttpInputDevNameDsc;
   struct dsc$descriptor_s  SysCommandDevNameDsc;
   struct dsc$descriptor_s  SysOutputDevNameDsc;

   /* used with memory buffer global section */
   uint  MemBufSize;
   uint64  MemBufCount64;
   BOOL  MemBufInProgress;
   char  MemBufGblSecName [32+1];
   void  *MemBufGblSecPtr;

   /* item list used for getting image name */
   char  JpiImagName [128];
   unsigned short  JpiImagNameLength;
   IO_SB  JpiImagNameIOsb;
   DCL_JPI_ITEM  JpiImagNameItem [3];

   /* item list, etc. for controlling CPU time consumed */
   unsigned long  JpiCpuTim,
                  ScriptCpuMax,
                  ScriptCpuTimMax;
   IO_SB  JpiCpuTimIOsb;
   DCL_JPI_ITEM  JpiCpuTimItem [3];

   /* MD5 hash of mapped path (used with RTEs) */
   MD5_HASH  Md5HashPath;

   /* pointer to proctor entry */
   PROCTOR_STRUCT  *ProctorPtr;

   /* "on-disk structure" when finding a script file */
   ODS_STRUCT  SearchOds;

   /* pointer a request using this DCL task structure */
   REQUEST_STRUCT  *RequestPtr;

   /* pointer to function, for specifying an "escape" processing function */
   REQUEST_AST CalloutFunction;

   /* pointer to function, for specifying the next task */
   REQUEST_AST NextTaskFunction;
};

#pragma member_alignment __restore

/***********************/
/* function prototypes */
/***********************/

/* NOTE ... pointers to request structure! */
int DclAllocateTask (REQUEST_STRUCT*, int, char*, int, char*, char*, char*); 
int DclBegin (REQUEST_STRUCT*, REQUEST_AST, char*, char*,
          char*, char*, char*, REQUEST_AST); 

DclBeginScript (DCL_TASK*);

/* NOTE ... pointer to request structure! */
DclCalloutQio (REQUEST_STRUCT*, char*, int); 
DclCalloutResume (REQUEST_STRUCT*);
DclCalloutDefault (REQUEST_STRUCT*);

int DclAnotherSysOutput (DCL_TASK*);
DclCgiPlusInAst (DCL_TASK*);
DclCgiPlusLifeTimeAst (DCL_TASK*);
void DclCleanupScratch (struct FAB*);
DclCgiPlusBodyAst (DCL_TASK*);
DclClientReadAst (REQUEST_STRUCT*);
DclClientReadHttpInputAst (DCL_TASK*);
int DclCgiScriptSysCommand (DCL_TASK*);
int DclCgiPlusScriptCgiPlusIn (DCL_TASK*);
DclCreateMailboxes (DCL_TASK*);
DclCreateScriptProcess (DCL_TASK*, char*, int);
void DclDeleteMailboxes (DCL_TASK*);
int DclDeleteProcess (DCL_TASK*);
DclDeallocateTask (DCL_TASK*);
int DclDelPrc (DCL_TASK*);
DclEscapeInProgress (DCL_TASK*);
DclFindScript (DCL_TASK*);
DclFindScriptEnd (DCL_TASK*, BOOL);
DclFindScriptParseAst (DCL_TASK*);
DclFindScriptSearchAst (DCL_TASK*);
char* DclGetPrcNam (ulong);
DclHttpInput (REQUEST_STRUCT*);
DclHttpInputAst (DCL_TASK*);
struct dsc$descriptor_s* DclNameProcess (DCL_TASK*);
DclQioSysCommand (DCL_TASK*, char*, int);
DclQioCgiPlusIn (DCL_TASK*, char*, int);
DclQioSysOutput (DCL_TASK*);
void DclTaskRecover ();
DclTaskRunDown (DCL_TASK*);

/* NOTE ... pointer to request structure! */
DclRequestEnd (REQUEST_STRUCT*);
DclSysOutputToClientAst (REQUEST_STRUCT*);

DclPlusScriptSysCommand (DCL_TASK*);
DclPlusScriptSysCgiPlusIn (DCL_TASK*);
DclPurgeScriptNameCache ();
DclPurgeCgiPlusScripts (REQUEST_STRUCT*, REQUEST_AST, BOOL);
DclForceImageExit (DCL_TASK*);
DclForceImageExitAst (DCL_TASK*);
DclSysCommandAst (DCL_TASK*);
DclSearchScriptNameCache (DCL_TASK*, REQUEST_STRUCT*);
DclScriptCpuTim (DCL_TASK*);
DclScriptCpuTimAst (DCL_TASK*);
DclScriptProcessCompletionAST (DCL_TASK*);
DclScriptProctor ();
DclScriptProctorReportFail (PROCTOR_STRUCT*, char*, ...);
DclScriptProctorAgent (REQUEST_STRUCT*);
DclScriptProctorAgentAst (REQUEST_STRUCT*);
DclScriptProctorAst (REQUEST_STRUCT*);
REQUEST_STRUCT* DclFauxRequest (REQUEST_STRUCT*, char*, REQUEST_AST);
DclSupervisor (int);
DclSysOutputHeader (DCL_TASK*);
DclSysOutputLocation (DCL_TASK*);
DclSysOutputAst (DCL_TASK*);
DclSysOutputWaitAst (DCL_TASK*);
DclSetZombieLifeTime (DCL_TASK*);
DclUpdateScriptNameCache (DCL_TASK*);
DclZombieLifeTimeAst (DCL_TASK*);
void DclScriptingReport (REQUEST_STRUCT*);
void DclPeekReport (REQUEST_STRUCT*);

void DclCountScriptProcess ();
char* DclControlPurgeScriptProcesses (BOOL, char*, char*, char*);

/* memory buffer module */
char* DclMemBufBegin (DCL_TASK*, char*);
int DclMemBufCreate (DCL_TASK*, int);
int DclMemBufDelete (DCL_TASK*);
char* DclMemBufEnd (DCL_TASK*, char*);
char* DclMemBufWrite (DCL_TASK*, char*);
void DclMemBufWriteAst (DCL_TASK*);

#endif /* DCL_H_LOADED */

/*****************************************************************************/

