static char rcsid[] = "@(#)$Id: read_rc.c,v 1.183 2006/06/25 10:41:04 hurtta Exp $";

/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.183 $   $State: Exp $
 *
 *  Modified by: Kari Hurtta <hurtta+elm@posti.FMI.FI> 
 *                       (was hurtta+elm@ozone.FMI.FI)
 *           or  Kari Hurtta <elm@elmme-mailer.org>
 *****************************************************************************
 *
 * Most of code copied from ../src/read_rc.c. It have following copyright:
 *
 *			Copyright (c) 1988-1992 USENET Community Trust
 *			Copyright (c) 1986,1987 Dave Taylor
 *****************************************************************************/

#define SAVE_OPTS
#include "headers.h"
#include "rc_imp.h"
#include "save_opts.h"
#include "s_elm.h"
#include "s_me.h"
#include "unidata.h"
#include "cs_imp.h"

#include "patchlevel.h"

#include <errno.h> 
#ifndef ANSI_C
extern int errno;
#endif

DEBUG_VAR(Debug,__FILE__,"config");

#ifdef PWDINSYS
#  include <sys/pwd.h>
#else
#  include <pwd.h>
#endif

#ifndef I_UNISTD 
char *getlogin();
unsigned short getgid(), getuid(); 
struct passwd *getpwuid();
#endif

# ifdef DOUNAME
#  include <sys/utsname.h>
# endif

struct hist_record {
    char *tag;
    struct rc_save_info_rec * entry;
    int changed;


    char  ** old_line;
    int   line_count;
};

static struct elmrc_recorder {
    struct hist_record *recs;
    int  rec_count;
    
} * recorders[RC_MODE_COUNT];

struct elmrc_recorder  * enable_recorder(mode)
     enum record_mode mode;
{
    if (mode < 0 || mode >= RC_MODE_COUNT) 
	panic("RC PANIC",__FILE__,__LINE__,"enable_recorder",
	      "Bad mode",0);

    if (! recorders[mode] ) {
	struct elmrc_recorder * X;

	X = safe_malloc(sizeof (*X));

	bzero((void *)X, sizeof (* (X)));

	X->recs      = NULL;
	X->rec_count = 0;

	recorders[mode] = X;
    }


    return recorders[mode];
}

static struct hist_record * record1 P_((struct elmrc_recorder  *recorder,
					struct rc_save_info_rec *X,
					char *tag));

static struct hist_record * record1(recorder,X,tag)
     struct elmrc_recorder  *recorder;
     struct rc_save_info_rec *X;
     char *tag;
{				       
    struct hist_record *r;


    recorder->recs = safe_realloc(recorder->recs,
					 sizeof (recorder->recs[0]) *
					 ( recorder->rec_count + 1 ));

    r = & (recorder->recs[recorder->rec_count]);

    bzero((void *)r, sizeof (*r));

    r->entry = X;
    r->tag   = NULL;

    if (tag)
	r->tag = safe_strdup(tag);

    r->old_line    = 0;
    r->line_count  = 0;
    r->changed     = 0;

    recorder->rec_count++;

    return r;
}

static struct hist_record * need_record P_((enum record_mode mode,
					    struct rc_save_info_rec *X,
					    char *tag));
static struct hist_record * need_record(mode,X,tag)
     enum record_mode mode;
     struct rc_save_info_rec * X;
     char *tag;
{
    int i;
    struct hist_record *r;


    if (! recorders[mode] ) 
	return NULL;


    /* If old value is already recorded, 
       do not add 'new' old value
    */

    for (i = 0; i < recorders[mode]->rec_count; i++) 
	if (recorders[mode]->recs[i].entry == X)
	    return NULL;
    

    return record1(recorders[mode],X,tag);
}					    

static char * split_keyword P_((char *buffer, int line_len,
				char *keyword, int size,
				char **tag,
				int *assig));
static struct rc_save_info_rec *locate_option P_((struct rc_save_info_rec * rc_options,
						  int          rc_option_count,
						  char *word1,
						  char *word2,
						  char *filename,
						  int *negate));

#define MAX_LINE 10000


int seed_history(F,filename,recorder)
     FILE *F; 
     char * filename;
     struct elmrc_recorder  *recorder;
{
    int ok = 1;
    char * buffer = NULL;
    int r;  /* length of line or error/eof status */
    int lineno = 0;
    char current_tag[SLEN];

    struct rc_save_info_rec * prev_type = NULL;
    struct hist_record      * rec       = NULL;
    int ignored = 0;

    current_tag[0] = '\0';

    /* malloc_gets does realloc, so buffer need not
       be freed on loop 
    */
    while (0 <= ( r = malloc_gets(&buffer,MAX_LINE,F))) {
	char   * tag         = NULL;
	char   keyword[SLEN], *c;
	char   * rest        = NULL;
	int    assig         = 0;
	
	int    negate = 0;

	lineno++;

	if (!buffer)           /* EOF           */
	    break;

	if (buffer[0] == '#'   /* comment       */
	    || r < 1)          /* empty line    */
	    continue;

	rest = split_keyword(buffer,r,keyword, sizeof keyword,
			     &tag,&assig);


	if (tag && !keyword[0]) {
	    strfcpy(current_tag, tag, sizeof current_tag);

	    if (rest[0] && '#' != rest[0]) {
		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmIgnoredLine,
				  "Rest of line ignored after \"%s:\" on line %d on file %s"),
			  tag, lineno,filename);
		ok = 0;
	    }

	} else if (!keyword[0]) {
	    if (prev_type != NULL) {
		
		if (RCTYPE_magic != prev_type->dt_type->magic)
		    panic("RC PANIC",__FILE__,__LINE__,"do_rc",
			  "Bad prev_type",0);
		
		if (rec) {
		    rec->old_line = safe_realloc(rec->old_line,
						 sizeof(rec->old_line[0]) *
						 ( rec->line_count + 1));
		    
		    rec->old_line [ rec->line_count ] = safe_strdup(rest);
		    rec->line_count++;

		    /* Preserve seeded data when printing again */
		    rec->changed++;
		}
	    }

	} else if (assig) {

	    if (tag || current_tag[0]) {
		struct rc_save_info_rec * rc_options      = NULL;
		int                     rc_option_count   = 0;
		
		if (!tag) 
		    tag = current_tag;
		else
		    ignored = 0;
		
#ifdef USE_DLOPEN
		if (give_options(tag,&rc_options,&rc_option_count)) {
		    
		    prev_type = locate_option(rc_options,rc_option_count,
					      keyword,rest,filename,
					      &negate);
		    ignored = 0;
		    
		    if (!prev_type) {
			lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadKeyTagInElmrc,
					  "I can't understand keyword \"%s\" (section %s) in line %d in \"%s\" file"),
				  keyword, tag,lineno,filename);
			ok = 0;
			continue;
		    }
		    
		} else if (!ignored) {
		    ignored = 1;
		    
		    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmIgnoredSection,
				      "Keywords on section \"%s\" ignored starting from line %d on file %s"),
			      tag, lineno,filename);
		    ok = 0;
		}
#else
		if (!ignored) {
		    ignored = 1;
		    
		    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmSharedIgnoredSection,
				      "Shared libraries not supported. Section \"%s\" ignored starting from line %d on file %s"),
			      tag, lineno,filename);
		    ok = 0;
		}
#endif
		
	    } else {
		
		prev_type = locate_option(save_info,NUMBER_OF_SAVEABLE_OPTIONS,
					  keyword,rest,filename,&negate);
		
		if (!prev_type) {	       
		    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadKeyInElmrc,
				      "I can't understand keyword \"%s\" in line %d in \"%s\" file"),
			      keyword, lineno,filename);
		    ok = 0;
		    continue;
		}
		
	    }
	    
	    rec = record1(recorder,prev_type,tag);
	    if (rec) {
		if (rec->line_count)
		    panic("RC PANIC",__FILE__,__LINE__,"do_rc",
			  "Bad prev_type",0);
		
		rec->old_line = safe_malloc(sizeof(rec->old_line[0]));
		
		rec->old_line[0] = safe_strdup(rest);
		
		rec->line_count = 1;
		rec->changed++;
	    }
	} else {
	    prev_type = NULL;

	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadLineInElmrc,
			      "Keyword \"%s\" without = -character in line %d in \"%s\" file"),
		      keyword, lineno,filename);
	    ok = 0;

	}
    }

    if (-1 == r) {	
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmTooLongLine,
			  "%.30s: %d: Too long line: %.30s..."),
		  filename,lineno+1,
		  buffer ? buffer : "<not available>");
	ok = 0;
    }

    if (ferror(F)) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmErrorReading,
			  "Error reading from %.50s"),
		  filename);
	ok = 0;
    }

    if (buffer)
	free(buffer);


    return ok;
}

static void print_history_record P_((FILE *F,struct hist_record *x));
static void print_history_record(F,x)
     FILE *F;
     struct hist_record *x;
{
    int i;

    fprintf(F,"\n%s = %s\n",
	    x->entry->name,
	    x->old_line[0]);

    for (i = 1; i < x->line_count; i++) {
	fprintf(F,"\t%s\n",
		x->old_line[i]);
    }


}

void print_history_changed(F,recorder)
     FILE *F; 
     struct elmrc_recorder  *recorder;
{
    int i;

    /* First print lines without tag */
    char * last_tag = NULL;


    for (i = 0; i < recorder->rec_count; i++) {

	if (recorder->recs[i].changed &&
	    NULL == recorder->recs[i].tag) {
	    print_history_record(F,& (recorder->recs[i]));
	}

    }

    /* Then print values with tag */

    for (i = 0; i < recorder->rec_count; i++) {

	if (recorder->recs[i].changed &&
	    NULL != recorder->recs[i].tag) {

	    if (!last_tag || 
		0 != strcmp(last_tag,
			    recorder->recs[i].tag)) {
		last_tag = recorder->recs[i].tag;

		fprintf(F,"\n\n%s:\n",
			last_tag);

		print_history_record(F,& (recorder->recs[i]));

	    }
	}
    }
}

void mark_XX(x)
     struct rc_save_info_rec *x;
{
    enum record_mode mode; 

    int found = 0;

    x->flags |= FL_LOCAL;
    x->flags |= FL_CHANGED;

    DPRINT(Debug,10,(&Debug,
		     "mark_XX: Setting %p %s changed\n",
		     x,x->name));
	
    for (mode = SYSTEM_RC; mode < RC_MODE_COUNT; mode++) {
    
	if (recorders[mode]) {
	    int i;

	    for (i = 0; i < recorders[mode]->rec_count; i++) 
		if (recorders[mode]->recs[i].entry == x) {
		    recorders[mode]->recs[i].changed++;
		    found++;

		    DPRINT(Debug,10,(&Debug,
				     "mark_XX: recorders[%d]->recs[%d].entry == %p\n",
				     mode,i,x));

		}
	} else {
	    DPRINT(Debug,10,(&Debug,
			     "mark_XX: no mode=%d\n",mode));
	}
    }
	
    if (!found) {
	DPRINT(Debug,10,(&Debug,
			 "mark_XX: no change record\n"));
    }

}

void mark_local_changed(A)
     void *A;
{
    int x;
    

    for (x = 0; x < NUMBER_OF_SAVEABLE_OPTIONS; x++) {
        if (save_info[x].val.dummy == A) {

	    DPRINT(Debug,10,(&Debug,
			     "mark_local_changed: %d: %p\n",
			     x,A));

	    mark_XX(& (save_info[x]));

	}
    }

#ifdef USE_DLOPEN
    mark_shared_changed(A);
#endif

    mark_delayed_changed(A);

}




void mark_flocal_changed(A)
     option_func *A;
{
    int x;
    

    for (x = 0; x < NUMBER_OF_SAVEABLE_OPTIONS; x++) {
        if (save_info[x].func_val == A) {

	    DPRINT(Debug,10,(&Debug,
			     "mark_flocal_changed: %d: %p\n",
			     x,A));

	    mark_XX(& (save_info[x]));

	}
    }

#ifdef USE_DLOPEN
    mark_fshared_changed(A);
#endif

    mark_fdelayed_changed(A);
}



#ifdef HAVE_CODESET
#include <langinfo.h>
#endif

static int lineno = 0;
static int errors = 0;

static void do_expand_env P_((char *, char *, char *, unsigned));
static void do_rc P_((FILE *file,enum record_mode lcl, char *filaname));

int parse_elmrc(F,global,filename)
     FILE *F;
     int global;
     char *filename;
{
    errors = 0;

    do_rc(F, global ? SYSTEM_RC : LOCAL_RC, filename);

    return errors;
}
#ifndef ok_rc_char
#define ok_rc_char(c)   (isalnum(c) || c == '-' || c == '_')
#endif

