/*-
 ***********************************************************************
 *
 * $Id: properties.c,v 1.45 2012/01/07 07:56:14 mavrik Exp $
 *
 ***********************************************************************
 *
 * Copyright 2001-2012 The WebJob Project, All Rights Reserved.
 *
 ***********************************************************************
 */

#include "all-includes.h"

/*-
 ***********************************************************************
 *
 * Defines
 *
 ***********************************************************************
 */
#define PROPERTIES_MAX_RECURSION_LEVEL 3
#define PROPERTIES_MAX_LINE_LENGTH 1024
#define PROPERTIES_COMMENT_C '#'
#define PROPERTIES_COMMENT_S "#"
#define PROPERTIES_SEPARATOR_C '='
#define PROPERTIES_SEPARATOR_S "="


/*-
 ***********************************************************************
 *
 * Macros
 *
 ***********************************************************************
 */
#define DUPLICATE_ERROR(b) \
  if ((b) == TRUE) \
  { \
    snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Duplicate controls aren't allowed.", acRoutine, pcControl); \
    return ER_DuplicateControl; \
  }

#define EVALUATE_TWOSTATE(pc, s1, s2, result) \
  if (strcasecmp(pc, s1) == 0) \
  {  \
    result = TRUE; \
  } \
  else if (strcasecmp(pc, s2) == 0) \
  {  \
    result = FALSE; \
  }  \
  else \
  { \
    snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Value = [%s], Value must be [%s|%s].", acRoutine, pcControl, pc, s1, s2); \
    return ER_Bool; \
  }


/*-
 ***********************************************************************
 *
 * PropertiesReadFile
 *
 ***********************************************************************
 */
int
PropertiesReadFile(char *pcFilename, WEBJOB_PROPERTIES *psProperties, char *pcError)
{
  const char          acRoutine[] = "PropertiesReadFile()";
  char                acLocalError[MESSAGE_SIZE] = "";
  char                acLine[PROPERTIES_MAX_LINE_LENGTH];
  char               *pc;
  int                 iError;
  int                 iLength;
  int                 iLineNumber;
  int                 iSaveLength;
  FILE               *pFile;
  struct stat         statEntry;

  /*-
   *********************************************************************
   *
   * Check recursion level. Abort, if the level is too high.
   *
   *********************************************************************
   */
  if (psProperties->iImportRecursionLevel > PROPERTIES_MAX_RECURSION_LEVEL)
  {
    snprintf(pcError, MESSAGE_SIZE, "%s: File = [%s], Imports may not exceed %d levels of recursion.", acRoutine, pcFilename, PROPERTIES_MAX_RECURSION_LEVEL);
    return ER_MaxIndirection;
  }

  if (strcmp(pcFilename, "-") == 0)
  {
    pFile = stdin;
  }
  else
  {
    iError = stat(pcFilename, &statEntry);
    if (iError == -1)
    {
      /*-
       *****************************************************************
       *
       * Return OK if the specified config file (Import) doesn't exist.
       * By making this allowance, an admin can (more easily) create a
       * generic config file that spans multiple clients or an entire
       * WebJob deployment. If the recursion level is zero, then we are
       * dealing with a command line config file, and in that case, the
       * file must exist.
       *
       *****************************************************************
       */
      if (psProperties->iImportRecursionLevel > 0 && errno == ENOENT)
      {
        return ER_OK;
      }
      snprintf(pcError, MESSAGE_SIZE, "%s: File = [%s]: %s", acRoutine, pcFilename, strerror(errno));
      return ER_lstat;
    }

    if (!((statEntry.st_mode & S_IFMT) == S_IFREG))
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: File = [%s]: A regular file is required.", acRoutine, pcFilename);
      return ER_BadValue;
    }

    if ((pFile = fopen(pcFilename, "r")) == NULL)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: File = [%s]: %s", acRoutine, pcFilename, strerror(errno));
      return ER_fopen;
    }
  }

  for (acLine[0] = 0, iLineNumber = 1; fgets(acLine, PROPERTIES_MAX_LINE_LENGTH, pFile) != NULL; acLine[0] = 0, iLineNumber++)
  {
    iLength = iSaveLength = strlen(acLine);

    /*-
     *******************************************************************
     *
     * Ignore full line comments.
     *
     *******************************************************************
     */
    if (acLine[0] == PROPERTIES_COMMENT_C)
    {
      continue;
    }

    /*-
     *******************************************************************
     *
     * Scan backwards over EOL characters.
     *
     *******************************************************************
     */
    while (iLength && ((acLine[iLength - 1] == '\r') || (acLine[iLength - 1] == '\n')))
    {
      iLength--;
    }

    /*-
     *******************************************************************
     *
     * Its an error if no EOL was found. The exception to this is EOF.
     *
     *******************************************************************
     */
    if (iLength == iSaveLength && !feof(pFile))
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: File = [%s], Line = [%d]: Length exceeds %d bytes.", acRoutine, pcFilename, iLineNumber, PROPERTIES_MAX_LINE_LENGTH - 1);
      if (pFile != stdin)
      {
        fclose(pFile);
      }
      return ER_Length;
    }

    /*-
     *******************************************************************
     *
     * Terminate the line excluding any EOL characters.
     *
     *******************************************************************
     */
    acLine[iLength] = 0;

    /*-
     *******************************************************************
     *
     * Look for the first imbedded comment and mark it.
     *
     *******************************************************************
     */
    if ((pc = strstr(acLine, PROPERTIES_COMMENT_S)) != NULL)
    {
      *pc = 0;
      iLength = strlen(acLine);
    }

    /*-
     *******************************************************************
     *
     * Burn any trailing white space off line.
     *
     *******************************************************************
     */
    while (iLength > 0 && isspace((int) acLine[iLength - 1]))
    {
      acLine[iLength--] = 0;
    }

    /*-
     *******************************************************************
     *
     * If there's anything left over, process it.
     *
     *******************************************************************
     */
    if (iLength)
    {
      iError = PropertiesReadLine(acLine, psProperties, acLocalError);
      if (iError != ER_OK)
      {
        snprintf(pcError, MESSAGE_SIZE, "%s: File = [%s], Line = [%d]: %s", acRoutine, pcFilename, iLineNumber, acLocalError);
        if (pFile != stdin)
        {
          fclose(pFile);
        }
        return iError;
      }
    }
  }
  if (ferror(pFile))
  {
    snprintf(pcError, MESSAGE_SIZE, "%s: File = [%s], Line = [%d]: %s", acRoutine, pcFilename, iLineNumber, strerror(errno));
    if (pFile != stdin)
    {
      fclose(pFile);
    }
    return ER_fgets;
  }
  if (pFile != stdin)
  {
    fclose(pFile);
  }

  return ER_OK;
}


