#ifndef _DWC_CONF_C
#define _DWC_CONF_C

/*--------------------------------------------------------------------------
 *  Copyright (c) 2001-2004 Igor Daniloff. 
 *	All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at this directory.
 *------------------------------------------------------------------------*/

#ifndef lint
static const char rcsid[] = "$Id: dwc_conf.c,v 1.43 2007/10/31 14:49:52 akorkov Exp $";
#endif
#define OKD(a) // printLib( DW_LL_ERROR, "ok - %d",a)
#ifdef __UNIX_DW 
#ifndef EMX_DW
#include <unistd.h>
#else /* EMX */
#include <io.h>
#endif /* EMX */
#endif /* UNIX */
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include "dwc_conf.h"
#if defined(__UNIX_DW)
#include "dwc_err.h"
#include "dwc_lib.h"
#endif /* UNIX */
#if defined(__WIN32_DW)
#include "dw_winlib.h"
#endif /* __WIN32_DW */

static int  getbool( char *str, DWC_bool_t *pb );
static int  getstring( char *str, char **pval, int len );

#define OBSOLETE_NO         (0)
#define OBSOLETE_CAN_SKIP   (1)
#define OBSOLETE_STOP       (2)

typedef struct {
    const char*     section;
    const char*     option;
    int             severity;
} dwc_obsolete_opt_t;

typedef struct {
    const char*     section;
    int             severity;
} dwc_obsolete_sec_t;

dwc_obsolete_sec_t obsolete_sections[] = {
    { "Submitter", OBSOLETE_STOP },
    { "SendmailCommunication", OBSOLETE_STOP },
    { "MailbombNotifications", OBSOLETE_CAN_SKIP },
    { NULL, 0 }
};

dwc_obsolete_opt_t obsolete_options[] = {
    { "Scanning", "StripPrefix", OBSOLETE_CAN_SKIP },    
    { "Scanning", "PathPrefix", OBSOLETE_CAN_SKIP },    
    { "Scanning", "IncludeViruses", OBSOLETE_CAN_SKIP },    
    { "Scanning", "DenyOnOne", OBSOLETE_CAN_SKIP },    
    { "Scanning", "HeloInReceived", OBSOLETE_CAN_SKIP },
    { "Actions", "MailbombObject", OBSOLETE_CAN_SKIP },
    { "Actions", "VirusReport", OBSOLETE_CAN_SKIP },    
    { "Actions", "SpamFilterAlert", OBSOLETE_CAN_SKIP },    
    { "Actions", "Incureable", OBSOLETE_CAN_SKIP },   
    { "Logging", "Location", OBSOLETE_STOP },
    { NULL, NULL, 0 }
};
#ifdef __UNIX_DW
/* like namespace MailDaemon
 * see drweb-unix-make/drweb-maild/ipc/proto-maild/dw_proto_id.h 
 */
enum DwConfigCmd {
  kCC_NONE,
  kCC_GET_ALL,
  kCC_RESPONSE,
  kCC_GET_DIFF
};
/* see drweb-unix-make/drweb-maild/ipc/dw_protocol_bases.h */
 enum eProtocolIDBases {
   kPIDBase_MailDaemon   = 0x1000,
   kPIDBase_ControlAgent = 0x2000
 };

enum eProtocolID {
            
  kPID_LicenseRequest   = kPIDBase_ControlAgent + 1,
  kPID_LicenseUpdate    = kPIDBase_ControlAgent + 2,
  kPID_Config           = kPIDBase_ControlAgent + 3,
  kPID_Virstat          = kPIDBase_ControlAgent + 4,
  kPID_Globalstat       = kPIDBase_ControlAgent + 5,
  kPID_LicenseRead      = kPIDBase_ControlAgent + 6,
  kPID_EmailsRead       = kPIDBase_ControlAgent + 7,
  kPID_ReloadComp       = kPIDBase_ControlAgent + 8,
  kPID_StartApp         = kPIDBase_ControlAgent + 9,
  kPID_StopApp          = kPIDBase_ControlAgent + 10,
  kPID_KeyUUID          = kPIDBase_ControlAgent + 11,
  kPID_Update           = kPIDBase_ControlAgent + 12,
            
  kPID_Enqueue          = kPIDBase_MailDaemon + 1,
  kPID_Notifier         = kPIDBase_MailDaemon + 2
};
 enum DwConfigCode {
   kCE_NONE,
   kCE_OK,
   kCE_ERROR
 };

char * extern_buf;
char * _extern_buf;
int extern_buf_len;
#endif /* __UNIX_DW */
/* -------------------------------------------------- */
int is_obsolete_section( const char* sec )
{
    int   i;
    
    for( i = 0; obsolete_sections[i].section != NULL; ++i )
    {
        if( 0 == DWC_strncasecmp( sec, obsolete_sections[i].section, strlen(obsolete_sections[i].section) ) )
        {
            return obsolete_sections[i].severity;
        }
    }
    return OBSOLETE_NO;
}

/* -------------------------------------------------- */
int is_obsolete_option( const char* sec, const char* opt )
{
    int   i;
    
    for( i = 0; obsolete_options[i].section != NULL; ++i )
    {
        if( (0 == DWC_strncasecmp( sec, obsolete_options[i].section, strlen(obsolete_options[i].section) ) )
            &&
            (0 == DWC_strncasecmp( opt, obsolete_options[i].option, strlen(obsolete_options[i].option) ) ) )
        {
            return obsolete_options[i].severity;
        }
    }
    return OBSOLETE_NO;
}


