/* OpenDoors Online Software Programming Toolkit
 * (C) Copyright 1991 - 1999 by Brian Pirie.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *
 *        File: ODCFile.c
 *
 * Description: Implements the configuration file sub-system.
 *
 *   Revisions: Date          Ver   Who  Change
 *              ---------------------------------------------------------------
 *              Oct 13, 1994  6.00  BP   New file header format.
 *              Dec 09, 1994  6.00  BP   Standardized coding style.
 *              Nov 11, 1995  6.00  BP   32-bit portability.
 *              Nov 11, 1995  6.00  BP   Removed register keyword.
 *              Nov 16, 1995  6.00  BP   Removed oddoor.h, added odcore.h.
 *              Dec 30, 1995  6.00  BP   Added ODCALL for calling convention.
 *              Jan 01, 1996  6.00  BP   Added DisableDTR and NoDTRDisable.
 *              Jan 19, 1996  6.00  BP   Display error if config file not found
 *              Feb 19, 1996  6.00  BP   Changed version number to 6.00.
 *              Mar 03, 1996  6.10  BP   Begin version 6.10.
 *              Mar 19, 1996  6.10  BP   MSVC15 source-level compatibility.
 *              Aug 10, 2003  6.23  SH   *nix support
 */

#define BUILDING_OPENDOORS

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

#include "OpenDoor.h"
#include "ODStr.h"
#include "ODCore.h"
#include "ODGen.h"
#include "ODInEx.h"
#include "ODUtil.h"


/* Internal private variables */
static WORD awTimeVal[3];
static BYTE btTimeNumVals;


/* Local functions. */
static WORD ODCfgGetWordDecimal(char *pszConfigText);
static DWORD ODCfgGetDWordDecimal(char *pszConfigText);
static WORD ODCfgGetWordHex(char *pszConfigText);
static void ODCfgGetNextTime(char **ppchConfigText);
static BOOL ODCfgIsTrue(char *pszConfigText);


/* ----------------------------------------------------------------------------
 * ODConfigInit()
 *
 * Called to perform OpenDoors initialization when the configuration file
 * system is being used. This function is called from the normal od_init(),
 * and also uses the normal od_init() to perform base initialization after
 * the configuration file has been read, but before certain configuration
 * settings are set in od_control.
 *
 * Parameters: none
 *
 *     Return: void
 */