/*-
 ***********************************************************************
 *
 * PropertiesReadLine
 *
 ***********************************************************************
 */
int
PropertiesReadLine(char *pcLine, WEBJOB_PROPERTIES *psProperties, char *pcError)
{
  const char          acRoutine[] = "PropertiesReadLine()";
  char                acLocalError[MESSAGE_SIZE] = "";
  char               *pc;
  char               *pcControl;
  char               *pcEnd;
  unsigned char      *pcTempHash;
  int                 iError;
  int                 iRunMode;
  int                 iValue;
  unsigned int        iLength;

  /*-
   *********************************************************************
   *
   * Process one line of input from the config file. It is assumed that
   * the input string has already been stripped of comments and EOLs.
   * The string is expected to have the following form: "control:value"
   *
   *********************************************************************
   */

  /*-
   *********************************************************************
   *
   * Look for the first separator, and mark it to isolate the control.
   *
   *********************************************************************
   */
  if ((pc = strstr(pcLine, PROPERTIES_SEPARATOR_S)) == NULL)
  {
    snprintf(pcError, MESSAGE_SIZE, "%s: Line does not contain a control/value separator (i.e. '%s').", acRoutine, PROPERTIES_SEPARATOR_S);
    return ER_Jibberish;
  }
  *pc++ = 0;
  pcControl = pcLine;

  /*-
   *********************************************************************
   *
   * Burn any leading white space off value.
   *
   *********************************************************************
   */
  while (isspace((int) *pc))
  {
    pc++;
  }

  /*-
   *********************************************************************
   *
   * Burn any trailing white space off value.
   *
   *********************************************************************
   */
  iLength = strlen(pc);
  if (iLength > 0)
  {
    pcEnd = &pc[iLength - 1];
    while (iLength > 0 && isspace((int) *pcEnd))
    {
      *pcEnd-- = 0;
      iLength--;
    }
  }

  /*-
   *********************************************************************
   *
   * Burn any leading white space off control.
   *
   *********************************************************************
   */
  while (isspace((int) *pcControl))
  {
    pcControl++;
  }

  /*-
   *********************************************************************
   *
   * Burn any trailing white space off control.
   *
   *********************************************************************
   */
  iLength = strlen(pcControl);
  if (iLength > 0)
  {
    pcEnd = &pcControl[iLength - 1];
    while (iLength > 0 && isspace((int) *pcEnd))
    {
      *pcEnd-- = 0;
      iLength--;
    }
  }

  /*-
   *********************************************************************
   *
   * At this point pc should be pointing at a control value. Sift
   * through the various controls and do the appropriate things. If
   * the control is unrecognized, complain about it.
   *
   *********************************************************************
   */
  iLength = strlen(pc);

  iRunMode = psProperties->iRunMode;

  if (strcasecmp(pcControl, KEY_HashType) == 0 && RUN_MODE_IS_SET(MODES_HashType, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.HashTypeFound);
    if (strcasecmp(pc, WEBJOB_HASHTYPE_MD5) == 0)
    {
      strncpy(psProperties->acHashType, WEBJOB_HASHTYPE_MD5, WEBJOB_HASHTYPE_SIZE);
      psProperties->iHashSize = MD5_HASH_SIZE;
      psProperties->piHashStream = MD5HashStream;
    }
    else if (strcasecmp(pc, WEBJOB_HASHTYPE_SHA1) == 0)
    {
      strncpy(psProperties->acHashType, WEBJOB_HASHTYPE_SHA1, WEBJOB_HASHTYPE_SIZE);
      psProperties->iHashSize = SHA1_HASH_SIZE;
      psProperties->piHashStream = SHA1HashStream;
    }
    else if (strcasecmp(pc, WEBJOB_HASHTYPE_SHA256) == 0)
    {
      strncpy(psProperties->acHashType, WEBJOB_HASHTYPE_SHA256, WEBJOB_HASHTYPE_SIZE);
      psProperties->iHashSize = SHA256_HASH_SIZE;
      psProperties->piHashStream = SHA256HashStream;
    }
    else
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Value must be [%s|%s|%s].",
        acRoutine,
        pcControl,
        WEBJOB_HASHTYPE_MD5,
        WEBJOB_HASHTYPE_SHA1,
        WEBJOB_HASHTYPE_SHA256
        );
      return ER_BadValue;
    }
    pcTempHash = realloc(psProperties->pcStdOutHash, psProperties->iHashSize);
    if (pcTempHash == NULL)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: realloc(): %s", acRoutine, strerror(errno));
      return ER;
    }
    psProperties->pcStdOutHash = pcTempHash;
    memset(psProperties->pcStdOutHash, 0, psProperties->iHashSize);
    pcTempHash = realloc(psProperties->pcStdErrHash, psProperties->iHashSize);
    if (pcTempHash == NULL)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: realloc(): %s", acRoutine, strerror(errno));
      return ER;
    }
    psProperties->pcStdErrHash = pcTempHash;
    memset(psProperties->pcStdErrHash, 0, psProperties->iHashSize);
    psProperties->sFound.HashTypeFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_Import) == 0 && RUN_MODE_IS_SET(MODES_Import, iRunMode))
  {
    psProperties->iImportRecursionLevel++;
    iError = PropertiesReadFile(pc, psProperties, acLocalError);
    if (iError != ER_OK)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s]: %s", acRoutine, pcControl, acLocalError);
      return iError;
    }
    psProperties->iImportRecursionLevel--;
  }

  else if (strcasecmp(pcControl, KEY_OverwriteExecutable) == 0 && RUN_MODE_IS_SET(MODES_OverwriteExecutable, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.OverwriteExecutableFound);
    EVALUATE_TWOSTATE(pc, "y", "n", psProperties->iOverwriteExecutable);
    psProperties->sFound.OverwriteExecutableFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_Priority) == 0 && RUN_MODE_IS_SET(MODES_Priority, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.PriorityFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_PRIORITY_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    strncpy(psProperties->acPriority, pc, WEBJOB_MAX_PRIORITY_LENGTH);
    psProperties->sFound.PriorityFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_RunType) == 0 && RUN_MODE_IS_SET(MODES_RunType, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.RunTypeFound);
    if (strcasecmp(pc, WEBJOB_RUNTYPE_LINKTEST) == 0)
    {
      strncpy(psProperties->acRunType, WEBJOB_RUNTYPE_LINKTEST, WEBJOB_RUNTYPE_SIZE);
    }
    else if (strcasecmp(pc, WEBJOB_RUNTYPE_SNAPSHOT) == 0)
    {
      strncpy(psProperties->acRunType, WEBJOB_RUNTYPE_SNAPSHOT, WEBJOB_RUNTYPE_SIZE);
    }
    else
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Value must be [%s|%s].", acRoutine, pcControl, WEBJOB_RUNTYPE_LINKTEST, WEBJOB_RUNTYPE_SNAPSHOT);
      return ER_BadValue;
    }
    psProperties->sFound.RunTypeFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_StrictControls) == 0 && RUN_MODE_IS_SET(MODES_StrictControls, iRunMode))
  {
    EVALUATE_TWOSTATE(pc, "y", "n", psProperties->iStrictControls);
  }

  else if (strcasecmp(pcControl, KEY_TempDirectory) == 0 && RUN_MODE_IS_SET(MODES_TempDirectory, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.TempDirectoryFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_PATHNAME_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    strncpy(psProperties->acTempDirectory, pc, WEBJOB_MAX_PATHNAME_LENGTH);
    psProperties->sFound.TempDirectoryFound = TRUE;
  }

#ifdef UNIX
  else if (strcasecmp(pcControl, KEY_TimeoutSignal) == 0 && RUN_MODE_IS_SET(MODES_TimeoutSignal, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.TimeoutSignalFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_32BIT_NUMBER_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    while (iLength > 0)
    {
      if (!isdigit((int) pc[iLength - 1]))
      {
        snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Value = [%s], Value must be %d-%d.", acRoutine, pcControl, pc, WEBJOB_MIN_SIGNAL, WEBJOB_MAX_SIGNAL);
        return ER_BadValue;
      }
      iLength--;
    }
    iValue = atoi(pc);
    if (iValue < WEBJOB_MIN_SIGNAL || iValue > WEBJOB_MAX_SIGNAL)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Value = [%d], Value must be %d-%d.", acRoutine, pcControl, iValue, WEBJOB_MIN_SIGNAL, WEBJOB_MAX_SIGNAL);
      return ER_BadValue;
    }
    else
    {
      psProperties->iTimeoutSignal = iValue;
    }
    psProperties->sFound.TimeoutSignalFound = TRUE;
  }
#endif

  else if (strcasecmp(pcControl, KEY_UnlinkExecutable) == 0 && RUN_MODE_IS_SET(MODES_UnlinkExecutable, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.UnlinkExecutableFound);
    EVALUATE_TWOSTATE(pc, "y", "n", psProperties->iUnlinkExecutable);
    psProperties->sFound.UnlinkExecutableFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_UnlinkOutput) == 0 && RUN_MODE_IS_SET(MODES_UnlinkOutput, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.UnlinkOutputFound);
    EVALUATE_TWOSTATE(pc, "y", "n", psProperties->iUnlinkOutput);
    psProperties->sFound.UnlinkOutputFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_UploadOnGetFailure) == 0 && RUN_MODE_IS_SET(MODES_UploadOnGetFailure, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.UploadOnGetFailureFound);
    EVALUATE_TWOSTATE(pc, "y", "n", psProperties->iUploadOnGetFailure);
    psProperties->sFound.UploadOnGetFailureFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_UrlAuthType) == 0 && RUN_MODE_IS_SET(MODES_UrlAuthType, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.UrlAuthTypeFound);
    if (strcasecmp(pc, "basic") == 0)
    {
      psProperties->iUrlAuthType = HTTP_AUTH_TYPE_BASIC;
    }
    else if (strcasecmp(pc, "none") == 0)
    {
      psProperties->iUrlAuthType = HTTP_AUTH_TYPE_NONE;
    }
    else
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Value must be [basic|none].", acRoutine, pcControl);
      return ER_BadValue;
    }
    psProperties->sFound.UrlAuthTypeFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_UrlGetProxyAuthType) == 0 && RUN_MODE_IS_SET(MODES_UrlGetProxyAuthType, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.UrlGetProxyAuthTypeFound);
    if (strcasecmp(pc, "basic") == 0)
    {
      psProperties->iUrlGetProxyAuthType = HTTP_AUTH_TYPE_BASIC;
    }
    else if (strcasecmp(pc, "none") == 0)
    {
      psProperties->iUrlGetProxyAuthType = HTTP_AUTH_TYPE_NONE;
    }
    else
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Value must be [basic|none].", acRoutine, pcControl);
      return ER_BadValue;
    }
    psProperties->sFound.UrlGetProxyAuthTypeFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_UrlGetProxyEnable) == 0 && RUN_MODE_IS_SET(MODES_UrlGetProxyEnable, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.UrlGetProxyEnableFound);
    EVALUATE_TWOSTATE(pc, "y", "n", psProperties->iUrlGetProxyEnable);
    psProperties->sFound.UrlGetProxyEnableFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_UrlGetProxyHost) == 0 && RUN_MODE_IS_SET(MODES_UrlGetProxyHost, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.UrlGetProxyHostFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_HOSTNAME_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    strncpy(psProperties->acUrlGetProxyHost, pc, WEBJOB_MAX_HOSTNAME_LENGTH);
    psProperties->sFound.UrlGetProxyHostFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_UrlGetProxyPassword) == 0 && RUN_MODE_IS_SET(MODES_UrlGetProxyPassword, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.UrlGetProxyPasswordFound);
    psProperties->pcUrlGetProxyPassword = WebJobDecodeValue(pc, acLocalError);
    if (psProperties->pcUrlGetProxyPassword == NULL)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s]: %s", acRoutine, pcControl, acLocalError);
      return ER;
    }
    psProperties->sFound.UrlGetProxyPasswordFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_UrlGetProxyPort) == 0 && RUN_MODE_IS_SET(MODES_UrlGetProxyPort, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.UrlGetProxyPortFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_PORT_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    strncpy(psProperties->acUrlGetProxyPort, pc, WEBJOB_MAX_PORT_LENGTH);
    psProperties->sFound.UrlGetProxyPortFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_UrlGetProxyUsername) == 0 && RUN_MODE_IS_SET(MODES_UrlGetProxyUsername, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.UrlGetProxyUsernameFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_USERNAME_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    strncpy(psProperties->acUrlGetProxyUsername, pc, WEBJOB_MAX_USERNAME_LENGTH);
    psProperties->sFound.UrlGetProxyUsernameFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_UrlPutProxyAuthType) == 0 && RUN_MODE_IS_SET(MODES_UrlPutProxyAuthType, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.UrlPutProxyAuthTypeFound);
    if (strcasecmp(pc, "basic") == 0)
    {
      psProperties->iUrlPutProxyAuthType = HTTP_AUTH_TYPE_BASIC;
    }
    else if (strcasecmp(pc, "none") == 0)
    {
      psProperties->iUrlPutProxyAuthType = HTTP_AUTH_TYPE_NONE;
    }
    else
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Value must be [basic|none].", acRoutine, pcControl);
      return ER_BadValue;
    }
    psProperties->sFound.UrlPutProxyAuthTypeFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_UrlPutProxyEnable) == 0 && RUN_MODE_IS_SET(MODES_UrlPutProxyEnable, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.UrlPutProxyEnableFound);
    EVALUATE_TWOSTATE(pc, "y", "n", psProperties->iUrlPutProxyEnable);
    psProperties->sFound.UrlPutProxyEnableFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_UrlPutProxyHost) == 0 && RUN_MODE_IS_SET(MODES_UrlPutProxyHost, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.UrlPutProxyHostFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_HOSTNAME_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    strncpy(psProperties->acUrlPutProxyHost, pc, WEBJOB_MAX_HOSTNAME_LENGTH);
    psProperties->sFound.UrlPutProxyHostFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_UrlPutProxyPassword) == 0 && RUN_MODE_IS_SET(MODES_UrlPutProxyPassword, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.UrlPutProxyPasswordFound);
    psProperties->pcUrlPutProxyPassword = WebJobDecodeValue(pc, acLocalError);
    if (psProperties->pcUrlPutProxyPassword == NULL)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s]: %s", acRoutine, pcControl, acLocalError);
      return ER;
    }
    psProperties->sFound.UrlPutProxyPasswordFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_UrlPutProxyPort) == 0 && RUN_MODE_IS_SET(MODES_UrlPutProxyPort, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.UrlPutProxyPortFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_PORT_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    strncpy(psProperties->acUrlPutProxyPort, pc, WEBJOB_MAX_PORT_LENGTH);
    psProperties->sFound.UrlPutProxyPortFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_UrlPutProxyUsername) == 0 && RUN_MODE_IS_SET(MODES_UrlPutProxyUsername, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.UrlPutProxyUsernameFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_USERNAME_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    strncpy(psProperties->acUrlPutProxyUsername, pc, WEBJOB_MAX_USERNAME_LENGTH);
    psProperties->sFound.UrlPutProxyUsernameFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_UrlGetUrl) == 0 && RUN_MODE_IS_SET(MODES_UrlGetUrl, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.UrlGetUrlFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_PATHNAME_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    psProperties->psGetUrl = HttpParseUrl(pc, acLocalError);
    if (psProperties->psGetUrl == NULL)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s]: %s", acRoutine, pcControl, acLocalError);
      return ER_HttpParseUrl;
    }
    psProperties->sFound.UrlGetUrlFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_UrlPutUrl) == 0 && RUN_MODE_IS_SET(MODES_UrlPutUrl, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.UrlPutUrlFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_PATHNAME_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    psProperties->psPutUrl = HttpParseUrl(pc, acLocalError);
    if (psProperties->psPutUrl == NULL)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s]: %s", acRoutine, pcControl, acLocalError);
      return ER_HttpParseUrl;
    }
    psProperties->sFound.UrlPutUrlFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_UrlDownloadLimit) == 0 && RUN_MODE_IS_SET(MODES_UrlDownloadLimit, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.UrlDownloadLimitFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_32BIT_NUMBER_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    while (iLength > 0)
    {
      if (!isdigit((int) pc[iLength - 1]))
      {
        snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Value = [%s], Value must be 0-%d.", acRoutine, pcControl, pc, WEBJOB_MAX_CONTENT_LENGTH);
        return ER_BadValue;
      }
      iLength--;
    }
    iValue = atoi(pc);
    if (iValue < 0 || iValue > WEBJOB_MAX_CONTENT_LENGTH)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Value = [%s], Value must be 0-%d.", acRoutine, pcControl, pc, WEBJOB_MAX_CONTENT_LENGTH);
      return ER_BadValue;
    }
    else
    {
      psProperties->iUrlDownloadLimit = iValue;
    }
    psProperties->sFound.UrlDownloadLimitFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_UrlUsername) == 0 && RUN_MODE_IS_SET(MODES_UrlUsername, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.UrlUsernameFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_USERNAME_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    strncpy(psProperties->acUrlUsername, pc, WEBJOB_MAX_USERNAME_LENGTH);
    psProperties->sFound.UrlUsernameFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_UrlPassword) == 0 && RUN_MODE_IS_SET(MODES_UrlPassword, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.UrlPasswordFound);
    psProperties->pcUrlPassword = WebJobDecodeValue(pc, acLocalError);
    if (psProperties->pcUrlPassword == NULL)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s]: %s", acRoutine, pcControl, acLocalError);
      return ER;
    }
    psProperties->sFound.UrlPasswordFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_GetTimeLimit) == 0 && RUN_MODE_IS_SET(MODES_GetTimeLimit, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.GetTimeLimitFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_32BIT_NUMBER_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    while (iLength > 0)
    {
      if (!isdigit((int) pc[iLength - 1]))
      {
        snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Value = [%s], Value must be %d-%d.", acRoutine, pcControl, pc, WEBJOB_MIN_TIME_LIMIT, WEBJOB_MAX_TIME_LIMIT);
        return ER_BadValue;
      }
      iLength--;
    }
    iValue = atoi(pc);
    if (iValue < WEBJOB_MIN_TIME_LIMIT || iValue > WEBJOB_MAX_TIME_LIMIT)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Value = [%s], Value must be %d-%d.", acRoutine, pcControl, pc, WEBJOB_MIN_TIME_LIMIT, WEBJOB_MAX_TIME_LIMIT);
      return ER_BadValue;
    }
    else
    {
      psProperties->iGetTimeLimit = iValue;
    }
    psProperties->sFound.GetTimeLimitFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_PutTimeLimit) == 0 && RUN_MODE_IS_SET(MODES_PutTimeLimit, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.PutTimeLimitFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_32BIT_NUMBER_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    while (iLength > 0)
    {
      if (!isdigit((int) pc[iLength - 1]))
      {
        snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Value = [%s], Value must be %d-%d.", acRoutine, pcControl, pc, WEBJOB_MIN_TIME_LIMIT, WEBJOB_MAX_TIME_LIMIT);
        return ER_BadValue;
      }
      iLength--;
    }
    iValue = atoi(pc);
    if (iValue < WEBJOB_MIN_TIME_LIMIT || iValue > WEBJOB_MAX_TIME_LIMIT)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Value = [%s], Value must be %d-%d.", acRoutine, pcControl, pc, WEBJOB_MIN_TIME_LIMIT, WEBJOB_MAX_TIME_LIMIT);
      return ER_BadValue;
    }
    else
    {
      psProperties->iPutTimeLimit = iValue;
    }
    psProperties->sFound.PutTimeLimitFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_RunTimeLimit) == 0 && RUN_MODE_IS_SET(MODES_RunTimeLimit, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.RunTimeLimitFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_32BIT_NUMBER_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    while (iLength > 0)
    {
      if (!isdigit((int) pc[iLength - 1]))
      {
        snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Value = [%s], Value must be %d-%d.", acRoutine, pcControl, pc, WEBJOB_MIN_TIME_LIMIT, WEBJOB_MAX_TIME_LIMIT);
        return ER_BadValue;
      }
      iLength--;
    }
    iValue = atoi(pc);
    if (iValue < WEBJOB_MIN_TIME_LIMIT || iValue > WEBJOB_MAX_TIME_LIMIT)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Value = [%s], Value must be %d-%d.", acRoutine, pcControl, pc, WEBJOB_MIN_TIME_LIMIT, WEBJOB_MAX_TIME_LIMIT);
      return ER_BadValue;
    }
    else
    {
      psProperties->iRunTimeLimit = iValue;
    }
    psProperties->sFound.RunTimeLimitFound = TRUE;
  }

