static char rcsid[] = "@(#)$Id: rc_handle.c,v 1.40 2006/06/21 18:30:32 hurtta Exp $";

/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.40 $   $State: Exp $
 *
 *  Author: Kari Hurtta <hurtta+elm@posti.FMI.FI> (was hurtta+elm@ozone.FMI.FI)
 ****************************************************************************
 *
 * Some of code comes from ../src/read_rc.c and ../src/save_opts.c. These
 * are following copyright:
 *
 *			Copyright (c) 1988-1992 USENET Community Trust
 *			Copyright (c) 1986,1987 Dave Taylor
 *****************************************************************************/

#include "headers.h"
#include "rc_imp.h"
#include "save_opts.h"
#ifdef USE_DLOPEN
#include "shared_imp.h"
#endif
#include "s_elm.h"

DEBUG_VAR(Debug,__FILE__,"config");

#ifdef ANSI_C
static rc_parse_line dt_SYN_parse_line;
#endif
static int dt_SYN_parse_line(r,lcl,value,lineno,filename, negate)
     struct rc_save_info_rec *r;
     int lcl;
     char *value; 
     int lineno; 
     char *filename;
     int negate;
{     
    if (negate) {
	char buffer[SLEN];
	buffer[0] = '!';
	strfcpy(buffer+1, r->val.str, sizeof buffer -1);
	
	if ( do_set(lcl,buffer,value,filename))
            return 1;

    } else { 
	if ( do_set(lcl, r->val.str, value, filename))
	    return 1;
    }

    return 0;
}

#ifdef ANSI_C
static rc_parse_cline BAD_parse_cline;
#endif
static int BAD_parse_cline(r,lcl,value,lineno,filename)
     struct rc_save_info_rec *r;
     int lcl;
     char *value; 
     int lineno; 
     char *filename;
{     
    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadContinuationInElmrc,
		      "Key \"%s\" does not accept continuation lines in line %d in \"%s\" file"),
	      r->name,lineno,filename);
    return 0;    
}

#if ANSI_C
static rc_print_value NO_print_value;
#endif
static void NO_print_value(F,r,comment)
     FILE *F;
     struct rc_save_info_rec *r;
     int comment;
{
    /* Empty */
}

#if ANSI_C
static rc_get_value NO_get_value;
#endif
static char * NO_get_value(r)
     struct rc_save_info_rec *r;
{
    return "*bad*";
}

struct rc_type rc_DT_SYN = { RCTYPE_magic,
			     dt_SYN_parse_line, BAD_parse_cline,
			     NO_print_value, NO_get_value };

#ifdef ANSI_C
static rc_parse_line dt_STR_parse_line;
#endif
static int dt_STR_parse_line(r,lcl,value,lineno,filename,  negate)
     struct rc_save_info_rec *r;
     int lcl;
     char *value; 
     int lineno; 
     char *filename;
     int negate;
{     
    if (negate) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadNegate,
			  "!%s is not supported in line %d in \"%s\" file"),
		  r->name,lineno,filename);
	return 0;
    }

    if (strlen(value) >= r->size_val) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLongValueInElmrc,
			  "Value of \"%s\" in line %d in \"%s\" file is too long"),
		  r->name,lineno,filename);
	return 0;
    }
	
    strfcpy(r->val.str, value, r->size_val);

    if (r->flags & FL_NOSPC) {
	char *s;
	for (s = r->val.str; *s; ++s)
	    if (*s == '_') *s=' ';
    }
    return 1;
}

/* Returns pointer to static area */
#if ANSI_C
static rc_get_value dt_STR_get_value;
#endif
static char * dt_STR_get_value(r)
     struct rc_save_info_rec *r;
{    
    if (r->flags & FL_NOSPC) {

	static char buffer[SLEN];

	char *t, *s;
	for (t = r->val.str, s = buffer; 
	     *t && s - buffer < sizeof buffer -1; 
	     ++t, ++s)
	    if ((*s = *t) == ' ') 
		*s='_';
	*s = '\0';

	return buffer;
    } else
	return r->val.str;
}


#if ANSI_C
static rc_print_value dt_STR_print_value;
#endif
static void dt_STR_print_value(F,r,comment)
     FILE *F;
     struct rc_save_info_rec *r;
     int comment;
{
    char * s = dt_STR_get_value(r);
    
    if (comment)
	fprintf(F, "### ");
    fprintf(F, "%s = %s\n", r->name, s);
    
    DPRINT(Debug,9,(&Debug, 
		    " option \"%s\", value=\"%s\"\n",
		    r->name,s ));
}


struct rc_type rc_DT_STR = { RCTYPE_magic,
			     dt_STR_parse_line, BAD_parse_cline,
			     dt_STR_print_value, dt_STR_get_value };

#ifdef ANSI_C
static rc_parse_line dt_NUM_parse_line;
#endif
static int dt_NUM_parse_line(r,lcl,value,lineno,filename, negate)
     struct rc_save_info_rec *r;
     int lcl;
     char *value; 
     int lineno; 
     char *filename;
     int negate;
{     
    char *p;
    long l = strtol(value,&p,10);

    if (negate) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadNegate,
			  "!%s is not supported in line %d in \"%s\" file"),
		  r->name,lineno,filename);
	return 0;
    }

    *(r->val.num) = l;

    return 1;
}

#if ANSI_C
static rc_print_value dt_NUM_print_value;
#endif
static void dt_NUM_print_value(F,r,comment)
     FILE *F;
     struct rc_save_info_rec *r;
     int comment;
{
    if (comment)
	fprintf(F, "### ");

    fprintf(F, "%s = %d\n", r->name, 
	    *r->val.num);
    
    DPRINT(Debug,9,(&Debug, 
		    " option \"%s\", value=%d\n",
		    r->name,*r->val.num ));
}