ODAPIDEF void ODCALL ODConfigInit(void)
{
   void (*custom_line_function)(char *keyword, char *options)
      = od_control.config_function;
   char *pchConfigText;
   WORD wCurrent;
   INT nConfigOption;
   BOOL bConfigFileRequired = TRUE;
   static FILE *pfConfigFile;
   static FILE *pfCustomDropFile = NULL;
   static char szConfigLine[257];
   static char szToken[33];
   static char szTempString[256];
   static char szWorkDir[80];
   static BOOL bWorkDirSet = FALSE;
   static time_t nUnixTime;
   static struct tm *TimeBlock;
   static INT16 nPageStart;
   static INT16 nPageEnd;
   static BOOL bPageSet = FALSE;
   static BOOL bInactivitySet = FALSE;
   static INT16 nInactivity;
   static char *pszWork;
   static BOOL bPageLengthSet = FALSE;
   static BYTE btPageLength;
   static char *apszFileNames[1];

   bIsCallbackActive = TRUE;

   nUnixTime = time(NULL);
   TimeBlock = localtime(&nUnixTime);

   /* Use default configuration file filename if none has been specified. */
   if(od_control.od_config_filename == NULL)
   {
      od_control.od_config_filename = "door.cfg";
      bConfigFileRequired = FALSE;
   }

   if((pfConfigFile = fopen(od_control.od_config_filename, "rt")) == NULL)
   {
      if(strchr(od_control.od_config_filename, DIRSEP) != NULL
         || strchr(od_control.od_config_filename, ':') != NULL)
      {
         wCurrent = strlen(od_control.od_config_filename);
         pchConfigText = (char *)od_control.od_config_filename + (wCurrent - 1);
         while(wCurrent > 0)
         {
            if(*pchConfigText == DIRSEP || *pchConfigText == ':')
            {
               strcpy(szConfigLine, (char *)pchConfigText + 1);
               pfConfigFile = fopen(szConfigLine, "rt");
               break;
            }

            --pchConfigText;
            --wCurrent;
         }
      }
      else
      {
         strcpy(szConfigLine, od_control.od_config_filename);
      }
   }

   /* If we were able to open the configuration file. */
   if(pfConfigFile != NULL)
   {
      /* Get configuration file strings in upper case. */
      for(wCurrent = 0; wCurrent < TEXT_SIZE; ++wCurrent)
      {
         strupr(od_config_text[wCurrent]);
      }
      for(wCurrent = 0; wCurrent < LINES_SIZE; ++wCurrent)
      {
         strupr(od_config_lines[wCurrent]);
      }

      for(;;)
      {
         /* Read the next line from the configuration file. */
         if(fgets(szConfigLine, 257, pfConfigFile) == NULL) break;

         /* Ignore all of line after comments or CR/LF char. */
         pchConfigText = (char *)szConfigLine;
         while(*pchConfigText)
         {
            if(*pchConfigText == '\n' || *pchConfigText == '\r'
               || *pchConfigText == ';')
            {
               *pchConfigText = '\0';
               break;
            }
            ++pchConfigText;
         }

         /* Search for beginning of first token on line. */
         pchConfigText = (char *)szConfigLine;
         while(*pchConfigText
            && (*pchConfigText == ' ' || *pchConfigText == '\t'))
         {
            ++pchConfigText;
         }
         if(!*pchConfigText) continue;

         /* Get first token from line. */
         wCurrent = 0;
         while(*pchConfigText
            && !(*pchConfigText == ' ' || *pchConfigText == '\t'))
         {
            if(wCurrent < 32) szToken[wCurrent++] = *pchConfigText;
            ++pchConfigText;
         }
         if(wCurrent <= 32)
         {
            szToken[wCurrent] = '\0';
         }
         else
         {
            szToken[32] = '\0';
         }
         strupr(szToken);

         /* Find beginning of configuration option parameters */
         while(*pchConfigText && (*pchConfigText == ' '
            || *pchConfigText == '\t'))
         {
            ++pchConfigText;
         }

         /* Trim trailing spaces from setting string. */
         for(wCurrent = strlen(pchConfigText) - 1; wCurrent > 0; --wCurrent)
         {
            if(pchConfigText[wCurrent] == ' '
               || pchConfigText[wCurrent] == '\t')
            {
               pchConfigText[wCurrent] = '\0';
            }
            else
            {
               break;
            }
         }


         for(wCurrent = 0; wCurrent < TEXT_SIZE; ++wCurrent)
         {
            if(strcmp(szToken, od_config_text[wCurrent]) == 0)
            {
               switch(wCurrent)
               {
                  case 0:
                     wODNodeNumber = ODCfgGetWordDecimal(pchConfigText);
                     break;

                  case 1:
                     strcpy(od_control.info_path,pchConfigText);
                     break;

                  case 2:
                     if(pchConfigText[strlen(pchConfigText) - 1] == DIRSEP
                        && pchConfigText[strlen(pchConfigText) - 2] != ':'
                        && strlen(pchConfigText) > 1)
                     {
                        pchConfigText[strlen(pchConfigText) - 1] = '\0';
                     }

                     szOriginalDir = (char *)malloc(256);
                     if(szOriginalDir != NULL)
                     {
                        ODDirGetCurrent(szOriginalDir, 256);
                     }

                     strcpy(szWorkDir, pchConfigText);
                     bWorkDirSet = TRUE;
                     break;

                  case 3:
                     strcpy(od_control.od_logfile_name, pchConfigText);
                     break;

                  case 4:
                     od_control.od_logfile_disable = TRUE;
                     break;

                  case 5:
                  case 6:
                  case 7:
                  case 8:
                  case 9:
                  case 10:
                  case 11:
                      if((wCurrent - 5) == (WORD)TimeBlock->tm_wday)
                      {
                         ODCfgGetNextTime((char **)&pchConfigText);
                         nPageStart = awTimeVal[0] * 60 + awTimeVal[1];
                         ODCfgGetNextTime((char **)&pchConfigText);
                         nPageEnd = awTimeVal[0] * 60 + awTimeVal[1];
                         bPageSet = TRUE;
                      }
                     break;

                  case 12:
                     od_control.od_maxtime = ODCfgGetWordDecimal(pchConfigText);
                     break;

                  case 13:
                     bSysopNameSet = TRUE;
                     strncpy((char *)&szForcedSysopName, pchConfigText, 39);
                     szForcedSysopName[39] = '\0';
                     break;

                  case 14:
                     bSystemNameSet = TRUE;
                     strncpy((char *)&szForcedSystemName, pchConfigText, 39);
                     szForcedSystemName[39] = '\0';
                     break;

                  case 15:
                     od_control.od_swapping_disable = TRUE;
                     break;

                  case 16:
                     strncpy(od_control.od_swapping_path, pchConfigText, 79);
                     od_control.od_swapping_path[79] = '\0';
                     break;

                  case 17:
                     od_control.od_swapping_noems = TRUE;
                     break;

                  case 18:
                     dwForcedBPS = ODCfgGetDWordDecimal(pchConfigText);
                     break;

                  case 19:
                     nForcedPort = ODCfgGetWordDecimal(pchConfigText);
                     break;

                  case 20:
                     if(pfCustomDropFile == NULL && !od_control.od_force_local)
                     {
                        apszFileNames[0] = (char *)pchConfigText;
                        if(ODSearchForDropFile(apszFileNames, 1, szTempString,
                           NULL) != -1)
                        {
                           if((pfCustomDropFile = fopen(szTempString, "rt"))
                              != NULL)
                           {
                              od_control.od_info_type = CUSTOM;
                              od_control.user_attribute = 0x06;
                              od_control.user_screen_length = 23;
                              od_control.user_ansi = TRUE;
                              od_control.user_rip = FALSE;
                              od_control.user_avatar = FALSE;
                              od_control.od_page_pausing = TRUE;
                              od_control.od_page_len = 15;
                              od_control.user_timelimit = 0;
                              strcpy(od_control.user_name, "Unknown User");
                              strcpy(od_control.user_location,
                                 "Unknown Location");
                              od_control.user_security = 1;
                           }
                        }
                     }
                     break;

                  case 21:
                     if(pfCustomDropFile != NULL)
                     {
                        if(fgets(szTempString, 255, pfCustomDropFile)!=NULL)
                        {
                           if(szTempString[strlen(szTempString) - 1] == '\n')
                           {
                              szTempString[strlen(szTempString) - 1] = '\0';
                           }
                           else
                           {
                              INT ch;
                              do
                              {
                                 ch = fgetc(pfCustomDropFile);
                              } while(ch != '\n' && ch != EOF);
                           }
                           if(szTempString[strlen(szTempString) - 1] == '\r')
                           {
                              szTempString[strlen(szTempString) - 1] = '\0';
                           }

                           strupr(pchConfigText);

                           for(nConfigOption = 0; nConfigOption < LINES_SIZE;
                              ++nConfigOption)
                           {
                              if(strcmp(pchConfigText,
                                 od_config_lines[nConfigOption]) == 0)
                              {
                                 switch(nConfigOption)
                                 {
                                    case 1:
                                       od_control.port =
                                          ODCfgGetWordDecimal(szTempString) - 1;
                                       break;

                                    case 2:
                                       od_control.port =
                                          ODCfgGetWordDecimal(szTempString);
                                       break;

                                    case 3:
                                       od_control.baud =
                                          ODCfgGetWordDecimal(szTempString);
                                       break;

                                    case 4:
                                       if(ODCfgIsTrue(szTempString))
                                       {
#ifdef ODPLAT_NIX
                                          od_control.baud = 1;
#else
                                          od_control.baud = 0;
#endif
                                       }
                                       break;

                                    case 5:
                                    case 6:
                                       ODStringToName(szTempString);
                                       strncpy(od_control.user_name,
                                          szTempString, 34);
                                       od_control.user_name[34] = '\0';
                                       break;

                                    case 7:
                                       strcat(od_control.user_name, " ");
                                       ODStringToName(szTempString);
                                       strncat(od_control.user_name,
                                          szTempString,
                                          35 - strlen(od_control.user_name));
                                       od_control.user_name[35] = '\0';
                                       break;

                                    case 8:
                                       ODStringToName(szTempString);
                                       strncpy(od_control.user_handle,
                                          szTempString, 35);
                                       od_control.user_handle[35] = '\0';
                                       break;

                                    case 9:
                                       pszWork = (char *)szTempString;
                                       ODCfgGetNextTime((char **)&pszWork);
                                       od_control.user_timelimit += 
                                          (awTimeVal[0] * 60);
                                       break;

                                    case 10:
                                       pszWork = (char *)szTempString;
                                       ODCfgGetNextTime((char **)&pszWork);
                                       if(btTimeNumVals <= 1)
                                       {
                                          od_control.user_timelimit +=
                                             awTimeVal[0];
                                       }
                                       else
                                       {
                                          od_control.user_timelimit +=
                                             awTimeVal[1] + (awTimeVal[0] * 60);
                                       }
                                       break;

                                    case 11:
                                       pszWork = (char *)szTempString;
                                       ODCfgGetNextTime((char **)&pszWork);
                                       if(btTimeNumVals <= 1)
                                       {
                                          od_control.user_timelimit +=
                                             awTimeVal[0] / 60;
                                       }
                                       else if(btTimeNumVals == 2)
                                       {
                                          od_control.user_timelimit +=
                                             (awTimeVal[1] / 60) + awTimeVal[0];
                                       }
                                       else
                                       {
                                          od_control.user_timelimit +=
                                             (awTimeVal[2] / 60) + awTimeVal[1]
                                             + (awTimeVal[0] * 60);
                                       }
                                       break;

                                    case 12:
                                       od_control.user_ansi =
                                          ODCfgIsTrue(szTempString);
                                       break;

                                    case 13:
                                       od_control.user_avatar =
                                          ODCfgIsTrue(szTempString);
                                       break;

                                    case 14:
                                       od_control.od_page_pausing =
                                          ODCfgIsTrue(szTempString);
                                       break;

                                    case 15:
                                       od_control.user_screen_length =
                                          ODCfgGetWordDecimal(szTempString);
                                       break;

                                    case 16:
                                       if(ODCfgIsTrue(szTempString))
                                        {
                                           od_control.user_attribute |= 0x02;
                                        }
                                       else
                                        {
                                           od_control.user_attribute &=~ 0x02;
                                        }
                                       break;

                                    case 17:
                                       od_control.user_security =
                                          ODCfgGetWordDecimal(szTempString);
                                       break;

                                    case 18:
                                       ODStringToName(szTempString);
                                       strncpy(od_control.user_location,
                                          szTempString, 25);
                                       od_control.user_location[25] = '\0';
                                       break;

                                    case 19:
                                       wODNodeNumber =
                                          ODCfgGetWordDecimal(szTempString);
                                       break;

                                    case 20:
                                    case 21:
                                       ODStringToName(szTempString);
                                       strncpy(od_control.sysop_name,
                                          szTempString, 38);
                                       od_control.sysop_name[38] = '\0';
                                       break;

                                    case 22:
                                       strcat(od_control.sysop_name, " ");
                                       ODStringToName(szTempString);
                                       strncat(od_control.sysop_name,
                                          szTempString,
                                          39 - strlen(od_control.system_name));
                                       od_control.sysop_name[39] = '\0';
                                       break;

                                    case 23:
                                       strncpy(od_control.system_name,
                                          szTempString, 39);
                                       od_control.system_name[39] = '\0';
                                       break;

                                    case 24:
                                       od_control.user_rip =
                                          ODCfgIsTrue(szTempString);
                                 }
                              }
                           }
                        }
                     }
                     break;

                  case 22:
                     bInactivitySet = TRUE;
                     nInactivity = ODCfgGetWordDecimal(pchConfigText);
                     if(nInactivity < 0) nInactivity = 0;
                     break;

                  case 23:
                     btPageLength = (BYTE)ODCfgGetWordDecimal(pchConfigText);
                     bPageLengthSet = TRUE;
                     break;

                  case 24:
                     od_control.od_chat_color2 = 
                        od_color_config(pchConfigText);
                     break;

                  case 25:
                     od_control.od_chat_color1 =
                        od_color_config(pchConfigText);
                     break;

                  case 26:
                     od_control.od_list_title_col =
                        od_color_config(pchConfigText);
                     break;

                  case 27:
                     od_control.od_list_name_col =
                        od_color_config(pchConfigText);
                     break;

                  case 28:
                     od_control.od_list_size_col = 
                        od_color_config(pchConfigText);
                     break;

                  case 29:
                     od_control.od_list_comment_col =
                        od_color_config(pchConfigText);
                     break;

                  case 30:
                     od_control.od_list_offline_col =
                        od_color_config(pchConfigText);
                     break;

                  case 31:
                     strncpy(szDesiredPersonality, pchConfigText, 32);
                     szDesiredPersonality[32] = '\0';
                     break;

                  case 32:
                     /* "NoFossil" */
                     od_control.od_no_fossil = TRUE;
                     break;

                  case 33:
                     /* "PortAddress" */
                     od_control.od_com_address = ODCfgGetWordHex(pchConfigText);
                     break;

                  case 34:
                     /* "PortIRQ" */
                     od_control.od_com_irq =
                        (char)ODCfgGetWordDecimal(pchConfigText);
                     break;

                  case 35:
                     /* "ReceiveBuffer" */
                     od_control.od_com_rx_buf =
                        ODCfgGetWordDecimal(pchConfigText);
                     break;

                  case 36:
                     /* "TransmitBuffer" */
                     od_control.od_com_tx_buf =
                        ODCfgGetWordDecimal(pchConfigText);
                     break;

                  case 37:
                     /* "PagePromptColour" */
                     od_control.od_continue_col =
                        od_color_config(pchConfigText);
                     break;

                  case 38:
                     /* "LocalMode" */
                     od_control.od_force_local = TRUE;
                     break;

                  case 39:
                     /* "PopupMenuTitleColour" */
                     od_control.od_menu_title_col =
                        od_color_config(pchConfigText);
                     break;

                  case 40:
                     /* "PopupMenuBorderColour" */
                     od_control.od_menu_border_col =
                        od_color_config(pchConfigText);
                     break;

                  case 41:
                     /* "PopupMenuTextColour" */
                     od_control.od_menu_text_col =
                        od_color_config(pchConfigText);
                     break;

                  case 42:
                     /* "PopupMenuKeyColour" */
                     od_control.od_menu_key_col =
                        od_color_config(pchConfigText);
                     break;

                  case 43:
                     /* "PopupMenuHighlightColour" */
                     od_control.od_menu_highlight_col =
                        od_color_config(pchConfigText);
                     break;

                  case 44:
                     /* "PopupMenuHighKeyColour" */
                     od_control.od_menu_highkey_col = 
                        od_color_config(pchConfigText);
                     break;

                  case 45:
                     /* "NoFIFO" */
                     od_control.od_com_no_fifo = TRUE;
                     break;

                  case 46:
                     /* "FIFOTriggerSize" */
                     od_control.od_com_fifo_trigger =
                        (BYTE)ODCfgGetWordDecimal(pchConfigText);
                     break;

                  case 47:
                     /* "DisableDTR" */
                     ODStringCopy(od_control.od_disable_dtr, pchConfigText,
                        sizeof(od_control.od_disable_dtr));
                     break;

                  case 48:
                     /* "NoDTRDisable" */
                     od_control.od_disable |= DIS_DTR_DISABLE;
                     break;
               }
            }
         }

         /* Check if command is a programmer customized option. */
         if(wCurrent >= TEXT_SIZE && custom_line_function != NULL)
         {
            (*custom_line_function)((char *)&szToken, pchConfigText);
         }
      }

      /* Close the configuration file. */
      fclose(pfConfigFile);}
   else
   {
      if(bConfigFileRequired)
      {
         od_control.od_error = ERR_FILEOPEN;
         ODInitError("Unable to access configuration file.");
         exit(od_control.od_errorlevel[1]);
      }
   }

   /* Close custom door info file */
   if(pfCustomDropFile != NULL)
   {
      fclose(pfCustomDropFile);
   }

   bIsCallbackActive = FALSE;

   /* Carry out normal OpenDoors initialization. */
   bCalledFromConfig = TRUE;
   od_init();
   bCalledFromConfig = FALSE;

   /* Update any settings that need to be updated. */
   if(bPageSet)
   {
      od_control.od_pagestartmin = nPageStart;
      od_control.od_pageendmin = nPageEnd;
   }

   if(bInactivitySet && nInactivity != 0)
   {
      od_control.od_inactivity = nInactivity;
   }

   if(bSysopNameSet)
   {
      strcpy((char *)&od_control.sysop_name, (char *)&szForcedSysopName);
   }

   if(bSystemNameSet)
   {
      strcpy((char *)&od_control.system_name, (char *)&szForcedSystemName);
   }

   if(bPageLengthSet)
   {
      od_control.od_page_len = btPageLength;
   }

   if(bWorkDirSet)
   {
      ODDirChangeCurrent(szWorkDir);
   }
}