char system_text_file[SLEN]     = SYSTEM_TEXT_FILE;
char system_data_file[SLEN]     = SYSTEM_DATA_FILE;
char system_rc_file[SLEN]       = SYSTEM_RC_FILE;
char system_mime_types[SLEN]    = SYSTEM_MIME_TYPES;
char system_iso2022_sets[SLEN]  = SYSTEM_ISO2022_SETS;
char system_terminal_info[SLEN] = SYSTEM_TERMINAL_INFO;
char system_mail_services[SLEN] = SYSTEM_MAIL_SERVICES;
char hostdomfile[SLEN]          = HOSTDOMFILE;
char system_mime_charsets[SLEN] = SYSTEM_MIME_CHARSETS;
ESTR map_txtdir_e = {            /* init_defaults */
    ESTR_meta|ESTR_slash,
    NULL,
    NULL
};
ESTR map_bindir_e = {            /* init_defaults */
    ESTR_meta|ESTR_slash,
    NULL,
    NULL
};
char unidata_path[SLEN] = {0};  /* init_defaults */
char raw_unidata_path[SLEN] =  "unidata.bin";     /* init_defaults */

char bindata_path_global[SLEN] = {0};   /* Used before user elm.rc is read */
char bindata_path[SLEN] = {0};  /* init_defaults */
char raw_bindata_path[SLEN] =  "bindata.bin";     /* init_defaults */

int  unstable_reverse_thread = 0;

char user_rc_file[SLEN]   = ELMRCFILE;              /* user_init fixes */
char user_text_file[SLEN] = USER_ALIAS_TEXT;        /* user_init fixes */
char user_data_file[SLEN] = USER_ALIAS_DATA;        /* user_init fixes */
char user_mime_types[SLEN] = USER_MIME_TYPES;       /* user_init fixes */
char user_mailheaders[SLEN] = MAILHEADERS;          /* user_init fixes */
char user_mime_charsets[SLEN] = USER_MIME_CHARSETS; /* user_init fixes */
char user_iso2022_sets[SLEN]  = USER_ISO2022_SETS;  /* user_init fixes */
char user_terminal_info[SLEN] = USER_TERMINAL_INFO; /* user_init fixes */
char user_mail_services[SLEN] = USER_MAIL_SERVICES; /* user_init fixes */

ESTR defaultfile_e = {	                /* name of default folder */
    0,
    NULL,
    NULL
};

ESTR calendar_file_e = {	/* name of file for clndr  */
    0,
    NULL,
    NULL
};

ESTR dead_letter_dir_e = {
    0,
    NULL, 
    NULL
};

int clear_pages = 0;		/* flag: act like "page" (more -c)? */
int title_messages = 1;		/* flag: title message display?     */

nl_catd  elm_msg_cat = 0; 	/* message catalog	    */
                         /* WARNING: Elm's version uses 0 as failure
                                     System uses (nl_catd) -1 as failure !
			 */


char username[SLEN] = {0};	/* return address name!    */
char home[SLEN] = {0};		/* home directory of user  */
int userid = -1;			/* uid for current user	      */
int groupid = -1;			/* groupid for current user   */

int mailgroupid;		/* groupid for current user   */
int have_saved_ids = 0;         /* sysconf _SC_SAVED_IDS      */

/* ------------- Variables in elmrc ------------------------------- */

int  add_irt_phrase = 0;        /* In-reply-to: Add phare to in-reply-to ?
			           True = Do not follow RFC 2822 
				*/
int add_sender_header = 1;     /* If set add Sender: header if user specifies
				  From: -header
				*/
int allow_charset_switching=0;   /* flag: allow changing charset of */
				 /* terminal if terminal supports   */

static struct sortval ASR_srtval[]={
    {"alias", ALIAS_SORT},
    {"name", NAME_SORT},
    {"text", TEXT_SORT},
    {NULL, 0} 
};

SORT alias_sortby = {            /* how to sort aliases...   */
    NAME_SORT,	           

    ASR_srtval
};

char alternative_editor[SLEN] = "EDITOR";  /* alternative editor...    */
PATH alternative_addresses = {	/* how else do we get mail? */
    PATH_sep_comma,
    NULL, 0,NULL
};

int always_del = 0;		/* flag: always delete marked msgs? */
int always_keep = 1;		/* flag: always keep unread msgs?   */
int always_store = 0;		/* flag: always store read msgs?    */
int arrow_cursor = 0;		/* flag: use "->" cursor regardless?*/
int question_me = 1;		/* flag: ask questions as we leave? */
int prompt_for_cc = 1;		/* flag: ask user for "cc:" value?  */
#ifdef USE_PGP
int pgp_askpgpsig=0; /* Should pgp ask userid to sign messages with? */


static char * PGP_SIGN_TYPES[] = { "application/pgp", "text/plain", 
				   "text/x-pgp", NULL };


ENUMERATE pgp_sign_type= {     /* 0 = application/pgp  */
    0,                         /* 1 = text/plain       */
    3, &(PGP_SIGN_TYPES[0])    /* 2 = text/x-pgp       */ 
};

static char * PGP_ENCRYPT_TYPES[] = { "application/pgp", "text/plain", 
				      "text/x-pgp", NULL };

ENUMERATE pgp_encrypt_type= {   /* 0 = application/pgp */
    0,                          /* 1 = text/plain */
    3, &(PGP_ENCRYPT_TYPES[0])  /* 2 = text/x-pgp */
};

int pgp_interactive=0; /* Should pgp/gpg encryption/signing to be
			  run always on interactive mode */

static char * PGP_VERSIONS[] = { "default", "pgp2", "pgp5", "gpg", NULL };
ENUMERATE send_pgp_version = {  /* preferred pgp version*/
    pgp_none,
    4, &(PGP_VERSIONS[0]) 
};
	
#endif
char attribution[SLEN] = {0};	/* attribution string for replies   */

static char * AUTO_ATTACH[] = { "none", "application", "non-text", NULL };
ENUMERATE  auto_attachment = {   /* 0 = none,                     */
    1,				   /* 1 = application,              */
    3, &(AUTO_ATTACH[0])	   /* 2 = non-text   		    */
};

int auto_copy = 0;		/* flag: automatically copy source? */
int auto_iso_8859 = 1;          /* flag: Should ISO-8859-X charsets defined
				   on demand ?                      */
#ifdef BACKGROUD_PROCESSES       
int background_wait_time = 2;    /* If > 0 background mailer after  */
				 /* this number of seconds          */
#endif

int browser_wildcards = 1;      /* flag: do wildcard match?         */
int builtin_lines= -3;		/* int: if < 0 use builtin if message*/
                                /* shorter than LINES+builtin_lines */
                                /* else use pager. If > 0 use builtin*/
                                /* if message has fewer than # of lines*/
int charset_convert_ok = 0;     /* flag: no warning about conversion? */
int check_type_pattern = 1;     /* flag: check magic numbers when paging */
char raw_text_charset[SLEN] = "DISPLAY";    /* name of character set     */
charset_t text_charset      = NULL;   	    /* pointer of character set  */
char raw_default_mimetext_charset[SLEN] = "US-ASCII"; 
                                                /* name of character set    */
charset_t default_mimetext_charset = NULL;      /* pointer to character set */
char raw_default_nomime_charset[SLEN] = "SYSTEM"; /* name of character set  */
charset_t default_nomime_charset = NULL;      /* pointer to character set   */

static char * FOLDER_STATUS[] = { "Read", "Old", "New", NULL };
ENUMERATE def_folder_status = {      /* 0 = Read                    */
    FOLDER_STATUS_OLD,               /* 1 = Old                     */
    3, &(FOLDER_STATUS[0])           /*	2 = New                     */
};

char config_options[SLEN] = {0};/* which options are in o)ptions    */
int confirm_append = 0;		/* flag: confirm append to folder?  */
int confirm_create = 0;		/* flag: confirm create new folder? */
int confirm_files = 0;		/* flag: confirm files for append?  */
int confirm_folders = 0;	/* flag: confirm folders for create?*/
int convert_comment = 1;        /* flag: convert comment to fullname ?  */
int convert_utf_header = 1; /* flag: convert utf-8 mime encoded words to utf-7 when sending?   */

int auto_copy_sent = -1;	  /* flag: automatically copy sent mail? */
char display_locale[SLEN] = "NONE";  /* LC_CTYPE locale (character set) */
char display_codeset[SLEN] = "";     /* nl_langinfo(CODESET) for current locale (character set) */

charset_t wanted_display_charset = NULL;
char raw_display_charset[SLEN]   = "SYSTEM";	
                               /* the wanted display charset set */
int DSN_success = 0;            /* flag: Ask successfull DSNes      */
char e_editor[SLEN] = {0};	/* "~e" editor...                   */

ESTR editor_e = {               /* editor for outgoing mail*/
    0,
    NULL,
    NULL
};

static char * MPAR[] = { "plain", "encoded", "plain-and-encoded" };
ENUMERATE mime_parameters = {
    2,
    3, &(MPAR[0])
};

static char * ENV_FROM_SOURCES[] = { "forward-from", "from", "return-path", 
				     NULL };
ENUMERATE env_from_source = {  /* 0 == forward-from,                */
    0,                         /*      1 == from,                   */
    3, &(ENV_FROM_SOURCES[0])  /*    2 == return-path               */
};

char escape_char = TILDE_ESCAPE;/* '~' or something else..          */
int force_name = 0;		/* flag: save by name forced?	    */

static char * FRAGMENTH_list[] = { "none", "manual", "auto" };
ENUMERATE fragment_handling = { /* 0 == none,                       */
    1,                          /* 1 == manual,                     */
    3, &(FRAGMENTH_list[0])     /* 2 == auto  */
};

int allow_forms = NO;		/* flag: are AT&T Mail forms okay?  */
char full_username[SLEN] = {0};	/* Full username - gecos            */

static char * HDR_PHRASE_DISPLAY_MODES[] = { "plain", "quoted", NULL };
ENUMERATE phrase_display_mode = {    /* 0 == plain, 1 = quoted */
    0,
    2, &(HDR_PHRASE_DISPLAY_MODES[0]) 
};

char hostdomain[SLEN] = {0};	/* name of domain we're in          */
char hostfullname[SLEN] = {0};	/* name of FQDN we're in            */
char hostname[SLEN] = {0};	/* name of machine we're on         */
#ifdef DISP_HOST
int  menu_display_host = TRUE;  /* flag: Display host on mailbox menu* */
#else
int  menu_display_host = FALSE;  /* flag: Display host on mailbox menu? */
#endif
int keep_empty_files = 0;	/* flag: leave empty folder files?  */
#ifdef USE_PGP
int pgp_keeppassfor = 300;      /* 5 minutes                        */
#endif

static struct sortval DIR_srtval[]={
    {"none", LD_NONE},
    {"name", LD_NAME_SORT},
    {"mtime", LD_MTIME_SORT},
    {NULL, 0} 
};

SORT local_dir_sortby = {            /* how to sort files...  */
    LD_NAME_SORT,	           
    DIR_srtval
};

int local_fast_lookup = 0;      /* flag: directory listing not needed 
				   for lookup */
char local_sessionlock_dir[SLEN] = default_temp;

static char * LSL_list[] = { "never", "spool", "always", "non-spool", NULL };
ENUMERATE local_sessionlock_use_home = {  /* 0 == newer,          */
    0,                                    /* 1 == spool           */
    4, &(LSL_list[0])			  /* 2 == always          */ 
};					  /* 3 == non-spool  	  */

char raw_local_fs_charset[SLEN] = "SYSTEM"; /* filesystem charset */
charset_t local_fs_charset      = NULL;     /* filesystem charset */

ESTR local_signature_e = {       /* local msg signature file     */
    0,
    NULL,
    NULL
};
                                /*               signature file     */


#if defined(WCHAR) && defined(__STDC_ISO_10646__)
PATH locale_charsets= {    /* Use type=unknown for these charsets
			    * if system charset
			    */
    0,                     /* flags */
    NULL , 0, NULL
};
#endif

#ifdef SYSCALL_LOCKING
int lockfolders  = 1;           /* Lock folder when open */
int lock_in_copy = 1;           /* Lock folder when copied to it    */
#else
int lockfolders  = 0;           /* Lock folder when open */
int lock_in_copy = 0;           /* Lock folder when copied to it    */
#endif

int long_encoded_headers = 1;   /* Produce over 80 character mime encoded
				   headers */