/* Returns static pointer */
#if ANSI_C
static rc_get_value dt_NUM_get_value;
#endif
static char * dt_NUM_get_value(r)
     struct rc_save_info_rec *r;
{
    static char * buffer = NULL;
    
    if (buffer)
	free(buffer);

    buffer = elm_message(FRM("%d"), *r->val.num);

    return buffer;
}


struct rc_type rc_DT_NUM = { RCTYPE_magic,
			     dt_NUM_parse_line, BAD_parse_cline,
			     dt_NUM_print_value, dt_NUM_get_value };

#ifdef ANSI_C
static rc_parse_line dt_BOL_parse_line;
#endif
static int dt_BOL_parse_line(r,lcl,value,lineno,filename, negate)
     struct rc_save_info_rec *r;
     int lcl;
     char *value; 
     int lineno; 
     char *filename;
     int negate;
{     
    if (negate) {
	if (r->flags & FL_OR)
	    *(r->val.bol) |= !is_it_on(value);
	else if (r->flags & FL_AND)
	    *(r->val.bol) &= !is_it_on(value);
	else
	    *(r->val.bol) = !is_it_on(value);    
    } else {
	if (r->flags & FL_OR)
	    *(r->val.bol) |= is_it_on(value);
	else if (r->flags & FL_AND)
	    *(r->val.bol) &= is_it_on(value);
	else
	    *(r->val.bol) = is_it_on(value);    
    }
    return 1;
}

#if ANSI_C
static rc_print_value dt_BOL_print_value;
#endif
static void dt_BOL_print_value(F,r,comment)
     FILE *F;
     struct rc_save_info_rec *r;
     int comment;
{
    char * s;
    if (comment)
	fprintf(F, "### ");

    s = *r->val.bol ? "ON" : "OFF";

    fprintf(F, "%s = %s\n", r->name, s);
    
    DPRINT(Debug,9,(&Debug, 
		    " option \"%s\", value=%s\n",
		    r->name,s ));
}

#if ANSI_C
static rc_get_value dt_BOL_get_value;
#endif
static char * dt_BOL_get_value(r)
     struct rc_save_info_rec *r;
{
    return *r->val.bol ? "ON" : "OFF";
}

struct rc_type rc_DT_BOL = { RCTYPE_magic,
			     dt_BOL_parse_line, BAD_parse_cline,
			     dt_BOL_print_value, dt_BOL_get_value };

#ifdef ANSI_C
static rc_parse_line dt_CHR_parse_line;
#endif
static int dt_CHR_parse_line(r,lcl,value,lineno,filename, negate)
     struct rc_save_info_rec *r;
     int lcl;
     char *value; 
     int lineno; 
     char *filename;
     int negate;
{     
    if (negate) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadNegate,
			  "!%s is not supported in line %d in \"%s\" file"),
		  r->name,lineno,filename);
	return 0;
    }

    *(r->val.chr) = value[0];
    return 1;
}

#if ANSI_C
static rc_print_value dt_CHR_print_value;
#endif
static void dt_CHR_print_value(F,r,comment)
     FILE *F;
     struct rc_save_info_rec *r;
     int comment;
{
    if (comment)
	fprintf(F, "### ");

    fprintf(F, "%s = %c\n", r->name, *r->val.chr);

    DPRINT(Debug,9,(&Debug, 		    
		    " option \"%s\", value=%c\n",
		    r->name, *r->val.chr));
}

#if ANSI_C
static rc_get_value dt_CHR_get_value;
#endif
static char * dt_CHR_get_value(r)
     struct rc_save_info_rec *r;
{
    static char buffer[2];

    buffer[0] = *r->val.chr;
    buffer[1] = '\0';

    return buffer;
}

struct rc_type rc_DT_CHR = { RCTYPE_magic,
			     dt_CHR_parse_line, BAD_parse_cline,
			     dt_CHR_print_value, dt_CHR_get_value };

#ifdef ANSI_C
static rc_parse_line dt_SORT_parse_line;
#endif
static int dt_SORT_parse_line(r,lcl,value,lineno,filename, negate)
     struct rc_save_info_rec *r;
     int lcl;
     char *value; 
     int lineno; 
     char *filename;
     int negate;
{     
    char buffer[SLEN];
    char *s = buffer;
    int f,y;
    
    f = 1;
    strfcpy(buffer, shift_lower(value), sizeof buffer);

    if (strncmp(s, "rev-", 4) == 0 ||
	strncmp(s, "reverse-", 8) == 0) {
	f = -f;
	s = index(s, '-') + 1;
    }
    
    if (negate)
	f = -f;

    for (y= 0; r->val.sort->sortval[y].kw; y++) {
	if (equal(s, r->val.sort->sortval[y].kw))
	    break;
    }
    if (r->val.sort->sortval[y].kw) {
	r->val.sort->val = f > 0 ? 
	    r->val.sort->sortval[y].sv : 
	    - r->val.sort->sortval[y].sv;
    } else {
	lib_error(CATGETS(elm_msg_cat, ElmSet, 
			  ElmBadSortKeyInElmrc,
			  "I can't understand sort key \"%s\" in line %d in \"%s\" file"),
		  value, lineno, filename);
	return 0;
    }
    return 1;
}

static char * give_sort_value P_((struct dt_sort_info *ptr));
static char * give_sort_value(ptr)
     struct dt_sort_info *ptr;
{
    int y;

    for (y= 0; ptr->sortval[y].kw; y++) {
	if (ptr->sortval[y].sv == ptr->val) 
	    return ptr->sortval[y].kw;
	else if (ptr->sortval[y].sv == - ptr->val) {

	    static char * buffer = NULL;
	    
	    buffer = strmcpy(buffer,"reverse-");
	    buffer = strmcat(buffer, ptr->sortval[y].kw);

	    return buffer;
	}
    }
    return "*bad*";

}

