/*
 * c.config
 *
 * Routines for reading the config file
 *
 * $Id: config,v 1.14 2000/02/08 23:56:29 joseph Exp $
 *
 */

#include <stdio.h> /* printf */
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "swis.h"

#include "proxy.h"
#include "macros.h"
#include "my_string.h"
#include "debug.h"

#include "config.h"

typedef enum
{
  conf_boolean,
  conf_string,
  conf_integer,
  conf_links
} conf_type;


#define config_file TASK_DIR ".Choices"
#define config_fileheader "# WebGet choices file\n# Version "
#define config_fileversion 1

int              config_maxfetchers = 5;
int              config_maxservers  = 10;
int              config_linkdepth   = 5;
conf_followlinks config_inlineimages = links_all;
int              config_inlineframes = 1;
int              config_openstatuswin = 1; /* auto open status window */
conf_followlinks config_links       = links_dir;
int              config_showlog     = 1; /* run html log file at end of fetch */

char config_proxyname[3][CONFIG_STRSIZE]  = { "", "", "" }; /* http, ftp, unknown and... ? */
char config_proxynotfor[CONFIG_STRSIZE]   = "";
int  config_proxyforunqualified = 1; /* if true, we proxy for an unqualified hostname - ie. a 'local' one */
char config_includefiles[256] = "*";
char config_excludefiles[256] = "*.zip *.spk *.arc *.exe http://ad.doubleclick.net/*";
char config_localurlprefix[32] = "file:/";

typedef struct
{
  const char  *tag;
  void        *var;
  conf_type   type;
  int         size;
} config_file_tags;



static config_file_tags config_filetags[] = {
  { "http_proxy",             config_proxyname[0],         conf_string,  CONFIG_STRSIZE },
  { "http_no_proxy",          config_proxynotfor,          conf_string,  CONFIG_STRSIZE },
  { "http_proxy_unqualified", &config_proxyforunqualified, conf_boolean, 0 },
  { "ftp_proxy",              config_proxyname[1],         conf_string,  CONFIG_STRSIZE },
  { "max_fetchers",           &config_maxfetchers,         conf_integer, MAXSESS },
  { "link_depth",             &config_linkdepth,           conf_integer, 0 },
  { "inline-images",          &config_inlineimages,        conf_links,   0 },
  { "frames",                 &config_inlineframes,        conf_boolean, 0 },
  { "open_status_win",        &config_openstatuswin,       conf_boolean, 0 },
  { "max_servers",            &config_maxservers,          conf_integer, 0 },
  { "links",                  &config_links,               conf_links,   0 },
  { "include",                config_includefiles,         conf_string,  sizeof config_includefiles },
  { "exclude",                config_excludefiles,         conf_string,  sizeof config_excludefiles },
  { "localurl_prefix",        config_localurlprefix,       conf_string,  sizeof config_localurlprefix },
  { "show-log",               &config_showlog,             conf_boolean, 0 },
  { NULL,                     NULL,                        conf_boolean, 0 },
};