/* ----------------------------------------------------------------------------
 * ODCfgGetWordDecimal()                               *** PRIVATE FUNCTION ***
 *
 * Obtains the value of the next decimal number in the provided string, in the
 * form of a WORD (16 bit value).
 *
 * Parameters: pszConfigText - String to examine.
 *
 *     Return: The first number obtained from the string.
 */
static WORD ODCfgGetWordDecimal(char *pszConfigText)
{
   ASSERT(pszConfigText != NULL);

   /* Skip any initial non-numerical characters. */
   while(*pszConfigText && (*pszConfigText < '0' || *pszConfigText > '9'))
   {
      ++pszConfigText;
   }

   /* Return value of number. */
   return(atoi(pszConfigText));
}


/* ----------------------------------------------------------------------------
 * ODCfgGetDWordDecimal()                              *** PRIVATE FUNCTION ***
 *
 * Obtains the value of the next decimal number in the provided string, in the
 * form of a DWORD (32 bit value).
 *
 * Parameters: pszConfigText - String to examine.
 *
 *     Return: The first number obtained from the string.
 */
static DWORD ODCfgGetDWordDecimal(char *pszConfigText)
{                                
   ASSERT(pszConfigText != NULL);

   /* Skip any initial non-numerical characters. */
   while(*pszConfigText && (*pszConfigText < '0' || *pszConfigText > '9'))
   {
      ++pszConfigText;
   }

   /* Return value of number. */
   return(atol(pszConfigText));
}