ESTR folders_e = 	{       /* folder home directory            */
    ESTR_slash,
    NULL,
    NULL
};   
ESTR extra_mailbox_dir_e = {
    ESTR_slash,
    NULL,
    NULL
};
ESTR attachment_dir_e = {   /* {doc} -prefix */
    0,                      /* Note that default assigment do not add / to end */
    NULL,
    NULL
};

int attachment_fix_extension = 1; /* flag: fix extension of attashment when saving */
int mail_permissions = 0600;	/* int: permissions for mailbox files */
int mini_menu = 1;		/* flag: menu specified?	    */

static char * hide_hacks[] = { "none", "FOLDER INTERNAL DATA", NULL };
ENUMERATE message_hide_hack = { /* 0 == none                          */
    0,                          /* 1 = FOLDER INTERNAL DATA           */
    2, &(hide_hacks[0])
};

ESTR metamail_path_e = {        /* Metamail path or "none"          */
     ESTR_none|ESTR_metamail,   /* if no metamail                   */
     NULL,
     NULL
};
PATH metamail_mailcaps = {   /* mailcaps for metamail */
    PATH_file|PATH_sep_colon|PATH_expand,
    NULL, 0,NULL
};

PATH internal_mailcaps = {   /* mailcaps for internal handler */
    PATH_file|PATH_sep_colon|PATH_expand,
    NULL, 0,NULL
};

PATH internal_mailcap_t_programs = {
    0,
    NULL, 0, NULL
};
int internal_mailcap_t_prompt = 0;


int metoo = 0;			/* flag: copy me on mail to alias?  */
int mime_body_keywords = TRUE;  /* flag: parse body looking for encode */
				/* keywords */
int mimeforward = FALSE;        /* flag: Forward as Message/rfc822  */
int askmimeforward = 1;         /* flag: prompt about messaga/rfc822 forward */
int move_when_paged = 0;	/* flag: move when '+' or '-' used? */
int names_only = 0;		/* flag: display user names only?   */

static char * NOENCODINGS[] = { "pass-7bit", "pass-8bit", "pass-binary", 
				NULL };
ENUMERATE allow_no_encoding = { /* 1: Allow 8bit without -B8BITMIME */
    0,                          /* 2: Allow binary without -BBINARYMIME and */
    3, &(NOENCODINGS[0])        /*    and 8bit without -B8BITMIME   */
};

int allow_no_hdrencoding = 0;   /* TRUE, if header encoding is      */
				/* not required                     */
int noheader = 1;		/* flag: copy + header to file?     */
int noheaderfwd = 0;		/* flag: copy + header to file(fwd)? */
int pagealternative=1;          /* Page if alternative have one know*/
                                /* subtype ?                        */
int page_known_charsets=1;      /* Page if charset is not unknown?  */
int pagemultipart=0;            /* Page unknown mime subparts?      */
int pagesigned=0;               /* Page unknown signed protocols?   */
ESTR pager_e = {                /* what pager to use                */
    0,
    NULL,
    NULL
};
char pager[SLEN] = {0};		/* what pager to use                */
char raw_pager[SLEN] = {0};	/* unexpanded what pager to use     */
#ifdef USE_PGP
ESTR pgp2_path_e = {            /* Pgp path or "none" if no pgp     */
    ESTR_none,
    NULL,
    NULL
};
ESTR pgp5_dir_e = {   /* pgp5 binary directory or "none" if no pgp5 */
    ESTR_slash|ESTR_none,
    NULL,
    NULL    
};
ESTR gpg_path_e  = {
    ESTR_none,
    NULL,
    NULL
};
#endif
int point_to_new = 1;		/* flag: start pointing at new msg? */
char allowed_precedences[SLEN] = {0};	/* list of precedences user */
                                /* may specify                      */
char prefixchars[SLEN] = "> ";	/* prefix char(s) for msgs          */
ESTR printout_e = {	        /* how to print messages            */
    ESTR_none,
    NULL,
    NULL
};
int prompt_after_pager = 1;     /* flag: prompt after pager exits   */
int prompt_after_metamail = 1;  /* flag: prompt after metamail exits     */
int  prompt_metamail = 1;     /* flag: prompt for calling of metamil */
int quote_forward = 0;		/* flag: fwd'd msgs quoted like replies */
int readdatapercentinc = 5;	/* data percent increment during new mbox read */

ESTR readmsg_e = {	        /* path to readmsg program	*/
    ESTR_meta,
    NULL,
    NULL
};

int readmsginc = 100;		/* increment of msg cnt when reading*/
                                /* new mbox                         */
ESTR recvd_mail_e = {	/* folder for storing received mail */
    ESTR_none|ESTR_meta,
    NULL,
    NULL
};

ESTR remote_signature_e = {     /* remote msg signature file    */
    0,
    NULL,
    NULL
};
int req_mime_bodyencoding = 1;  /*                                  */
int req_mime_hdrencoding = 0;   /*                                  */
int resolve_mode = 1;		/* flag: delete saved mail?	    */
int save_by_name = 1;		/* flag: save mail by login name?   */

ESTR sent_mail_e  = {	        /* name of file to save copies to   */
    ESTR_none|ESTR_meta,
    NULL,
    NULL
};

int send_mime_plain  = 1;       /* flag: send plain text as MIME?   */
ESTR shell_e  = {	        /* current system shell             */
    ESTR_bin,
    NULL,
    NULL
};

int  set_window_title = 0;      /* flag: set (xterm?) window title and 
				   icon name */
#ifdef USE_PGP
int pgp_noarmor=1;      /* Should Elm display text before PGP armor */
#endif
int showto = 0;                 /*                                  */

static char * HEADER_ERROR_MODES[] = 
    { "OFF", "ON", "store", NULL };
ENUMERATE show_header_errors_e = {
    2,
    3, &(HEADER_ERROR_MODES[0]),
};

int sig_dashes = 1;		/* flag: include dashes above sigs? */
int sleepmsg = 2;		/* time to sleep for messages being */
                                /* overwritten on screen            */


static struct sortval SRT_srtval[]={
    {"sent", SENT_DATE},
    {"thread", THREAD},
    {"received", RECEIVED_DATE},
    {"recieved", RECEIVED_DATE},
    {"rec", RECEIVED_DATE},
    {"from", SENDER},
    {"sender", SENDER},
    {"size", SIZE},
    {"lines", SIZE},
    {"subject", SUBJECT},
    {"mailbox", MAILBOX_ORDER},
    {"folder", MAILBOX_ORDER},
    {"status", STATUS},
    {NULL, 0} 
};

SORT sortby = {                 /* how to sort incoming mail...     */
    REVERSE SENT_DATE,	

    SRT_srtval
};

static struct sortval THREAD_srtval[]={
    {"sent",    SENT_DATE},
    {"subject", SUBJECT},
    {NULL, 0} 
};


SORT thread_sortby = {          /* how to sort threads of messages */
    REVERSE SENT_DATE,	

    THREAD_srtval
} ;      

long elm_timeout = 600L;	/* timeout (secs) on main prompt    */
int sort_thread_max_time = 30;  /* Number of days which can considered 
				    be same thread */
ESTR temp_dir_e  = {         /* name of temp directory           */
    ESTR_slash,
    NULL,
    NULL
};

#ifdef USE_PGP
int pgp_keeppass=0;             /* should Elm keep the passphrase in*/
                                /* memory?                          */
#endif

static char * USERLEVELS[] = { "beginner", "intermediate", "expert", NULL };
ENUMERATE user_level = { 	/* flag: how good is the user?      */
    0,
    3, &(USERLEVELS[0]) 
};

int use_tite = 1;		/* flag: use termcap/terminfo ti/te?*/
int utf7_encode_optional = 1;   /* flag: Should utf7 optional direct 
				   characters to be encoded?        */
#ifdef I_NETDB
int verify_domain = 0;          /* flag: Should we try check existence
				   of mail domain
				*/
#endif
int verify_local_address = 0;    /* flag: Should we try check existence
				    of local user
				 */
char v_editor[SLEN] = {0};	/* "~v" editor...                   */
int elm_filter = 1;		/* flag: weed out header lines?	    */
PATH weedlist = {
    PATH_sep_comma|PATH_quote|PATH_convert_underline,
    NULL, 0,NULL
};


#ifdef REMOTE_MBX
static struct sortval IMAP_srtval[]={
    {"none", ID_NONE},
    {"name", ID_NAME_SORT},
    {NULL, 0} 
};

SORT imap_dir_sortby = {            /* how to sort imap folders...  */
    ID_NONE,	           
    IMAP_srtval
};


char raw_imap_charset[SLEN] = "SYSTEM";  /* IMAP foldername charset */
int imap_fast_lookup = 0;           /* flag: skip some directory listing */
int imap_max_dl_size = 4*1024;      /* Maximum size of message to be
				     * downloaded 
				     */
charset_t imap_charset = NULL;           /* IMAP foldername charset */
int IMAP_connection_cache = 1; /* flag: call cache_connection() ? */
int IMAP_name_convention = 1; /* flag: Should imap intearnational folder
				 convention be used? */
int IMAP_use_examine   = 1;  /* flag: Should EXAMINE command to be used?    */
int IMAP_show_greeting = 1;  /* flag: Should untagged OK messages be shown? */
int IMAP_show_warning  = 1;  /* flag: Should untagged NO messages be shown? */
int IMAP_show_error    = 1;  /* flag: Should untagged BAD messages be shown? */
int pop_max_dl_size = 4*1024;      /* Maximum size of message to be
				     * downloaded 
				     */
int POP_show_greeting  = 1;  /* flag: Should POP server greeting be shown?  */
#endif

/* ---------------------------------------------------------------- */

static void do_expand_env P_((char  *descr, char *dest, char *src,
			      unsigned	destlen));
static void do_expand_env(descr, dest, src, destlen)
     char	*descr, *dest, *src;
     unsigned	destlen;
{
    if (expand_env(dest, src, destlen) != 0) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCannotInitErrorExpanding,
			  "Cannot initialize \"%s\" - error expanding \"%s\"."),
		  descr, src);
	errors++;
	dest[0] = '\0';
    }
}

static void do_expand_meta P_((char  *descr, char *dest, char *src,
			      unsigned	destlen));
static void do_expand_meta(descr, dest, src, destlen)
    char	*descr, *dest, *src;
    unsigned	destlen;
{
    if (expand_meta(dest, src, destlen) != 0) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCannotInitErrorExpanding,
			  "Cannot initialize \"%s\" - error expanding \"%s\"."),
		  descr, src);
	errors++;
	dest[0] = '\0';
    }
}

static void expand_map_bin P_((char  *descr, char *dest, char *src,
			      unsigned	destlen));
static void expand_map_bin(descr, dest, src, destlen)
    char	*descr, *dest, *src;
    unsigned	destlen;
{
    if (strcmp(src,"none") == 0 || src[0] == '\0') {
	
	strfcpy(dest,"none",destlen);
	
    } else if (NULL == strpbrk(src,"/$\\;{}()")) {

	/* give_dt_estr_as_str adds / to end */
	char * map_bindir_val = give_dt_estr_as_str(&map_bindir_e,
						    "map-bin-dir");

	if (!map_bindir_val) {
	    dest[0] = '\0';
	    return;
	}

	if (0 != access(map_bindir_val,ACCESS_EXISTS)) {
	    int err = errno;
	    lib_error(CATGETS(elm_msg_cat, ElmSet,ElmNoBinMapDirX,
			      "%s: no map-bin-dir exist: %s: %s"),
		      descr,
		      map_bindir_val,error_description(err));
	    
	    /* No error counter incrementging because 
	       map-bin-dir can be modified only on system 
	       elm.rc
	    */
	}
	elm_sfprintf(dest,destlen,
		     FRM("%s/%s"),
		     map_bindir_val,src);
	
    } else
	do_expand_meta(descr, dest, src, destlen);


    DPRINT(Debug,10,(&Debug, "%s expanded: %s => %s (destlen %d)\n",
		     descr,src,dest,destlen));


}

/* sets locale and elm_msg_cat */
static int locale_init_called = 0;
static int locale_error = 0;