int config_load( void )
{
  FILE *f = fopen( config_file, "r" );
  int overlong;
  char line[1024];
  char val[1024];
  _kernel_oserror *e;
  unsigned int flags;

  if ( !f )
  {
    E_REPORT( "Could not open config file!" );
    return -1;
  }

  if ( fread( line, 1, sizeof(config_fileheader)-1, f ) != sizeof(config_fileheader)-1 )
  {
    E_REPORT( "Error reading config file header" );
    fclose(f);
    return -1;
  }
  if ( memcmp( line, config_fileheader, sizeof(config_fileheader)-1 ) )
  {
    E_REPORT( "Invalid file header found reading config file" );
    fclose(f);
    return -1;
  }
  if ( ! fgets( line, sizeof line, f ) )
  {
    E_REPORT( "Error reading config file version" );
    fclose(f);
    return -1;
  }

  if ( atoi( line ) != config_fileversion )
  {
    E_REPORT( "Config file version wrong\n" );
    fclose(f);
    return -1;
  }

  overlong = 0;
  while ( fgets( line, sizeof line, f ) )
  {
    char *ptr = line + strlen(line) - 1;
    char *start = line;

    if ( *ptr != '\n' ) { overlong = 1; continue; }
    if ( overlong )
    {
      overlong = 0;
      E_REPORT("Overlong line found reading Choices file - ignored");
      continue;
    }
    while ( isspace( *start ) ) start++; /* skip leading space */
    if ( *start == '#' || !*start ) continue; /* skip comments, null line and blank lines */
    *ptr = 0;

//    debug_printf(( "Read: '%s'\n", start ));
    ptr = strchr( start, ':' );
    if ( !ptr )
    {
      char error[100];
      strcpy( error, "Error reading config file, no ':' in \"" );
      strncat( error, start, sizeof(error) - strlen(start) - 1 - 1 );
      strcat( error, "\"" );
      E_REPORT( error );
      continue;
    }
    *ptr = 0;
    {
      config_file_tags *tag = config_filetags;
      while ( tag->tag && my_strcasecmp( tag->tag, start ) != 0 ) tag++;
/*      if ( tag->tag )
        debug_printf(( "%s matches %s\n", tag->tag, start ));
        */
      if ( !tag->tag )
      {
        char error[100];
        strcpy( error, "Error reading config file, tag unknown (\"" );
        strncat( error, start, sizeof(error) - strlen(start) - 1 - 2 );
        strcat( error, "\")" );
        E_REPORT( error );
        continue;
      }
      while ( isspace( *++ptr ) ); /* skip white space after ':' */
      e = _swix( OS_GSTrans, _INR(0,2) | _OUT(_FLAGS), ptr, val, sizeof(val) - 1, &flags );
      if ( e || (flags & _C) )
      {
        char error[100];
        strcpy( error, "Error reading config file, GSTrans failed - string too long? (tag \"" );
        strncat( error, start, sizeof(error) - strlen(start) - 1 - 2 );
        strcat( error, "\")" );
        E_REPORT( error );
        continue;
      }
      switch ( tag->type )
      {
        case conf_boolean:
          switch ( tolower(*val) )
          {
            case 'y': *(int *)tag->var = 1; break;
            case 'n': *(int *)tag->var = 0; break;
            default: debug_printf(( "%s is not yes or no\n", val ));
          }
          break;

        case conf_string:
        {
          int len = strlen(val) + 1;
          if ( len > tag->size )
          {
            char error[128];
            strcpy( error, "Error reading config file, tag value exceeds maximum length, truncated (\"" );
            strncat( error, start, sizeof(error) - strlen(start) - 1 - 2 );
            strcat( error, "\")" );
            E_REPORT( error );
            *(char *)tag->var = 0;
            strncat( tag->var, val, tag->size - 1 );
          }
          else
          {
            memcpy( tag->var, val, len );
          }
          break;
        }

        case conf_integer:
        {
          int value;
          if ( !isdigit( *val ) )
          {
            debug_printf(( "%s is not an integer\n", val ));
            continue;
          }
          value = atoi( val );
          if ( tag->size > 0 && value > tag->size )
            value = tag->size;
          *(int *)tag->var = value;
          break;
        }

        case conf_links:
          switch ( tolower(*val) )
          {
            case 'y':
            case 'a':
              *(conf_followlinks *)tag->var = links_all;  break; /* 'y'/all */
            case 'h':
              *(conf_followlinks *)tag->var = links_host; break; /* host */
            case 'n':
              *(conf_followlinks *)tag->var = links_none; break; /* 'n'/'none' */
            default:
              *(conf_followlinks *)tag->var = links_dir;         /* dir */
          }
          break;
      }
    }
  }

  fclose(f);
  debug_printf(("Read config, httpproxy='%s'!\n", config_proxyname[0]));

  return 0;
}