#if ANSI_C
static rc_get_value dt_SORT_get_value;
#endif
static char * dt_SORT_get_value(r)
     struct rc_save_info_rec *r;
{
    return give_sort_value(r->val.sort);
}

CONST char * give_dt_sort_as_str(ptr)
     struct dt_sort_info *ptr;
{
    return give_sort_value(ptr);
}

int give_dt_sort_as_int(ptr)
     struct dt_sort_info *ptr;
{
    return ptr->val;
}

void set_dt_sort_as_int(ptr,val)
     struct dt_sort_info *ptr; 
     int val;
{
    ptr->val = val;
}

#if ANSI_C
static rc_print_value dt_SORT_print_value;
#endif
static void dt_SORT_print_value(F,r,comment)
     FILE *F;
     struct rc_save_info_rec *r;
     int comment;
{
    if (comment)
	fprintf(F, "### ");

    fprintf(F, "%s = %s\n", r->name, 
	    dt_SORT_get_value(r));
}

struct rc_type rc_DT_SORT = { RCTYPE_magic,
			      dt_SORT_parse_line, BAD_parse_cline,
			      dt_SORT_print_value, dt_SORT_get_value };

#ifdef ANSI_C
static rc_parse_line dt_MLT_parse_line;
#endif
static int dt_MLT_parse_line(r,lcl,value,lineno,filename, negate)
     struct rc_save_info_rec *r;
     int lcl;
     char *value; 
     int lineno; 
     char *filename;
     int negate;
{     
    int ok = 1;
    char **s;
    
    if (negate) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadNegate,
			  "!%s is not supported in line %d in \"%s\" file"),
		  r->name,lineno,filename);
	return 0;
    }
    
    for (s = r->val.mlt; *s; ++s) {
	if (!do_set(lcl, *s, value, filename))
	    ok = 0;
    }

    return ok;
}

struct rc_type rc_DT_MLT = { RCTYPE_magic,
			     dt_MLT_parse_line, BAD_parse_cline,
			     NO_print_value, NO_get_value };

#ifdef ANSI_C
static rc_parse_line dt_PRM_parse_line;
#endif
static int dt_PRM_parse_line(r,lcl,value,lineno,filename, negate)
     struct rc_save_info_rec *r;
     int lcl;
     char *value; 
     int lineno; 
     char *filename;
     int negate;
{     
    char *s = value;
    int m = 0;
    char *modecharp = "rwxrwxrwx";
    int modebit = 0400;
    char c;

    if (negate) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadNegate,
			  "!%s is not supported in line %d in \"%s\" file"),
		  r->name,lineno,filename);
	return 0;
    }

    while ((c = *s++) != '\0') {
	if (c == *modecharp)
	    m |= modebit;
	else if (c != '-') {

	    lib_error(CATGETS(elm_msg_cat, ElmSet, 
			      ElmBadModeInElmrc,
			      "I can't understand file permissions \"%s\" in line %d in \"%s\" file"),
		      value, lineno,filename);
	    return 0;
	}
	modecharp++;
	modebit >>= 1;
    }
    if (*modecharp != '\0') {	
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadModeInElmrc,
			  "I can't understand file permissions \"%s\" in line %d in \"%s\" file"),
		  value, lineno,filename);
	return 0;
    }
    *(r->val.num) = m;

    return 1;
}

#if ANSI_C
static rc_print_value dt_PRM_print_value;
#endif
static void dt_PRM_print_value(F,r,comment)
     FILE *F;
     struct rc_save_info_rec *r;
     int comment;
{
    char *s = mode_to_str(*(r->val.num));

    if (comment)
	fprintf(F, "### ");
    
    fprintf(F, "%s = %s\n", r->name, s);
}

#if ANSI_C
static rc_get_value dt_PRM_get_value;
#endif
static char * dt_PRM_get_value(r)
     struct rc_save_info_rec *r;
{
    return mode_to_str(*(r->val.num));
}

struct rc_type rc_DT_PRM = { RCTYPE_magic,
			     dt_PRM_parse_line, BAD_parse_cline,
			     dt_PRM_print_value, dt_PRM_get_value };

#ifdef ANSI_C
static rc_parse_line dt_FUNC_parse_line;
#endif
static int dt_FUNC_parse_line(r,lcl,value,lineno,filename, negate)
     struct rc_save_info_rec *r;
     int lcl;
     char *value; 
     int lineno; 
     char *filename;
     int negate;
{     
    if (negate) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadNegate,
			  "!%s is not supported in line %d in \"%s\" file"),
		  r->name,lineno,filename);
	return 0;
    }

    if (!r->func_val(&value,1,lineno,filename)) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadValueInElmrc,
			  "Value of \"%s\" in line %d in \"%s\" file is bad"),
		  r->name,lineno,filename);
	return 0;
    }
    
    return 1;
}

#if ANSI_C
static rc_print_value dt_FUNC_print_value;
#endif
static void dt_FUNC_print_value(F,r,comment)
     FILE *F;
     struct rc_save_info_rec *r;
     int comment;
{
    char *s = NULL;

    r->func_val(&s,0,0,NULL);
    if (s) {
	if (comment)
	    fprintf(F, "### ");
	
	fprintf(F, "%s = %s\n", r->name, s);
    }
}

#if ANSI_C
static rc_get_value dt_FUNC_get_value;
#endif
static char * dt_FUNC_get_value(r)
     struct rc_save_info_rec *r;
{
    char *s = NULL;

    r->func_val(&s,0,0,NULL);

    return s;
}