/* -------------------------------------------------- */
void delete_spaces( char *s )
{
    int i, len, in_quote = 0;

    len = strlen( s );
    for( i = 0; i <= len; ++i )
    {        
        if( s[i] == '"' )
        {
            in_quote = !in_quote;
            continue;
        }
        if( isspace(((int)s[i])) && !in_quote )
        {
            memcpy( &s[i], &s[i+1], len - i );
            --len;
            --i;
        }
    }
    s[i-1] = NULLCHAR;
    return;
}

/* -------------------------------------------------- */
void delete_quotes( char *s )
{
    int i, len;

    len = strlen( s );
    for( i = 0; i <= len; ++i )
    {
        if( s[i] == '"' )
        {
            memcpy( &s[i], &s[i+1], len - i );
            --len;
            --i;
        }
    }
    return;
}

/* -------------------------------------------------- */
static int getbool( char *str, DWC_bool_t *pb )
{
    if( !pb || !str )
    {
        return 0;
    }
    delete_quotes( str );    
    
    if( (strcasecmp( str, "yes" ) == 0)
        ||
        (strcasecmp( str, "on" ) == 0)
        ||
        (strcasecmp( str, "true" ) == 0) )
    {
        *pb = TRUE;
        return 1;
    }
    else if( (strcasecmp( str, "no" ) == 0)
             ||
             (strcasecmp( str, "off" ) == 0)
             ||
             (strcasecmp( str, "false" ) == 0) )
    {
        *pb = FALSE;
        return 1;
    }
    return 0;
}

/* -------------------------------------------------- */
static int getstringlist( char *str, dwc_multistring_t *pval, char sep )
{
    char    *p;
    char    *s;
    
    *pval = dw_multistring_create( 0 );
    if( !(*pval) )
    {
        printLib( DW_LL_ERROR, "dwlib: getstringlist: cannot create string list" );
        return 0;
    }
    s = NULL;
    while( NULL != (p = strchr( str, sep )) )
    {
        /* del separator and step */
        *p = NULLCHAR;        
        ++p;
        if( !getstring( str, &s, 0 ) || !dw_multistring_add( *pval, s ) )
        {
            printLib( DW_LL_ERROR, "dwlib: getstringlist: cannot add %s to list", str );            
            goto error_exit;
        }
        DWC_Free( s );
        str = p;
    }
    if( !getstring( str, &s, 0 ) || !dw_multistring_add( *pval, s ) )
    {
        printLib( DW_LL_ERROR, "dwlib: getstringlist: cannot add %s to list", str );            
        goto error_exit;
    }
    DWC_Free( s );
    return 1;
    
  error_exit:
    dw_multistring_delete( *pval );
    DWC_Free( s );
    return 0;
}

/* -------------------------------------------------- */
static int getstring( char *str, char **pval, int len )
{
    int     slen;
    char   *p;
    
    delete_quotes( str );
    
    slen = strlen( str );
    if( len != 0 )
    {
        if( len > slen )
        {
            strncpy( *pval, str, len );
            (*pval)[len - 1] = NULLCHAR;
            return 1;
        }
        else
        {
            printLib( DW_LL_ERROR, "dwlib: getstring: too long (passed %d, real %s)", len, slen );
            return 0;
        }
    }
    else
    {
        p = DWC_Strdup( str );
        if( !p )
        {
            printLib( DW_LL_ERROR, "dwlib: getstring: no memory for <%s>", str );
            return 0;
        }
        DWC_Free( *pval );
        *pval = p;
        return 1;
    }
}

/* -------------------------------------------------- */
dwc_bool_t isseparator( char sep )
{
    if( (sep == '#') || (sep == '"') || (sep == '_') )
    {
        return FALSE;
    }
    if( isspace( (int)sep ) )
    {
        return FALSE;
    }
    if( isalnum( (int)sep ) )
    {
        return FALSE;
    }
    return TRUE;
}