#ifdef USE_SSL
  else if (strcasecmp(pcControl, KEY_SslBundledCAsFile) == 0 && RUN_MODE_IS_SET(MODES_SslBundledCAsFile, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.SslBundledCAsFileFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_PATHNAME_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    iError = SslSetBundledCAsFile(psProperties->psSslProperties, pc, acLocalError);
    if (iError != ER_OK)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s]: %s", acRoutine, pcControl, acLocalError);
      return iError;
    }
    psProperties->sFound.SslBundledCAsFileFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_SslPassPhrase) == 0 && RUN_MODE_IS_SET(MODES_SslPassPhrase, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.SslPassPhraseFound);
    pc = WebJobDecodeValue(pc, acLocalError);
    if (pc == NULL)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s]: %s", acRoutine, pcControl, acLocalError);
      return ER;
    }
    iError = SslSetPassPhrase(psProperties->psSslProperties, pc, acLocalError);
    if (iError != ER_OK)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s]: %s", acRoutine, pcControl, acLocalError);
      free(pc);
      return iError;
    }
    free(pc);
    psProperties->sFound.SslPassPhraseFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_SslPublicCertFile) == 0 && RUN_MODE_IS_SET(MODES_SslPublicCertFile, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.SslPublicCertFileFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_PATHNAME_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    iError = SslSetPublicCertFile(psProperties->psSslProperties, pc, acLocalError);
    if (iError != ER_OK)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s]: %s", acRoutine, pcControl, acLocalError);
      return iError;
    }
    psProperties->sFound.SslPublicCertFileFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_SslMaxChainLength) == 0 && RUN_MODE_IS_SET(MODES_SslMaxChainLength, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.SslMaxChainLengthFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_32BIT_NUMBER_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    while (iLength > 0)
    {
      if (!isdigit((int) pc[iLength - 1]))
      {
        snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Value = [%s], Value must be 1-10.", acRoutine, pcControl, pc);
        return ER_BadValue;
      }
      iLength--;
    }
    iValue = atoi(pc);
    if (iValue < 1 || iValue > 10 /*SSL_MAX_CHAIN_LENGTH*/)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Value = [%d], Value must be 1-10.", acRoutine, pcControl, iValue);
      return ER_BadValue;
    }
    else
    {
      psProperties->psSslProperties->iMaxChainLength = iValue;
    }
    psProperties->sFound.SslMaxChainLengthFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_SslPrivateKeyFile) == 0 && RUN_MODE_IS_SET(MODES_SslPrivateKeyFile, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.SslPrivateKeyFileFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_PATHNAME_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    iError = SslSetPrivateKeyFile(psProperties->psSslProperties, pc, acLocalError);
    if (iError != ER_OK)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s]: %s", acRoutine, pcControl, acLocalError);
      return iError;
    }
    psProperties->sFound.SslPrivateKeyFileFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_SslExpectedPeerCN) == 0 && RUN_MODE_IS_SET(MODES_SslExpectedPeerCN, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.SslExpectedPeerCNFound);
    iError = SslSetExpectedPeerCN(psProperties->psSslProperties, pc, acLocalError);
    if (iError != ER_OK)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s]: %s", acRoutine, pcControl, acLocalError);
      return iError;
    }
    psProperties->sFound.SslExpectedPeerCNFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_SslUseCertificate) == 0 && RUN_MODE_IS_SET(MODES_SslUseCertificate, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.SslUseCertificateFound);
    EVALUATE_TWOSTATE(pc, "y", "n", psProperties->psSslProperties->iUseCertificate);
    psProperties->sFound.SslUseCertificateFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_SslVerifyPeerCert) == 0 && RUN_MODE_IS_SET(MODES_SslVerifyPeerCert, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.SslVerifyPeerCertFound);
    EVALUATE_TWOSTATE(pc, "y", "n", psProperties->psSslProperties->iVerifyPeerCert);
    psProperties->sFound.SslVerifyPeerCertFound = TRUE;
  }