struct rc_type rc_DT_FUNC = { RCTYPE_magic,
			      dt_FUNC_parse_line, BAD_parse_cline,
			      dt_FUNC_print_value, dt_FUNC_get_value };

#ifdef ANSI_C
static rc_parse_line dt_LONG_parse_line;
#endif
static int dt_LONG_parse_line(r,lcl,value,lineno,filename, negate)
     struct rc_save_info_rec *r;
     int lcl;
     char *value; 
     int lineno; 
     char *filename;
     int negate;
{   
    char *p;
    long l;
    
    if (negate) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadNegate,
			  "!%s is not supported in line %d in \"%s\" file"),
		  r->name,lineno,filename);
	return 0;
    }
    
    l = strtol(value,&p,10);
    *(r->val.l_num) = l;

    return 1;
}

#if ANSI_C
static rc_print_value dt_LONG_print_value;
#endif
static void dt_LONG_print_value(F,r,comment)
     FILE *F;
     struct rc_save_info_rec *r;
     int comment;
{
    if (comment)
	fprintf(F, "### ");
    
    fprintf(F, "%s = %ld\n", r->name, *r->val.l_num);
}

#if ANSI_C
static rc_get_value dt_LONG_get_value;
#endif
static char * dt_LONG_get_value(r)
     struct rc_save_info_rec *r;
{
    static char * buffer = NULL;
    
    if (buffer)
	free(buffer);
    buffer = elm_message(FRM("%ld"), *r->val.l_num);

    return buffer;
}


struct rc_type rc_DT_LONG = { RCTYPE_magic,
			      dt_LONG_parse_line, BAD_parse_cline,
			      dt_LONG_print_value, dt_LONG_get_value };