void locale_init () {
#ifdef I_LOCALE
    char *res;
#endif
    
    DPRINT(Debug,9,(&Debug, 
		    "locale_init: called = %d\n",
		    locale_init_called));
    
#ifdef I_LOCALE

    if (setlocale(LC_ALL, "") == NULL) {
	lib_error(FRM("Elm: Unsupported locale (check $LANG)\n"));
	if (setlocale(LC_CTYPE,"") != NULL) {
	    lib_error(FRM("Elm: ... but succeed setting of LC_CTYPE\n"));
	} else {
	    lib_error(FRM("Elm: ... check also $LC_CTYPE\n"));
	}
	locale_error = 1;
    }
#endif
  
    /* WARNING: Elm's version uses 0 as failure
     *  System uses (nl_catd) -1 as failure !
     */


    elm_msg_cat       = catopen("elm2.4me+", 0);
    if (0            == elm_msg_cat ||
	(nl_catd) -1 == elm_msg_cat) {
	DPRINT(Debug,9,(&Debug, 
			"locale_init: catopen elm2.4me+ failed\n"));
    }
    /* NOTE:    elm_msg_cat    'leaks' on end of program   ... */

#ifdef  I_LOCALE
    res = setlocale(LC_CTYPE,NULL);
    if (!res) {
	lib_error(FRM("Elm: Unable to get current locale (LC_CTYPE)\n"));
	locale_error = 1;
    } else
	strfcpy(display_locale,res, sizeof display_locale);
#endif
  
#ifdef HAVE_CODESET
    res = nl_langinfo(CODESET);

  if (!res) {
      lib_error(FRM("Elm: Unable to get CODESET for current locale\n"));
      locale_error = 1;
  } else	  
      strfcpy(display_codeset,res, sizeof display_codeset);
#endif

  locale_init_called++;
}

enum matches { match_exact = 0, 
	       match_codeset,
	       match_charset, 
	       match_lang_country, match_lang, MATCH_COUNT };

struct charset_map_item  * system_charset_map = NULL;
struct charset_map_item  * user_charset_map   = NULL;

static void map_system_charset P_((CONST char * lc_ctype, CONST char * codeset));
static void map_system_charset(lc_ctype, codeset)
     CONST char * lc_ctype;
     CONST char * codeset;
{  
    CONST char *lang = NULL;
    CONST char *lang_country = NULL;
    CONST char *charset = NULL;
    charset_t d_matches[MATCH_COUNT];
    int i,j;

    char * default_system_charset = DEFAULT_SYSTEM_CHARSET;
    char * c1;

    char lbuf[3], cbuf[6];

    if (!getenv("NOMETAMAIL") && (c1 = getenv("MM_CHARSET")) &&
	c1[0]) {

	default_system_charset  = c1;
	DPRINT(Debug,9,(&Debug, 
			"map_system_charset: using $MM_CHARSET (%s) as default system charset\n",
			default_system_charset));
    }

    for (i = 0; i < MATCH_COUNT; i++)
	d_matches[i] = NULL;

    if (isascii(lc_ctype[0]) && isalpha(lc_ctype[0]) &&
	isascii(lc_ctype[1]) && isalpha(lc_ctype[1]) &&
	('.' == lc_ctype[2] || '_' == lc_ctype[2] || '\0' == lc_ctype[2])) {
	strncpy(lbuf,lc_ctype,3);
	lbuf[2] = '\0';
	lang = lbuf;
	
	if ('_' == lc_ctype[2]) {
	    if (isascii(lc_ctype[3]) && isalpha(lc_ctype[3]) &&
		isascii(lc_ctype[4]) && isalpha(lc_ctype[4]) &&
		('.' == lc_ctype[5] || '\0' == lc_ctype[5])) {

		strncpy(cbuf,lc_ctype,6);
		cbuf[5] = '\0';
		lang_country = cbuf;
		
		if ('.' == lc_ctype[5])
		    charset = lc_ctype+6;
	    }
	} else if ('.' == lc_ctype[2])
	    charset = lc_ctype+3;      
    }
    
    if (codeset[0]) {
	DPRINT(Debug,10,(&Debug,
			 "map_system_charset: codeset: %s\n", 
			 codeset));
	d_matches[match_codeset] = codeset_name_to_charset(codeset);
	if (!d_matches[match_codeset]) {
	    DPRINT(Debug,1,(&Debug,
			    "map_system_charset: codeset name %s unknown!\n",codeset)); 
	}
    }

    if (lang) {
	DPRINT(Debug,10,(&Debug,
			 "map_system_charset: %s -> lang: %s\n", 
			 lc_ctype,lang));
    } 
    if (lang_country) {
	DPRINT(Debug,10,(&Debug,
			 "map_system_charset: %s -> lang_country: %s\n", 
			 lc_ctype,lang_country));
    }
    if (charset) {
	DPRINT(Debug,10,(&Debug,
			 "map_system_charset: %s -> charset: %s\n", 
			 lc_ctype,charset));
    }

    for (i = 0; i < 3; i++) {
	if ( i < 2) {
	    int k;
	    struct charset_map_item * F = user_charset_map;
	    if (1 == i)
		F = system_charset_map;

	    if (!F)
		continue;

	    for (k = 0; F[k].charset; k++) {
		if (F[k].match) {
		    if (istrcmp (F[k].match, lc_ctype) == 0) {
			d_matches[match_exact] = F[k].charset;
			
			DPRINT(Debug,3,(&Debug,
					"map_system_charset: user defined \"%s\" as %s\n", 
					lc_ctype, 
					d_matches[match_exact]->MIME_name ?
					d_matches[match_exact]->MIME_name :
					"<no MIME name>"));
		    }
		    if (charset && strncmp(F[k].match,"*.",2) == 0  &&
			istrcmp (F[k].match+2, charset) == 0) {
			
			d_matches[match_charset] = F[k].charset;
			
			DPRINT(Debug,3,(&Debug,
					"map_system_charset: user defined \"%s\" (*.%s) as %s\n", 
					lc_ctype, charset,
					d_matches[match_charset]->MIME_name ?
					d_matches[match_charset]->MIME_name :
					"<no MIME name>"));	      
		    }
		    if (lang_country && istrcmp (F[k].match, lang_country) == 0) {
			d_matches[match_lang_country] = F[k].charset;

			DPRINT(Debug,3,(&Debug,
					"map_system_charset: user defined \"%s\" (%s) as %s\n", 
					lc_ctype, lang_country, 
					d_matches[match_lang_country]->MIME_name ?
					d_matches[match_lang_country]->MIME_name :
					"<no MIME name>")); 
			
		    }
		    
		    if (lang_country && istrcmp (F[k].match, lang) == 0) {
			d_matches[match_lang] = F[k].charset;
			
			DPRINT(Debug,3,(&Debug,
					"map_system_charset: user defined \"%s\" (%s) as %s\n", 
					lc_ctype, lang, 
					d_matches[match_lang]->MIME_name ?
					d_matches[match_lang]->MIME_name :
					"<no MIME name>"));
		    }
		}
	    }

	    for (j = 0; j < MATCH_COUNT; j++)
		if (d_matches[j]) {
		    system_charset = d_matches[j];
		  
		    DPRINT(Debug,3,(&Debug,
				    "map_system_charset: using match %d: \"%s\" (codeset \"%s\") as %s\n", 
				    j,lc_ctype,codeset,
				    system_charset->MIME_name ?
				    system_charset->MIME_name :
				    "<no MIME name>"));
		    return;
		}
	} else {
	    int val;
	    char buffer[STRING];
	
	    if (d_matches[match_codeset]) {
		system_charset = d_matches[match_codeset];
		DPRINT(Debug,3,(&Debug,
				"map_display_charset: using match codeset: \"%s\" (codeset \"%s\") as %s\n", 
				lc_ctype,codeset,
				system_charset->MIME_name ?
				system_charset->MIME_name :
				"<no MIME name>"));
		return;
	    }
  
	    /*  1) ------ guess based on codeset ------------------------ */

	    if (codeset[0] &&
		     0 == strincmp(codeset,"ISO-8859-",9) &&
		     0 < (val = atoi(codeset+9))) {
		elm_sfprintf(buffer, sizeof buffer,
			     FRM("ISO-8859-%d"),
			     val);
		system_charset = MIME_name_to_charset(buffer,
						      CHARSET_create);
	    } else if (codeset[0] &&
		       0 == strincmp(codeset,"ISO_8859-",9) &&
		       0 < (val = atoi(codeset+9))) {
		elm_sfprintf(buffer, sizeof buffer,
			     FRM("ISO-8859-%d"),
			     val);
		system_charset = MIME_name_to_charset(buffer,
						      CHARSET_create);
	    } else if (codeset[0] &&
		       0 == strincmp(codeset,"ISO8859-",8) &&
		       0 < (val = atoi(codeset+8))) {
		elm_sfprintf(buffer, sizeof buffer,
			     FRM("ISO-8859-%d"),
			     val);
		system_charset = MIME_name_to_charset(buffer,
						      CHARSET_create);
	    } else if (codeset[0] &&
		       0 == strincmp(codeset,"ISO8859",7) &&
		       isascii(codeset[7]) && isdigit(codeset[7]) && 
		       '\0' == codeset[8]) {
		elm_sfprintf(buffer, sizeof buffer,
			     FRM("ISO-8859-%c"),
			     codeset[7]);
		system_charset = MIME_name_to_charset(buffer,
						      CHARSET_create);

	    /*  2) ------ guess based on lc_ctype ------------------------ */

	    } else if (0 == strcmp(lc_ctype,"C"))
		system_charset = MIME_name_to_charset("US-ASCII",
						      CHARSET_create); 
	    else if (0 == istrcmp(lc_ctype,"ASCII") ||
		     0 == istrcmp(lc_ctype,"US-ASCII"))
		system_charset = MIME_name_to_charset("US_ASCII",
						      CHARSET_create);
	    else if (0 == strincmp(lc_ctype,"ISO-8859-",9) &&
		     0 < (val = atoi(lc_ctype+9))) {
		elm_sfprintf(buffer, sizeof buffer,
			     FRM("ISO-8859-%d"),
			     val);
		system_charset = MIME_name_to_charset(buffer,CHARSET_create);
	    } else if (0 == strincmp(lc_ctype,"ISO_8859-",9) &&
		       0 < (val = atoi(lc_ctype+9))) {
		elm_sfprintf(buffer, sizeof buffer,
			     FRM("ISO-8859-%d"),
			     val);
		system_charset = MIME_name_to_charset(buffer,CHARSET_create);
	    } else if (0 == strincmp(lc_ctype,"ISO8859-",8) &&
		       0 < (val = atoi(lc_ctype+8))) {
		elm_sfprintf(buffer, sizeof buffer,
			     FRM("ISO-8859-%d"),
			     val);
		system_charset = MIME_name_to_charset(buffer,CHARSET_create);

	    /*  3) ------ guess based on charset part of locale ------------------------ */

	    } else if (charset && (0 == istrcmp(charset,"ASCII") ||
				   0 == istrcmp(charset,"US-ASCII")))
		system_charset = MIME_name_to_charset("US-ASCII",
						      CHARSET_create);
	    else if (charset &&
		     0 == strincmp(charset,"ISO-8859-",9) &&
		     0 < (val = atoi(charset+9))) {
		elm_sfprintf(buffer, sizeof buffer,
			     FRM("ISO-8859-%d"),
			     val);
		system_charset = MIME_name_to_charset(buffer,
						      CHARSET_create);
	    } else if (charset &&
		       0 == strincmp(charset,"ISO_8859-",9) &&
		       0 < (val = atoi(charset+9))) {
		elm_sfprintf(buffer, sizeof buffer,
			     FRM("ISO-8859-%d"),
			     val);
		system_charset = MIME_name_to_charset(buffer,
						      CHARSET_create);
	    } else if (charset &&
		       0 == strincmp(charset,"ISO8859-",8) &&
		       0 < (val = atoi(charset+8))) {
		elm_sfprintf(buffer, sizeof buffer,
			     FRM("ISO-8859-%d"),
			     val);
		system_charset = MIME_name_to_charset(buffer,
						      CHARSET_create);
	    } else if (charset &&
		       0 == strincmp(charset,"ISO8859",7) &&
		       isascii(charset[7]) && isdigit(charset[7]) && 
		       '\0' == charset[8]) {
		elm_sfprintf(buffer, sizeof buffer,
			     FRM("ISO-8859-%c"),
			     charset[7]);
		system_charset = MIME_name_to_charset(buffer,
						      CHARSET_create);
	    } else {
	      
		lib_error(FRM("Elm: Unable to map %.20s locale (LC_CTYPE) to MIME charset."),
			  lc_ctype);

		if (codeset[0]) {
		    system_charset = MIME_name_to_charset(codeset,
							  CHARSET_create);
		    lib_error(FRM("     Codeset name %s was unknown. Treating %s as MIME name."),
			      codeset,codeset);
		    lib_error(FRM("     Check %.100s or %.100s"),
			      system_mime_charsets, user_mime_charsets);

		} else {
		    system_charset = MIME_name_to_charset(default_system_charset,
							  CHARSET_create);
		    lib_error(FRM("     Using default (%.20s). Check %.100s or\n      %.100s"),
			      default_system_charset,system_mime_charsets,
			      user_mime_charsets);
		}
		locale_error = 1;
	    }

	    DPRINT(Debug,3,(&Debug,
			    "map_display_charset: default \"%s\" as \"%s\"\n", 
			    lc_ctype, system_charset->MIME_name));
	}
    }
}