/* -------------------------------------------------- */
#ifdef __UNIX_DW
int read_section_agent ( char * _buf_fs, int* line, const char* section, dwc_conf_set_t* vars, char sep, char list_sep )
{    
  char * buf_fs=_buf_fs; // buf_fs - fake pointer like FILE *
  int             itmp, n, chkline, obs;
  long            offset;
    char            buf[DWC_LINE_SIZE], com[DWC_NAME_SIZE];
    char            fmt[32];
    dwc_bool_t      matched;
    char           *pstr,*pbuf;
    dwc_conf_set_t *pv = NULL;
    
    if( !isseparator( sep ) )
    {
        printLib( DW_LL_ERROR, "dwlib: read_section(%s): invalid separator (%c) passed", section, sep );
        return -1;
    }
    if( !isseparator( list_sep ) )
    {
        printLib( DW_LL_ERROR, "dwlib: read_section(%s): invalid separator (%c) passed", section, list_sep );
        return -1;
    }
    /* check list of parameters and sets default values */
    for( chkline = 1, pv = vars; pv->vtype != DWC_CV_NONE; ++pv, ++chkline )
    {
        if( !pv->name )
        {
            printLib( DW_LL_ERROR, "dwlib: read_section(%s): null name for %d variable passed", section, chkline );
            goto error_exit;
        }
        if( !pv->vptr.pint )
        {
            printLib( DW_LL_ERROR, "dwlib: read_section(%s): null pointer to value for %d variable passed", section, chkline );
            goto error_exit;
        }
        switch( pv->vtype )
        {
             case DWC_CV_INT    :
                 if( pv->vlen != sizeof(int) )
                 {
                     printLib( DW_LL_ERROR, "dwlib: read_section(%s): wrong len (%d) of storage for %d variable passed", section, pv->vlen, chkline );
                     goto error_exit;
                 }
                 *pv->vptr.pint = pv->vdefault.vint;
                 printLib( DW_LL_DEBUG, "dwlib: read_section(%s): for %s default = %d, value = %d", section, pv->name, pv->vdefault.vint, *pv->vptr.pint );
                 break;
             case DWC_CV_COUNT  :
             case DWC_CV_OCTAL  :
                 if( pv->vlen != sizeof(dwc_count_t) )
                 {
                     printLib( DW_LL_ERROR, "dwlib: read_section(%s): wrong len (%d) of storage for %d variable passed", section, pv->vlen, chkline );
                     goto error_exit;
                 }
                 *pv->vptr.pcount = pv->vdefault.vcount;
                 printLib( DW_LL_DEBUG, "dwlib: read_section(%s): for %s default = %d, value = %d", section, pv->name, pv->vdefault.vcount, *pv->vptr.pcount );
                 break;
             case DWC_CV_BOOL   :                 
                 if( pv->vlen != sizeof(dwc_bool_t) )
                 {
                     printLib( DW_LL_ERROR, "dwlib: read_section(%s): wrong len (%d) of storage for %d variable passed", section, pv->vlen, chkline );
                     goto error_exit;
                 }
                 *pv->vptr.pbool = pv->vdefault.vbool;
                 printLib( DW_LL_DEBUG, "dwlib: read_section(%s): for %s default = %d, value = %d", section, pv->name, pv->vdefault.vbool, *pv->vptr.pbool );
                 break;
             case DWC_CV_STRING :              
                 if( !pv->vdefault.vstring )
                 {
                     printLib( DW_LL_DEBUG, "dwlib: read_section(%s): null default for %d variable passed", section, chkline );
                     *pv->vptr.pstring = NULL;
                 }
                 else if( pv->vlen == 0 )
                 {
                     *pv->vptr.pstring = DWC_Strdup( pv->vdefault.vstring );
                     if( !*pv->vptr.pstring )
                     {
                         printLib( DW_LL_DEBUG, "dwlib: read_section(%s): cannot allocate storage for %d variable passed", section, chkline );
                         goto error_exit;
                     }
                 }
                 else if( pv->vlen >= DWC_strlen( pv->vdefault.vstring ) )
                 {
                     strncpy( *pv->vptr.pstring, pv->vdefault.vstring, DWC_strlen(pv->vdefault.vstring) );
                     (*pv->vptr.pstring)[ pv->vlen - 1 ] = NULLCHAR;
                 }                    
                 else
                 {
                     printLib( DW_LL_ERROR, "dwlib: read_section(%s): storage not enough (%d) for default (%d) for %d variable passed", section, pv->vlen, strlen(pv->vdefault.vstring), chkline );
                     goto error_exit;
                 }
                 if( pv->vdefault.vstring )
                 {
                     printLib( DW_LL_DEBUG, "dwlib: read_section(%s): for %s default = %s, value = %s", section, pv->name, pv->vdefault.vstring, *pv->vptr.pstring );
                 }
                 else
                 {
                     printLib( DW_LL_DEBUG, "dwlib: read_section(%s): for %s default = NULL, value = NULL", section, pv->name );
                 }
                 break;                    
             case DWC_CV_STRING_LIST :              
                 if( !pv->vdefault.vstringlist )
                 {
                     printLib( DW_LL_DEBUG, "dwlib: read_section(%s): null default for %d variable passed", section, chkline );
                     *pv->vptr.pstringlist = NULL;
                 }
                 else
                 {
                     printLib( DW_LL_ERROR, "dwlib: read_section(%s): default value for string list currently not supported", section );
                     goto error_exit;
                 }
                 break;                    
             default :              
                 printLib( DW_LL_ERROR, "dwlib: read_section(%s): wrong type (%d) of value for %d variable passed", section, pv->vtype, chkline );
                 goto error_exit;
        }                
    }
    /* prepare format string */
    if( snprintf( fmt, sizeof(fmt)-1, "%%%d[a-zA-Z_.]%c", sizeof(com)-1, sep ) < 0 )
    {
        printLib( DW_LL_ERROR, "dwlib: read_section(%s): cannot create format string for parser", section );
        goto error_exit;
    }
    fmt[sizeof(fmt)-1] = NULLCHAR;
    printLib( DW_LL_DEBUG, "dwlib: read_section(%s): format string = <%s>", section, fmt ); 
   
    // for( buf[0] = NULLCHAR, offset = 0 ; fgets( buf, sizeof(buf), fs) != NULL; ++(*line), offset = ftell(fs), buf[0] = NULLCHAR )
    for( buf[0] = NULLCHAR, offset = 0 ; (strncpy( buf, buf_fs , sizeof(buf)) != NULL); ++(*line), buf[0] = NULLCHAR )
    {
        if (( buf_fs - _extern_buf) >= extern_buf_len ) {extern_buf=buf_fs; break;}
        offset+=strlen(buf);
        /* search first non-blank line */
        for( pbuf = buf; *pbuf && isspace((int)*pbuf); ++pbuf );
        /* ignore remark line */
        if( (*pbuf == '#') || (*pbuf == '\n') || (*pbuf == NULLCHAR) ) 
        {
	    buf_fs++;
            continue;
        }
        delete_spaces( pbuf );
        /* search begin of section */
        if( *pbuf == '[' )   
        { 
	    extern_buf=buf_fs; /* storing of the shift for the fake file */
            return 0;            
        }
	buf_fs+=offset;
	offset=0;
        n = sscanf( pbuf, fmt, com );
        if( n < 1 )
        {
            printLib( DW_LL_ERROR, "dwlib: read_section(%s): illegal line %d", section, (*line) );
            goto error_exit;
        }
        com[sizeof(com)-1] = NULLCHAR;
        pstr = strchr( pbuf, sep );
        if( !pstr )
        {
            printLib( DW_LL_ERROR, "dwlib: read_section(%s): no separator (%c) in line %d", section, sep, (*line) );
            goto error_exit;
        }
        ++pstr;
        obs = is_obsolete_option( section, com );
        if( OBSOLETE_STOP == obs )
        {            
            printLib( DW_LL_ERROR, "dwlib: read_section(%s): parameter %s is obsolete - stop parsing, please read documentation", section, com );
            goto error_exit;
        } 
        else if( OBSOLETE_CAN_SKIP == obs )
        {
            printLib( DW_LL_ALERT, "dwlib: read_section(%s): parameter %s is obsolete - continue, but please read documentation", section, com );
        }
        for( matched = FALSE, pv = vars ; pv->vtype != DWC_CV_NONE; ++pv )
        {
             if( DWC_strcasecmp( com, pv->name ) ) 
             {
                 continue;
             }
             /* match */
             switch( pv->vtype )
             {
                case DWC_CV_INT:
                    n = sscanf( pstr, "%d", pv->vptr.pint );
                    break ;
                case DWC_CV_OCTAL:
                    n = sscanf( pstr, "%o", pv->vptr.pcount );
                    break ;
                case DWC_CV_COUNT:
                    n = sscanf( pstr, "%u", &itmp );
                    if( n )
                    {
                        if( itmp < 0 )
                        {
                            n = 0;
                        }
                        else
                        {
                            *pv->vptr.pcount = itmp;
                        }
                    }
                    break ;
                case DWC_CV_BOOL:
                    n = getbool( pstr, pv->vptr.pbool );
                    break ;
                case DWC_CV_STRING:
                    n = getstring( pstr, pv->vptr.pstring, pv->vlen );
                    break ;
                case DWC_CV_STRING_LIST:
                    n = getstringlist( pstr, pv->vptr.pstringlist, list_sep );
                    break ;
                default:
                    printLib( DW_LL_DEBUG, "dwlib: read_section(%s): wrong type (%d) value", section, pv->vtype );
                    break;
            } /* end switch */
            if( n < 1 )
            {
                printLib( DW_LL_ERROR, "dwlib: read_section(%s): illegal value in line %d", section, (*line) );
                goto error_exit;
            }
            matched = TRUE;
            break;
        } /* end for */
        if( !matched )
        {
            printLib( DW_LL_VERBOSE, "dwlib: read_section(%s): unknown variable %s in line %d", section, com, (*line) );
        }
    }  /* end while */
    return 0;
    
  error_exit:
    for( pv = vars ; chkline > 1; --chkline, ++pv )
    {
         if( (pv->vtype == DWC_CV_STRING) && (pv->vlen == 0) && (*pv->vptr.pstring != NULL) )
         {
             DWC_Free( *pv->vptr.pstring );
         }
         else if( (pv->vtype == DWC_CV_STRING) && (*pv->vptr.pstringlist != NULL) )
         {
             dw_multistring_delete( *pv->vptr.pstringlist );
         }
    }
    return -1;    
}
#endif /* __UNIX_DW */
/* -------------------------------------------------- */
int read_section ( FILE* fs, int* line, const char* section, dwc_conf_set_t* vars, char sep, char list_sep )
{    
    int             itmp, n, chkline, obs;
    long            offset;
    char            buf[DWC_LINE_SIZE], com[DWC_NAME_SIZE];
    char            fmt[32];
    dwc_bool_t      matched;
    char           *pstr,*pbuf;
    dwc_conf_set_t *pv = NULL;
    
    if( !isseparator( sep ) )
    {
        printLib( DW_LL_ERROR, "dwlib: read_section(%s): invalid separator (%c) passed", section, sep );
        return -1;
    }
    if( !isseparator( list_sep ) )
    {
        printLib( DW_LL_ERROR, "dwlib: read_section(%s): invalid separator (%c) passed", section, list_sep );
        return -1;
    }
    /* check list of parameters and sets default values */
    for( chkline = 1, pv = vars; pv->vtype != DWC_CV_NONE; ++pv, ++chkline )
    {
        if( !pv->name )
        {
            printLib( DW_LL_ERROR, "dwlib: read_section(%s): null name for %d variable passed", section, chkline );
            goto error_exit;
        }
        if( !pv->vptr.pint )
        {
            printLib( DW_LL_ERROR, "dwlib: read_section(%s): null pointer to value for %d variable passed", section, chkline );
            goto error_exit;
        }
        switch( pv->vtype )
        {
             case DWC_CV_INT    :
                 if( pv->vlen != sizeof(int) )
                 {
                     printLib( DW_LL_ERROR, "dwlib: read_section(%s): wrong len (%d) of storage for %d variable passed", section, pv->vlen, chkline );
                     goto error_exit;
                 }
                 *pv->vptr.pint = pv->vdefault.vint;
                 printLib( DW_LL_DEBUG, "dwlib: read_section(%s): for %s default = %d, value = %d", section, pv->name, pv->vdefault.vint, *pv->vptr.pint );
                 break;
             case DWC_CV_COUNT  :
             case DWC_CV_OCTAL  :
                 if( pv->vlen != sizeof(dwc_count_t) )
                 {
                     printLib( DW_LL_ERROR, "dwlib: read_section(%s): wrong len (%d) of storage for %d variable passed", section, pv->vlen, chkline );
                     goto error_exit;
                 }
                 *pv->vptr.pcount = pv->vdefault.vcount;
                 printLib( DW_LL_DEBUG, "dwlib: read_section(%s): for %s default = %d, value = %d", section, pv->name, pv->vdefault.vcount, *pv->vptr.pcount );
                 break;
             case DWC_CV_BOOL   :                 
                 if( pv->vlen != sizeof(dwc_bool_t) )
                 {
                     printLib( DW_LL_ERROR, "dwlib: read_section(%s): wrong len (%d) of storage for %d variable passed", section, pv->vlen, chkline );
                     goto error_exit;
                 }
                 *pv->vptr.pbool = pv->vdefault.vbool;
                 printLib( DW_LL_DEBUG, "dwlib: read_section(%s): for %s default = %d, value = %d", section, pv->name, pv->vdefault.vbool, *pv->vptr.pbool );
                 break;
             case DWC_CV_STRING :              
                 if( !pv->vdefault.vstring )
                 {
                     printLib( DW_LL_DEBUG, "dwlib: read_section(%s): null default for %d variable passed", section, chkline );
                     *pv->vptr.pstring = NULL;
                 }
                 else if( pv->vlen == 0 )
                 {
                     *pv->vptr.pstring = DWC_Strdup( pv->vdefault.vstring );
                     if( !*pv->vptr.pstring )
                     {
                         printLib( DW_LL_DEBUG, "dwlib: read_section(%s): cannot allocate storage for %d variable passed", section, chkline );
                         goto error_exit;
                     }
                 }
                 else if( pv->vlen >= DWC_strlen( pv->vdefault.vstring ) )
                 {
                     strncpy( *pv->vptr.pstring, pv->vdefault.vstring, DWC_strlen(pv->vdefault.vstring) );
                     (*pv->vptr.pstring)[ pv->vlen - 1 ] = NULLCHAR;
                 }                    
                 else
                 {
                     printLib( DW_LL_ERROR, "dwlib: read_section(%s): storage not enough (%d) for default (%d) for %d variable passed", section, pv->vlen, strlen(pv->vdefault.vstring), chkline );
                     goto error_exit;
                 }
                 if( pv->vdefault.vstring )
                 {
                     printLib( DW_LL_DEBUG, "dwlib: read_section(%s): for %s default = %s, value = %s", section, pv->name, pv->vdefault.vstring, *pv->vptr.pstring );
                 }
                 else
                 {
                     printLib( DW_LL_DEBUG, "dwlib: read_section(%s): for %s default = NULL, value = NULL", section, pv->name );
                 }
                 break;                    
             case DWC_CV_STRING_LIST :              
                 if( !pv->vdefault.vstringlist )
                 {
                     printLib( DW_LL_DEBUG, "dwlib: read_section(%s): null default for %d variable passed", section, chkline );
                     *pv->vptr.pstringlist = NULL;
                 }
                 else
                 {
                     printLib( DW_LL_ERROR, "dwlib: read_section(%s): default value for string list currently not supported", section );
                     goto error_exit;
                 }
                 break;                    
             default :              
                 printLib( DW_LL_ERROR, "dwlib: read_section(%s): wrong type (%d) of value for %d variable passed", section, pv->vtype, chkline );
                 goto error_exit;
        }                
    }
    /* prepare format string */
    if( snprintf( fmt, sizeof(fmt)-1, "%%%d[a-zA-Z_.]%c", sizeof(com)-1, sep ) < 0 )
    {
        printLib( DW_LL_ERROR, "dwlib: read_section(%s): cannot create format string for parser", section );
        goto error_exit;
    }
    fmt[sizeof(fmt)-1] = NULLCHAR;
    printLib( DW_LL_DEBUG, "dwlib: read_section(%s): format string = <%s>", section, fmt ); 
    for( buf[0] = NULLCHAR, offset = 0 ; fgets( buf, sizeof(buf), fs) != NULL; ++(*line), offset = ftell(fs), buf[0] = NULLCHAR )
    {
        /* search first non-blank line */
        for( pbuf = buf; *pbuf && isspace((int)*pbuf); ++pbuf );
        /* ignore remark line */
        if( (*pbuf == '#') || (*pbuf == '\n') || (*pbuf == NULLCHAR) ) 
        {
            continue;
        }
        delete_spaces( pbuf );
        /* search begin of section */
        if( *pbuf == '[' )
        {
            if( offset < 0 )
            {
                printLib( DW_LL_ERROR, "dwlib: read_section(%s): invalid saved offset %d", section, offset );
                goto error_exit;
            }
            if( fseek( fs, offset, SEEK_SET ) < 0 )
            {
                printLib( DW_LL_ERROR, "dwlib: read_section(%s): cannot rewind file stream on %d offset - %s", section, offset, stdlib_error(errno) );
                goto error_exit;
            }      
            return 0;            
        }
        n = sscanf( pbuf, fmt, com );
        if( n < 1 )
        {
            printLib( DW_LL_ERROR, "dwlib: read_section(%s): illegal line %d", section, (*line) );
            goto error_exit;
        }
        com[sizeof(com)-1] = NULLCHAR;
        pstr = strchr( pbuf, sep );
        if( !pstr )
        {
            printLib( DW_LL_ERROR, "dwlib: read_section(%s): no separator (%c) in line %d", section, sep, (*line) );
            goto error_exit;
        }
        ++pstr;
        obs = is_obsolete_option( section, com );
        if( OBSOLETE_STOP == obs )
        {            
            printLib( DW_LL_ERROR, "dwlib: read_section(%s): parameter %s is obsolete - stop parsing, please read documentation", section, com );
            goto error_exit;
        } 
        else if( OBSOLETE_CAN_SKIP == obs )
        {
            printLib( DW_LL_ALERT, "dwlib: read_section(%s): parameter %s is obsolete - continue, but please read documentation", section, com );
        }
        for( matched = FALSE, pv = vars ; pv->vtype != DWC_CV_NONE; ++pv )
        {
             if( DWC_strcasecmp( com, pv->name ) ) 
             {
                 continue;
             }
             /* match */
             switch( pv->vtype )
             {
                case DWC_CV_INT:
                    n = sscanf( pstr, "%d", pv->vptr.pint );
                    break ;
                case DWC_CV_OCTAL:
                    n = sscanf( pstr, "%o", pv->vptr.pcount );
                    break ;
                case DWC_CV_COUNT:
                    n = sscanf( pstr, "%u", &itmp );
                    if( n )
                    {
                        if( itmp < 0 )
                        {
                            n = 0;
                        }
                        else
                        {
                            *pv->vptr.pcount = itmp;
                        }
                    }
                    break ;
                case DWC_CV_BOOL:
                    n = getbool( pstr, pv->vptr.pbool );
                    break ;
                case DWC_CV_STRING:
                    n = getstring( pstr, pv->vptr.pstring, pv->vlen );
                    break ;
                case DWC_CV_STRING_LIST:
                    n = getstringlist( pstr, pv->vptr.pstringlist, list_sep );
                    break ;
                default:
                    printLib( DW_LL_DEBUG, "dwlib: read_section(%s): wrong type (%d) value", section, pv->vtype );
                    break;
            } /* end switch */
            if( n < 1 )
            {
                printLib( DW_LL_ERROR, "dwlib: read_section(%s): illegal value in line %d", section, (*line) );
                goto error_exit;
            }
            matched = TRUE;
            break;
        } /* end for */
        if( !matched )
        {
            printLib( DW_LL_VERBOSE, "dwlib: read_section(%s): unknown variable %s in line %d", section, com, (*line) );
        }
    }  /* end while */
    return 0;
    
  error_exit:
    for( pv = vars ; chkline > 1; --chkline, ++pv )
    {
         if( (pv->vtype == DWC_CV_STRING) && (pv->vlen == 0) && (*pv->vptr.pstring != NULL) )
         {
             DWC_Free( *pv->vptr.pstring );
         }
         else if( (pv->vtype == DWC_CV_STRING) && (*pv->vptr.pstringlist != NULL) )
         {
             dw_multistring_delete( *pv->vptr.pstringlist );
         }
    }
    return -1;    
}
/* ------------------------------------------------- */
#ifdef __UNIX_DW
char * get_head(char * str){
  char * ret;
  int c=0;
  while (*(str+c) != '/') c++;
  ret = (char * )malloc(c);
  *ret='\0';
  strncat(ret,str,c);
  return ret;
}