/* Appends expanded value to list 
   0 == failure
   1 == succeed
*/
int expand_dt_path(ptr,fieldname,val, recursive)
     struct dt_path_info *ptr; 
     char *fieldname; 
     char *val;
     int recursive;   /* 0 if not recursive call */
{
    int ret = 1;
    
    int  is_file         = ptr->flags & PATH_file;
    int  is_dir          = ptr->flags & PATH_dir;
    int  is_quote        = (ptr->flags & PATH_quote)  && 0 == recursive;
    int  is_expand       = (ptr->flags & PATH_expand) && 0 == recursive;
    int  is_sep_comma    = ptr->flags & PATH_sep_comma;
    int  is_sep_colon    = ptr->flags & PATH_sep_colon;
    int  is_sep_space    =                             0 == recursive;
    int  is_quote_single = (ptr->flags & PATH_quote_single) && 0 == recursive;
    int  convert_underline = (ptr->flags & PATH_convert_underline) 
	&& 0 == recursive;

    char *p;
    char * start_val =  NULL;
    int  q = 0;
    int quit_flag = 0;

    if (!recursive) {
	DPRINT(Debug,8,(&Debug, "expand_dt_path: %s: %s\n",
			fieldname,val));

	if (0 == strcmp(val,"none") && 0 == ptr->nlen) {

	    /* Set dummy value indicating none ... */
	    ptr->list    = safe_realloc(ptr->list,sizeof (ptr->list[0]));
	    ptr->list[0] = NULL;
	    ptr->nlen    = 0;

	    return ret;
	}


    } else {
	DPRINT(Debug,11,(&Debug, "expand_dt_path: %s: %s (recursive=%d)\n",
			 fieldname,val,recursive));
    }

    for (p = val; !quit_flag && (*p || start_val); p++) {
	char * value = NULL;

	/* Quarantee that we do not advance bast of \0 */
	quit_flag = !*p;

	/* Recognize \ escape only in quoted strings */
	if (q && '\\' == *p) {
	    p++;
	    if (!*p) {
		lib_error(CATGETS(elm_msg_cat, ElmSet, 
				  ElmTrailingBackslashInElmrc,		   
				  "Trailing backslash (\\) on key \"%s\" value \"%s\""),			  
			  fieldname,val);
		ret = 0;
	    }
	    continue;
	}

	if (!start_val) {
	    if (q || !*p) {
		panic("RC PANIC",__FILE__,__LINE__,"expand_dt_path",
		      "Bad state on !start_val",0);
	    }

	    if (is_quote && '"' == *p) {
		start_val = p+1;
		q         = '"';
		continue;
	    }

	    if (is_quote_single && '\'' == *p) {
		start_val = p+1;
		q         = '\'';
		continue;
	    }

	    /* Empty values not allowed */
	    if (is_sep_comma && ',' == *p  ||	       
	   	is_sep_colon && ':' == *p  ||	      
		is_sep_space && ' ' == *p ||	       
		is_sep_space && '\t' == *p)
		continue;

	    start_val = p;


	} else if (q) {

	    if (q == *p || '\0' == *p) {
		int Len = p - start_val;
		char * t, *s;

		if (!*p) {
		    lib_error(CATGETS(elm_msg_cat, ElmSet, 
				      ElmUnbalancedQuoteInElmrc,
				      "Unbalanced quote (%c) on key \"%s\" value \"%s\""),
			      q,fieldname,val);
		    ret = 0;
		}

		DPRINT(Debug,11,(&Debug, 
				 "expand_dt_path (clip len=%d)=%.*s\n",
				 Len,Len,start_val));

		value = safe_malloc( Len +1 );
		
		for (s = start_val, t = value;
		     t-value < Len && s < p;) {
		    if ('\\' == *s)
			s++;
		    *t++ = *s++;
		}
		*t = '\0';
		q  = 0;

		DPRINT(Debug,11,(&Debug, 
				 "expand_dt_path    (unquoted)=%s\n",
				 value));

		start_val = NULL;	    
		goto expand_value;
	    }

	} else {

	    if (is_sep_comma && ',' == *p ||
		is_sep_colon && ':' == *p ||
		is_sep_space && ' ' == *p ||
		is_sep_space && '\t'  == *p || 
		'\0'  == *p ) {

		int Len = p - start_val;
		
		DPRINT(Debug,11,(&Debug, 
				 "expand_dt_path (clip len=%d)=%.*s\n",
				 Len,Len,start_val));

		value = safe_malloc( Len +1 );

		memcpy(value,start_val,Len);
		value[Len] = '\0';

		if (convert_underline) {
		    int i;

		    for (i = 0; i < Len; i++)
			if ('_' == value[i])
			    value[i] = ' ';
		}

		start_val = NULL;	    
		goto expand_value;
	    }
	    
	    if (is_quote && '"' == *p) {

		int Len = p - start_val;

		/* Split on quote */
		q = '"';

		DPRINT(Debug,11,(&Debug, 
				 "expand_dt_path (clip len=%d)=%.*s\n",
				 Len,Len,start_val));

		value = safe_malloc( Len +1 );

		memcpy(value,start_val,Len);
		value[Len] = '\0';

		start_val = NULL;	    
		goto expand_value;
	    }

	    if (is_quote_single && '\'' == *p) {

		int Len = p - start_val;

		/* Split on quote */
		q = '\'';
		
		DPRINT(Debug,11,(&Debug, 
				 "expand_dt_path (clip len=%d)=%.*s\n",
				 Len,Len,start_val));

		value = safe_malloc( Len +1 );

		memcpy(value,start_val,Len);
		value[Len] = '\0';

		start_val = NULL;	    
		goto expand_value;
	    }

	}

	
	if (0) {
	expand_value:
	    if (is_expand) {
		char buffer[1024];

		int v = expand_path(buffer,value,sizeof buffer);

		if (v < 0) {		
		    lib_error(CATGETS(elm_msg_cat, ElmSet, 
				      ElmBadVariableInElmrc,
				      "Bad variable on key \"%s\" value \"%s\""),
			      fieldname,val);
		    ret = 0;
		} else if (v > 0) { 

		    DPRINT(Debug,11,(&Debug, 
				     "expand_dt_path    (expanded)=%s\n",
				     buffer));

		    if (recursive < 2 &&
			(is_sep_colon || is_sep_comma)) {
			
			if (!expand_dt_path(ptr,fieldname,buffer,recursive+1))
			    ret = 0;

			free(value); value = NULL; 
			continue;
		    }

		    value = strmcpy(value,buffer);
		}
	    }
	     
	    if (is_file || is_dir) {
		struct stat S;
		if ('/' !=  value[0]) {		    
		    if (0 == recursive) {

			DPRINT(Debug,9,(&Debug, 
					"expand_dt_path  not absolute=%s\n",
					value));
	    
			lib_error(CATGETS(elm_msg_cat, ElmSet, 
					  ElmNotAbsoluteInElmrc,	  
					  "Path component \"%s\" not absolute on key \"%s\" value \"%s\""),
				  value,fieldname,val);
			ret = 0;
		    }
		    free(value); value = NULL;
		    continue;
		} 

		if (-1 == stat(value,&S)) {

		    DPRINT(Debug,9,(&Debug, 
				    "expand_dt_path  not accessib=%s\n",
				    value));

		    if (0 == recursive) {
			lib_error(CATGETS(elm_msg_cat, ElmSet, 
					  ElmNotAccessibleInElmrc,	  
					  "Path component \"%s\" not accessible on key \"%s\" value \"%s\""),
				  value,fieldname,val);
			ret = 0;
		    }
		    free(value); value = NULL;
		    continue;
		} 
		
		if (is_dir &&
#ifdef S_ISDIR
		    !S_ISDIR(S.st_mode)
#else
		    S_IFDIR != (S.st_mode & S_IFMT)
#endif
		    ) {

		    DPRINT(Debug,9,(&Debug, 
				    "expand_dt_path  not director=%s\n",
				    value));

		    if (0 == recursive) {
			lib_error(CATGETS(elm_msg_cat, ElmSet, 
					  ElmNotDirInElmrc,	  
					  "Path component \"%s\" not a directory on key \"%s\" value \"%s\""),
				  value,fieldname,val);
			ret = 0;
		    }
		    free(value); value = NULL;
		    continue;
		    
		}

		if (is_file &&
#ifdef S_ISREG
		    !S_ISREG(S.st_mode)
#else
		    S_IFREG != (S.st_mode & S_IFMT)
#endif
		    ) {

		    DPRINT(Debug,9,(&Debug, 
				    "expand_dt_path  not a file  =%s\n",
				    value));

		    if (0 == recursive) {
			lib_error(CATGETS(elm_msg_cat, ElmSet, 
					  ElmNotFileInElmrc,	  
					  "Path component \"%s\" not a file on key \"%s\" value \"%s\""),
				  value,fieldname,val);
			ret = 0;
		    }
		    free(value); value = NULL;
		    continue;
		    
		}

	    }


	    DPRINT(Debug,9,(&Debug, 
			    "expand_dt_path          [%d]=%s\n",
			    ptr->nlen,value));
	    
	    ptr->list = safe_realloc(ptr->list,
				   (ptr->nlen+1)* sizeof (ptr->list[0]));
	    ptr->list[ptr->nlen++] = value;

	    if (q) {
		DPRINT(Debug,9,(&Debug, 
				"expand_dt_path : Starting next quoted value...\n"));
		start_val = p+1;		    
	    }
	}	
    }

    if (start_val || q) {
	panic("RC PANIC",__FILE__,__LINE__,"expand_dt_path",
	      "Bad state on end",0);
    }

    if (!recursive) {
	DPRINT(Debug,9,(&Debug, 
			"expand_dt_path=%d\n",
			ret));
    } else {
	DPRINT(Debug,11,(&Debug, 
			 "expand_dt_path=%d (recursive=%d)\n",
			 ret,recursive));
    }


    if (ptr->nlen > 0) {
	/* Add trailing NULL */
	ptr->list = safe_realloc(ptr->list,
				 (ptr->nlen+1)* sizeof (ptr->list[0]));
	ptr->list[ptr->nlen] = NULL;
    }

    return ret;
}