#endif

  else if (strcasecmp(pcControl, KEY_GetHookEnable) == 0 && RUN_MODE_IS_SET(MODES_GetHookEnable, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.GetHookEnableFound);
    EVALUATE_TWOSTATE(pc, "y", "n", psProperties->psGetHook->iActive);
    iError = HookSetValue(psProperties->psGetHook, HOOK_VALUE_ORIGINAL_FILENAME, psProperties->sWEBJOB.pcCommand, acLocalError);
    if (iError != ER_OK)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s]: %s", acRoutine, pcControl, acLocalError);
      return ER;
    }
    psProperties->sFound.GetHookEnableFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_GetHookCommandLine) == 0 && RUN_MODE_IS_SET(MODES_GetHookCommandLine, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.GetHookCommandLineFound);
    iError = HookSetValue(psProperties->psGetHook, HOOK_VALUE_ORIGINAL_COMMAND_LINE, pc, acLocalError);
    if (iError != ER_OK)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s]: %s", acRoutine, pcControl, acLocalError);
      return iError;
    }
    psProperties->sFound.GetHookCommandLineFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_GetHookStatus) == 0 && RUN_MODE_IS_SET(MODES_GetHookStatus, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.GetHookStatusFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_32BIT_NUMBER_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    while (iLength > 0)
    {
      if (!isdigit((int) pc[iLength - 1]))
      {
        snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Value = [%s], Value must be 0-%d.", acRoutine, pcControl, pc, XER_MaxExternalErrorCode);
        return ER_BadValue;
      }
      iLength--;
    }
    iValue = atoi(pc);
    if (iValue < 0 || iValue > XER_MaxExternalErrorCode)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Value = [%d], Value must be 0-%d.", acRoutine, pcControl, iValue, XER_MaxExternalErrorCode);
      return ER_BadValue;
    }
    else
    {
      psProperties->psGetHook->iTargetStatus = iValue;
    }
    psProperties->sFound.GetHookStatusFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_GetHookSuffix) == 0 && RUN_MODE_IS_SET(MODES_GetHookSuffix, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.GetHookSuffixFound);
    iError = HookSetValue(psProperties->psGetHook, HOOK_VALUE_SUFFIX, pc, acLocalError);
    if (iError != ER_OK)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s]: %s", acRoutine, pcControl, acLocalError);
      return iError;
    }
    psProperties->sFound.GetHookSuffixFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_ClientId) == 0 && RUN_MODE_IS_SET(MODES_ClientId, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.ClientIdFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_CLIENTID_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    strncpy(psProperties->acClientId, pc, WEBJOB_MAX_CLIENTID_LENGTH);
    psProperties->sFound.ClientIdFound = TRUE;
  }