/* shell value from passwd */
static char shell0[STRING] = "";

void user_init() 
{
    char *cp;
    int r;
    
    /** initialize the whole ball of wax.
     **/
    struct passwd *pass;
    
    if (!locale_init_called)
	locale_init ();
    
    /* save original user and group ids */
    userid  = getuid();
    groupid = getgid();	
    
    /* GNU library seems give _SC_SAVED_IDS as enumerated
       value instead of #define so we can not test if
       it is defined (as macro)
    */
#if defined(_SC_SAVED_IDS) || defined(_POSIX_VERSION)
    r = sysconf(_SC_SAVED_IDS);
    if (r < 0) {
	int err = errno;
	DPRINT(Debug,1,(&Debug,
			"sysconf(_SC_SAVED_IDS) failed: (errno=%d) %s\n",
			err,error_description(err)));	
	    
	have_saved_ids = 0;
    } else {
	have_saved_ids = r > 0;
	DPRINT(Debug,1,(&Debug,
			"*** have_saved_ids=%d\n",have_saved_ids));
    }
#else
    have_saved_ids = 0;
#endif
    mailgroupid = getegid();
    
    /* Get username (logname), home (login directory), and full_username
     * (part of GCOS) field from the password entry for this user id.
     * Full_username will get overridden by fullname in elmrc, if defined.
     *
     * For those sites that have various user names with the same user
     * ID, use the passwd entry corresponding to the user name as long 
     * as it matches the user ID.  Otherwise fall back on the entry 
     * associated with the user ID alone.
     */

    if((cp = getenv("LOGNAME")) == NULL)
	cp = getenv("USER");
    if(cp != NULL && (pass = getpwnam(cp)) != NULL &&
       pass->pw_uid == userid) {
	;  /* Null body */
    } else if((pass = getpwuid(userid)) == NULL) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmYouHaveNoPasswordEntry,
			  "You have no password entry!"));
	exit(1);
    }

    strfcpy(username, pass->pw_name, sizeof username);

    if (pass->pw_dir)
	strfcpy(home, pass->pw_dir, sizeof home);
    else if (NULL != (cp = getenv("HOME")))
	strfcpy(home,cp,sizeof home);
    else
	strfcpy(home,"/",sizeof home);
    
    if (pass->pw_shell)
	strfcpy(shell0, pass->pw_shell, sizeof shell0);

    /* Null shell in /etc/passwd means /bin/sh */
    if ('\0' == shell0[0]) 
	strfcpy(shell0, "/bin/sh", sizeof shell0);

    
    if((cp = get_full_name(username)) != NULL)
	strfcpy(full_username, cp, sizeof full_username);
    else
	strfcpy(full_username, username, sizeof full_username);	
    /* fall back on logname */

    elm_sfprintf(user_rc_file, sizeof user_rc_file,
		 FRM("%s/%s"), home, ELMRCFILE);
    elm_sfprintf(user_text_file, sizeof user_text_file,
		 FRM("%s/%s"), home, USER_ALIAS_TEXT);
    elm_sfprintf(user_data_file, sizeof user_data_file,
		 FRM("%s/%s"), home, USER_ALIAS_DATA);
    elm_sfprintf(user_mime_types, sizeof user_mime_types,
		 FRM("%s/%s"), home, USER_MIME_TYPES);
    elm_sfprintf(user_mailheaders, sizeof user_mailheaders,
		 FRM("%s/%s"), home, MAILHEADERS);
    elm_sfprintf(user_mime_charsets, sizeof user_mime_charsets,
		 FRM("%s/%s"), home, USER_MIME_CHARSETS);
    elm_sfprintf(user_iso2022_sets, sizeof user_iso2022_sets,
		 FRM("%s/%s"), home, USER_ISO2022_SETS);
    elm_sfprintf(user_terminal_info, sizeof user_terminal_info,
		 FRM("%s/%s"), home, USER_TERMINAL_INFO);
    elm_sfprintf(user_mail_services, sizeof user_mail_services,
		 FRM("%s/%s"), home, USER_MAIL_SERVICES);

#if DEBUG    
    /* Open debug files and print spooled debug output */
    debug_user_init();
#endif
}

#ifdef I_NETDB
/* Seems that h_errno is macro on AIX */
#ifndef h_errno
extern int h_errno;
#endif
#endif

static int figure_domain P_((void));
static int figure_domain() 
{
#ifdef I_NETDB
    if (hostname[0]) {
	struct hostent *he = gethostbyname(hostname);
	if (!he) {
	    DPRINT(Debug,3,(&Debug,
			    "figure_domain: %s: h_errno=%d\n",
			    hostname,h_errno));
	    switch(h_errno) {
	    case TRY_AGAIN:
		lib_error(CATGETS(elm_msg_cat, MeSet,MeTemporary,
				  "Address for %s is not yet found..."),
			  hostname);
	    }
	} else {
	    int ok = 0;
	    int idx;
	    char *p;
	    if (NULL != (p = 
			 strchr(he->h_name ,'.'))) {
		if (!hostdomain[0])
		    strfcpy(hostdomain,p,sizeof hostdomain);
		if (!hostfullname[0]) 
		    strfcpy(hostfullname, he->h_name, sizeof hostfullname);
		ok = 1;
	    } 
	    for (idx = 0; !ok && he->h_aliases[idx]; idx++) 
		if (NULL != (p = 
			     strchr(he->h_aliases[idx],'.'))) {
		    if (!hostdomain[0])
			strfcpy(hostdomain,p,sizeof hostdomain);
		    if (!hostfullname[0]) 
			strfcpy(hostfullname, he->h_aliases[idx], 
				sizeof hostfullname);
		    ok = 1;
		} 
	    if (ok) {
		DPRINT(Debug,3,(&Debug,
				"hostname=\"%s\" -> hostdomain=\"%s\", hostfullname=\"%s\"\n",
				hostname,hostdomain,hostfullname));
	    }
	    return ok;
	}
    }
#endif    
    return 0;
}

static void generate_hostfullname P_((void));
static void generate_hostfullname() 
{
    int hostlen, domlen;

    /*
     * now the tough part:
     *	we need to make three variables out of this stuff:
     *	hostname = just the hostname, as in bangpaths,
     *		this is whatever the user gave us so far,
     *		we wont change this one
     *	hostdomain = this is the domain considered local to this
     *		machine, and should be what we got above.
     *	hostfullname = this is the full FQDN of this machine,
     *		and is a strange combination of the first two.
     *	if tail(hostname) == hostdomain
     *		then hostfullname = hostname
     *			ie: node.ld.domain.type, ld.domain.type -> node.ld.domain.type
     *	else if hostname == hostdomain + 1
     *		then hostfullname = hostname
     *			ie: domain.type, .domain.type -> domain.type
     *	
     *	else hostfullname = hostname + hostdomain
     *			ie: host, .domain.type -> host.domain.type
     * lost yet?
     */
    
    DPRINT(Debug,3,(&Debug,
		    "hostname=\"%s\",hostdomain=\"%s\" ",
		    hostname,hostfullname));
    
    hostlen = strlen(hostname);
    domlen = strlen(hostdomain);
    if (hostlen >= domlen) {
	if (istrcmp(&hostname[hostlen - domlen], hostdomain) == 0)
	    strfcpy(hostfullname, hostname, sizeof hostfullname);
	else {
	    strfcpy(hostfullname, hostname, sizeof hostfullname);
	    strfcat(hostfullname, hostdomain, sizeof hostfullname);
	}
    } else {
	if (istrcmp(hostname, hostdomain + 1) == 0)
	    strfcpy(hostfullname, hostname, sizeof hostfullname);
	else {
	    strfcpy(hostfullname, hostname, sizeof hostfullname);
	    strfcat(hostfullname, hostdomain, sizeof hostfullname);
	}
    }
    
    DPRINT(Debug,3,(&Debug,
		    "-> hostfullname=\"%s\"\n",
		    hostfullname));
}

static int init_defaults_called = 0;

static init_default_hook **hooklist = NULL;
static int                hooklist_len = 0;

void add_init_default_hook(hook)
     init_default_hook *hook;
{

    if (init_defaults_called) {
	hook(&errors);
    }

    hooklist = safe_realloc(hooklist,(hooklist_len+1) * sizeof(hooklist[0]));

    hooklist[hooklist_len] = hook;
    hooklist_len++;
}