char ** give_dt_path_as_elems(ptr, fieldname)
     struct dt_path_info *ptr;
     char * fieldname;
{
    if (!ptr->list && ptr->unexpanded)
	expand_dt_path(ptr,fieldname,ptr->unexpanded,0);
    return ptr->list;
}

char * give_dt_path_as_str(ptr,fieldname)
     struct dt_path_info *ptr;
     char * fieldname;
{
    char *res,*p;
    int sep;
    int quote;

    int i,L = 1;
    if (!ptr->list && ptr->unexpanded)
	expand_dt_path(ptr,fieldname,ptr->unexpanded,0);
    if (!ptr->list)
	return NULL;

    if (ptr->list && 0 == ptr->nlen) {
	res = safe_strdup("none");

	DPRINT(Debug,9,(&Debug, 
			"give_dt_path_as_str=%s\n",res));
	
	return res;
    }


    for (i = 0; i < ptr->nlen; i++) 
	L += strlen(ptr->list[i]) +1;

    if (ptr->flags & PATH_sep_comma) sep = ',';
    else if (ptr->flags & PATH_sep_colon) sep = ':';
    else sep = ' ';

    if (ptr->flags & PATH_quote) quote = '"';
    else if (ptr->flags & PATH_quote_single) quote = '\'';
    else quote = 0;

    if (quote)
	L += ptr->nlen * 2;

    res = safe_malloc(L);
   
    for (i = 0, p = res; i < ptr->nlen;i++) {
	int l = strlen(ptr->list[i]);
	
	if (p+l+1 + (quote ? 2 : 0) >= res+L)
	    panic("RC PANIC",__FILE__,__LINE__,"give_dt_path_as_str",
		  "Overflow",0);
	if (i > 0)
	    *p++ = sep;

	if (quote)
	    *p++ = quote;

	memcpy(p,ptr->list[i],l);
	p += l;	    

	if (quote)
	    *p++ = quote;

    }
    *p = '\0';

    DPRINT(Debug,9,(&Debug, 
		    "give_dt_path_as_str (len=%d)=%s\n",L,res));

    return res;
}


#if ANSI_C
static rc_parse_line dt_PATH_parse_line;
#endif

static int dt_PATH_parse_line(r,lcl,value,lineno,filename,negate)
     struct rc_save_info_rec *r;
     int lcl;
     char *value; 
     int lineno; 
     char *filename;
     int negate;
{
    if (negate) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadNegate,
			  "!%s is not supported in line %d in \"%s\" file"),
		  r->name,lineno,filename);
	return 0;
    }

    r->val.path->unexpanded = strmcpy(r->val.path->unexpanded,value);

    /* Free old value */
    if (r->val.path->list) {
	int i;

	for (i = 0; i < r->val.path->nlen; i++) {
	    if (r->val.path->list[i]) {
		r->val.path->list[i] = NULL;
	    }
	}
	free(r->val.path->list);
    }
    r->val.path->list = NULL;
    r->val.path->nlen = 0;

    return 1;
}

#if ANSI_C
static rc_parse_cline dt_PATH_parse_cline;
#endif

static int dt_PATH_parse_cline(r,lcl,value,lineno,filename)
     struct rc_save_info_rec *r;
     int lcl;
     char *value; 
     int lineno; 
     char *filename;
{
    int ret = 1;

    /* First line is unexpanded so expand it .... */
    if (r->val.path->unexpanded) {

	ret = expand_dt_path(r->val.path,
			     r->name,r->val.path->unexpanded,0);

	if (!ret) {
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadValueInElmrc,
			      "Value of \"%s\" in line %d in \"%s\" file is bad"),
		      r->name,lineno-1,filename);
	}


	free(r->val.path->unexpanded); r->val.path->unexpanded = NULL;
    }

    if (!expand_dt_path(r->val.path,r->name,value,0)) {
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadValueInElmrc,
			      "Value of \"%s\" in line %d in \"%s\" file is bad"),
		      r->name,lineno,filename);
	    ret = 0;
    }
    
    return ret;
}

#if ANSI_C
static rc_print_value dt_PATH_print_value;
#endif

static void dt_PATH_print_value(F,r,comment)
     FILE *F;
     struct rc_save_info_rec *r;
     int comment;
{

    if (r->val.path->unexpanded) {
	if (comment)
	    fprintf(F, "### ");
	fprintf(F, "%s = %s\n", r->name, r->val.path->unexpanded);
    } else {
	int i;
	int len = strlen(r->name) + 3;

	if (comment)
	    fprintf(F, "### ");
	
	fprintf(F, "%s = ",r->name);

	if (r->val.path->list && 0 == r->val.path->nlen) {
	    fprintf(F, "none");
	}

	for (i = 0; i < r->val.path->nlen; i++) {
	    /* NOTE: space is always valid separator even when
	       PATH_sep_comma or PATH_sep_colon is set */

	    if (i > 0) {
		if (len + strlen(r->val.path->list[i]) > 70) {
		    fprintf(F, "\n");
		    if (comment)
			fprintf(F, "### ");
		    fprintf(F, "\t");	
		    len = 8;
		} else 
		    fprintf(F, " ");
		
	    }
	    if (r->val.path->flags & PATH_quote)
		elm_fprintf(F,FRM("%Q"),r->val.path->list[i]);
	    else if (r->val.path->flags & PATH_quote_single) {
		fputc('\'',F);
		fputs(r->val.path->list[i],F);
		fputc('\'',F);
	    } else
		fputs(r->val.path->list[i],F);
	    len += strlen(r->val.path->list[i]) + 1;
	}

	fprintf(F, "\n");
    }
}