/* ----------------------------------------------------------------------------
 * ODCfgGetWordHex()                                   *** PRIVATE FUNCTION ***
 *
 * Obtains the value of the next hexidecimal number in the provided string, in
 * the form of a WORD (16 bit value).
 *
 * Parameters: pszConfigText - String to examine.
 *
 *     Return: The first number obtained from the string.
 */
static WORD ODCfgGetWordHex(char *pszConfigText)
{
   WORD wToReturn;

   ASSERT(pszConfigText != NULL);

   /* Skip any initial non-hexidecimal characters. */
   while(*pszConfigText && (*pszConfigText < '0' || *pszConfigText > '9')
      && (toupper(*pszConfigText) < 'A' || toupper(*pszConfigText) > 'F'))
   {
      ++pszConfigText;
   }

   sscanf(pszConfigText, "%x", &wToReturn);

   return(wToReturn);
}


/* ----------------------------------------------------------------------------
 * ODCfgGetNextTime()                                  *** PRIVATE FUNCTION ***
 *
 * Obtains the next time from a string, updating the string pointer to point to
 * the position in the string after the end of the time. The time information
 * is stored in the btTimeNumVals and awTimeVal private global variables.
 *
 * Parameters: ppchConfigText - Pointer to character pointer to the string,
 *                              which is to be updated.
 *
 *     Return: void
 */