int init_defaults() {
    char     *cp;
    FILE * file;
#ifdef DOUNAME
    struct utsname u_name;
#endif
    int i;

    /* Establish some defaults in case elmrc is incomplete or not there.
     * Defaults for other elmrc options were established in their
     * declaration - in elm.h.  And defaults for sent_mail and recvd_mail
     * are established after the elmrc is read in since these default
     * are based on the folders directory name, which may be given
     * in the emrc.
   */
    

    if (init_defaults_called) {
	DPRINT(Debug,1,(&Debug,"init_defaults called twice!!\n"));	
    }
    init_defaults_called = 1;

    errors = 0;

    /*
     * Get the host name as per configured behavior.
     */

#ifdef GETHOSTNAME
    if (-1 == gethostname(hostname, sizeof(hostname))) {
	int err = errno;
	DPRINT(Debug,1,(&Debug,
			"gethostname failed: (errno=%d) %s\n",
			err,error_description(err)));	
    } else {
	DPRINT(Debug,3,(&Debug,
			"gethostname: Setting hostname to %s\n",
			hostname));
    }
#endif   
   
#ifdef DOUNAME
    if (-1 == uname(&u_name)) {
	int err = errno;
	DPRINT(Debug,1,(&Debug,
			"uname failed: (errno=%d) %s\n",
			err,error_description(err)));	
	
    } else if (!hostname[0]) {
	strfcpy(hostname, u_name.nodename, sizeof hostname);
	DPRINT(Debug,3,(&Debug,
			"uname: Setting hostname to %s\n",
			hostname));
    }
#endif

    if (!hostname[0]) {
	DPRINT(Debug,1,(&Debug, 
			"Default host name is not available\n"));
    }
    
    /*
     * now get the domain name, used to build the full name
     */
    if (!figure_domain()) {
	if (gethostdomain(hostdomain, sizeof(hostdomain)) <0) {
	    	DPRINT(Debug,1,(&Debug, 
				"Default domain name is not available\n"));
		hostdomain[0] = '\0';
	} else if (hostname[0] && hostdomain[0]) {
	    generate_hostfullname();
	}
    }
    
    /* Determine the default mail file name.
     * 
     * First look for an environment variable MAIL, then
     * use then mailhome if it is not found
     */
    
    {
	char *X = elm_message(FRM("%s%s"), mailhome, username);
	set_dt_estr(&defaultfile_e,X,"MAIL");
	free(X);
    }

    allowed_precedences[0] = '\0';
    /* no defaults for those */


    set_dt_estr(&shell_e,shell0,"SHELL");
    /* Shell is set from /etc/passwd in user_init () */
      
#ifdef USE_BUILTIN_PAGER
    set_dt_estr(&pager_e, "builtin++", NULL);
#else
    set_dt_estr(&pager_e,default_pager,"PAGER");
#endif    

    set_dt_estr(&temp_dir_e,default_temp,"TMPDIR");
    set_dt_estr(&editor_e,default_editor,"EDITOR");

    if ((cp = getenv("MAILCAPS")) == NULL) {
	/* RFC 1524:

   For UNIX, a path search of mailcap files is specified.  The default
   path search is specified as including at least the following:

   $HOME/.mailcap:/etc/mailcap:/usr/etc/mailcap:/usr/local/etc/mailcap

	*/
	char *X[] = { "/etc/mailcap", "/usr/etc/mailcap",
		     "/usr/local/etc/mailcap", NULL };
	char *G = elm_message(FRM("%s/.mailcap"),home);
	char **X1;
	
	/* Fake recursive call -- expand_dt_path ignores non-existiant
	   entries.
	 */
	DPRINT(Debug,9,(&Debug,
			"Adding default entry to metamail-mailcaps: %s\n",
			G));
	expand_dt_path(&metamail_mailcaps,"metamail-mailcaps",
		       G,2);
	for (X1 = X; *X1; X1++) {
	    DPRINT(Debug,9,(&Debug,
			    "Adding default entry to metamail-mailcap: %s\n",
			    *X1));
	    expand_dt_path(&metamail_mailcaps,"metamail-mailcaps",
			   *X1,2);	    
	}


	DPRINT(Debug,9,(&Debug,
			"Adding default entry to internal-mailcaps: %s\n",
			G));
	expand_dt_path(&internal_mailcaps,"internal-mailcaps",
		       G,2);
	for (X1 = X; *X1; X1++) {
	    DPRINT(Debug,9,(&Debug,
			    "Adding default entry to internal-mailcap: %s\n",
			    *X1));
	    expand_dt_path(&internal_mailcaps,"internal-mailcaps",
			   *X1,2);	    
	}
	
	free(G);
    } else {
	DPRINT(Debug,9,(&Debug,
			"Adding unexpanded entry to metamail-mailcaps: $MAILCAPS\n"
			));

	metamail_mailcaps.unexpanded = safe_strdup("$MAILCAPS");


	DPRINT(Debug,9,(&Debug,
			"Adding unexpanded entry to internal-mailcaps: $MAILCAPS\n"
			));

	internal_mailcaps.unexpanded = safe_strdup("$MAILCAPS");
    }

    folders_e.unexpanded    = elm_message(FRM("~/%s"), default_folders);
    map_txtdir_e.unexpanded = safe_strdup("{lib}/elm.map.txt");
    map_bindir_e.unexpanded = safe_strdup("{lib}/elm.map.bin");

    readmsg_e.unexpanded = safe_strdup("{bin}/readmsg");
       
    calendar_file_e.unexpanded = 
	elm_message(FRM("~/%s"), dflt_calendar_file);

    dead_letter_dir_e.unexpanded = safe_strdup("~/Canceled.mail.dir");

    strfcpy(e_editor, emacs_editor, sizeof e_editor);
    strfcpy(v_editor, default_editor, sizeof v_editor);

#ifdef USE_PGP
    set_dt_estr(&gpg_path_e,GPG_PATH,NULL);
    set_dt_estr(&pgp2_path_e,PGP2_PATH,NULL);
    set_dt_estr(&pgp5_dir_e,PGP5_DIR,NULL);
#endif
    set_dt_estr(&metamail_path_e,METAMAIL_PATH,NULL);            
    set_dt_estr(&printout_e,DEFAULT_PRINTOUT,NULL);            

    /* try system-wide rc file */
    file = fopen(system_rc_file, "r");
    if ( file != NULL ) {
	do_rc(file, SYSTEM_RC,system_rc_file);
	fclose(file);
    } else if (!hostname[0] || !hostdomain[0] || !hostfullname[0]) {
	int err = errno;
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmFailedSystemRC,
			  "Failed to open RC file %s: %s"),
		  system_rc_file,error_description(err));    
	errors++;
    } 
    if (figure_domain()) {
	/* Do nothing */
    } else if (!hostname[0] || !hostdomain[0]) {
	if (hostfullname[0]) {
	    char * p = strchr(hostfullname,'.');
	    if (!hostname[0]) 
		strfcpy(hostname,hostfullname,sizeof hostname);
	    if (!hostdomain[0]) {
		if (p)
		    strfcpy(hostdomain,p,sizeof hostdomain);
		else 	      
		    strfcpy(hostdomain,".localdomain",sizeof hostdomain);
	    }
	} else {
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmDefineHostname,
			      "Give \"hostname\", \"hostfullname\" and \"hostdomain\" on RC file: %s"),
		      system_rc_file);
	    if (!hostname[0]) 
		strfcpy(hostname,"localhost",sizeof hostname);
	    if (!hostdomain[0]) 
		strfcpy(hostdomain,".localdomain",sizeof hostdomain);
	    if (!hostfullname[0])
		strfcpy(hostfullname,hostname,sizeof hostfullname);
	    errors++;       
	}
    } else if (!hostfullname[0]) {
	if ('.' != hostdomain[0]) {
	    char buffer[SLEN];
	    strfcpy(buffer,hostdomain,sizeof buffer);
	    strfcpy(hostdomain,".",sizeof hostdomain);
	    strfcat(hostdomain,buffer,sizeof hostdomain);
	    DPRINT(Debug,3,(&Debug,
			    "hostdomain=\"%s\" -> hostdomain=\"%s\"\n",
			    buffer,hostdomain));
	}
	generate_hostfullname();
    }

    /* Also bindata  ... notice temorary variable */
    expand_map_bin("bindata", bindata_path_global, raw_bindata_path,
		   sizeof(bindata_path));

    parse_iso2022_map(system_iso2022_sets,&errors,ml_system);
    system_charset_map = load_charset_map(system_mime_charsets,&errors);

#ifdef REMOTE_MBX
    parse_service_entries(system_mail_services,1 /* SYSTEM */,&errors);
#endif

    for (i = 0; i < hooklist_len; i++) {
	hooklist[i](&errors);
    }

    DPRINT(Debug,3,(&Debug, 
		    "init_defaults=%d (errors)\n",errors));

    return errors;
}

enum charset_keyword { cskw_none = 0, cskw_SYSTEM, cskw_DISPLAY, cskw_TEXT };

static enum charset_keyword special_charset_keyword P_((const char *value));
static enum charset_keyword special_charset_keyword(value)
     CONST char *value;
{
    if (0 == strcmp(value,"SYSTEM"))
	return cskw_SYSTEM;
    else if (0 == strcmp(value,"DISPLAY"))
	return cskw_DISPLAY;
    else if (0 == strcmp(value,"TEXT"))
	return cskw_TEXT;
    else
	return cskw_none;
}

void post_process_charset_options()
{
    switch (special_charset_keyword(raw_text_charset)) {
    case cskw_SYSTEM:   text_charset = system_charset;  break;
    case cskw_DISPLAY:  text_charset = display_charset; break;
    case cskw_TEXT:     
	text_charset = display_charset;
	strfcpy(raw_text_charset,"DISPLAY",sizeof raw_text_charset);
	break;
    }

    switch (special_charset_keyword(raw_display_charset)) {
    case cskw_SYSTEM:   wanted_display_charset = system_charset;  break;
    case cskw_DISPLAY:  wanted_display_charset = display_charset; break;
    case cskw_TEXT:     wanted_display_charset = text_charset;    break;
    }

    if (!wanted_display_charset ||
	0 == (charset_properties(wanted_display_charset) & CS_mapping)) {
	if (0 != charset_properties(system_charset)) 
	    wanted_display_charset = system_charset;
	else
	    wanted_display_charset = ASCII_SET;

	DPRINT(Debug,2,(&Debug,
			"Setting (wanted) display-charset to %s instead.\n",
			wanted_display_charset->MIME_name ?
			wanted_display_charset->MIME_name :
			"<no MIME name>"));
    }
    if (!text_charset || !text_charset->MIME_name) {
	text_charset = ASCII_SET;
	DPRINT(Debug,2,(&Debug,
			"Setting text-charset to %s instead.\n",
			text_charset->MIME_name ?
			text_charset->MIME_name :
			"<no MIME name"));
    }

    switch (special_charset_keyword(raw_local_fs_charset)) {
    case cskw_SYSTEM:   local_fs_charset = system_charset;  break;
    case cskw_DISPLAY:  local_fs_charset = display_charset; break;
    case cskw_TEXT:     local_fs_charset = text_charset;    break;
    }

    switch (special_charset_keyword(raw_default_nomime_charset)) {
    case cskw_SYSTEM:   default_nomime_charset = system_charset;  break;
    case cskw_DISPLAY:  default_nomime_charset = display_charset; break;
    case cskw_TEXT:     default_nomime_charset = text_charset;    break;
    }

    switch (special_charset_keyword(raw_default_mimetext_charset)) {
    case cskw_SYSTEM:   default_mimetext_charset = system_charset;  break;
    case cskw_DISPLAY:  default_mimetext_charset = display_charset; break;
    case cskw_TEXT:     default_mimetext_charset = text_charset;    break;
    }

#ifdef REMOTE_MBX
    switch (special_charset_keyword(raw_imap_charset)) {
    case cskw_SYSTEM:   imap_charset = system_charset;  break;
    case cskw_DISPLAY:  imap_charset = display_charset; break;
    case cskw_TEXT:     imap_charset = text_charset;    break;
    }
#endif
	
}


static init_default_hook **hooklist_rc = NULL;
static int                hooklist_rc_len = 0;

static int read_rc_file_called = 0;

void add_read_rc_file_hook(hook)
     init_default_hook *hook;
{

    if (read_rc_file_called) {
	hook(&errors);
    }

    hooklist_rc = safe_realloc(hooklist_rc,
			       (hooklist_rc_len+1) * sizeof(hooklist_rc[0]));

    hooklist_rc[hooklist_rc_len] = hook;
    hooklist_rc_len++;
}



int read_rc_file(flag)
     int flag;
{
    /** this routine does all the actual work of reading in the
	.rc file... **/

    int err;
    int i;

    errors = 0;
    
    if (read_rc_file_called) {
	DPRINT(Debug,1,(&Debug,"read_rc_file called twice!\n"));
    }
    read_rc_file_called = 1;

    /* Look for the elmrc file */
    err = can_open(user_rc_file, "r");
    if (err) {
	DPRINT(Debug,2,(&Debug,
			"Warning:User has no \"%s\" file (can_open)\n\n",
			user_rc_file));

    } else {
	FILE *file = NULL;
    
	if ((file = fopen(user_rc_file, "r")) == NULL) {
	    DPRINT(Debug,2,(&Debug,
			    "Warning:Open \"%s\" failed\n\n",
			user_rc_file));
	    
	}
    
	if (file != NULL) {
	    do_rc(file, LOCAL_RC, ELMRCFILE);
	    fclose(file);
	}
    }


    /* Also bindata  ... */
    expand_map_bin("bindata", bindata_path, raw_bindata_path,
		   sizeof(bindata_path));

    parse_iso2022_map(user_iso2022_sets,&errors, ml_user);
    user_charset_map   = load_charset_map(user_mime_charsets,&errors);

#ifdef REMOTE_MBX
    parse_service_entries(user_mail_services,0 /* USER */,&errors);
#endif 

    for (i = 0; i < hooklist_rc_len; i++) {
	hooklist_rc[i](&errors);
    }


    post_init_check(flag);
    
    DPRINT(Debug,3,(&Debug, 
		    "read_rc_file=%d (errors)\n",errors));

    return errors;
}

void post_init_check(flag) 
     int flag; 
{

    struct stat st_buffer;
    char *t, *t1;

    t  = give_dt_estr_as_str(&folders_e,"maildir");
    t1 = give_dt_estr_as_str(&extra_mailbox_dir_e,
			     "extra-mailbox-dir");
       
    if (t1 && t && 0 == strcmp(t1,t)) {
	errors++;
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmExtraNoFolders,
			  "\"extra-mailbox-dir\" should not be \"folders\" or \"maildir\" directory."));	    

	free(extra_mailbox_dir_e.unexpanded);
	extra_mailbox_dir_e.unexpanded = NULL;

	mark_local_changed(& extra_mailbox_dir_e);
    }

    t = give_dt_estr_as_str(&dead_letter_dir_e,"dead-letter-dir");
			    
    /* dead-letter-dir is create automatically, if it does not exists */
    if (t &&
	0 == stat(t,&st_buffer) &&
#ifdef S_ISDIR
	!S_ISDIR(st_buffer.st_mode)
#else
	S_IFDIR != (st_buffer.st_mode & S_IFMT)
#endif
	) {
	errors++;
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadDeadLetterDir,
			  "\"dead-letter-dir\" should be directory."));

	free(dead_letter_dir_e.unexpanded);
	dead_letter_dir_e.unexpanded = NULL;

	mark_local_changed(& dead_letter_dir_e);
    }

    
    if (! attachment_dir_e.unexpanded) {
	char * tmp = elm_message(FRM("%s/Documents"),home);
	
	if (0 == access(tmp,ACCESS_EXISTS)) {
	    attachment_dir_e.expanded = tmp;
	    attachment_dir_e.unexpanded = safe_strdup("~/Documents");

	} else
	    free(tmp);
    } 
                      
    allow_forms = (allow_forms?MAYBE:NO);
    
    if ((elm_timeout != 0) && (elm_timeout < 10)) {
	errors++;
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmTimeoutLTTen,
			  "Warning: timeout is set to less than 10 seconds. Ignored."));
	elm_timeout = 0;
    }
    
    if (readdatapercentinc < 1) {
	errors++;
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmReadDataIncrement,
			  "Warning: readdatapercentinc is set to less than 1.  Ignored."));
	readdatapercentinc = 1;

	mark_local_changed(& readdatapercentinc);
    }

    if (readmsginc < 1) {
	errors++;
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmReadMessageIncrement,
			  "Warning: readmsginc is set to less than 1.  Ignored."));
	readmsginc = 1;

	mark_local_changed(& readmsginc);
    }

    if (sleepmsg < 0) {
	errors++;
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmSleepMessageInvalid,
			  "Warning: sleepmsg is set to less than 0.  Setting to 0."));
	sleepmsg = 0;

	mark_local_changed(& sleepmsg);
    }
    