struct rc_type rc_DT_PATH = { RCTYPE_magic,
			      dt_PATH_parse_line, dt_PATH_parse_cline,
			      dt_PATH_print_value, NO_get_value };

#ifdef ANSI_C
static rc_parse_line dt_OBS_parse_line;
#endif
static int dt_OBS_parse_line(r,lcl,value,lineno,filename, negate)
     struct rc_save_info_rec *r;
     int lcl;
     char *value; 
     int lineno; 
     char *filename;
     int negate;
{     
    /* This message is not perhaps very visible, because
       ELm starts anyway, but it was requested on that way.
    */
    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmObsoleteInElmrc,

		      "Elmrc variable \"%s\" is obsolete and should be removed from line %d in \"%s\" file"),
	      r->name,lineno,filename);
    return 1; /* Mark as succeed */
}


struct rc_type rc_DT_OBS = { RCTYPE_magic,
			     dt_OBS_parse_line, BAD_parse_cline,
			     NO_print_value, NO_get_value };


static void metamail_expand(struct dt_estr_info *ptr);
static void metamail_expand(ptr)
     struct dt_estr_info *ptr;
{
    if (getenv("NOMETAMAIL")) {
	if (ptr->expanded)
	    free(ptr->expanded);
	ptr->expanded = NULL;		
    } else {
	ptr->expanded = strmcpy(ptr->expanded,"metamail");
    }
}

/* 
   0 == failure
   1 == succeed
*/


static void estr_set_expanded P_((struct dt_estr_info *ptr, 
				  const char *buffer));
static void estr_set_expanded(ptr,buffer)
     struct dt_estr_info *ptr; 
     CONST char *buffer;
{
    /* Fix shell if needed */
    if (ptr->flags & ESTR_bin) { 
	if (buffer[0] != '/') {
	    char * A = elm_message(FRM("/bin/%s"), buffer);

	    if (ptr->expanded)
		free(ptr->expanded);
	    ptr->expanded = A;
	    return;
	}
    }

    ptr->expanded = strmcpy(ptr->expanded,buffer);

    /* Fix temp_dir if needed */
    if (ptr->flags & ESTR_slash) { 
	int l = strlen(buffer);

	if (0 == l || buffer[l-1] != '/') 
	    ptr->expanded = strmcat(ptr->expanded,"/");
    }
}

int expand_dt_estr(ptr,fieldname,val)
     struct dt_estr_info *ptr; 
     char *fieldname; 
     char *val;
{
    char buffer[1024];

    int x;

    if (ptr->flags & ESTR_none) {
	if (0 == strcmp("none",ptr->unexpanded)) {

	    if (ptr->expanded)
		free(ptr->expanded);
	    ptr->expanded = NULL;
	    return 1;
	}
    }

    if (ptr->flags & ESTR_metamail) {
	if (0 == strcmp("metamail",ptr->unexpanded)) {
	    metamail_expand(ptr);
	    return 1;
	}
    }

    if (ptr->flags & ESTR_meta)
	x = expand_meta(buffer, ptr->unexpanded, sizeof buffer);
    else 
	x = expand_env(buffer, ptr->unexpanded, sizeof buffer);

    if (x != 0) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, 
			  ElmBadVariableInElmrc,
			  "Bad variable on key \"%s\" value \"%s\""),
		  fieldname,val);
	return 0;
    }

    estr_set_expanded(ptr,buffer);
    
    return 1;
}

/* Retuns 1 if sepecial value "none" */

int dt_estr_is_disabled(ptr)
     struct dt_estr_info *ptr;
{
    if (ptr->flags & ESTR_none) {
	if (0 == strcmp("none",ptr->unexpanded)) {
	    return 1;
	}
    }

    return 0;
}

char * give_dt_estr_as_str(ptr,fieldname)
     struct dt_estr_info *ptr;
     char * fieldname;
{
    if (!ptr->expanded && ptr->unexpanded)
	expand_dt_estr(ptr,fieldname,ptr->unexpanded);

    return ptr->expanded;
}

/* Set initial value */
extern void set_dt_estr(ptr, const_val, def_env)
     struct dt_estr_info *ptr;
     CONST char *const_val;
     char *def_env;
{
    char *cp;

    if (def_env &&
	(cp = getenv(def_env)) &&
	cp[0]) {
	char *x = elm_message(FRM("$%s"),def_env);

	ptr->unexpanded = strmcpy(ptr->unexpanded,x);

	estr_set_expanded(ptr,cp);

	free(x);
    } else {
	
	if (ptr->flags & ESTR_none) {
	    if (0 == strcmp("none",const_val)) {
		ptr->unexpanded = strmcpy(ptr->unexpanded,const_val);
		
		if (ptr->expanded)
		    free(ptr->expanded);
		ptr->expanded = NULL;
		
		return;
	    }
	}

	if (ptr->flags & ESTR_metamail) {
	    if (0 == strcmp("metamail",const_val)) {
		ptr->unexpanded = strmcpy(ptr->unexpanded,const_val);
		metamail_expand(ptr);
		return;
	    }
	}

	ptr->unexpanded = strmcpy(ptr->unexpanded,const_val);

	estr_set_expanded(ptr,const_val);
    }
}