#ifdef USE_DSV
  else if (strcasecmp(pcControl, KEY_DsvCertificateTree) == 0 && RUN_MODE_IS_SET(MODES_DsvCertificateTree, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.DsvCertificateTreeFound);
    if (iLength < 1 || iLength > WEBJOB_MAX_PATHNAME_LENGTH - 1)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], Invalid length [%d].", acRoutine, pcControl, iLength);
      return ER_Length;
    }
    strncpy(psProperties->acDsvCertificateTree, pc, WEBJOB_MAX_PATHNAME_LENGTH);
    psProperties->sFound.DsvCertificateTreeFound = TRUE;
  }

  else if (strcasecmp(pcControl, KEY_DsvVerifySignature) == 0 && RUN_MODE_IS_SET(MODES_DsvVerifySignature, iRunMode))
  {
    DUPLICATE_ERROR(psProperties->sFound.DsvVerifySignatureFound);
    EVALUATE_TWOSTATE(pc, "y", "n", psProperties->iDsvVerifySignature);
    psProperties->sFound.DsvVerifySignatureFound = TRUE;
  }
#endif

  else
  {
    if (psProperties->iStrictControls)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: Control = [%s], The specified control is not valid in this mode of operation.", acRoutine, pcControl);
      return ER_Jibberish;
    }
  }

  return ER_OK;
}