#ifdef BACKGROUD_PROCESSES       
    if (background_wait_time  < 0) {
	errors++;
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBackgroundLLT,
			  "Warning: background_wait_time is set less than 0. Setting to 0."));
	background_wait_time = 0;

	mark_local_changed(& background_wait_time); 
    }
#endif
    
    
    /* If recvd_mail or sent_mail havent't yet been established in
     * the elmrc, establish them from their defaults.
     * Then if they begin with a metacharacter, replace it with the
     * folders directory name.
     */
    if(!recvd_mail_e.unexpanded) {
	recvd_mail_e.unexpanded = safe_strdup(default_recvdmail);
    }
    
    if(!sent_mail_e.unexpanded) {
	sent_mail_e.unexpanded  = safe_strdup(default_sentmail);
    }

    if (-1 == auto_copy_sent) {
	if (dt_estr_is_disabled(&sent_mail_e)) {
	    DPRINT(Debug,5,(&Debug,"'copy' defaults to OFF (sentmail is disabled)\n"));
	    auto_copy_sent = 0;
	} else {
	    DPRINT(Debug,5,(&Debug,"'copy' defaults to ON\n"));
	    auto_copy_sent = 1;
	}
    }


    expand_map_bin("unidata", unidata_path, raw_unidata_path,
		   sizeof(unidata_path));

    expand_map_bin("bindata", bindata_path, raw_bindata_path,
		   sizeof(bindata_path));
    
    
    map_system_charset(display_locale,display_codeset);
    
#if defined(WCHAR) && defined(__STDC_ISO_10646__)
    change_system_charset();
#endif 

    /* Current display charset is locale charset */
    display_charset = system_charset;
    
    if (!special_charset_keyword(raw_text_charset)) {

	if (! load_charset_map_info(&text_charset,
				    raw_text_charset) ) {

	    char buffer[LONG_STRING];

	    do_expand_env("text-charset", buffer, 
			  raw_text_charset, 
			  sizeof(buffer));
	    text_charset = MIME_name_to_charset(buffer,CHARSET_create);
	}

	if (!(CS_mapping & charset_properties(text_charset))) {
	    errors++;
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmUnknownTextCharset,
			      "text-charset %s is unknown, conversion to text-charset does not work"),
		      text_charset->MIME_name ? 
		      text_charset->MIME_name :
		      raw_text_charset);
	    strfcpy(raw_text_charset,"DISPLAY",sizeof raw_text_charset);
	    text_charset = display_charset;

	    mark_local_changed(& raw_text_charset);
	}        
    } 
    
    if (!special_charset_keyword(raw_display_charset)) {

	if (! load_charset_map_info(& wanted_display_charset,
				    raw_display_charset )) {

	    char buffer[LONG_STRING];
	    do_expand_env("display-charset", buffer, 
			  raw_display_charset, 
			  sizeof(buffer));
	    wanted_display_charset = MIME_name_to_charset(buffer,CHARSET_create);
	}

	if (!(CS_mapping & charset_properties(wanted_display_charset))) {
	    errors++;
	    lib_error(CATGETS(elm_msg_cat, ElmSet, 
			      ElmUnknownDisplayCharset,
			      "display-charset %s is unsupported, charset switching does not work"),
		      wanted_display_charset->MIME_name ? 
		      wanted_display_charset->MIME_name :
		      raw_display_charset);
	    strfcpy(raw_display_charset,"SYSTEM",
		    sizeof raw_display_charset);
	    wanted_display_charset = system_charset;

	    mark_local_changed(& raw_display_charset);
	}
    }

    if (!special_charset_keyword(raw_local_fs_charset)) {

	if (! load_charset_map_info(&local_fs_charset,
				    raw_local_fs_charset) ) {
	    char buffer[LONG_STRING];
	    do_expand_env("local-fs-charset", buffer, 
			  raw_local_fs_charset, 
			  sizeof(buffer));
	    local_fs_charset = MIME_name_to_charset(buffer,CHARSET_create);
	}

	if (!(CS_mapping & charset_properties(local_fs_charset))) {
	    errors++;
	    lib_error(CATGETS(elm_msg_cat, ElmSet, 
			      ElmUnknownFSCharset,
			      "local-fs-charset %s is unsupported, file access does not work"),
		      local_fs_charset->MIME_name ? 
		      local_fs_charset->MIME_name :
		      raw_local_fs_charset);
	    strfcpy(raw_local_fs_charset,"SYSTEM",
		    sizeof raw_local_fs_charset);
	    local_fs_charset = system_charset;		

	    mark_local_changed(& raw_local_fs_charset);
	}
    }
    
    if (!special_charset_keyword(raw_default_nomime_charset)) {

	if (! load_charset_map_info(& default_nomime_charset,
				    raw_default_nomime_charset) ) {
	    char buffer[LONG_STRING];

	    do_expand_env("default-nomime-charset", buffer, 
			  raw_default_nomime_charset, 
			  sizeof(buffer));
	    default_nomime_charset = MIME_name_to_charset(buffer,CHARSET_create);
	}

	if (!(CS_mapping & charset_properties(default_nomime_charset))) {
	    errors++;
	    lib_error(CATGETS(elm_msg_cat, ElmSet, 
			      ElmUnknownDef1Charset,
			      "default-nomime-charset %s is unsupported"),
		      default_nomime_charset->MIME_name ? 
		      default_nomime_charset->MIME_name :
		      raw_default_nomime_charset);

		strfcpy(raw_default_nomime_charset,"SYSTEM",
			sizeof raw_default_nomime_charset);
		default_nomime_charset = system_charset;		

		mark_local_changed(&  raw_default_nomime_charset);
	}
    }

    if (!special_charset_keyword(raw_default_mimetext_charset)) {

	if (! load_charset_map_info(& default_mimetext_charset,
				    raw_default_mimetext_charset) ) {

	    char buffer[LONG_STRING];
	    do_expand_env("default-mime-text-charset", buffer, 
			  raw_default_mimetext_charset, 
			  sizeof(buffer));
	    default_mimetext_charset = MIME_name_to_charset(buffer,CHARSET_create);
	}

	if (!(CS_mapping & charset_properties(default_mimetext_charset))) {
	    errors++;
	    lib_error(CATGETS(elm_msg_cat, ElmSet, 
			      ElmUnknownDef2Charset,
			      "default-mime-text-charset %s is unsupported"),
		      default_mimetext_charset->MIME_name ? 
		      default_mimetext_charset->MIME_name :
		      raw_default_mimetext_charset);

		strfcpy(raw_default_mimetext_charset,"US-ASCII",
			sizeof raw_default_mimetext_charset);
		default_mimetext_charset = ASCII_SET;		

		mark_local_changed(&  raw_default_mimetext_charset);
	}
    }

    
#ifdef REMOTE_MBX
    if (!special_charset_keyword(raw_imap_charset)) {

	if (! load_charset_map_info(& imap_charset,
				    raw_imap_charset) ) {

	    char buffer[LONG_STRING];
	    do_expand_env("imap-charset", buffer, 
			  raw_imap_charset, 
			  sizeof(buffer));
	    imap_charset = MIME_name_to_charset(buffer,CHARSET_create);
	}

	if (!(CS_mapping & charset_properties(imap_charset))) {
	    errors++;
	    lib_error(CATGETS(elm_msg_cat, ElmSet, 
			      ElmUnknownIMAPCharset,
			      "imap-charset %s is unsupported"),
		      imap_charset->MIME_name ? 
		      imap_charset->MIME_name :
		      raw_imap_charset);

	    strfcpy(raw_imap_charset,"SYSTEM",
		    sizeof raw_imap_charset);
	    imap_charset = system_charset;		

	    mark_local_changed(&  raw_imap_charset);
	}
    }
#endif
    
    post_process_charset_options();
    
    if (!(CS_mapping & charset_properties(system_charset))) {
	/* Don't increment errors variable because this comes
	 * from locale (via mime.charsets) and not from elmrc
	 */
	
	if (system_charset->MIME_name)
	    lib_error(CATGETS(elm_msg_cat, ElmSet, 
			      ElmUnsupportedLocale,
			      "WARNING: Locale %s (charset %s) is unsupported, will cause problems!"), 
		      display_locale,system_charset->MIME_name);
	else
	    lib_error(CATGETS(elm_msg_cat, ElmSet, 
			      ElmUnsupportedLocale2,
			      "WARNING: Locale %s is unsupported, will cause problems!"), 
		      display_locale);
	locale_error = 1;
    } 
    
    if (locale_error == 1) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, 
			  ElmLocaleProblem,
			  "Problem with locale (system character set)! Elm ME+ will behave erratically."));
	/* Long wait that message will be noticed ... */
#if POLL_METHOD	  
	wait_for_timeout(10);
#else
	sleep(10);
#endif	    
	locale_error++;
    }
    
    if (
	(
	 (wanted_display_charset != system_charset &&	     
	  0 != (CS_mapping & charset_properties(wanted_display_charset)) &&
	  (!wanted_display_charset->MIME_name ||
	   0 != istrcmp(wanted_display_charset->MIME_name,"US-ASCII")) 
#ifndef ASCII_CTYPE
	  && (!wanted_display_charset->MIME_name ||
	      0 != istrcmp(wanted_display_charset->MIME_name,"ISO-8859-1"))
#endif
	  )
	 || allow_charset_switching
	 ) &&
	0 != strcmp(unidata_path,"none")) {
	
	/* We are going to need unidata information --
	   therefore check availivility ! */
	
	if (0 == (flag & READ_FLAG_UNIDATA_INIT) 
	    &&
	    !default_unidata()) {
	    
	    lib_error(CATGETS(elm_msg_cat, ElmSet,ElmNoUnicodeData,
			      "No Unicode data available: unidata: %s"),
		      raw_unidata_path);
	    
	    errors++;
	    
	    lib_error(CATGETS(elm_msg_cat, ElmSet,ElmUnidataSetting,
			      "Setting unidata=none, displaycharset=SYSTEM, allow-charset-switching=OFF"));
	    
	    strfcpy(raw_unidata_path,"none",sizeof raw_unidata_path);
	    strfcpy(unidata_path,"none",sizeof unidata_path);
	    
	    strfcpy(raw_display_charset,"SYSTEM", 
		    sizeof raw_display_charset);
	    wanted_display_charset = system_charset;		

	    allow_charset_switching = 0;

	    mark_local_changed(& raw_unidata_path);
	    mark_local_changed(& raw_display_charset);
	    mark_local_changed(& allow_charset_switching);

	}
	
    }
    
    if (0 != strcmp(bindata_path,"none") &&
	0 != strcmp(bindata_path_global,bindata_path)) {

	if (0 == (flag & READ_FLAG_BINDATA_INIT) 
	    &&
	    !default_bindata()) {
	    
	    lib_error(CATGETS(elm_msg_cat, ElmSet,ElmBinaryMapData,
			      "No binary map data available: bindata: %s"),
		      raw_bindata_path);
	    
	    errors++;

	    strfcpy(raw_bindata_path,"none",sizeof raw_bindata_path);
	    strfcpy(bindata_path,"none",sizeof bindata_path);

	    mark_local_changed(& raw_bindata_path);
	}
    }

#ifdef USE_PGP
    if (pgp_none == give_dt_enumerate_as_int(&send_pgp_version)) {
	char * gpg_path_val  = give_dt_estr_as_str(&gpg_path_e, "gpg");
	char * pgp2_path_val = give_dt_estr_as_str(&pgp2_path_e, "pgp2");
	char * pgp5_dir_val  = give_dt_estr_as_str(&pgp5_dir_e, "pgp5-dir");

	if (gpg_path_val &&  '/' == gpg_path_val[0]) 
	    send_pgp_version.val = gpg;
	if (pgp5_dir_val && '/' == pgp5_dir_val[0]) 
	    send_pgp_version.val = pgp5;
	if (pgp2_path_val && '/' == pgp2_path_val[0]) 
	    send_pgp_version.val = pgp2;
    }