#ifdef ANSI_C
static rc_parse_line dt_ESTR_parse_line;
#endif
static int dt_ESTR_parse_line(r,lcl,value,lineno,filename, negate)
     struct rc_save_info_rec *r;
     int lcl;
     char *value; 
     int lineno; 
     char *filename;
     int negate;
{     
    if (negate) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadNegate,
			  "!%s is not supported in line %d in \"%s\" file"),
		  r->name,lineno,filename);
	return 0;
    }

    r->val.estr->unexpanded = strmcpy(r->val.estr->unexpanded,value);
    
    /* Free old value */
    if (r->val.estr->expanded) {
	free(r->val.estr->expanded);
	r->val.estr->expanded = NULL;
    }
    
    return 1;
}

#if ANSI_C
static rc_get_value dt_ESTR_get_value;
#endif
static char * dt_ESTR_get_value(r)
     struct rc_save_info_rec *r;
{    
    return r->val.estr->unexpanded;
}

#if ANSI_C
static rc_print_value dt_ESTR_print_value;
#endif
static void dt_ESTR_print_value(F,r,comment)
     FILE *F;
     struct rc_save_info_rec *r;
     int comment;
{  
    if (r->val.estr->unexpanded) {
	if (comment)
	    fprintf(F, "### ");
	fprintf(F, "%s = %s\n", r->name, r->val.estr->unexpanded);
    } else {
	fprintf(F, "### %s (not set)\n", r->name);
    }
}

struct rc_type rc_DT_ESTR = { RCTYPE_magic,
			      dt_ESTR_parse_line, BAD_parse_cline,
			      dt_ESTR_print_value, dt_ESTR_get_value };


int give_dt_enumerate_as_int(ptr)
     struct dt_enumerate_info *ptr;
{
    return ptr->val;
}

CONST char * give_dt_enumerate_as_str(ptr)
     struct dt_enumerate_info *ptr;
{
    static char * buffer = NULL;
    
    if (ptr->val >= 0 && 
	ptr->val < ptr->nlen) 
	return ptr->list[ptr->val];

    if (buffer)
	free(buffer);
    buffer = elm_message(FRM("%d"), ptr->val);

    return buffer;
}

int set_dt_enumerate_as_str(ptr,str)
     struct dt_enumerate_info *ptr;
     char *str;
{
    int ci = -1, i;

    int e_val;

    e_val = 0;    /* First value is 'unknown' */

    for (i = 0; i < ptr->nlen; i++)
	if (0 == strcmp(ptr->list[i],str)) {
	    e_val = i;
	    break;
	} else if (0 == istrcmp(ptr->list[i],str))
	    ci = i;

    if (!e_val && ci >= 0)
	e_val = ci;

    if (i == ptr->nlen) {
	char *p;	    
	
	if ((e_val = strtol(str,&p,10)) < 0 || *p != '\0') 
	    return 0;

    }
    
    ptr->val = e_val;

    return 1;
}



#ifdef ANSI_C
static rc_parse_line dt_ENUM_parse_line;
#endif
static int dt_ENUM_parse_line(r,lcl,value,lineno,filename, negate)
     struct rc_save_info_rec *r;
     int lcl;
     char *value; 
     int lineno; 
     char *filename;
     int negate;
{     
    if (negate) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadNegate,
			  "!%s is not supported in line %d in \"%s\" file"),
		  r->name,lineno,filename);
	return 0;
    }
    
    if (!set_dt_enumerate_as_str(r->val.enumerate,value)) {
	int i;

	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadEKeyInElmrc,
			  "I can't understand %s key \"%s\" in line %d in \"%s\" file"),
		  r->name,value, lineno,filename);
	
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadEKeyValues,
			  "Possible values are:"));
	for (i = 0; i < r->val.enumerate->nlen; i++)
	    lib_error(FRM(" - %s"),
		      r->val.enumerate->list[i]);
	
	return 0;
    }

    return 1;
}

#if ANSI_C
static rc_get_value dt_ENUM_get_value;
#endif
static char * dt_ENUM_get_value(r)
     struct rc_save_info_rec *r;
{    
    static char * buffer = NULL;
    
    if (r->val.enumerate->val >= 0 && 
	r->val.enumerate->val < r->val.enumerate->nlen) 
	return r->val.enumerate->list[r->val.enumerate->val];

    if (buffer)
	free(buffer);
    buffer = elm_message(FRM("%d"), r->val.enumerate->val);

    return buffer;
}

#if ANSI_C
static rc_print_value dt_ENUM_print_value;
#endif
static void dt_ENUM_print_value(F,r,comment)
     FILE *F;
     struct rc_save_info_rec *r;
     int comment;
{  

    if (comment)
	fprintf(F, "### ");

    if (r->val.enumerate->val >= 0 && 
        r->val.enumerate->val < r->val.enumerate->nlen) {

	char * s = r->val.enumerate->list[r->val.enumerate->val];

	fprintf(F, "%s = %s\n", r->name, s);

       	DPRINT(Debug,9,(&Debug, 			
			" option \"%s\", value=\"%s\"\n",
			r->name,s ));

    } else {
	fprintf(F, "%s = %d\n", r->name, 
		r->val.enumerate->val);
	
	DPRINT(Debug,9,(&Debug, 
			" option \"%s\", value=%d\n",
			r->name,r->val.enumerate->val ));

    }  
}


struct rc_type rc_DT_ENUM = { RCTYPE_magic,
			      dt_ENUM_parse_line, BAD_parse_cline,
			      dt_ENUM_print_value, dt_ENUM_get_value };



/*
 * Local Variables:
 *  mode:c
 *  c-basic-offset:4
 *  buffer-file-coding-system: iso-8859-1
 * End:
 */


syntax highlighted by Code2HTML, v. 0.9.1