static void ODCfgGetNextTime(char **ppchConfigText)
{
   char *pchConfigText = (char *)(*ppchConfigText);

   ASSERT(ppchConfigText != NULL);
   ASSERT(*ppchConfigText != NULL);

   btTimeNumVals = 0;
   awTimeVal[0] = 0;
   awTimeVal[1] = 0;
   awTimeVal[2] = 0;


   while(*pchConfigText && (*pchConfigText == ' ' || *pchConfigText == '\t'))
   {
      ++pchConfigText;
   }


   while(*pchConfigText && btTimeNumVals < 3)
   {
      if(*pchConfigText < '0' || *pchConfigText > '9') break;
      awTimeVal[btTimeNumVals++] = atoi(pchConfigText);
      while(*pchConfigText && *pchConfigText >= '0' && *pchConfigText <= '9')
      {
         ++pchConfigText;
      }
      if(*pchConfigText == ':' || *pchConfigText == '.' || *pchConfigText == ','
         || *pchConfigText == ';')
      {
         ++pchConfigText;
      }
   }

   *ppchConfigText = (char *)pchConfigText;
}


/* ----------------------------------------------------------------------------
 * ODCfgIsTrue()                                       *** PRIVATE FUNCTION ***
 *
 * Determines whether the specified string represents a TRUE or FALSE value.
 * For example "Yes", "TRUE", "Y" and "1" all represent TRUE values, while
 * "No", "FALSE", "N" and "0" all represent FALSE values.
 *
 * Parameters: pszConfigText - String to examine.
 *
 *     Return: The Boolean value represented by the string.
 */
static BOOL ODCfgIsTrue(char *pszConfigText)
{
   ASSERT(pszConfigText != NULL);

   while(*pszConfigText && (*pszConfigText == ' ' || *pszConfigText == '\t'))
   {
      ++pszConfigText;
   }

   switch(*pszConfigText)
   {
      case '1':
      case 't':
      case 'T':
      case 'y':
      case 'Y':
      case 'g':
      case 'G':
         return(TRUE);
   }

   return(FALSE);
}