char * transform_agent_buf(char ** list, int list_len)
{
  int i = 0;
  int list_size = 0;
  char * new_buf;
  char active_head[1000]="";
  char * cur_head;

  for (i=0;i<list_len;i++) list_size += (strlen(list[i])+1);
  new_buf = (char *) malloc(list_size*sizeof(char));
  *new_buf='\0';

  for (i=0;i<list_len;i++){
     cur_head=get_head(list[i]);
    if (strstr(active_head,cur_head)==active_head) {
      strcat(new_buf,list[i]+1+strlen(cur_head));
      strcat(new_buf,"\n\n");
    }
    else {
      strcpy(active_head,cur_head);
      strcat(new_buf,"[");
      strcat(new_buf,active_head);
      strcat(new_buf,"]\n\n");
      strcat(new_buf,list[i]+1+strlen(cur_head));
      strcat(new_buf,"\n\n");
    }
  }
  list_size=strlen(new_buf);
  for (i=0;i<list_size;i++) {
    if (*(new_buf+i)=='\n') {*(new_buf+i)='\0';i++;}
  }
  extern_buf_len = list_size;
  //for (i=0;i<list_size;i++) printf("%c",new_buf[i]);
  return (new_buf ? new_buf : NULL);
}

/* -------------------------------------------------- */
/* Analog of function read_conf() for getting settings from agent */
int read_conf_agent ( const char* address, dwc_conf_task_t* task )
{

  dwc_bool_t       found_section;
  char             buf[DWC_LINE_SIZE];
  char            *pb;
  int              line, obs;
  dwc_conf_task_t *pt;
  int              protoId=kPID_Config; /* kPIDBase_ControlAgent+kPID_Config */
  int              method=kCC_GET_ALL; /* only ALL */
  int              appId=30; /* see smb_spider.amc */
  char             compName[]="smb_spider";
  int              pid=getpid();
  dwc_ipc_t        s;
  unsigned int     code;
  unsigned         num;
  char **          list;
  char *           prm,*val;
  unsigned int     prm_len,val_len;
  int              i=0;
  int              offset=0;

  init_ipc_subsystem();
  if( !address )
    {
      printLib( DW_LL_ERROR, "dwlib: read_conf_agent: null address passed" );
      return -1;
    }
  if( !task )
    {
      printLib( DW_LL_ERROR, "dwlib: read_conf_agent(%s): null task list passed", address );
      return -1;
    }

  s = dwc_ipc_create_client( address, 10, TRUE );
  if (!s)
    {
      printLib( DW_LL_ERROR, "dwlib: read_conf_agent: cannot create dwc_ipc_t" );
      return -1;
    }

  if ( !dw_proto_write_int(s, protoId ) 
       || !dw_proto_write_int(s, method )
       || !dw_proto_write_int(s, appId )
       || !dw_proto_write_bytestring(s, strlen(compName), compName )
       || !dw_proto_write_int(s, pid )) {
    printLib( DW_LL_ERROR, "dwlib: read_conf_agent: cannot send query" );
    return -1;
  }
  
  dw_proto_read_int(s,&code);
  if ( code != kCC_RESPONSE ) {
    printLib( DW_LL_ERROR, "dwlib: read_conf_agent: invalid response type" );
    return -1;
  }

  dw_proto_read_int(s,&code);
  if ( code != kCE_OK ) {
    printLib( DW_LL_ERROR, "dwlib: read_conf_agent: invalid response code" );
    return -1;
  }
  
  if ( !dw_proto_read_int(s, &num) ){
    printLib( DW_LL_ERROR, "dwlib: read_conf_agent: ERROR_RESPONSE" );
    return -1;
  }
  list = (char**) malloc(num*sizeof(char**));
  for (  i = 0; i < num; i++ ) {
     if (dw_proto_read_bytestring(s, &prm_len, &prm,TRUE )
	&& dw_proto_read_bytestring(s, &val_len, &val,TRUE )) {
      list[i]=(char*)malloc(sizeof(char*)*(prm_len+val_len+3));
      *list[i]='\0';
      strcat(list[i],prm);
      strcat(list[i]," = ");
      strcat(list[i],val);
    }
    else {
      printLib( DW_LL_ERROR, "dwlib: read_conf_agent: ERROR_RESPONSE" );
      return -1;
    }
  }

  delete_ipc(&s);
  /*!  necessary tranform config from afent-format to standart by function transform_agent_buf.
   *   _extern_buf for storage, extern_buf - for change.
   *   further the index on the buffer as the index on a file is used.
   *   but for work with address to the buffer it is necessary to use functions with a suffix _agent.
   *   While all is realized that is necessary only for the smb_spider
   *   parsers of sections for other projects it is necessary to make on similarity parsers for smb_spider.
   */

  extern_buf = transform_agent_buf(list,num);

  _extern_buf = extern_buf;
  for( line = 1, buf[0] = NULLCHAR ; (strncpy( buf, extern_buf, sizeof(buf)) != NULL); ++line, buf[0] = NULLCHAR )
    {

      //printLib(DW_LL_ERROR,"%s",extern_buf);
      if (( extern_buf - _extern_buf) >= extern_buf_len ) { break;}
      offset+=strlen(buf);
      /* search first non-blank line */
      for( pb = buf; (*pb != NULLCHAR) && isspace((int)*pb); ++pb );
      /* ignore remark line */
      if( (*pb == '#') || (*pb == '\n') || (*pb == NULLCHAR) ) 
        {
          extern_buf++; 
	  continue;
        }

      delete_spaces( pb );
      /* search begin of section */
      if( *pb == '[' )
        {            
	  obs = is_obsolete_section( &pb[1] );
	  if( OBSOLETE_STOP == obs )
            {
	      printLib( DW_LL_ERROR, "dwlib: read_conf(%s): section %s is obsolete - stop parsing, please read documentation", address, pb );
	      goto error_exit;
            }
	  else if( OBSOLETE_CAN_SKIP == obs )
            {
	      printLib( DW_LL_ALERT, "dwlib: read_conf(%s): section %s is obsolete - continue, but please read documentation", address, pb );
            }
	  /* search begin of target section */
	  for( found_section = FALSE, pt = task; pt->name; ++pt )
            {
	      if( 0 == DWC_strncasecmp( &pb[1], pt->name, strlen(pt->name) ) )
                {
		  found_section = TRUE;
		  ++line;

		  if( !pt->read_proc( (FILE*)(char *)(extern_buf+offset), &line, pt->name, pt->data ) )
                    {
		      printLib( DW_LL_INFO, "dwlib: read_conf(%s): error in section [%s]", address, pt->name );
		      goto error_exit;
                    }

		  offset=0;
		  --line;
		  pt->need_clean = TRUE;                    
		  break;
                }
            }
	  if( !found_section )
            {
	      printLib( DW_LL_INFO, "dwlib: read_conf_agent(%s): unknown section %s", address, pb );
            }
        }
    }  /*end while*/
  printLib( DW_LL_INFO, "dwlib: read_conf_agent(%s): successfully loaded", address );
  return 0;
        
 error_exit:

  free_conf( task );
  return -1;
}
#endif /* __UNIX_DW */
/* -------------------------------------------------- */
int read_conf ( const char* filename, dwc_conf_task_t* task )
{
    FILE            *fp = NULL;
    dwc_bool_t       found_section;
    char             buf[DWC_LINE_SIZE];
    char            *pb;
    int              line, obs;
    dwc_conf_task_t *pt;
    struct stat      st;
        
    if( !filename )
    {
        printLib( DW_LL_ERROR, "dwlib: read_conf: null filename passed" );
        return -1;
    }
    if( !task )
    {
        printLib( DW_LL_ERROR, "dwlib: read_conf(%s): null task list passed", filename );
        return -1;
    }
    if( stat( filename, &st ) < 0 )
    {
        printLib( DW_LL_ERROR, "dwlib: read_conf(%s): %s", filename, stdlib_error(errno) );
        return -1;
    }
    if( st.st_mode & S_IFDIR )
    {
        printLib( DW_LL_ERROR, "dwlib: read_conf(%s): full pathname should be specified, not directory only", filename );
        return -1;
    }
    /* get parameters from config file */
#if defined( __UNIX_DW) && !defined(EMX_DW)
    fp = fopen( filename, "r" );    
#else /* not Unix or EMX */
    fp = fopen( filename, "rb" );    
#endif /* EMX */
    if( fp == NULL )
    {
        printLib( DW_LL_ERROR, "dwlib: read_conf(%s): cannot open - %s", filename, stdlib_error(errno) );
        goto error_exit;
    }    
    for( line = 1, buf[0] = NULLCHAR ; fgets( buf, sizeof(buf), fp) != NULL; ++line, buf[0] = NULLCHAR )
    {
        /* search first non-blank line */
        for( pb = buf; (*pb != NULLCHAR) && isspace((int)*pb); ++pb );
        /* ignore remark line */
        if( (*pb == '#') || (*pb == '\n') || (*pb == NULLCHAR) ) 
        {
            continue;
        }
        delete_spaces( pb );
        /* search begin of section */
        if( *pb == '[' )
        {            
            obs = is_obsolete_section( &pb[1] );
            if( OBSOLETE_STOP == obs )
            {
                printLib( DW_LL_ERROR, "dwlib: read_conf(%s): section %s is obsolete - stop parsing, please read documentation", filename, pb );
                goto error_exit;
            }
            else if( OBSOLETE_CAN_SKIP == obs )
            {
                printLib( DW_LL_ALERT, "dwlib: read_conf(%s): section %s is obsolete - continue, but please read documentation", filename, pb );
            }
            /* search begin of target section */
            for( found_section = FALSE, pt = task; pt->name; ++pt )
            {
                if( 0 == DWC_strncasecmp( &pb[1], pt->name, strlen(pt->name) ) )
                {
                    found_section = TRUE;
                    ++line;
                    if( !pt->read_proc( fp, &line, pt->name, pt->data ) )
                    {
                        printLib( DW_LL_INFO, "dwlib: read_conf(%s): error in section [%s]", filename, pt->name );
                        goto error_exit;
                    }
                    --line;
                    pt->need_clean = TRUE;                    
                    break;
                }
            }
            if( !found_section )
            {
                printLib( DW_LL_INFO, "dwlib: read_conf(%s): unknown section %s", filename, pb );
            }
        }
    }  /*end while*/
    if( !feof(fp) || ferror(fp) )
    {
        printLib( DW_LL_ERROR, "dwlib: read_conf(%s): error at reading file - %s", filename, stdlib_error(errno) );
        goto error_exit;        
    }
    if( fclose( fp ) != 0 )
    {
        printLib( DW_LL_ERROR, "dwlib: read_conf(%s): cannot close file - %s", filename, stdlib_error(errno) );
        fp = NULL;
        goto error_exit;
    }
    fp = NULL;
    for( pt = task; pt->name; ++pt )
    {
        if( !pt->need_clean && !pt->can_missed )
        {
            printLib( DW_LL_ERROR, "dwlib: read_conf(%s): section [%s] missed", filename, pt->name );
            goto error_exit;
        }
    }
    printLib( DW_LL_INFO, "dwlib: read_conf(%s): successfully loaded", filename );
    return 0;
        
  error_exit:
    if( fp )
    {
        if( fclose( fp ) != 0 )
        {
            printLib( DW_LL_ERROR, "dwlib: read_conf(%s): cannot close file - %s", filename, stdlib_error(errno) );
        }
    }
    free_conf( task );
    return -1;
}

/* -------------------------------------------------- */
int free_conf ( dwc_conf_task_t* task )
{
    dwc_conf_task_t *pt;
    
    /* clean already readed sections */
    for( pt = task; pt->name; ++pt )
    {
        if( pt->need_clean )
        {
            pt->clean_proc( pt->name, pt->data );
            pt->need_clean = 0;
        }
    }
    return 0;
}

#endif /* _DWC_CONF_C */