#endif
    
#ifdef USE_DLOPEN
    post_init_shared_options(&errors);
#endif
}



/* Return rest */

static char * split_keyword(buffer,line_len,keyword,size,tag,
			    assig)
     char *buffer; 
     int line_len;				
     char *keyword; 
     int size;
     char **tag;
     int *assig;
{
    int i;
    char * c;

    DPRINT(Debug,10,(&Debug,
		     "split_keyword len=%d, buffer=%s\n",
		     line_len,buffer));

    *assig = 0;

    i = 0;
    for (c = buffer; c - buffer < line_len && i < size; c++) {
	if ('_' == *c)
	    keyword[i++] = '-';
	else if (!*tag && ':' == *c) {
	    /* Mark tag from buffer */
	    *c = '\0';
	    *tag = buffer;
	    i = 0;
	} else if (!isascii(*c))
	    break;
	else if (!ok_rc_char(*c))
	    break;
	else {
	    keyword[i++] = tolower((unsigned char)*c);
	}
    }

    keyword[i] = '\0';
	
    while (whitespace(*c)) 
	c++;
    
    if ('=' == *c) {
	c++;
	*assig = 1;
    }
    while (whitespace(*c)) 
	c++;

    DPRINT(Debug,10,(&Debug,
		     "split_keyword: keyword(i=%d)=%s\n",
		     i,keyword));

    if (*tag) {
	DPRINT(Debug,10,(&Debug,
			 "split_keyword: tag=%s\n",*tag));	
    }

    DPRINT(Debug,10,(&Debug,
		     "split_keyword=%s\n",c));	

    return c;
}

static void do_rc(file, lcl, filename)
     FILE *file;
     enum record_mode lcl;
     char *filename;
{
    struct rc_save_info_rec * prev_type = NULL;
    struct hist_record      * rec       = NULL;

    char current_tag[SLEN];

    int ignored = 0;
       
    char * buffer = NULL;
    int r;  /* length of line or error/eof status */

    if (!file) 
	return;
    lineno=0;

    current_tag[0] = '\0';

    while (0 <= ( r = malloc_gets(&buffer,MAX_LINE,file))) {

	char   * tag         = NULL;
	char   keyword[SLEN], *c;
	char   * rest        = NULL;

	int    negate = 0;
	int    assig  = 0;
	int i;

	lineno++;

	if (!buffer)           /* EOF           */
	    break;

	if (buffer[0] == '#'   /* comment       */
	    || r < 1)          /* empty line    */
	    continue;
	
	
	rest = split_keyword(buffer,r,keyword, sizeof keyword,&tag,
			     &assig);

	if (tag && !keyword[0]) {
	    strfcpy(current_tag, tag, sizeof current_tag);

	    if (rest[0] && '#' != rest[0]) {
		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmIgnoredLine,
				  "Rest of line ignored after \"%s:\" on line %d on file %s"),
			  tag, lineno,filename);
		errors++;
	    }

	} else if (!keyword[0]) {
	    if (prev_type != NULL) {
		
		if (RCTYPE_magic != prev_type->dt_type->magic)
		    panic("RC PANIC",__FILE__,__LINE__,"do_rc",
			  "Bad prev_type",0);

		if (rec) {
		    rec->old_line = safe_realloc(rec->old_line,
						sizeof(rec->old_line[0]) *
						( rec->line_count + 1));
		    
		    rec->old_line [ rec->line_count ] = safe_strdup(rest);
		    rec->line_count++;
		}

		if (!prev_type->dt_type -> 
		    parse_cline(prev_type,
				lcl,
				rest,
				lineno,
				filename)) {
		    errors++;

		    /* If there was errors, then assume that rewriting
		       of elmrc entry causes it to be rewritten
		    */
		    if (rec)
			rec->changed++;
		}
	    }
	} else if (assig) {  

	    if (tag || current_tag[0]) {
		struct rc_save_info_rec * rc_options      = NULL;
		int                     rc_option_count   = 0;
		
		if (!tag) 
		    tag = current_tag;
		else
		    ignored = 0;


#ifdef USE_DLOPEN
		if (give_options(tag,&rc_options,&rc_option_count)) {
		    
		    prev_type = locate_option(rc_options,rc_option_count,
					      keyword,rest,filename,
					      &negate);
		    ignored = 0;
		    
		    if (!prev_type) {
			errors++;
			lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadKeyTagInElmrc,
					  "I can't understand keyword \"%s\" (section %s) in line %d in \"%s\" file"),
				  keyword, tag,lineno,filename);
			continue;
		    }
		    
		    
		} else if (!ignored) {
		    ignored = 1;
		    
		    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmIgnoredSection,
				      "Keywords on section \"%s\" ignored starting from line %d on file %s"),
			      tag, lineno,filename);
		    
		}
#else
		if (!ignored) {
		    ignored = 1;
		    
		    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmSharedIgnoredSection,
				      "Shared libraries not supported. Section \"%s\" ignored starting from line %d on file %s"),
			      tag, lineno,filename);
		    errors++;		
		}
#endif
		
	    } else {
		
		prev_type = locate_option(save_info,NUMBER_OF_SAVEABLE_OPTIONS,
					  keyword,rest,filename,&negate);
		
		
		
		if (!prev_type) {
		    errors++;
		    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadKeyInElmrc,
				      "I can't understand keyword \"%s\" in line %d in \"%s\" file"),
			      keyword, lineno,filename);
		    
		    continue;
		}
		
	    }
	    
	    if (!prev_type) 
		continue;

	    rec = need_record(lcl,prev_type,tag);
	    if (rec) {
		if (rec->line_count)
		    panic("RC PANIC",__FILE__,__LINE__,"do_rc",
			  "Bad prev_type",0);
		
		rec->old_line = safe_malloc(sizeof(rec->old_line[0]));
		
		rec->old_line[0] = safe_strdup(rest);
		
		rec->line_count = 1;
	    }
	    
	    if (ignored)
		continue;

	    if (prev_type->flags & FL_SYS && lcl == LOCAL_RC) {
		lib_error(CATGETS(elm_msg_cat, ElmSet, 
				  ElmBadLocalKeyInElmrc,
				  "Keyword \"%s\" is not valid on user file %s"),
			  prev_type->name,filename);
		continue;
	    }
	

	    if (!rc_eval_tail(prev_type,lcl,rest,lineno,filename,negate)) {
		errors++;

		/* If there was errors, then assume that rewriting
		   of elmrc entry causes it to be rewritten
		*/
		if (rec)
		    rec->changed++;

	    }
	} else {
	    prev_type = NULL;

	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadLineInElmrc,
			      "Keyword \"%s\" without = -character in line %d in \"%s\" file"),
		      keyword, lineno,filename);
	    errors++;
	}
    }

    if (-1 == r) {	
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmTooLongLine,
			  "%.30s: %d: Too long line: %.30s..."),
		  filename,lineno+1,
		  buffer ? buffer : "<not available>");
	errors++;
    }

    if (ferror(file)) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmErrorReading,
			  "Error reading from %.50s"),
		  filename);
	errors++;
    }

    if (buffer)
	free(buffer);

}

/*
 * set the named parameter according to save_info structure.
 * This routine may call itself (DT_SYN or DT_MLT).
 * Also tags params that were set in "local" (personal) RC file
 * so we know to save them back out in "o)ptions" screen.
 * Uses an internal table to decode sort-by params...should be coupled
 * with sort_name(), etc...but...
 */

/* read_rc.c. -- return NULL on failure 
                 otherwise pointer to option
 */


static struct rc_save_info_rec *locate_option(rc_options,rc_option_count,
    word1,word2,filename,negate)
     struct rc_save_info_rec * rc_options;
     int                       rc_option_count;
     char *word1; 
     char *word2;
     char *filename;
     int *negate;
{
    int x, y = 0;


    if ('!' == *word1) {
	(*negate)++;
	word1++;
    }

    for (x=0; x < rc_option_count; ++x) {
	y = strcmp(word1, rc_options[x].name);
	if (y <= 0)
	    break;
    }

    if (y != 0)
	return NULL;

    return & (rc_options[x]);
}

int rc_eval_tail(ret,lcl,value,lineno,filename,negate)
     struct rc_save_info_rec *ret;
     int lcl;
     char *value;
     int lineno; 
     char *filename; 
     int negate;
{

    if (lcl == LOCAL_RC)
	ret->flags |= FL_LOCAL;
    ret->flags |= FL_CHANGED;
    
    if (RCTYPE_magic != ret->dt_type->magic)
	panic("RC PANIC",__FILE__,__LINE__,"rc_eval_tail",
	      "Bad config item type",0);
    
    if (! ret->dt_type->parse_line(ret,
				   lcl,
				   value,
				   lineno,
				   filename,
				   negate))
	return 0;

    return 1;
}

struct rc_save_info_rec * do_set(lcl, word1, word2, filename)
     int lcl;
     char *word1, *word2;
     char *filename;
{
    int negate = 0;

    struct rc_save_info_rec * ret =  locate_option(save_info,
						   NUMBER_OF_SAVEABLE_OPTIONS,
						   word1,word2,filename,
						   &negate);

    if (!ret) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadKeyInElmrc,
			  "I can't understand keyword \"%s\" in line %d in \"%s\" file"),
		  word1, lineno,filename);
	
	return NULL;
    }

    
    if (!rc_eval_tail(ret,lcl,word2,lineno,filename,negate))
	return NULL;

    return ret;
}

static CONST char WEED_NO_DEFAULT[] = "*clear-weed-list*";
	

int matches_weedlist(buffer)
     char *buffer;
{
	/** returns true iff the first 'n' characters of 'buffer' 
	    match an entry of the weedlist **/
	
	int i;

	static char *default_list[] = 
	    { ">From", "In-Reply-To:",
	      "References:", "Newsgroups:", "Received:",
	      "Apparently-To:", "Message-Id:", "Content-Type:",
	      "Content-Length:", "MIME-Version:",
	      "Content-Transfer-Encoding:",
	      "From", "X-Mailer:", "Status:",
	      "X-ELM-",
	      "X-UIDL", /* Generated by some POP deamons */ 
	      "Return-Path:",
	      "List-ID:", 
	      "List-Help:", "List-Subscribe:", "List-Unsubscribe:",
	      "List-Post:", "List-Owner:", "List-Archive:",
	      "*end-of-defaults*", NULL
	    };

	char **list = give_dt_path_as_elems(&weedlist,"weedout");

	/* If fist elem is "*clear-weed-list*" then default list is not 
	   used
	*/

	if (!list || !list[0] ||
	    0 != strcmp(list[0],WEED_NO_DEFAULT)) {
	    

	    for (i = 0; default_list[i]; i++) {
		if (strincmp(buffer, default_list[i], strlen(default_list[i])) == 0) 
		    return(1);

	    }
	    
	}

	if (list) {
	    for (i=0;list[i]; i++) {
		if (strincmp(buffer, list[i], strlen(list[i])) == 0) 
		    return(1);
	    }
	}
	return(0);
}

extern int is_it_on(word)
     char *word;
{
    /** Returns TRUE if the specified word is either 'ON', 'YES'
	or 'TRUE', and FALSE otherwise.   We explicitly translate
	to lowercase here to ensure that we have the fastest
	routine possible 
    **/

    char mybuffer[NLEN];
    int i, j;

    for (i=0, j=0; word[i] != '\0'; i++)
#ifdef ASCII_CTYPE
	if (isascii(word[i]))
#endif
	    mybuffer[j++] = tolower((unsigned char)word[i]);
    mybuffer[j] = '\0';

    return(  (strncmp(mybuffer, "on",   2) == 0) ||
	     (strncmp(mybuffer, "yes",  3) == 0) ||
	     (strncmp(mybuffer, "true", 4) == 0)
	     );
}

char * mode_to_str(mode)
     int mode;
{
	static char modestr[9+1];	/* "rwxrwxrwx\0" */
	char *s = &modestr[0];
	char *modecharp = "rwxrwxrwx";
	int modebit = 0400;

	while (modebit != 0) {
	    if (mode & modebit)
	        *s++ = *modecharp;
	    else
		*s++ = '-';
	    modecharp++;
	    modebit >>= 1;
	}
	*s = '\0';
	return(modestr);
}

int null_option_func(value,enter, lineno, filename)
     char **value; 
     int enter;
     int lineno; 
     char *filename;
{
    return 0;
}

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


syntax highlighted by Code2HTML, v. 0.9.1