#if !defined(lint) && !defined(DOS)
static char rcsid[] = "$Id: conf.c 1167 2008-08-23 00:07:05Z hubert@u.washington.edu $";
#endif

/*
 * ========================================================================
 * Copyright 2006-2008 University of Washington
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * ========================================================================
 */

/*======================================================================
     conf.c
     Implements the Pine configuration management routines
  ====*/


#include "../pith/headers.h"
#include "../pith/init.h"
#include "../pith/conf.h"
#include "../pith/state.h"
#include "../pith/remote.h"
#include "../pith/keyword.h"
#include "../pith/mailview.h"
#include "../pith/list.h"
#include "../pith/status.h"
#include "../pith/ldap.h"
#include "../pith/folder.h"
#include "../pith/thread.h"
#include "../pith/news.h"
#include "../pith/util.h"
#include "../pith/pattern.h"
#include "../pith/color.h"
#include "../pith/options.h"
#include "../pith/busy.h"
#include "../pith/readfile.h"
#include "../pith/hist.h"
#include "../pith/mailindx.h"
#include "../pith/tempfile.h"
#include "../pith/icache.h"
#include "../pith/sort.h"
#include "../pith/smime.h"
#include "../pith/charconv/utf8.h"
#ifdef _WINDOWS
#include "../pico/osdep/mswin.h"
#endif


#define	TO_BAIL_THRESHOLD	60


/*
 * Internal prototypes
 */
void     convert_configvars_to_utf8(struct variable *, char *);
void     convert_configvar_to_utf8(struct variable *, char *);
void     set_current_pattern_vals(struct pine *);
void     convert_pattern_data(void);
void     convert_filts_pattern_data(void);
void     convert_scores_pattern_data(void);
void     convert_pinerc_patterns(long);
void     convert_pinerc_filts_patterns(long);
void     convert_pinerc_scores_patterns(long);
void	 set_old_growth_bits(struct pine *, int);
int      var_is_in_rest_of_file(char *, char *);
char    *skip_over_this_var(char *, char *);
char    *native_nl(char *);
void     set_color_val(struct variable *, int);
int      copy_localfile_to_remotefldr(RemType, char *, char *, char *, char **);
char    *backcompat_convert_from_utf8(char *, size_t, char *);
#ifdef	_WINDOWS
char    *transformed_color(char *);
int      convert_pc_gray_names(struct pine *, PINERC_S *, EditWhich);
int      unix_color_style_in_pinerc(PINERC_S *);
char	*pcpine_general_help(char *);
char    *pcpine_help(HelpType);  /* defined in alpine/help */
#endif	/* _WINDOWS */


/* hook too allow caller to decide what to do about failure */
int	(*pith_opt_remote_pinerc_failure)(void);


/*------------------------------------
Some definitions to keep the static "variable" array below 
a bit more readable...
  ----*/
CONF_TXT_T cf_text_comment[] = "#\n# Alpine configuration file\n#\n# This file sets the configuration options used by Alpine and PC-Alpine. These\n# options are usually set from within Alpine or PC-Alpine. There may be a\n# system-wide configuration file which sets the defaults for some of the\n# variables. On Unix, run alpine -conf to see how system defaults have been set.\n# For variables that accept multiple values, list elements are\
 separated by\n# commas. A line beginning with a space or tab is considered to be a\n# continuation of the previous line. For a variable to be unset its value must\n# be blank. To set a variable to the empty string its value should be \"\".\n# You can override system defaults by setting a variable to the empty string.\n# Lines beginning with \"#\" are comments, and ignored by Alpine.\n";


CONF_TXT_T cf_text_personal_name[] =	"Over-rides your full name from Unix password file. Required for PC-Alpine.";

CONF_TXT_T cf_text_user_id[] =		"Your login/e-mail user name";

CONF_TXT_T cf_text_user_domain[] =		"Sets domain part of From: and local addresses in outgoing mail.";

CONF_TXT_T cf_text_smtp_server[] =		"List of SMTP servers for sending mail. If blank: Unix Alpine uses sendmail.";

CONF_TXT_T cf_text_nntp_server[] =		"NNTP server for posting news. Also sets news-collections for news reading.";

#ifdef	SMIME

CONF_TXT_T cf_text_publiccertdir[] =		"Public certificates are kept in files in this directory. The files should\n# contain certificates in PEM format. The name of each file should look\n# like <emailaddress>.crt. The default directory is .alpine-smime/public.";

CONF_TXT_T cf_text_privatekeydir[] =		"Private keys are kept in files in this directory. The files are in PEM format.\n# The name of a file should look like <emailaddress>.key.\n# The default directory is .alpine-smime/private.";

CONF_TXT_T cf_text_cacertdir[] =		"Certificate Authority certificates (in addition to the normal CACerts for the\n# system) are kept in files in this directory. The files are in PEM format.\n# Filenames should end with .crt. The default directory is .alpine-smime/ca.";

CONF_TXT_T cf_text_publiccertcontainer[] =	"If this option is set then public certificates are kept in a single container\n# \"file\" similar to a remote configuration file instead of in the\n# smime-publiccert-directory. The value can be a remote or local folder\n# specification like for a non-standard pinerc value. The default\n# is that it is not set.";

CONF_TXT_T cf_text_privatekeycontainer[] =	"If this option is set then private keys are kept in a single container\n# \"file\" similar to a remote configuration file instead of in the\n# private-key-directory. The value can be a remote or local folder\n# specification like for a non-standard pinerc value. The default\n# is that it is not set.";

CONF_TXT_T cf_text_cacertcontainer[] =	"If this option is set then CAcerts are kept in a single container\n# \"file\" similar to a remote configuration file instead of in the\n# ca-cert-directory. The value can be a remote or local folder\n# specification like for a non-standard pinerc value. The default\n# is that it is not set.";

#endif	/* SMIME */

#ifdef	ENABLE_LDAP
CONF_TXT_T cf_text_ldap_server[] =		"LDAP servers for looking up addresses.";
#endif	/* ENABLE_LDAP */

CONF_TXT_T cf_text_rss_news[] =			"RSS News feed";

CONF_TXT_T cf_text_rss_weather[] =		"RSS Weather feed";

CONF_TXT_T cf_text_wp_indexheight[] =		"Web Alpine index table row height";

CONF_TXT_T cf_text_wp_indexlines[] =		"Web Alpine number of index lines in table";

CONF_TXT_T cf_text_wp_aggstate[] =		"Web Alpine aggregate operations tab state";

CONF_TXT_T cf_text_wp_state[] =			"Web Alpine various aspects of cross-session state";

CONF_TXT_T cf_text_wp_columns[] =		"Web Alpine preferred width for message display in characters";

CONF_TXT_T cf_text_inbox_path[] =		"Path of (local or remote) INBOX, e.g. ={mail.somewhere.edu}inbox\n# Normal Unix default is the local INBOX (usually /usr/spool/mail/$USER).";

CONF_TXT_T cf_text_incoming_folders[] =	"List of incoming msg folders besides INBOX, e.g. ={host2}inbox, {host3}inbox\n# Syntax: optnl-label {optnl-imap-host-name}folder-path";

CONF_TXT_T cf_text_folder_collections[] =	"List of directories where saved-message folders may be. First one is\n# the default for Saves. Example: Main {host1}mail/[], Desktop mail\\[]\n# Syntax: optnl-label {optnl-imap-hostname}optnl-directory-path[]";

CONF_TXT_T cf_text_news_collections[] =	"List, only needed if nntp-server not set, or news is on a different host\n# than used for NNTP posting. Examples: News *[] or News *{host3/nntp}[]\n# Syntax: optnl-label *{news-host/protocol}[]";

CONF_TXT_T cf_text_pruned_folders[] =	"List of folders, assumed to be in first folder collection,\n# offered for pruning each month.  For example: mumble";

CONF_TXT_T cf_text_default_fcc[] =		"Over-rides default path for sent-mail folder, e.g. =old-mail (using first\n# folder collection dir) or ={host2}sent-mail or =\"\" (to suppress saving).\n# Default: sent-mail (Unix) or SENTMAIL.MTX (PC) in default folder collection.";

CONF_TXT_T cf_text_default_saved[] =	"Over-rides default path for saved-msg folder, e.g. =saved-messages (using 1st\n# folder collection dir) or ={host2}saved-mail or =\"\" (to suppress saving).\n# Default: saved-messages (Unix) or SAVEMAIL.MTX (PC) in default collection.";

CONF_TXT_T cf_text_postponed_folder[] =	"Over-rides default path for postponed messages folder, e.g. =pm (which uses\n# first folder collection dir) or ={host4}pm (using home dir on host4).\n# Default: postponed-msgs (Unix) or POSTPOND.MTX (PC) in default fldr coltn.";

CONF_TXT_T cf_text_mail_directory[] =	"Alpine compares this value with the first folder collection directory.\n# If they match (or no folder collections are defined), and the directory\n# does not exist, Alpine will create and use it. Default: ~/mail";

CONF_TXT_T cf_text_read_message_folder[] =	"If set, specifies where already-read messages will be moved upon quitting.";

CONF_TXT_T cf_text_form_letter_folder[] =	"If set, specifies where form letters should be stored.";

CONF_TXT_T cf_text_trash_folder[] =	"If set, specifies where trash is moved to in Web Alpine.";

CONF_TXT_T cf_text_signature_file[] =	"Over-rides default path for signature file. Default is ~/.signature";

CONF_TXT_T cf_text_literal_sig[] =	"Contains the actual signature contents as opposed to the signature filename.\n# If defined, this overrides the signature-file. Default is undefined.";

CONF_TXT_T cf_text_global_address_book[] =	"List of file or path names for global/shared addressbook(s).\n# Default: none\n# Syntax: optnl-label path-name";

CONF_TXT_T cf_text_address_book[] =	"List of file or path names for personal addressbook(s).\n# Default: ~/.addressbook (Unix) or \\PINE\\ADDRBOOK (PC)\n# Syntax: optnl-label path-name";

CONF_TXT_T cf_text_feature_list[] =	"List of features; see Alpine's Setup/options menu for the current set.\n# e.g. feature-list= select-without-confirm, signature-at-bottom\n# Default condition for all of the features is no-.";

CONF_TXT_T cf_text_initial_keystroke_list[] =	"Alpine executes these keys upon startup (e.g. to view msg 13: i,j,1,3,CR,v)";

CONF_TXT_T cf_text_default_composer_hdrs[] =	"Only show these headers (by default) when composing messages";

CONF_TXT_T cf_text_customized_hdrs[] =	"Add these customized headers (and possible default values) when composing";

CONF_TXT_T cf_text_view_headers[] =	"When viewing messages, include this list of headers";

CONF_TXT_T cf_text_view_margin_left[] =	"When viewing messages, number of blank spaces between left display edge and text";

CONF_TXT_T cf_text_view_margin_right[] =	"When viewing messages, number of blank spaces between right display edge and text";

CONF_TXT_T cf_text_quote_suppression[] =	"When viewing messages, number of lines of quote displayed before suppressing";

CONF_TXT_T cf_text_wordsep[] =	"When these characters appear in the middle of a word in the composer\n# the forward word function will stop at the first text following (as happens\n# with SPACE characters by default)";

CONF_TXT_T cf_text_color_style[] =	"Controls display of color";

CONF_TXT_T cf_text_current_indexline_style[] =	"Controls display of color for current index line";

CONF_TXT_T cf_text_titlebar_color_style[] =	"Controls display of color for the titlebar at top of screen";

CONF_TXT_T cf_text_view_hdr_color[] =	"When viewing messages, these are the header colors";

CONF_TXT_T cf_text_save_msg_name_rule[] =	"Determines default folder name for Saves...\n# Choices: default-folder, by-sender, by-from, by-recipient, last-folder-used.\n# Default: \"default-folder\", i.e. \"saved-messages\" (Unix) or \"SAVEMAIL\" (PC).";

CONF_TXT_T cf_text_fcc_name_rule[] =	"Determines default name for Fcc...\n# Choices: default-fcc, by-recipient, last-fcc-used.\n# Default: \"default-fcc\" (see also \"default-fcc=\" variable.)";

CONF_TXT_T cf_text_sort_key[] =		"Sets presentation order of messages in Index. Choices:\n# Subject, From, Arrival, Date, Size, To, Cc, OrderedSubj, Score, and Thread.\n# Order may be reversed by appending /Reverse. Default: \"Arrival\".";

CONF_TXT_T cf_text_addrbook_sort_rule[] =	"Sets presentation order of address book entries. Choices: dont-sort,\n# fullname-with-lists-last, fullname, nickname-with-lists-last, nickname\n# Default: \"fullname-with-lists-last\".";

CONF_TXT_T cf_text_folder_sort_rule[] =	"Sets presentation order of folder list entries. Choices: alphabetical,\n# alpha-with-dirs-last, alpha-with-dirs-first.\n# Default: \"alpha-with-directories-last\".";

CONF_TXT_T cf_text_old_char_set[] =	"Character-set is obsolete, use display-character-set, keyboard-character-set,\n# and posting-character-set.";

CONF_TXT_T cf_text_disp_char_set[] =	"Reflects capabilities of the display you have.\n# If unset, the default is taken from your locale. That is usually the right\n# thing to use. Typical alternatives include UTF-8, ISO-8859-x, and EUC-JP\n# (where x is a number between 1 and 9).";

CONF_TXT_T cf_text_key_char_set[] =	"Reflects capabilities of the keyboard you have.\n# If unset, the default is to use the same value\n# used for the display-character-set.";

CONF_TXT_T cf_text_post_character_set[] =	"Defaults to UTF-8. This is used for outgoing messages.\n# It is usually correct to leave this unset.";

CONF_TXT_T cf_text_unk_character_set[] =	"Defaults to nothing, which is equivalent to US-ASCII. This is used for\n# unlabeled incoming messages. It is ok to leave this unset but if you receive\n# unlabeled mail that is usually in some known character set, set that here.";

CONF_TXT_T cf_text_editor[] =		"Specifies the program invoked by ^_ in the Composer,\n# or the \"enable-alternate-editor-implicitly\" feature.";

CONF_TXT_T cf_text_speller[] =		"Specifies the program invoked by ^T in the Composer.";

CONF_TXT_T cf_text_deadlets[] =		"Specifies the number of dead letter files to keep when canceling.";

CONF_TXT_T cf_text_fillcol[] =		"Specifies the column of the screen where the composer should wrap.";

CONF_TXT_T cf_text_replystr[] =		"Specifies the string to insert when replying to a message.";

CONF_TXT_T cf_text_quotereplstr[] =    	"Specifies the string to replace quotes with when viewing a message.";

CONF_TXT_T cf_text_replyintro[] =	"Specifies the introduction to insert when replying to a message.";

CONF_TXT_T cf_text_emptyhdr[] =		"Specifies the string to use when sending a  message with no to or cc.";

CONF_TXT_T cf_text_image_viewer[] =	"Program to view images (e.g. GIF or TIFF attachments).";

CONF_TXT_T cf_text_browser[] =		"List of programs to open Internet URLs (e.g. http or ftp references).";

CONF_TXT_T cf_text_inc_startup[] =	"Sets message which cursor begins on. Choices: first-unseen, first-recent,\n# first-important, first-important-or-unseen, first-important-or-recent,\n# first, last. Default: \"first-unseen\".";

CONF_TXT_T cf_pruning_rule[] =		"Allows a default answer for the prune folder questions. Choices: yes-ask,\n# yes-no, no-ask, no-no, ask-ask, ask-no. Default: \"ask-ask\".";

CONF_TXT_T cf_reopen_rule[] =		"Controls behavior when reopening an already open folder.";

CONF_TXT_T cf_text_thread_disp_style[] = "Style that MESSAGE INDEX is displayed in when threading.";

CONF_TXT_T cf_text_thread_index_style[] = "Style of THREAD INDEX or default MESSAGE INDEX when threading.";

CONF_TXT_T cf_text_thread_more_char[] =	"When threading, character used to indicate collapsed messages underneath.";

CONF_TXT_T cf_text_thread_exp_char[] =	"When threading, character used to indicate expanded messages underneath.";

CONF_TXT_T cf_text_thread_lastreply_char[] =	"When threading, character used to indicate this is the last reply\n# to the parent of this message.";

CONF_TXT_T cf_text_use_only_domain_name[] = "If \"user-domain\" not set, strips hostname in FROM address. (Unix only)";

CONF_TXT_T cf_text_printer[] =		"Your default printer selection";

CONF_TXT_T cf_text_personal_print_command[] =	"List of special print commands";

CONF_TXT_T cf_text_personal_print_cat[] =	"Which category default print command is in";

CONF_TXT_T cf_text_standard_printer[] =	"The system wide standard printers";

CONF_TXT_T cf_text_last_time_prune_quest[] =	"Set by Alpine; controls beginning-of-month sent-mail pruning.";

CONF_TXT_T cf_text_last_version_used[] =	"Set by Alpine; controls display of \"new version\" message.";

CONF_TXT_T cf_text_disable_drivers[] =		"List of mail drivers to disable.";

CONF_TXT_T cf_text_disable_auths[] =		"List of SASL authenticators to disable.";

CONF_TXT_T cf_text_remote_abook_metafile[] =	"Set by Alpine; contains data for caching remote address books.";

CONF_TXT_T cf_text_old_patterns[] =		"Patterns is obsolete, use patterns-xxx";

CONF_TXT_T cf_text_old_filters[] =		"Patterns-filters is obsolete, use patterns-filters2";

CONF_TXT_T cf_text_old_scores[] =		"Patterns-scores is obsolete, use patterns-scores2";

CONF_TXT_T cf_text_patterns[] =			"Patterns and their actions are stored here.";

CONF_TXT_T cf_text_remote_abook_history[] =	"How many extra copies of remote address book should be kept. Default: 3";

CONF_TXT_T cf_text_remote_abook_validity[] =	"Minimum number of minutes between checks for remote address book changes.\n# 0 means never check except when opening a remote address book.\n# -1 means never check. Default: 5";

CONF_TXT_T cf_text_bugs_fullname[] =	"Full name for bug report address used by \"Report Bug\" command";

CONF_TXT_T cf_text_bugs_address[] =	"Email address used to send bug reports";

CONF_TXT_T cf_text_bugs_extras[] =		"Program/Script used by \"Report Bug\" command. No default.";

CONF_TXT_T cf_text_suggest_fullname[] =	"Full name for suggestion address used by \"Report Bug\" command";

CONF_TXT_T cf_text_suggest_address[] =	"Email address used to send suggestions";

CONF_TXT_T cf_text_local_fullname[] =	"Full name for \"local support\" address used by \"Report Bug\" command.\n# Default: Local Support";

CONF_TXT_T cf_text_local_address[] =	"Email address used to send to \"local support\".\n# Default: postmaster";

CONF_TXT_T cf_text_forced_abook[] =	"Force these address book entries into all writable personal address books.\n# Syntax is   forced-abook-entry=nickname|fullname|address\n# This is a comma-separated list of entries, each with syntax above.\n# Existing entries with same nickname are not replaced.\n# Example: help|Help Desk|help@ourdomain.com";

CONF_TXT_T cf_text_kblock_passwd[] =	"This is a number between 1 and 5.  It is the number of times a user will\n# have to enter a password when they run the keyboard lock command in the\n# main menu.  Default is 1.";

CONF_TXT_T cf_text_sendmail_path[] =	"This names the path to an alternative program, and any necessary arguments,\n# to be used in posting mail messages.  Example:\n#                    /usr/lib/sendmail -oem -t -oi\n# or,\n#                    /usr/local/bin/sendit.sh\n# The latter a script found in Alpine distribution's contrib/util directory.\n# NOTE: The program MUST read the message to be posted on standard input,\n#       AND operate in the style of sendmail's \"-t\" option.";

CONF_TXT_T cf_text_oper_dir[] =	"This names the root of the tree to which the user is restricted when reading\n# and writing folders and files.  For example, on Unix ~/work confines the\n# user to the subtree beginning with their work subdirectory.\n# (Note: this alone is not sufficient for preventing access.  You will also\n# need to restrict shell access and so on, see Alpine Technical Notes.)\n# Default: not set (so no restriction)";

CONF_TXT_T cf_text_in_fltr[] = 		"This variable takes a list of programs that message text is piped into\n# after MIME decoding, prior to display.";

CONF_TXT_T cf_text_out_fltr[] =		"This defines a program that message text is piped into before MIME\n# encoding, prior to sending";

CONF_TXT_T cf_text_alt_addrs[] =	"A list of alternate addresses the user is known by";

CONF_TXT_T cf_text_keywords[] =		"A list of keywords for use in categorizing messages";

CONF_TXT_T cf_text_kw_colors[] =	"Colors used to display keywords in the index";

CONF_TXT_T cf_text_kw_braces[] =	"Characters which surround keywords in SUBJKEY token.\n# Default is \"{\" \"} \"";

CONF_TXT_T cf_text_opening_sep[] =	"Characters between subject and opening text in SUBJECTTEXT token.\n# Default is \" - \"";

CONF_TXT_T cf_text_abook_formats[] =	"This is a list of formats for address books.  Each entry in the list is made\n# up of space-delimited tokens telling which fields are displayed and in\n# which order.  See help text";

CONF_TXT_T cf_text_index_format[] =	"This gives a format for displaying the index.  It is made\n# up of space-delimited tokens telling which fields are displayed and in\n# which order.  See help text";

CONF_TXT_T cf_text_overlap[] =		"The number of lines of overlap when scrolling through message text";

CONF_TXT_T cf_text_maxremstreams[] =	"The maximum number of non-stayopen remote connections that Alpine will use";

CONF_TXT_T cf_text_permlocked[] =	"A list of folders that should be left open once opened (INBOX is implicit)";

CONF_TXT_T cf_text_margin[] =		"Number of lines from top and bottom of screen where single\n# line scrolling occurs.";

CONF_TXT_T cf_text_stat_msg_delay[] =	"The number of seconds to sleep after writing a status message";

CONF_TXT_T cf_text_busy_cue_rate[] =	"Number of times per-second to update busy cue messages";

CONF_TXT_T cf_text_mailcheck[] =	"The approximate number of seconds between checks for new mail";

CONF_TXT_T cf_text_mailchecknoncurr[] =	"The approximate number of seconds between checks for new mail in folders\n# other than the current folder and inbox.\n# Default is same as mail-check-interval";

CONF_TXT_T cf_text_maildropcheck[] =	"The minimum number of seconds between checks for new mail in a Mail Drop.\n# This is always effectively at least as large as the mail-check-interval";

CONF_TXT_T cf_text_nntprange[] =	"For newsgroups accessed using NNTP, only messages numbered in the range\n# lastmsg-range+1 to lastmsg will be considered";

CONF_TXT_T cf_text_news_active[] =	"Path and filename of news configuration's active file.\n# The default is typically \"/usr/lib/news/active\".";

CONF_TXT_T cf_text_news_spooldir[] =	"Directory containing system's news data.\n# The default is typically \"/usr/spool/news\"";

CONF_TXT_T cf_text_upload_cmd[] =	"Path and filename of the program used to upload text from your terminal\n# emulator's into Alpine's composer.";

CONF_TXT_T cf_text_upload_prefix[] =	"Text sent to terminal emulator prior to invoking the program defined by\n# the upload-command variable.\n# Note: _FILE_ will be replaced with the temporary file used in the upload.";

CONF_TXT_T cf_text_download_cmd[] =	"Path and filename of the program used to download text via your terminal\n# emulator from Alpine's export and save commands.";

CONF_TXT_T cf_text_download_prefix[] =	"Text sent to terminal emulator prior to invoking the program defined by\n# the download-command variable.\n# Note: _FILE_ will be replaced with the temporary file used in the download.";

CONF_TXT_T cf_text_goto_default[] =	"Sets the default folder and collection offered at the Goto Command's prompt.";

CONF_TXT_T cf_text_mailcap_path[] =	"Sets the search path for the mailcap configuration file.\n# NOTE: colon delimited under UNIX, semi-colon delimited under DOS/Windows/OS2.";

CONF_TXT_T cf_text_mimetype_path[] =	"Sets the search path for the mimetypes configuration file.\n# NOTE: colon delimited under UNIX, semi-colon delimited under DOS/Windows/OS2.";

CONF_TXT_T cf_text_newmail_fifo_path[] = "Sets the filename for the newmail fifo (named pipe). Unix only.";

CONF_TXT_T cf_text_nmw_width[] = "Sets the width for the NewMail screen.";

CONF_TXT_T cf_text_user_input_timeo[] =	"If no user input for this many hours, Alpine will exit if in an idle loop\n# waiting for a new command.  If set to zero (the default), then there will\n# be no timeout.";

CONF_TXT_T cf_text_debug_mem[] =	"Debug-memory is obsolete";

CONF_TXT_T cf_text_tcp_open_timeo[] =	"Sets the time in seconds that Alpine will attempt to open a network\n# connection.  The default is 30, the minimum is 5, and the maximum is\n# system defined (typically 75).";

CONF_TXT_T cf_text_tcp_read_timeo[] =	"Network read warning timeout. The default is 15, the minimum is 5, and the\n# maximum is 1000.";

CONF_TXT_T cf_text_tcp_write_timeo[] =	"Network write warning timeout. The default is 0 (unset), the minimum\n# is 5 (if not 0), and the maximum is 1000.";

CONF_TXT_T cf_text_tcp_query_timeo[] =	"If this much time has elapsed at the time of a tcp read or write\n# timeout, Alpine will ask if you want to break the connection.\n# Default is 60 seconds, minimum is 5, maximum is 1000.";

CONF_TXT_T cf_text_rsh_open_timeo[] =	"Sets the time in seconds that Alpine will attempt to open a UNIX remote\n# shell connection.  The default is 15, min is 5, and max is unlimited.\n# Zero disables rsh altogether.";

CONF_TXT_T cf_text_rsh_path[] =		"Sets the name of the command used to open a UNIX remote shell connection.\n# The default is typically /usr/ucb/rsh.";

CONF_TXT_T cf_text_rsh_command[] =	"Sets the format of the command used to open a UNIX remote\n# shell connection.  The default is \"%s %s -l %s exec /etc/r%sd\"\n# NOTE: the 4 (four) \"%s\" entries MUST exist in the provided command\n# where the first is for the command's path, the second is for the\n# host to connect to, the third is for the user to connect as, and the\n# fourth is for the connection method (typically \"imap\")";

CONF_TXT_T cf_text_ssh_open_timeo[] =	"Sets the time in seconds that Alpine will attempt to open a UNIX secure\n# shell connection.  The default is 15, min is 5, and max is unlimited.\n# Zero disables ssh altogether.";

CONF_TXT_T cf_text_inc_check_timeo[] =	"Sets the time in seconds that Alpine will attempt to open a network\n# connection when checking for new unseen messages in an incoming folder.\n#  The default is 5.";

CONF_TXT_T cf_text_inc_check_interval[] = "Sets the approximate number of seconds between checks for unseen messages\n# in incoming folders. The default is 180.";

CONF_TXT_T cf_text_inc_second_check_interval[] = "Sets the approximate number of seconds between checks for unseen messages\n# for other than local or IMAP folders. The default is 180.";

CONF_TXT_T cf_text_inc_check_list[] =	"List of incoming folders to check for unseen messages. The default if left\n# blank is to check all incoming folders.";

CONF_TXT_T cf_text_ssh_path[] =		"Sets the name of the command used to open a UNIX secure shell connection.\n# Typically this is /usr/bin/ssh.";

CONF_TXT_T cf_text_ssh_command[] =	"Sets the format of the command used to open a UNIX secure\n# shell connection.  The default is \"%s %s -l %s exec /etc/r%sd\"\n# NOTE: the 4 (four) \"%s\" entries MUST exist in the provided command\n# where the first is for the command's path, the second is for the\n# host to connect to, the third is for the user to connect as, and the\n# fourth is for the connection method (typically \"imap\")";

CONF_TXT_T cf_text_version_threshold[] = "Sets the version number Alpine will use as a threshold for offering\n# its new version message on startup.";

CONF_TXT_T cf_text_archived_folders[] =	"List of folder pairs; the first indicates a folder to archive, and the\n# second indicates the folder read messages in the first should\n# be moved to.";

CONF_TXT_T cf_text_elm_style_save[] =	"Elm-style-save is obsolete, use saved-msg-name-rule";

CONF_TXT_T cf_text_header_in_reply[] =	"Header-in-reply is obsolete, use include-header-in-reply in feature-list";

CONF_TXT_T cf_text_feature_level[] =	"Feature-level is obsolete, use feature-list";

CONF_TXT_T cf_text_old_style_reply[] =	"Old-style-reply is obsolete, use signature-at-bottom in feature-list";

CONF_TXT_T cf_text_compose_mime[] =	"Compose-mime is obsolete";

CONF_TXT_T cf_text_show_all_characters[] =	"Show-all-characters is obsolete";

CONF_TXT_T cf_text_save_by_sender[] =	"Save-by-sender is obsolete, use saved-msg-name-rule";

CONF_TXT_T cf_text_file_dir[] =		"Default directory used for Attachment handling (attach and save)\n# and Export command output";

CONF_TXT_T cf_text_folder_extension[] =	"Folder-extension is obsolete";

CONF_TXT_T cf_text_normal_foreground_color[] =	"Choose: black, blue, green, cyan, red, magenta, yellow, or white.";

CONF_TXT_T cf_text_window_position[] =	"Window position in the format: CxR+X+Y\n# Where C and R are the window size in characters and X and Y are the\n# screen position of the top left corner of the window.\n# This is no longer used unless position is not set in registry.";

CONF_TXT_T cf_text_newsrc_path[] =		"Full path and name of NEWSRC file";


/*----------------------------------------------------------------------
These are the variables that control a number of pine functions.  They
come out of the .pinerc and the /usr/local/lib/pine.conf files.  Some can
be set by the user while in Alpine.  Eventually all the local ones should
be so and maybe the global ones too.

Each variable can have a command-line, user, global, and current value.
All of these values are malloc'd.  The user value is the one read out of
the user's .pinerc, the global value is the one from the system pine
configuration file.  There are often defaults for the global values, set
at the start of init_vars().  Perhaps someday there will be group values.
The current value is the one that is actually in use.
  ----*/
/* name                                                  is_changed_val
                                                       remove_quotes  |
                                                     is_outermost  |  |
                                                   is_onlymain  |  |  |
                                                   is_fixed  |  |  |  |
                                                 is_list  |  |  |  |  |
                                            is_global  |  |  |  |  |  |
                                           is_user  |  |  |  |  |  |  |
                                   been_written  |  |  |  |  |  |  |  |
                                     is_used  |  |  |  |  |  |  |  |  |
                              is_obsolete  |  |  |  |  |  |  |  |  |  |
                                        |  |  |  |  |  |  |  |  |  |  |
  (on following line) description       |  |  |  |  |  |  |  |  |  |  |
                                |       |  |  |  |  |  |  |  |  |  |  |
                                |       |  |  |  |  |  |  |  |  |  |  |  */
static struct variable variables[] = {
{"personal-name",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_personal_name},
{
#if defined(DOS) || defined(OS2)
                        /* Have to have this on DOS, PC's, Macs, etc... */
 "user-id",				0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0,
#else			/* Don't allow on UNIX machines for some security */
 "user-id",				0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0,
#endif
	"User ID",		cf_text_user_id},
{"user-domain",				0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_user_domain},
{"smtp-server",				0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
	"SMTP Server (for sending)",	cf_text_smtp_server},
{"nntp-server",				0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
	"NNTP Server (for news)",	cf_text_nntp_server},
{"inbox-path",				0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_inbox_path},
{"incoming-archive-folders",		0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_archived_folders},
{"pruned-folders",			0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
	NULL,			cf_text_pruned_folders},
{"default-fcc",				0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"Default Fcc (File carbon copy)",	cf_text_default_fcc},
{"default-saved-msg-folder",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"Default Saved Message Folder",	cf_text_default_saved},
{"postponed-folder",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_postponed_folder},
{"read-message-folder",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_read_message_folder},
{"form-letter-folder",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_form_letter_folder},
{"trash-folder",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_trash_folder},
{"literal-signature",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_literal_sig},
{"signature-file",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_signature_file},
{"feature-list",			0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_feature_list},
{"initial-keystroke-list",		0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_initial_keystroke_list},
{"default-composer-hdrs",		0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	"Default Composer Headers",	cf_text_default_composer_hdrs},
{"customized-hdrs",			0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	"Customized Headers",	cf_text_customized_hdrs},
{"viewer-hdrs",				0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	"Viewer Headers",	cf_text_view_headers},
{"viewer-margin-left",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_view_margin_left},
{"viewer-margin-right",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_view_margin_right},
{"quote-suppression-threshold",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_quote_suppression},
{"saved-msg-name-rule",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"Saved Message Name Rule",	cf_text_save_msg_name_rule},
{"fcc-name-rule",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_fcc_name_rule},
{"sort-key",				0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_sort_key},
{"addrbook-sort-rule",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"Address Book Sort Rule",	cf_text_addrbook_sort_rule},
{"folder-sort-rule",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_folder_sort_rule},
{"goto-default-rule",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_goto_default},
{"incoming-startup-rule",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_inc_startup},
{"pruning-rule",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_pruning_rule},
{"folder-reopen-rule",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_reopen_rule},
{"threading-display-style",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_thread_disp_style},
{"threading-index-style",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_thread_index_style},
{"threading-indicator-character",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_thread_more_char},
{"threading-expanded-character",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_thread_exp_char},
{"threading-lastreply-character",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"Threading Last Reply Character",	cf_text_thread_lastreply_char},
#ifndef	_WINDOWS
{"display-character-set",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_disp_char_set},
{"character-set",			1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_old_char_set},
{"keyboard-character-set",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_key_char_set},
#endif	/* ! _WINDOWS */
{"posting-character-set",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_post_character_set},
{"unknown-character-set",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_unk_character_set},
{"editor",				0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
	NULL,			cf_text_editor},
{"speller",				0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_speller},
{"composer-wrap-column",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_fillcol},
{"reply-indent-string",			0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0,
	NULL,			cf_text_replystr},
{"reply-leadin",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_replyintro},
{"quote-replace-string",		0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0,
	NULL,			cf_text_quotereplstr},
{"composer-word-separators",		0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
	NULL,			cf_text_wordsep},
{"empty-header-message",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_emptyhdr},
{"image-viewer",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_image_viewer},
{"use-only-domain-name",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_use_only_domain_name},
{"bugs-fullname",			0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_bugs_fullname},
{"bugs-address",			0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_bugs_address},
{"bugs-additional-data",		0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_bugs_extras},
{"suggest-fullname",			0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_suggest_fullname},
{"suggest-address",			0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_suggest_address},
{"local-fullname",			0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_local_fullname},
{"local-address",			0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_local_address},
{"forced-abook-entry",			0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_forced_abook},
{"kblock-passwd-count",			0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_kblock_passwd},
{"display-filters",			0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_in_fltr},
{"sending-filters",			0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_out_fltr},
{"alt-addresses",			0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	"Alternate Addresses",	cf_text_alt_addrs},
{"keywords",				0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_keywords},
{"keyword-surrounding-chars",		0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0,
	"Keyword Surrounding Characters",	cf_text_kw_braces},
{"opening-text-separator-chars",	0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0,
	"Opening Text Separator Characters",	cf_text_opening_sep},
{"addressbook-formats",			0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	"Address Book Formats",			cf_text_abook_formats},
{"index-format",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_index_format},
{"viewer-overlap",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_overlap},
{"scroll-margin",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_margin},
{"status-message-delay",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_stat_msg_delay},
{"busy-cue-rate",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_busy_cue_rate},
{"mail-check-interval",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_mailcheck},
{"mail-check-interval-noncurrent",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_mailchecknoncurr},
{"maildrop-check-minimum",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_maildropcheck},
{"nntp-range",				0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"NNTP Range",		cf_text_nntprange},
{"newsrc-path",				0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_newsrc_path},
{"news-active-file-path",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_news_active},
{"news-spool-directory",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_news_spooldir},
{"upload-command",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_upload_cmd},
{"upload-command-prefix",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_upload_prefix},
{"download-command",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_download_cmd},
{"download-command-prefix",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_download_prefix},
{"mailcap-search-path",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_mailcap_path},
{"mimetype-search-path",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_mimetype_path},
{"url-viewers",				0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	"URL-Viewers",		cf_text_browser},
{"max-remote-connections",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"Maximum Remote Connections",	cf_text_maxremstreams},
{"stay-open-folders",			0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	"Stayopen Folders",	cf_text_permlocked},
{"incoming-check-timeout",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_inc_check_timeo},
{"incoming-check-interval",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_inc_check_interval},
{"incoming-check-interval-secondary",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_inc_second_check_interval},
{"incoming-check-list",			0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_inc_check_list},
{"dead-letter-files",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_deadlets},
#if !defined(DOS) && !defined(OS2) && !defined(LEAVEOUTFIFO)
{"newmail-fifo-path",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"NewMail FIFO Path",	cf_text_newmail_fifo_path},
#endif
{"newmail-window-width",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"NewMail Window Width",	cf_text_nmw_width},
/*
 * Starting here, the variables are hidden in the Setup/Config screen.
 * They are exposed if feature expose-hidden-config is set.
 */
{"incoming-folders",			0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_incoming_folders},
{"mail-directory",			0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_mail_directory},
{"folder-collections",			0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_folder_collections},
{"news-collections",			0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_news_collections},
{"address-book",			0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_address_book},
{"global-address-book",			0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_global_address_book},
{"standard-printer",			0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_standard_printer},
{"last-time-prune-questioned",		0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0,
	NULL,			cf_text_last_time_prune_quest},
{"last-version-used",			0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0,
	NULL,			cf_text_last_version_used},
{"sendmail-path",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_sendmail_path},
{"operating-dir",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_oper_dir},
{"user-input-timeout",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_user_input_timeo},
/* OBSOLETE */
#ifdef DEBUGJOURNAL
{"debug-memory",			1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_debug_mem},
#endif
{"tcp-open-timeout",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"TCP Open Timeout",	cf_text_tcp_open_timeo},
{"tcp-read-warning-timeout",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"TCP Read Warning Timeout",	cf_text_tcp_read_timeo},
{"tcp-write-warning-timeout",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"TCP Write Warning Timeout",	cf_text_tcp_write_timeo},
{"tcp-query-timeout",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"TCP Query Timeout",	cf_text_tcp_query_timeo},
{"rsh-command",				0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_rsh_command},
{"rsh-path",				0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_rsh_path},
{"rsh-open-timeout",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_rsh_open_timeo},
{"ssh-command",				0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_ssh_command},
{"ssh-path",				0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_ssh_path},
{"ssh-open-timeout",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_ssh_open_timeo},
{"new-version-threshold",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_version_threshold},
{"disable-these-drivers",		0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
	NULL,			cf_text_disable_drivers},
{"disable-these-authenticators",	0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
	NULL,			cf_text_disable_auths},
{"remote-abook-metafile",		0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0,
	NULL,			cf_text_remote_abook_metafile},
{"remote-abook-history",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_remote_abook_history},
{"remote-abook-validity",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_remote_abook_validity},
{"printer",				0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_printer},
{"personal-print-command",		0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_personal_print_command},
{"personal-print-category",		0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_personal_print_cat},
{"patterns",				1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_old_patterns},
{"patterns-roles",			0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_patterns},
{"patterns-filters2",			0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	"Patterns Filters",	cf_text_patterns},
{"patterns-filters",			1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_old_filters},
{"patterns-scores2",			0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	"Patterns Scores",	cf_text_patterns},
{"patterns-scores",			1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_old_scores},
{"patterns-indexcolors",		0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_patterns},
{"patterns-other",			0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_patterns},
{"patterns-search",			0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	NULL,			cf_text_patterns},
/* OBSOLETE VARS */
{"elm-style-save",			1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_elm_style_save},
{"header-in-reply",			1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_header_in_reply},
{"feature-level",			1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_feature_level},
{"old-style-reply",			1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_old_style_reply},
{"compose-mime",			1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_compose_mime},
{"show-all-characters",			1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_show_all_characters},
{"save-by-sender",			1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_save_by_sender},
#if defined(DOS) || defined(OS2)
{"file-directory",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_file_dir},
{"folder-extension",			1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_folder_extension},
#endif
#ifndef	_WINDOWS
{"color-style",				0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_color_style},
#endif
{"current-indexline-style",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_current_indexline_style},
{"titlebar-color-style",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_titlebar_color_style},
{"normal-foreground-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			cf_text_normal_foreground_color},
{"normal-background-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"reverse-foreground-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"reverse-background-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"title-foreground-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"title-background-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"title-closed-foreground-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"title-closed-background-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"status-foreground-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"status-background-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"keylabel-foreground-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"keylabel-background-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"keyname-foreground-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"keyname-background-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"selectable-item-foreground-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"selectable-item-background-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"meta-message-foreground-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"meta-message-background-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"quote1-foreground-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"quote1-background-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"quote2-foreground-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"quote2-background-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"quote3-foreground-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"quote3-background-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"incoming-unseen-foreground-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"incoming-unseen-background-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"signature-foreground-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"signature-background-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"prompt-foreground-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"prompt-background-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"header-general-foreground-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"header-general-background-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-to-me-foreground-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-to-me-background-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-important-foreground-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-important-background-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-deleted-foreground-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-deleted-background-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-answered-foreground-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-answered-background-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-new-foreground-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-new-background-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-recent-foreground-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-recent-background-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-forward-foreground-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-forward-background-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-unseen-foreground-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-unseen-background-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-highpriority-foreground-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-highpriority-background-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-lowpriority-foreground-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-lowpriority-background-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-arrow-foreground-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-arrow-background-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-subject-foreground-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-subject-background-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-from-foreground-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-from-background-color",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-opening-foreground-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"index-opening-background-color",	0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0},
{"viewer-hdr-colors",			0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
	"Viewer Header Colors",	cf_text_view_hdr_color},
{"keyword-colors",			0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0,
	NULL,			cf_text_kw_colors},
#ifdef _WINDOWS
{"font-name",				0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			"name and size of font."},
{"font-size",				0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, NULL},
{"font-style",				0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, NULL},
{"font-char-set",      			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, NULL},
{"print-font-name",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	NULL,			"name and size of printer font."},
{"print-font-size",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, NULL},
{"print-font-style",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, NULL},
{"print-font-char-set",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, NULL},
{"window-position",			0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0,
	NULL,			cf_text_window_position},
{"cursor-style",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, NULL},
#endif	/* _WINDOWS */
#ifdef	SMIME
{"smime-public-cert-directory",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"S/MIME - Public Cert Directory",	cf_text_publiccertdir},
{"smime-public-cert-container",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"S/MIME - Public Cert Container",	cf_text_publiccertcontainer},
{"smime-private-key-directory",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"S/MIME - Private Key Directory",	cf_text_privatekeydir},
{"smime-private-key-container",		0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"S/MIME - Private Key Container",	cf_text_privatekeycontainer},
{"smime-cacert-directory",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"S/MIME - Cert Authority Directory", cf_text_cacertdir},
{"smime-cacert-container",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"S/MIME - Cert Authority Container", cf_text_cacertcontainer},
#endif	/* SMIME */
#ifdef	ENABLE_LDAP
{"ldap-servers",			0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
	"LDAP Servers",		cf_text_ldap_server},
#endif	/* ENABLE_LDAP */
{"rss-news",				0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"WEB ALPINE - RSS News",	cf_text_rss_news},
{"rss-weather",				0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"WEB ALPINE - RSS Weather",	cf_text_rss_weather},
{"wp-indexheight", 			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"WEB ALPINE - Index Height",	cf_text_wp_indexheight},
{"wp-indexlines",			0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"WEB ALPINE - Index Lines",	cf_text_wp_indexlines},
{"wp-aggstate",				0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"WEB ALPINE - Aggregate State",	cf_text_wp_aggstate},
{"wp-state",				0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0,
	"WEB ALPINE - Cross Session State",	cf_text_wp_state},
{"wp-columns",				0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0,
	"WEB ALPINE - Columns",	cf_text_wp_columns},
{NULL,					0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL,NULL}
};


struct variable *
var_from_name(char *name)
{
    struct variable *v;
    int	             i;

    if(!(name && name[0]))
      return(NULL);

    for(i = 0; (v = &variables[i]) && v->name; i++)
      if(!strucmp(v->name,name))
	return(v);

    return(NULL);
}


void
init_init_vars(struct pine *ps)
{
    ps->vars = variables;
}


#define DSIZE (25000)
/* this is just like dprint except it prints to a char * */
#ifdef DEBUG
#define   mprint(n,x) {			\
	       if(debug >= (n)){	\
		   snprintf x ;		\
		   db += strlen(db);	\
	       }			\
	   }
#else
#define   mprint(n,x)
#endif

/*
 * this was split out from init_vars so we can get at the
 * pinerc location sooner.
 */
void
init_pinerc(struct pine *ps, char **debug_out)
{
    char      buf[MAXPATH+1], *p, *db;
#if defined(DOS) || defined(OS2)
    char      buf2[MAXPATH+1], l_pinerc[MAXPATH+1];
    int nopinerc = 0, confregset = -1;
    register struct variable *vars = ps->vars;
#endif

#ifdef DEBUG
    /*
     * Since this routine is called before we've had a chance to set up
     * the debug file for output, we put the debugging into memory and
     * pass it back to the caller for use after init_debug(). We just
     * allocate plenty of space.
     */
    if(debug_out){
	db = *debug_out = (char *)fs_get(DSIZE * sizeof(char));
	db[0] = '\0';
    }
#endif

    mprint(2, (db, DSIZE-(db-(*debug_out)), "\n -- init_pinerc --\n\n"));

#if defined(DOS) || defined(OS2)
    /*
     * Rules for the config/support file locations under DOS are:
     *
     * 1) The location of the PINERC is searched for in the following
     *    order of precedence:
     *	     - File pointed to by '-p' command line option
     *       - File pointed to by PINERC environment variable
     *       - $HOME\pine
     *       - same dir as argv[0]
     *
     * 2) The HOME environment variable, if not set, defaults to 
     *    root of the current working drive (see alpine.c)
     * 
     * 3) The default for external files (PINE.SIG and ADDRBOOK) is the
     *    same directory as the pinerc
     *
     * 4) The support files (PINE.HLP and PINE.NDX) are expected to be in
     *    the same directory as PINE.EXE.
     */

    if(ps->prc){
      mprint(2, (db, DSIZE-(db-(*debug_out)),
	     "Personal config \"%.100s\" comes from command line\n",
	     (ps->prc && ps->prc->name) ? ps->prc->name : "<no name>"));
    }
    else{
      mprint(2, (db, DSIZE-(db-(*debug_out)),
	     "Personal config not set on cmdline, checking for $PINERC\n"));
    }

    /*
     * First, if prc hasn't been set by a command-line -p, check to see
     * if PINERC is in the environment. If so, treat it just like we
     * would have treated it if it were a command-line arg.
     */
    if(!ps->prc && (p = getenv("PINERC")) && *p){
	char path[MAXPATH], dir[MAXPATH];

	if(IS_REMOTE(p) || is_absolute_path(p)){
	    strncpy(path, p, sizeof(path)-1);
	    path[sizeof(path)-1] = '\0';
	}
	else{
	    getcwd(dir, sizeof(dir));
	    build_path(path, dir, p, sizeof(path));
	}

	if(!IS_REMOTE(p))
	  ps->pinerc = cpystr(path);

	ps->prc = new_pinerc_s(path);

	if(ps->prc){
	  mprint(2, (db, DSIZE-(db-(*debug_out)),
	  "  yes, personal config \"%.100s\" comes from $PINERC\n",
		 (ps->prc && ps->prc->name) ? ps->prc->name : "<no name>"));
	}
    }

    /*
     * Pinerc used to be the name of the pinerc file. Then we added
     * the possibility of the pinerc file being remote, and we replaced
     * the variable pinerc with the structure prc. Unfortunately, some
     * parts of pine rely on the fact that pinerc is the name of the
     * pinerc _file_, and use the directory that the pinerc file is located
     * in for their own purposes. We want to preserve that so things will
     * keep working. So, even if the real pinerc is remote, we need to
     * put the name of a pinerc file in the pinerc variable so that the
     * directory which contains that file is writable. The file itself
     * doesn't have to exist for this purpose, since we are really only
     * using the name of the directory containing the file. Twisted.
     * (Alternatively, we could fix all of the code that uses the pinerc
     * variable for this purpose to use a new variable which really is
     * just a directory.) hubert 2000-sep
     *
     * There are 3 cases. If pinerc is already set that means that the user
     * gave either a -p pinerc or an environment pinerc that is a local file,
     * and we are done. If pinerc is not set, then either prc is set or not.
     * If prc is set then the -p arg or PINERC value is a remote pinerc.
     * In that case we need to find a local directory to use, and put that
     * directory in the pinerc variable (with a fake filename tagged on).
     * If prc is not set, then user hasn't told us anything so we have to
     * try to find the default pinerc file by looking down the path of
     * possibilities. When we find it, we'll also use that directory.
     */
    if(!ps->pinerc){
	*l_pinerc = '\0';
	*buf = '\0';

	if(ps->prc){				/* remote pinerc case */
	    /*
	     * We don't give them an l_pinerc unless they tell us where
	     * to put it.
	     */
	    if(ps->aux_files_dir)
	      build_path(l_pinerc, ps->aux_files_dir, SYSTEM_PINERC,
			 sizeof(l_pinerc));
	    else{
		/*
		 * Search for a writable directory.
		 * Mimic what happens in !prc for local case, except we
		 * don't need to look for the actual file.
		 */

		/* check if $HOME\PINE is writable */
		build_path(buf2, ps->home_dir, DF_PINEDIR, sizeof(buf2));
		if(is_writable_dir(buf2) == 0)
		  build_path(l_pinerc, buf2, SYSTEM_PINERC, sizeof(l_pinerc));
		else{			/* $HOME\PINE not a writable dir */
		    /* use this unless registry redirects us */
		    build_path(l_pinerc, ps->pine_dir, SYSTEM_PINERC,
			       sizeof(l_pinerc));
#ifdef	_WINDOWS
		    /* if in registry, use that value */
		    if(mswin_reg(MSWR_OP_GET, MSWR_PINE_RC, buf2, sizeof(buf2))
		       && !IS_REMOTE(buf2)){
			strncpy(l_pinerc, buf2, sizeof(l_pinerc)-1);
			l_pinerc[sizeof(l_pinerc)-1] = '\0';
		    }
#endif
		}
	    }
	}
	else{			/* searching for pinerc file to use */
	    /*
	     * Buf2 is $HOME\PINE. If $HOME is not explicitly set,
	     * it defaults to the current working drive (often C:).
	     * See alpine.c to see how it is initially set.
	     */

	    mprint(2, (db, DSIZE-(db-(*debug_out)), "  no, searching...\n"));
	    build_path(buf2, ps->home_dir, DF_PINEDIR, sizeof(buf2));
	    mprint(2, (db, DSIZE-(db-(*debug_out)),
	      "  checking for writable %.100s dir \"%.100s\" off of homedir\n",
		   DF_PINEDIR, buf2));
	    if(is_writable_dir(buf2) == 0){
		/*
		 * $HOME\PINE exists and is writable.
		 * See if $HOME\PINE\PINERC exists.
		 */
		build_path(buf, buf2, SYSTEM_PINERC, sizeof(buf));
		strncpy(l_pinerc, buf, sizeof(l_pinerc)-1);
		l_pinerc[sizeof(l_pinerc)-1] = '\0';
		mprint(2, (db, DSIZE-(db-(*debug_out)), "  yes, now checking for file \"%.100s\"\n",
		       buf));
		if(can_access(buf, ACCESS_EXISTS) == 0){	/* found it! */
		    /*
		     * Buf is what we were looking for.
		     * It is local and can be used for the directory, too.
		     */
		    mprint(2, (db, DSIZE-(db-(*debug_out)), "  found it\n"));
		}
		else{
		    /*
		     * No $HOME\PINE\PINERC, look for
		     * one in same dir as PINE.EXE.
		     */
		    build_path(buf2, ps->pine_dir, SYSTEM_PINERC,
			       sizeof(buf2));
		    mprint(2, (db, DSIZE-(db-(*debug_out)),
			   "  no, checking for \"%.100s\" in pine.exe dir\n",
			   buf2));
		    if(can_access(buf2, ACCESS_EXISTS) == 0){
			/* found it! */
			mprint(2, (db, DSIZE-(db-(*debug_out)), "  found it\n"));
			strncpy(buf, buf2, sizeof(buf)-1);
			buf[sizeof(buf)-1] = '\0';
			strncpy(l_pinerc, buf2, sizeof(l_pinerc)-1);
			l_pinerc[sizeof(l_pinerc)-1] = '\0';
		    }
		    else{
#ifdef	_WINDOWS
			mprint(2, (db, DSIZE-(db-(*debug_out)), "  no, checking in registry\n"));
			if(mswin_reg(MSWR_OP_GET, MSWR_PINE_RC,
				     buf2, sizeof(buf2))){
			    strncpy(buf, buf2, sizeof(buf)-1);
			    buf[sizeof(buf)-1] = '\0';
			    if(!IS_REMOTE(buf2)){
				strncpy(l_pinerc, buf2, sizeof(l_pinerc)-1);
				l_pinerc[sizeof(l_pinerc)-1] = '\0';
			    }
			    /*
			     * Now buf is the pinerc to be used, l_pinerc is
			     * the directory, which may be either same as buf
			     * or it may be $HOME\PINE if registry gives us
			     * a remote pinerc.
			     */
			    mprint(2, (db, DSIZE-(db-(*debug_out)), "  found \"%.100s\" in registry\n",
				   buf));
			}
			else{
			    nopinerc = 1;
			    mprint(2, (db, DSIZE-(db-(*debug_out)), "  not found, asking user\n"));
			}
#else
			mprint(2, (db, DSIZE-(db-(*debug_out)), "  not found\n"));
#endif
		    }
		}

		/*
		 * Buf is the pinerc (could be remote if from registry)
		 * and l_pinerc is the local pinerc, which may not exist.
		 */
	    }
	    else{			/* $HOME\PINE not a writable dir */
		/*
		 * We notice that the order of checking in the registry
		 * and checking in the ALPINE.EXE directory are different
		 * in this case versus the is_writable_dir(buf2) case, and
		 * that does sort of look like a bug. However,
		 * we don't think this is a bug since we did it on purpose
		 * a long time ago. So even though we can't remember why
		 * it is this way, we think we would rediscover why if we
		 * changed it! So we won't change it.
		 */

		/*
		 * Change the default to use to the ALPINE.EXE directory.
		 */
		build_path(buf, ps->pine_dir, SYSTEM_PINERC, sizeof(buf));
		strncpy(l_pinerc, buf, sizeof(l_pinerc)-1);
		l_pinerc[sizeof(l_pinerc)-1] = '\0';
#ifdef	_WINDOWS
		mprint(2, (db, DSIZE-(db-(*debug_out)), "  no, not writable, checking in registry\n"));
		/* if in registry, use that value */
		if(mswin_reg(MSWR_OP_GET, MSWR_PINE_RC, buf2, sizeof(buf2))){
		    strncpy(buf, buf2, sizeof(buf)-1);
		    buf[sizeof(buf)-1] = '\0';
		    mprint(2, (db, DSIZE-(db-(*debug_out)), "  found \"%.100s\" in registry\n",
			   buf));
		    if(!IS_REMOTE(buf)){
			strncpy(l_pinerc, buf, sizeof(l_pinerc)-1);
			l_pinerc[sizeof(l_pinerc)-1] = '\0';
		    }
		}
		else{
		    mprint(2, (db, DSIZE-(db-(*debug_out)),
			"  no, checking for \"%.100s\" in alpine.exe dir\n",
			buf));

		    if(can_access(buf, ACCESS_EXISTS) == 0){
			mprint(2, (db, DSIZE-(db-(*debug_out)), "  found it\n"));
		    }
		    else{
			nopinerc = 1;
			mprint(2, (db, DSIZE-(db-(*debug_out)), "  not found, asking user\n"));
		    }
		}
#else
		mprint(2, (db, DSIZE-(db-(*debug_out)),
			"  no, checking for \"%.100s\" in alpine.exe dir\n",
			buf));

		if(can_access(buf, ACCESS_EXISTS) == 0){
		    mprint(2, (db, DSIZE-(db-(*debug_out)), "  found it\n"));
		}
		else{
		    mprint(2, (db, DSIZE-(db-(*debug_out)), "  not found, creating it\n"));
		}
#endif
	    }

	    /*
	     * When we get here we have buf set to the name of the
	     * pinerc, which could be local or remote. We have l_pinerc
	     * set to the same as buf if buf is local, and set to another
	     * name otherwise, hopefully contained in a writable directory.
	     */
#ifdef _WINDOWS
	    if(nopinerc || ps_global->install_flag){
		char buf3[MAXPATH+1];

		confregset = 0;
		strncpy(buf3, buf, MAXPATH);
		buf3[MAXPATH] = '\0';
		if(os_config_dialog(buf3, MAXPATH,
				    &confregset, nopinerc) == 0){
		    strncpy(buf, buf3, MAXPATH);
		    buf[MAXPATH] = '\0';
		    mprint(2, (db, DSIZE-(db-(*debug_out)), "  not found, creating it\n"));
		    mprint(2, (db, DSIZE-(db-(*debug_out)), "  user says use \"%.100s\"\n", buf));
		    if(!IS_REMOTE(buf)){
			strncpy(l_pinerc, buf, MAXPATH);
			l_pinerc[MAXPATH] = '\0';
		    }
		}
		else{
		    exit(-1);
		}
	    }
#endif
	    ps->prc = new_pinerc_s(buf);
	}

	ps->pinerc = cpystr(l_pinerc);
    }

#if defined(DOS) || defined(OS2)
    /* 
     * The goal here is to set the auxiliary directory in the pinerc variable.
     * We are making the assumption that any reference to the pinerc variable
     * after this point is used only as a directory in which to store things,
     * with the prc variable being the preferred place to store pinerc location.
     * If -aux isn't set, then there is no change. -jpf 08/2001
     */
    if(ps->aux_files_dir){
	l_pinerc[0] = '\0';
	build_path(l_pinerc, ps->aux_files_dir, SYSTEM_PINERC,
		   sizeof(l_pinerc));
	if(ps->pinerc) fs_give((void **)&ps->pinerc);
	ps->pinerc = cpystr(l_pinerc);
	mprint(2, (db, DSIZE-(db-(*debug_out)), "Setting aux_files_dir to \"%.100s\"\n",
	       ps->aux_files_dir));
    }
#endif

#ifdef	_WINDOWS
    if(confregset && (ps->update_registry != UREG_NEVER_SET))
      mswin_reg(MSWR_OP_SET | ((ps->update_registry == UREG_ALWAYS_SET)
			       || confregset == 1 ? MSWR_OP_FORCE : 0),
		MSWR_PINE_RC, 
		(ps->prc && ps->prc->name) ?
		ps->prc->name : ps->pinerc, (size_t)NULL);
#endif

    /*
     * Now that we know the default for the PINERC, build NEWSRC default.
     * Backward compatibility makes this kind of funky.  If what the
     * c-client thinks the NEWSRC should be exists *AND* it doesn't
     * already exist in the PINERC's dir, use c-client's default, otherwise
     * use the one next to the PINERC...
     */
    p = last_cmpnt(ps->pinerc);
    buf[0] = '\0';
    if(p != NULL){
	strncpy(buf, ps->pinerc, MIN(p - ps->pinerc, sizeof(buf)-1));
	buf[MIN(p - ps->pinerc, sizeof(buf)-1)] = '\0';
    }

    mprint(2, (db, DSIZE-(db-(*debug_out)), "Using directory \"%.100s\" for auxiliary files\n", buf));
    strncat(buf, "NEWSRC", sizeof(buf)-1-strlen(buf));

    if(!(p = (void *) mail_parameters(NULL, GET_NEWSRC, (void *)NULL))
       || can_access(p, ACCESS_EXISTS) < 0
       || can_access(buf, ACCESS_EXISTS) == 0){
	mail_parameters(NULL, SET_NEWSRC, (void *)buf);
	GLO_NEWSRC_PATH = cpystr(buf);
    }
    else
      GLO_NEWSRC_PATH = cpystr(p);

    if(ps->pconf){
      mprint(2, (db, DSIZE-(db-(*debug_out)), "Global config \"%.100s\" comes from command line\n",
	     (ps->pconf && ps->pconf->name) ? ps->pconf->name : "<no name>"));
    }
    else{
      mprint(2, (db, DSIZE-(db-(*debug_out)),
	     "Global config not set on cmdline, checking for $PINECONF\n"));
    }

    if(!ps->pconf && (p = getenv("PINECONF"))){
	ps->pconf = new_pinerc_s(p);
	if(ps->pconf){
	  mprint(2, (db, DSIZE-(db-(*debug_out)),
	     "  yes, global config \"%.100s\" comes from $PINECONF\n",
	     (ps->pconf && ps->pconf->name) ? ps->pconf->name : "<no name>"));
	}
    }
#ifdef _WINDOWS
    else if(!ps->pconf
	    && mswin_reg(MSWR_OP_GET, MSWR_PINE_CONF, buf2, sizeof(buf2))){
	ps->pconf = new_pinerc_s(buf2);
	if(ps->pconf){
	    mprint(2, (db, DSIZE-(db-(*debug_out)),
	     "  yes, global config \"%.100s\" comes from Registry\n",
	     (ps->pconf && ps->pconf->name) ? ps->pconf->name : "<no name>"));
	}
    }
#endif
    if(!ps->pconf){
      mprint(2, (db, DSIZE-(db-(*debug_out)), "  no, there is no global config\n"));
    }
#ifdef _WINDOWS
    else if (ps->pconf && ps->pconf->name && 
	     (ps->update_registry != UREG_NEVER_SET)){
	mswin_reg(MSWR_OP_SET | ((ps->update_registry == UREG_ALWAYS_SET)
				 ? MSWR_OP_FORCE : 0),
		  MSWR_PINE_CONF,
		  ps->pconf->name, (size_t)NULL);
    }
#endif
    
    if(!ps->prc)
      ps->prc = new_pinerc_s(ps->pinerc);

    if(ps->exceptions){
      mprint(2, (db, DSIZE-(db-(*debug_out)),
	     "Exceptions config \"%.100s\" comes from command line\n",
	     ps->exceptions));
    }
    else{
      mprint(2, (db, DSIZE-(db-(*debug_out)),
	     "Exceptions config not set on cmdline, checking for $PINERCEX\n"));
    }

    /*
     * Exceptions is done slightly differently from pinerc. Instead of setting
     * post_prc in args.c we just set the string and use it here. We do
     * that so that we can put it in the same directory as the pinerc if
     * exceptions is a relative name, and pinerc may not be set until here.
     *
     * First, just like for pinerc, check environment variable if it wasn't
     * set on the command line.
     */
    if(!ps->exceptions && (p = getenv("PINERCEX")) && *p){
	ps->exceptions = cpystr(p);
	if(ps->exceptions){
	  mprint(2, (db, DSIZE-(db-(*debug_out)),
		 "  yes, exceptions config \"%.100s\" comes from $PINERCEX\n",
		 ps->exceptions));
	}
    }

    /*
     * If still not set, try specific file in same dir as pinerc.
     * Only use it if the file exists.
     */
    if(!ps->exceptions){
	p = last_cmpnt(ps->pinerc);
	buf[0] = '\0';
	if(p != NULL){
	    strncpy(buf, ps->pinerc, MIN(p - ps->pinerc, sizeof(buf)-1));
	    buf[MIN(p - ps->pinerc, sizeof(buf)-1)] = '\0';
	}

	strncat(buf, "PINERCEX", sizeof(buf)-1-strlen(buf));

	mprint(2, (db, DSIZE-(db-(*debug_out)),
	       "  no, checking for default \"%.100s\" in pinerc dir\n", buf));
	if(can_access(buf, ACCESS_EXISTS) == 0)		/* found it! */
	  ps->exceptions = cpystr(buf);

	if(ps->exceptions){
	  mprint(2, (db, DSIZE-(db-(*debug_out)),
		 "  yes, exceptions config \"%.100s\" comes from default\n",
		 ps->exceptions));
	}
	else{
	  mprint(2, (db, DSIZE-(db-(*debug_out)), "  no, there is no exceptions config\n"));
	}
    }

#else /* unix */

    if(ps->pconf){
      mprint(2, (db, DSIZE-(db-(*debug_out)), "Global config \"%.100s\" comes from command line\n",
	     (ps->pconf && ps->pconf->name) ? ps->pconf->name : "<no name>"));
    }

    if(!ps->pconf){
	ps->pconf = new_pinerc_s(SYSTEM_PINERC);
	if(ps->pconf){
	  mprint(2, (db, DSIZE-(db-(*debug_out)), "Global config \"%.100s\" is default\n",
	     (ps->pconf && ps->pconf->name) ? ps->pconf->name : "<no name>"));
	}
    }

    if(!ps->pconf){
      mprint(2, (db, DSIZE-(db-(*debug_out)), "No global config!\n"));
    }

    if(ps->prc){
      mprint(2, (db, DSIZE-(db-(*debug_out)), "Personal config \"%.100s\" comes from command line\n",
	     (ps->prc && ps->prc->name) ? ps->prc->name : "<no name>"));
    }

    if(!ps->pinerc){
      build_path(buf, ps->home_dir, ".pinerc", sizeof(buf));
      ps->pinerc = cpystr(buf);
    }

    if(!ps->prc){
	ps->prc = new_pinerc_s(ps->pinerc);
	if(ps->prc){
	  mprint(2, (db, DSIZE-(db-(*debug_out)), "Personal config \"%.100s\" is default\n",
	     (ps->prc && ps->prc->name) ? ps->prc->name : "<no name>"));
	}
    }

    if(!ps->prc){
      mprint(2, (db, DSIZE-(db-(*debug_out)), "No personal config!\n"));
    }

    if(ps->exceptions){
      mprint(2, (db, DSIZE-(db-(*debug_out)),
	     "Exceptions config \"%.100s\" comes from command line\n",
	     ps->exceptions));
    }

    /*
     * If not set, try specific file in same dir as pinerc.
     * Only use it if the file exists.
     */
    if(!ps->exceptions){
	p = last_cmpnt(ps->pinerc);
	buf[0] = '\0';
	if(p != NULL){
	    strncpy(buf, ps->pinerc, MIN(p - ps->pinerc, sizeof(buf)-1));
	    buf[MIN(p - ps->pinerc, sizeof(buf)-1)] = '\0';
	}

	strncat(buf, ".pinercex", sizeof(buf)-1-strlen(buf));
        mprint(2, (db, DSIZE-(db-(*debug_out)), "Exceptions config not set on cmdline\n  checking for default \"%.100s\" in pinerc dir\n", buf));

	if(can_access(buf, ACCESS_EXISTS) == 0)		/* found it! */
	  ps->exceptions = cpystr(buf);

	if(ps->exceptions){
	  mprint(2, (db, DSIZE-(db-(*debug_out)),
		 "  yes, exceptions config \"%.100s\" is default\n",
		 ps->exceptions));
	}
	else{
	  mprint(2, (db, DSIZE-(db-(*debug_out)), "  no, there is no exceptions config\n"));
	}
    }

#endif /* unix */

    if(ps->exceptions){

	if(!IS_REMOTE(ps->exceptions) &&
	   !is_absolute_path(ps->exceptions)){
#if defined(DOS) || defined(OS2)
	    p = last_cmpnt(ps->pinerc);
	    buf[0] = '\0';
	    if(p != NULL){
		strncpy(buf, ps->pinerc, MIN(p - ps->pinerc, sizeof(buf)-1));
		buf[MIN(p - ps->pinerc, sizeof(buf)-1)] = '\0';
	    }

	    strncat(buf, ps->exceptions, sizeof(buf)-1-strlen(buf));
#else
	    build_path(buf, ps->home_dir, ps->exceptions, sizeof(buf));
#endif
	}
	else{
	    strncpy(buf, ps->exceptions, sizeof(buf)-1);
	    buf[sizeof(buf)-1] = '\0';
	}

	ps->post_prc = new_pinerc_s(buf);

	fs_give((void **)&ps->exceptions);
    }

    mprint(2, (db, DSIZE-(db-(*debug_out)), "\n  Global config:     %.100s\n",
	   (ps->pconf && ps->pconf->name) ? ps->pconf->name : "<none>"));
    mprint(2, (db, DSIZE-(db-(*debug_out)), "  Personal config:   %.100s\n",
	   (ps->prc && ps->prc->name) ? ps->prc->name : "<none>"));
    mprint(2, (db, DSIZE-(db-(*debug_out)), "  Exceptions config: %.100s\n",
	   (ps->post_prc && ps->post_prc->name) ? ps->post_prc->name
						: "<none>"));
#if !defined(DOS) && !defined(OS2)
    if(SYSTEM_PINERC_FIXED){
      mprint(2, (db, DSIZE-(db-(*debug_out)), "  Fixed config:      %.100s\n", SYSTEM_PINERC_FIXED));
    }
#endif

    mprint(2, (db, DSIZE-(db-(*debug_out)), "\n"));
}
    

/*----------------------------------------------------------------------
     Initialize the variables

 Args:   ps   -- The usual pine structure

 Result: 

  This reads the system pine configuration file and the user's pine
configuration file ".pinerc" and places the results in the variables 
structure.  It sorts out what was read and sets a few other variables 
based on the contents.
  ----*/
void 
init_vars(struct pine *ps, void (*cmds_f) (struct pine *, char **))
{
    char	 buf[MAXPATH+1], *p, *q, **s;
    register struct variable *vars = ps->vars;
    int		 obs_header_in_reply = 0,     /* the obs_ variables are to       */
		 obs_old_style_reply = 0,     /* support backwards compatibility */
		 obs_save_by_sender, i, def_sort_rev;
    long         rvl;
    PINERC_S    *fixedprc = NULL;
    FeatureLevel obs_feature_level;
    char        *fromcharset = NULL;
    char        *err = NULL;

    dprint((5, "init_vars:\n"));

    /*--- The defaults here are defined in os-xxx.h so they can vary
          per machine ---*/

    GLO_PRINTER			= cpystr(DF_DEFAULT_PRINTER);
    GLO_ELM_STYLE_SAVE		= cpystr(DF_ELM_STYLE_SAVE);
    GLO_SAVE_BY_SENDER		= cpystr(DF_SAVE_BY_SENDER);
    GLO_HEADER_IN_REPLY		= cpystr(DF_HEADER_IN_REPLY);
    GLO_INBOX_PATH		= cpystr("inbox");
    GLO_DEFAULT_FCC		= cpystr(DF_DEFAULT_FCC);
    GLO_DEFAULT_SAVE_FOLDER	= cpystr(DEFAULT_SAVE);
    GLO_POSTPONED_FOLDER	= cpystr(POSTPONED_MSGS);
    GLO_TRASH_FOLDER		= cpystr(TRASH_FOLDER);
    GLO_USE_ONLY_DOMAIN_NAME	= cpystr(DF_USE_ONLY_DOMAIN_NAME);
    GLO_FEATURE_LEVEL		= cpystr("sappling");
    GLO_OLD_STYLE_REPLY		= cpystr(DF_OLD_STYLE_REPLY);
    GLO_SORT_KEY		= cpystr(DF_SORT_KEY);
    GLO_SAVED_MSG_NAME_RULE	= cpystr(DF_SAVED_MSG_NAME_RULE);
    GLO_FCC_RULE		= cpystr(DF_FCC_RULE);
    GLO_AB_SORT_RULE		= cpystr(DF_AB_SORT_RULE);
    GLO_FLD_SORT_RULE		= cpystr(DF_FLD_SORT_RULE);
    GLO_SIGNATURE_FILE		= cpystr(DF_SIGNATURE_FILE);
    GLO_MAIL_DIRECTORY		= cpystr(DF_MAIL_DIRECTORY);
    GLO_REMOTE_ABOOK_HISTORY	= cpystr(DF_REMOTE_ABOOK_HISTORY);
    GLO_REMOTE_ABOOK_VALIDITY	= cpystr(DF_REMOTE_ABOOK_VALIDITY);
    GLO_GOTO_DEFAULT_RULE	= cpystr(DF_GOTO_DEFAULT_RULE);
    GLO_INCOMING_STARTUP	= cpystr(DF_INCOMING_STARTUP);
    GLO_PRUNING_RULE		= cpystr(DF_PRUNING_RULE);
    GLO_REOPEN_RULE		= cpystr(DF_REOPEN_RULE);
    GLO_THREAD_DISP_STYLE	= cpystr(DF_THREAD_DISP_STYLE);
    GLO_THREAD_INDEX_STYLE	= cpystr(DF_THREAD_INDEX_STYLE);
    GLO_THREAD_MORE_CHAR	= cpystr(DF_THREAD_MORE_CHAR);
    GLO_THREAD_EXP_CHAR		= cpystr(DF_THREAD_EXP_CHAR);
    GLO_THREAD_LASTREPLY_CHAR	= cpystr(DF_THREAD_LASTREPLY_CHAR);
    GLO_BUGS_FULLNAME		= cpystr("Sorry No Address");
    GLO_BUGS_ADDRESS		= cpystr("nobody");
    GLO_SUGGEST_FULLNAME	= cpystr("Sorry No Address");
    GLO_SUGGEST_ADDRESS		= cpystr("nobody");
    GLO_LOCAL_FULLNAME		= cpystr(DF_LOCAL_FULLNAME);
    GLO_LOCAL_ADDRESS		= cpystr(DF_LOCAL_ADDRESS);
    GLO_OVERLAP			= cpystr(DF_OVERLAP);
    GLO_MAXREMSTREAM		= cpystr(DF_MAXREMSTREAM);
    GLO_MARGIN			= cpystr(DF_MARGIN);
    GLO_FILLCOL			= cpystr(DF_FILLCOL);
    GLO_DEADLETS		= cpystr(DF_DEADLETS);
    GLO_NMW_WIDTH		= cpystr(DF_NMW_WIDTH);
    GLO_REPLY_STRING		= cpystr("> ");
    GLO_REPLY_INTRO		= cpystr(DEFAULT_REPLY_INTRO);
    GLO_EMPTY_HDR_MSG		= cpystr("undisclosed-recipients");
    GLO_STATUS_MSG_DELAY	= cpystr("0");
    GLO_ACTIVE_MSG_INTERVAL	= cpystr("12");
    GLO_USERINPUTTIMEO		= cpystr("0");
    GLO_INCCHECKTIMEO		= cpystr("5");
    GLO_INCCHECKINTERVAL	= cpystr("180");
    GLO_INC2NDCHECKINTERVAL	= cpystr("180");
    GLO_MAILCHECK		= cpystr(DF_MAILCHECK);
    GLO_MAILCHECKNONCURR	= cpystr("0");
    GLO_MAILDROPCHECK		= cpystr(DF_MAILDROPCHECK);
    GLO_NNTPRANGE		= cpystr("0");
    GLO_KBLOCK_PASSWD_COUNT	= cpystr(DF_KBLOCK_PASSWD_COUNT);
    GLO_INDEX_COLOR_STYLE	= cpystr("flip-colors");
    GLO_TITLEBAR_COLOR_STYLE	= cpystr("default");
    GLO_POST_CHAR_SET		= cpystr("UTF-8");
#ifdef	DF_FOLDER_EXTENSION
    GLO_FOLDER_EXTENSION	= cpystr(DF_FOLDER_EXTENSION);
#endif
#ifdef	DF_SMTP_SERVER
    GLO_SMTP_SERVER		= parse_list(DF_SMTP_SERVER, 1,
					     PL_REMSURRQUOT, NULL);
#endif
#ifndef	_WINDOWS
    GLO_COLOR_STYLE		= cpystr("no-color");
    GLO_NORM_FORE_COLOR		= cpystr(DEFAULT_NORM_FORE_RGB);
    GLO_NORM_BACK_COLOR		= cpystr(DEFAULT_NORM_BACK_RGB);
#endif
    GLO_TITLE_FORE_COLOR	= cpystr(DEFAULT_TITLE_FORE_RGB);
    GLO_TITLE_BACK_COLOR	= cpystr(DEFAULT_TITLE_BACK_RGB);
    GLO_TITLECLOSED_FORE_COLOR	= cpystr(DEFAULT_TITLECLOSED_FORE_RGB);
    GLO_TITLECLOSED_BACK_COLOR	= cpystr(DEFAULT_TITLECLOSED_BACK_RGB);
    GLO_METAMSG_FORE_COLOR	= cpystr(DEFAULT_METAMSG_FORE_RGB);
    GLO_METAMSG_BACK_COLOR	= cpystr(DEFAULT_METAMSG_BACK_RGB);
    GLO_QUOTE1_FORE_COLOR	= cpystr(DEFAULT_QUOTE1_FORE_RGB);
    GLO_QUOTE1_BACK_COLOR	= cpystr(DEFAULT_QUOTE1_BACK_RGB);
    GLO_QUOTE2_FORE_COLOR	= cpystr(DEFAULT_QUOTE2_FORE_RGB);
    GLO_QUOTE2_BACK_COLOR	= cpystr(DEFAULT_QUOTE2_BACK_RGB);
    GLO_QUOTE3_FORE_COLOR	= cpystr(DEFAULT_QUOTE3_FORE_RGB);
    GLO_QUOTE3_BACK_COLOR	= cpystr(DEFAULT_QUOTE3_BACK_RGB);
    GLO_SIGNATURE_FORE_COLOR	= cpystr(DEFAULT_SIGNATURE_FORE_RGB);
    GLO_SIGNATURE_BACK_COLOR	= cpystr(DEFAULT_SIGNATURE_BACK_RGB);
    GLO_IND_PLUS_FORE_COLOR	= cpystr(DEFAULT_IND_PLUS_FORE_RGB);
    GLO_IND_PLUS_BACK_COLOR	= cpystr(DEFAULT_IND_PLUS_BACK_RGB);
    GLO_IND_IMP_FORE_COLOR	= cpystr(DEFAULT_IND_IMP_FORE_RGB);
    GLO_IND_IMP_BACK_COLOR	= cpystr(DEFAULT_IND_IMP_BACK_RGB);
    GLO_IND_ANS_FORE_COLOR	= cpystr(DEFAULT_IND_ANS_FORE_RGB);
    GLO_IND_ANS_BACK_COLOR	= cpystr(DEFAULT_IND_ANS_BACK_RGB);
    GLO_IND_NEW_FORE_COLOR	= cpystr(DEFAULT_IND_NEW_FORE_RGB);
    GLO_IND_NEW_BACK_COLOR	= cpystr(DEFAULT_IND_NEW_BACK_RGB);
    GLO_IND_OP_FORE_COLOR	= cpystr(DEFAULT_IND_OP_FORE_RGB);
    GLO_IND_OP_BACK_COLOR	= cpystr(DEFAULT_IND_OP_BACK_RGB);
    GLO_VIEW_MARGIN_LEFT	= cpystr("0");
    GLO_VIEW_MARGIN_RIGHT	= cpystr(DF_VIEW_MARGIN_RIGHT);
    GLO_QUOTE_SUPPRESSION	= cpystr(DF_QUOTE_SUPPRESSION);
    GLO_KW_BRACES		= cpystr("\"{\" \"} \"");
    GLO_OPENING_SEP		= cpystr(" - ");
    GLO_WP_INDEXHEIGHT          = cpystr("24");
    GLO_WP_AGGSTATE		= cpystr("1");
    GLO_WP_STATE		= cpystr("");
#ifdef	DF_VAR_SPELLER
    GLO_SPELLER			= cpystr(DF_VAR_SPELLER);
#endif
#ifdef	SMIME
    GLO_PUBLICCERT_DIR		= cpystr(DF_PUBLICCERT_DIR);
    GLO_PRIVATEKEY_DIR		= cpystr(DF_PRIVATEKEY_DIR);
    GLO_CACERT_DIR		= cpystr(DF_CACERT_DIR);
#endif	/* SMIME */

    /*
     * Default first value for addrbook list if none set.
     * We also want to be sure to set global_val to the default
     * if is_fixed, so that address-book= will cause the default to happen.
     */
    if(!GLO_ADDRESSBOOK && !FIX_ADDRESSBOOK)
      GLO_ADDRESSBOOK = parse_list(DF_ADDRESSBOOK, 1, 0, NULL);

    /*
     * Default first value if none set.
     */
    if(!GLO_STANDARD_PRINTER && !FIX_STANDARD_PRINTER)
      GLO_STANDARD_PRINTER = parse_list(DF_STANDARD_PRINTER, 1, 0, NULL);

#if !defined(DOS) && !defined(OS2)
    /*
     * This is here instead of in init_pinerc so that we can get by without
     * having a global fixedprc, since we don't need it anymore after this.
     */
    fixedprc = new_pinerc_s(SYSTEM_PINERC_FIXED);
#endif

    if(ps->pconf){
	read_pinerc(ps->pconf, vars, ParseGlobal);
	if(ps->pconf->type != Loc)
	  rd_close_remote(ps->pconf->rd);
    }

    if(ps->prc){
	read_pinerc(ps->prc, vars, ParsePers);
	if(ps->prc->type != Loc)
	  rd_close_remote(ps->prc->rd);
    }

    if(ps->post_prc){
	read_pinerc(ps->post_prc, vars, ParsePersPost);
	if(ps->post_prc->type != Loc)
	  rd_close_remote(ps->post_prc->rd);
    }

    if(fixedprc){
	read_pinerc(fixedprc, vars, ParseFixed);
	free_pinerc_s(&fixedprc);
    }

    ps->ew_for_except_vars = ps->post_prc ? Post : Main;

    if(ps->exit_if_no_pinerc && ps->first_time_user){

	/* TRANSLATORS: -bail is a literal option name, don't change it. */
	exceptional_exit(_("Exiting because -bail option is set and config file doesn't exist."), -1);
    }

    /*
     * Convert everything having to do with the config to UTF-8
     * in order to avoid having to worry about it all over the
     * place.
     * Set the character-set first so that we may use that in
     * the conversion process.
     */
    set_collation(0, 1);

#ifndef	_WINDOWS
#if (HAVE_LANGINFO_H && defined(CODESET))

    if(output_charset_is_supported(nl_langinfo_codeset_wrapper()))
      ps->GLO_CHAR_SET = cpystr(nl_langinfo_codeset_wrapper());
    else{
	ps->GLO_CHAR_SET = cpystr("UTF-8");
        dprint((1,"nl_langinfo(CODESET) returns unrecognized value=\"%s\", using UTF-8 as default\n", (p=nl_langinfo(CODESET)) ? p : ""));
    }
#else
    ps->GLO_CHAR_SET = cpystr("UTF-8");
#endif

    set_current_val(&vars[V_CHAR_SET], TRUE, TRUE);
    set_current_val(&vars[V_OLD_CHAR_SET], TRUE, TRUE);
    set_current_val(&vars[V_KEY_CHAR_SET], TRUE, TRUE);
#endif	/* ! _WINDOWS */

    set_current_val(&vars[V_POST_CHAR_SET], TRUE, TRUE);

    /*
     * Also set up the feature list because we need the
     * Use-System-Translation feature to set up the charmaps.
     */

    /* way obsolete, backwards compatibility */
    set_current_val(&vars[V_FEATURE_LEVEL], TRUE, TRUE);
    if(strucmp(VAR_FEATURE_LEVEL, "seedling") == 0)
      obs_feature_level = Seedling;
    else if(strucmp(VAR_FEATURE_LEVEL, "old-growth") == 0)
      obs_feature_level = Seasoned;
    else
      obs_feature_level = Sapling;

    /* obsolete, backwards compatibility */
    set_current_val(&vars[V_OLD_STYLE_REPLY], TRUE, TRUE);
    obs_old_style_reply = !strucmp(VAR_OLD_STYLE_REPLY, "yes");

    set_feature_list_current_val(&vars[V_FEATURE_LIST]);
    process_feature_list(ps, VAR_FEATURE_LIST,
           (obs_feature_level == Seasoned) ? 1 : 0,
	   obs_header_in_reply, obs_old_style_reply);


    /*
     * Redo set_collation call with correct value for collation,
     * but we're hardwiring ctype on now. That's because nl_langinfo()
     * call needs it and system-dependent wcwidth and wcrtomb functions
     * need it.
     */
    set_collation(F_OFF(F_DISABLE_SETLOCALE_COLLATE, ps_global), 1);

    /*
     * Set up to send the correct sequence of bytes to the display terminal.
     */

    if(reset_character_set_stuff(&err) == -1)
      panic(err ? err : "trouble with character set setup");
    else if(err){
	init_error(ps, SM_ORDER | SM_DING, 3, 5, err);
	fs_give((void **) &err);
    }

    /*
     * Now we use the configvars from above to convert the rest
     * to UTF-8. That should be ok because the ones above should
     * be ASCII.
     */
    if(ps->keyboard_charmap && strucmp(ps->keyboard_charmap, "UTF-8")
       &&  strucmp(ps->keyboard_charmap, "US-ASCII"))
      fromcharset = ps->keyboard_charmap;
    else if(ps->display_charmap && strucmp(ps->display_charmap, "UTF-8")
       &&  strucmp(ps->display_charmap, "US-ASCII"))
      fromcharset = ps->display_charmap;
#ifndef	_WINDOWS
    else if(VAR_OLD_CHAR_SET && strucmp(VAR_OLD_CHAR_SET, "UTF-8")
       &&  strucmp(VAR_OLD_CHAR_SET, "US-ASCII"))
      fromcharset = VAR_OLD_CHAR_SET;
#endif	/* ! _WINDOWS */

    convert_configvars_to_utf8(vars, fromcharset);

    /*
     * If we already set this while reading the remote pinerc, don't
     * change it.
     */
    if(!VAR_REMOTE_ABOOK_METADATA || !VAR_REMOTE_ABOOK_METADATA[0])
      set_current_val(&vars[V_REMOTE_ABOOK_METADATA], TRUE, TRUE);

    /*
     * mail-directory variable is obsolete, put its value in
     * default folder-collection list
     */
    set_current_val(&vars[V_MAIL_DIRECTORY], TRUE, TRUE);
    if(!GLO_FOLDER_SPEC){
	build_path(tmp_20k_buf, VAR_MAIL_DIRECTORY, "[]", SIZEOF_20KBUF);
	GLO_FOLDER_SPEC = parse_list(tmp_20k_buf, 1, 0, NULL);
    }

    set_current_val(&vars[V_FOLDER_SPEC], TRUE, TRUE);

    set_current_val(&vars[V_NNTP_SERVER], TRUE, TRUE);
    for(i = 0; VAR_NNTP_SERVER && VAR_NNTP_SERVER[i]; i++)
      removing_quotes(VAR_NNTP_SERVER[i]);

    set_news_spec_current_val(TRUE, TRUE);

    set_current_val(&vars[V_INBOX_PATH], TRUE, TRUE);

    set_current_val(&vars[V_USER_DOMAIN], TRUE, TRUE);
    if(VAR_USER_DOMAIN
       && VAR_USER_DOMAIN[0]
       && (p = strrindex(VAR_USER_DOMAIN, '@'))){
	if(*(++p)){
	    char *q;

	    snprintf(tmp_20k_buf, SIZEOF_20KBUF,
		    "User-domain (%s) cannot contain \"@\", using \"%s\"",
		    VAR_USER_DOMAIN, p);
	    init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
	    q = VAR_USER_DOMAIN;
	    while((*q++ = *p++) != '\0')
	      ;/* do nothing */
	}
	else{
	    snprintf(tmp_20k_buf, SIZEOF_20KBUF,
		    "User-domain (%s) cannot contain \"@\", deleting",
		    VAR_USER_DOMAIN);
	    init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
	    if(ps->vars[V_USER_DOMAIN].post_user_val.p){
		fs_give((void **)&ps->vars[V_USER_DOMAIN].post_user_val.p);
		set_current_val(&vars[V_USER_DOMAIN], TRUE, TRUE);
	    }

	    if(VAR_USER_DOMAIN
	       && VAR_USER_DOMAIN[0]
	       && (p = strrindex(VAR_USER_DOMAIN, '@'))){
		if(ps->vars[V_USER_DOMAIN].main_user_val.p){
		    fs_give((void **)&ps->vars[V_USER_DOMAIN].main_user_val.p);
		    set_current_val(&vars[V_USER_DOMAIN], TRUE, TRUE);
		}
	    }
	}
    }

    set_current_val(&vars[V_USE_ONLY_DOMAIN_NAME], TRUE, TRUE);
    set_current_val(&vars[V_REPLY_STRING], TRUE, TRUE);
    set_current_val(&vars[V_WORDSEPS], TRUE, TRUE);
    set_current_val(&vars[V_QUOTE_REPLACE_STRING], TRUE, TRUE);
    set_current_val(&vars[V_REPLY_INTRO], TRUE, TRUE);
    set_current_val(&vars[V_EMPTY_HDR_MSG], TRUE, TRUE);

#ifdef	ENABLE_LDAP
    set_current_val(&vars[V_LDAP_SERVERS], TRUE, TRUE);
#endif	/* ENABLE_LDAP */

    /* obsolete, backwards compatibility */
    set_current_val(&vars[V_HEADER_IN_REPLY], TRUE, TRUE);
    obs_header_in_reply=!strucmp(VAR_HEADER_IN_REPLY, "yes");

    set_current_val(&vars[V_PERSONAL_PRINT_COMMAND], TRUE, TRUE);
    set_current_val(&vars[V_STANDARD_PRINTER], TRUE, TRUE);
    set_current_val(&vars[V_PRINTER], TRUE, TRUE);
    if(vars[V_PERSONAL_PRINT_COMMAND].is_fixed && !vars[V_PRINTER].is_fixed)
      printer_value_check_and_adjust();

    set_current_val(&vars[V_LAST_TIME_PRUNE_QUESTION], TRUE, TRUE);
    if(VAR_LAST_TIME_PRUNE_QUESTION != NULL){
        /* The month value in the file runs from 1-12, the variable here
           runs from 0-11; the value in the file used to be 0-11, but we're 
           fixing it in January */
        ps->last_expire_year  = atoi(VAR_LAST_TIME_PRUNE_QUESTION);
        ps->last_expire_month =
			atoi(strindex(VAR_LAST_TIME_PRUNE_QUESTION, '.') + 1);
        if(ps->last_expire_month == 0){
            /* Fix for 0 because of old bug */
            snprintf(buf, sizeof(buf), "%d.%d", ps_global->last_expire_year,
              ps_global->last_expire_month + 1);
            set_variable(V_LAST_TIME_PRUNE_QUESTION, buf, 1, 1, Main);
        }else{
            ps->last_expire_month--; 
        } 
    }else{
        ps->last_expire_year  = -1;
        ps->last_expire_month = -1;
    }

    set_current_val(&vars[V_BUGS_FULLNAME], TRUE, TRUE);
    set_current_val(&vars[V_BUGS_ADDRESS], TRUE, TRUE);
    set_current_val(&vars[V_SUGGEST_FULLNAME], TRUE, TRUE);
    set_current_val(&vars[V_SUGGEST_ADDRESS], TRUE, TRUE);
    set_current_val(&vars[V_LOCAL_FULLNAME], TRUE, TRUE);
    set_current_val(&vars[V_LOCAL_ADDRESS], TRUE, TRUE);
    set_current_val(&vars[V_BUGS_EXTRAS], TRUE, TRUE);
    set_current_val(&vars[V_KBLOCK_PASSWD_COUNT], TRUE, TRUE);
    set_current_val(&vars[V_DEFAULT_FCC], TRUE, TRUE);
    set_current_val(&vars[V_POSTPONED_FOLDER], TRUE, TRUE);
    set_current_val(&vars[V_TRASH_FOLDER], TRUE, TRUE);
    set_current_val(&vars[V_READ_MESSAGE_FOLDER], TRUE, TRUE);
    set_current_val(&vars[V_FORM_FOLDER], TRUE, TRUE);
    set_current_val(&vars[V_EDITOR], TRUE, TRUE);
    set_current_val(&vars[V_SPELLER], TRUE, TRUE);
    set_current_val(&vars[V_IMAGE_VIEWER], TRUE, TRUE);
    set_current_val(&vars[V_BROWSER], TRUE, TRUE);
    set_current_val(&vars[V_SMTP_SERVER], TRUE, TRUE);
    set_current_val(&vars[V_COMP_HDRS], TRUE, TRUE);
    set_current_val(&vars[V_CUSTOM_HDRS], TRUE, TRUE);
    set_current_val(&vars[V_SENDMAIL_PATH], TRUE, TRUE);
    set_current_val(&vars[V_DISPLAY_FILTERS], TRUE, TRUE);
    set_current_val(&vars[V_SEND_FILTER], TRUE, TRUE);
    set_current_val(&vars[V_ALT_ADDRS], TRUE, TRUE);
    set_current_val(&vars[V_ABOOK_FORMATS], TRUE, TRUE);
    set_current_val(&vars[V_KW_BRACES], TRUE, TRUE);
    set_current_val(&vars[V_OPENING_SEP], TRUE, TRUE);
    set_current_val(&vars[V_UNK_CHAR_SET], TRUE, TRUE);
#ifdef	SMIME
    set_current_val(&vars[V_PUBLICCERT_DIR], TRUE, TRUE);
    set_current_val(&vars[V_PUBLICCERT_CONTAINER], TRUE, TRUE);
    set_current_val(&vars[V_PRIVATEKEY_DIR], TRUE, TRUE);
    set_current_val(&vars[V_PRIVATEKEY_CONTAINER], TRUE, TRUE);
    set_current_val(&vars[V_CACERT_DIR], TRUE, TRUE);
    set_current_val(&vars[V_CACERT_CONTAINER], TRUE, TRUE);
#endif	/* SMIME */

    set_current_val(&vars[V_KEYWORDS], TRUE, TRUE);
    ps_global->keywords = init_keyword_list(VAR_KEYWORDS);

    set_current_val(&vars[V_OPER_DIR], TRUE, TRUE);
    if(VAR_OPER_DIR && !VAR_OPER_DIR[0]){
	init_error(ps, SM_ORDER | SM_DING, 3, 5,
 "Setting operating-dir to the empty string is not allowed.  Will be ignored.");
	fs_give((void **)&VAR_OPER_DIR);
	if(FIX_OPER_DIR)
	  fs_give((void **)&FIX_OPER_DIR);
	if(GLO_OPER_DIR)
	  fs_give((void **)&GLO_OPER_DIR);
	if(COM_OPER_DIR)
	  fs_give((void **)&COM_OPER_DIR);
	if(ps_global->vars[V_OPER_DIR].post_user_val.p)
	  fs_give((void **)&ps_global->vars[V_OPER_DIR].post_user_val.p);
	if(ps_global->vars[V_OPER_DIR].main_user_val.p)
	  fs_give((void **)&ps_global->vars[V_OPER_DIR].main_user_val.p);
    }

    set_current_val(&vars[V_PERSONAL_PRINT_CATEGORY], TRUE, TRUE);
    ps->printer_category = -1;
    if(VAR_PERSONAL_PRINT_CATEGORY != NULL)
      ps->printer_category = atoi(VAR_PERSONAL_PRINT_CATEGORY);

    if(ps->printer_category < 1 || ps->printer_category > 3){
	char **tt;
	char aname[100], wname[100];

	strncpy(aname, ANSI_PRINTER, sizeof(aname));
	aname[sizeof(aname)-1] = '\0';
	strncat(aname, "-no-formfeed", sizeof(aname)-strlen(aname)-1);
	strncpy(wname, WYSE_PRINTER, sizeof(wname));
	wname[sizeof(wname)-1] = '\0';
	strncat(wname, "-no-formfeed", sizeof(wname)-strlen(wname)-1);
	if(strucmp(VAR_PRINTER, ANSI_PRINTER) == 0
	  || strucmp(VAR_PRINTER, aname) == 0
	  || strucmp(VAR_PRINTER, WYSE_PRINTER) == 0
	  || strucmp(VAR_PRINTER, wname) == 0)
	  ps->printer_category = 1;
	else if(VAR_STANDARD_PRINTER && VAR_STANDARD_PRINTER[0]){
	    for(tt = VAR_STANDARD_PRINTER; *tt; tt++)
	      if(strucmp(VAR_PRINTER, *tt) == 0)
		break;
	    
	    if(*tt)
	      ps->printer_category = 2;
	}

	/* didn't find it yet */
	if(ps->printer_category < 1 || ps->printer_category > 3){
	    if(VAR_PERSONAL_PRINT_COMMAND && VAR_PERSONAL_PRINT_COMMAND[0]){
		for(tt = VAR_PERSONAL_PRINT_COMMAND; *tt; tt++)
		  if(strucmp(VAR_PRINTER, *tt) == 0)
		    break;
		
		if(*tt)
		  ps->printer_category = 3;
	    }
	}
    }

    set_current_val(&vars[V_OVERLAP], TRUE, TRUE);
    ps->viewer_overlap = i = atoi(DF_OVERLAP);
    if(SVAR_OVERLAP(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
    else
      ps->viewer_overlap = i;

    set_current_val(&vars[V_MARGIN], TRUE, TRUE);
    ps->scroll_margin = i = atoi(DF_MARGIN);
    if(SVAR_MARGIN(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
    else
      ps->scroll_margin = i;

    set_current_val(&vars[V_FILLCOL], TRUE, TRUE);
    ps->composer_fillcol = i = atoi(DF_FILLCOL);
    if(SVAR_FILLCOL(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
    else
      ps->composer_fillcol = i;

    set_current_val(&vars[V_QUOTE_SUPPRESSION], TRUE, TRUE);
    ps->quote_suppression_threshold = i = atoi(DF_QUOTE_SUPPRESSION);
    if(SVAR_QUOTE_SUPPRESSION(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
    else{
	if(i > 0 && i < Q_SUPP_LIMIT){
	    snprintf(tmp_20k_buf, SIZEOF_20KBUF,
		"Ignoring Quote-Suppression-Threshold value of %.50s, see help",
		VAR_QUOTE_SUPPRESSION);
	    init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
	}
	else{
	    if(i < 0 && i != Q_DEL_ALL)
	      ps->quote_suppression_threshold = -i;
	    else
	      ps->quote_suppression_threshold = i;
	}
    }
    
    set_current_val(&vars[V_DEADLETS], TRUE, TRUE);
    ps->deadlets = i = atoi(DF_DEADLETS);
    if(SVAR_DEADLETS(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
    else
      ps->deadlets = i;
    
    set_current_val(&vars[V_STATUS_MSG_DELAY], TRUE, TRUE);
    ps->status_msg_delay = i = 0;
    if(SVAR_MSGDLAY(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
    else
      ps->status_msg_delay = i;

    set_current_val(&vars[V_ACTIVE_MSG_INTERVAL], TRUE, TRUE);
    ps->active_status_interval = i = 8;
    if(SVAR_ACTIVEINTERVAL(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
    else
      ps->active_status_interval = i;

    set_current_val(&vars[V_REMOTE_ABOOK_HISTORY], TRUE, TRUE);
    ps->remote_abook_history = i = atoi(DF_REMOTE_ABOOK_HISTORY);
    if(SVAR_AB_HIST(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
    else
      ps->remote_abook_history = i;

    set_current_val(&vars[V_REMOTE_ABOOK_VALIDITY], TRUE, TRUE);
    ps->remote_abook_validity = i = atoi(DF_REMOTE_ABOOK_VALIDITY);
    if(SVAR_AB_VALID(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
    else
      ps->remote_abook_validity = i;

    set_current_val(&vars[V_USERINPUTTIMEO], TRUE, TRUE);
    ps->hours_to_timeout = i = 0;
    if(SVAR_USER_INPUT(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
    else
      ps->hours_to_timeout = i;

    /* timeo is a regular extern int because it is referenced in pico */
    set_current_val(&vars[V_MAILCHECK], TRUE, TRUE);
    set_input_timeout(i = 15);
    if(SVAR_MAILCHK(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
    else
      set_input_timeout(i);

    set_current_val(&vars[V_MAILCHECKNONCURR], TRUE, TRUE);
    ps->check_interval_for_noncurr = i = 0;
    if(SVAR_MAILCHKNONCURR(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
    else
      ps->check_interval_for_noncurr = i;

#ifdef DEBUGJOURNAL
    ps->debugmem = 1;
#else
    ps->debugmem = 0;
#endif

    i = 30;
    set_current_val(&vars[V_TCPOPENTIMEO], TRUE, TRUE);
    /* this is just for the error, we don't save the result */
    if(VAR_TCPOPENTIMEO && SVAR_TCP_OPEN(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);

    i = 15;
    set_current_val(&vars[V_TCPREADWARNTIMEO], TRUE, TRUE);
    /* this is just for the error, we don't save the result */
    if(VAR_TCPREADWARNTIMEO && SVAR_TCP_READWARN(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);

    i = 0;
    set_current_val(&vars[V_TCPWRITEWARNTIMEO], TRUE, TRUE);
    /* this is just for the error, we don't save the result */
    if(VAR_TCPWRITEWARNTIMEO && SVAR_TCP_WRITEWARN(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);

    i = 15;
    set_current_val(&vars[V_RSHOPENTIMEO], TRUE, TRUE);
    /* this is just for the error, we don't save the result */
    if(VAR_RSHOPENTIMEO && SVAR_RSH_OPEN(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);

    i = 15;
    set_current_val(&vars[V_SSHOPENTIMEO], TRUE, TRUE);
    /* this is just for the error, we don't save the result */
    if(VAR_SSHOPENTIMEO && SVAR_SSH_OPEN(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);

    set_current_val(&vars[V_INCCHECKLIST], TRUE, TRUE);

    set_current_val(&vars[V_INCCHECKTIMEO], TRUE, TRUE);
    ps->inc_check_timeout = i = 5;
    if(SVAR_INC_CHECK_TIMEO(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
    else
      ps->inc_check_timeout = i;

    set_current_val(&vars[V_INCCHECKINTERVAL], TRUE, TRUE);
    ps->inc_check_interval = i = 180;
    if(SVAR_INC_CHECK_INTERV(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
    else
      ps->inc_check_interval = i;

    set_current_val(&vars[V_INC2NDCHECKINTERVAL], TRUE, TRUE);
    ps->inc_second_check_interval = i = 180;
    if(SVAR_INC_2NDCHECK_INTERV(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
    else
      ps->inc_second_check_interval = i;

    rvl = 60L;
    set_current_val(&vars[V_MAILDROPCHECK], TRUE, TRUE);
    /* this is just for the error, we don't save the result */
    if(VAR_MAILDROPCHECK && SVAR_MAILDCHK(ps, rvl, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);

    rvl = 0L;
    set_current_val(&vars[V_NNTPRANGE], TRUE, TRUE);
    /* this is just for the error, we don't save the result */
    if(VAR_NNTPRANGE && SVAR_NNTPRANGE(ps, rvl, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);

    set_current_val(&vars[V_TCPQUERYTIMEO], TRUE, TRUE);
    ps->tcp_query_timeout = i = TO_BAIL_THRESHOLD;
    if(VAR_TCPQUERYTIMEO && SVAR_TCP_QUERY(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
    else
      ps->tcp_query_timeout = i;

    set_current_val(&vars[V_NEWSRC_PATH], TRUE, TRUE);
    if(VAR_NEWSRC_PATH && VAR_NEWSRC_PATH[0])
      mail_parameters(NULL, SET_NEWSRC, (void *)VAR_NEWSRC_PATH);

    set_current_val(&vars[V_NEWS_ACTIVE_PATH], TRUE, TRUE);
    if(VAR_NEWS_ACTIVE_PATH)
      mail_parameters(NULL, SET_NEWSACTIVE,
		      (void *)VAR_NEWS_ACTIVE_PATH);

    set_current_val(&vars[V_NEWS_SPOOL_DIR], TRUE, TRUE);
    if(VAR_NEWS_SPOOL_DIR)
      mail_parameters(NULL, SET_NEWSSPOOL,
		      (void *)VAR_NEWS_SPOOL_DIR);

    /* guarantee a save default */
    set_current_val(&vars[V_DEFAULT_SAVE_FOLDER], TRUE, TRUE);
    if(!VAR_DEFAULT_SAVE_FOLDER || !VAR_DEFAULT_SAVE_FOLDER[0])
      set_variable(V_DEFAULT_SAVE_FOLDER,
		   (GLO_DEFAULT_SAVE_FOLDER && GLO_DEFAULT_SAVE_FOLDER[0])
		     ? GLO_DEFAULT_SAVE_FOLDER
		     : DEFAULT_SAVE, 1, 0, Main);

    set_current_val(&vars[V_SIGNATURE_FILE], TRUE, TRUE);
    set_current_val(&vars[V_LITERAL_SIG], TRUE, TRUE);
    set_current_val(&vars[V_GLOB_ADDRBOOK], TRUE, TRUE);
    set_current_val(&vars[V_ADDRESSBOOK], TRUE, TRUE);
    set_current_val(&vars[V_FORCED_ABOOK_ENTRY], TRUE, TRUE);
    set_current_val(&vars[V_DISABLE_DRIVERS], TRUE, TRUE);
    set_current_val(&vars[V_DISABLE_AUTHS], TRUE, TRUE);

    set_current_val(&vars[V_VIEW_HEADERS], TRUE, TRUE);
    /* strip spaces and colons */
    if(ps->VAR_VIEW_HEADERS){
	for(s = ps->VAR_VIEW_HEADERS; (q = *s) != NULL; s++){
	    if(q[0]){
		removing_leading_white_space(q);
		/* look for colon or space or end */
		for(p = q; *p && !isspace((unsigned char)*p) && *p != ':'; p++)
		  ;/* do nothing */
		
		*p = '\0';
		if(strucmp(q, ALL_EXCEPT) == 0)
		  ps->view_all_except = 1;
	    }
	}
    }

    set_current_val(&vars[V_VIEW_MARGIN_LEFT], TRUE, TRUE);
    set_current_val(&vars[V_VIEW_MARGIN_RIGHT], TRUE, TRUE);
    set_current_val(&vars[V_UPLOAD_CMD], TRUE, TRUE);
    set_current_val(&vars[V_UPLOAD_CMD_PREFIX], TRUE, TRUE);
    set_current_val(&vars[V_DOWNLOAD_CMD], TRUE, TRUE);
    set_current_val(&vars[V_DOWNLOAD_CMD_PREFIX], TRUE, TRUE);
    set_current_val(&vars[V_MAILCAP_PATH], TRUE, TRUE);
    set_current_val(&vars[V_MIMETYPE_PATH], TRUE, TRUE);
#if !defined(DOS) && !defined(OS2) && !defined(LEAVEOUTFIFO)
    set_current_val(&vars[V_FIFOPATH], TRUE, TRUE);
#endif

    set_current_val(&vars[V_RSHPATH], TRUE, TRUE);
    if(VAR_RSHPATH
       && is_absolute_path(VAR_RSHPATH)
       && can_access(VAR_RSHPATH, EXECUTE_ACCESS) == 0){
	mail_parameters(NULL, SET_RSHPATH, (void *) VAR_RSHPATH);
    }

    set_current_val(&vars[V_RSHCMD], TRUE, TRUE);
    if(VAR_RSHCMD){
	mail_parameters(NULL, SET_RSHCOMMAND, (void *) VAR_RSHCMD);
    }

    set_current_val(&vars[V_SSHPATH], TRUE, TRUE);
    if(VAR_SSHPATH
       && is_absolute_path(VAR_SSHPATH)
       && can_access(VAR_SSHPATH, EXECUTE_ACCESS) == 0){
	mail_parameters(NULL, SET_SSHPATH, (void *) VAR_SSHPATH);
    }

    set_current_val(&vars[V_SSHCMD], TRUE, TRUE);
    if(VAR_SSHCMD){
	mail_parameters(NULL, SET_SSHCOMMAND, (void *) VAR_SSHCMD);
    }

#if	defined(DOS) || defined(OS2)

    set_current_val(&vars[V_FILE_DIR], TRUE, TRUE);

#ifdef	_WINDOWS
    set_current_val(&vars[V_FONT_NAME], TRUE, TRUE);
    set_current_val(&vars[V_FONT_SIZE], TRUE, TRUE);
    set_current_val(&vars[V_FONT_STYLE], TRUE, TRUE);
    set_current_val(&vars[V_FONT_CHAR_SET], TRUE, TRUE);
    set_current_val(&vars[V_CURSOR_STYLE], TRUE, TRUE);
    set_current_val(&vars[V_WINDOW_POSITION], TRUE, TRUE);

    if(F_OFF(F_STORE_WINPOS_IN_CONFIG, ps_global)){
	/* if win position is in the registry, use it */
	if(mswin_reg(MSWR_OP_GET, MSWR_PINE_POS, buf, sizeof(buf))){
	    if(VAR_WINDOW_POSITION)
	      fs_give((void **)&VAR_WINDOW_POSITION);
	    
	    VAR_WINDOW_POSITION = cpystr(buf);
	}
	else if(VAR_WINDOW_POSITION
	    && (ps->update_registry != UREG_NEVER_SET)){
	    /* otherwise, put it there */
	    mswin_reg(MSWR_OP_SET | ((ps->update_registry == UREG_ALWAYS_SET)
				     ? MSWR_OP_FORCE : 0),
		      MSWR_PINE_POS, 
		      VAR_WINDOW_POSITION, (size_t)NULL);
	}
    }

    mswin_setwindow (VAR_FONT_NAME, VAR_FONT_SIZE, 
		     VAR_FONT_STYLE, VAR_WINDOW_POSITION,
		     VAR_CURSOR_STYLE, VAR_FONT_CHAR_SET);

    /* this is no longer used */
    if(VAR_WINDOW_POSITION)
      fs_give((void **)&VAR_WINDOW_POSITION);

    set_current_val(&vars[V_PRINT_FONT_NAME], TRUE, TRUE);
    set_current_val(&vars[V_PRINT_FONT_SIZE], TRUE, TRUE);
    set_current_val(&vars[V_PRINT_FONT_STYLE], TRUE, TRUE);
    set_current_val(&vars[V_PRINT_FONT_CHAR_SET], TRUE, TRUE);
    mswin_setprintfont (VAR_PRINT_FONT_NAME,
			VAR_PRINT_FONT_SIZE,
			VAR_PRINT_FONT_STYLE,
			VAR_PRINT_FONT_CHAR_SET);

    mswin_setgenhelptextcallback(pcpine_general_help);

    mswin_setclosetext ("Use the \"Q\" command to exit Alpine.");

    {
	char foreColor[64], backColor[64];

	mswin_getwindow(NULL, 0, NULL, 0, NULL, 0, NULL, 0,
			foreColor, sizeof(foreColor), backColor, sizeof(backColor),
			NULL, 0, NULL, 0);
	if(!GLO_NORM_FORE_COLOR)
	  GLO_NORM_FORE_COLOR = cpystr(foreColor);

	if(!GLO_NORM_BACK_COLOR)
	  GLO_NORM_BACK_COLOR = cpystr(backColor);
    }
#endif	/* _WINDOWS */
#endif	/* DOS */

    /*
     * We want the version number to start out as 1.0 for Alpine, but
     * we also want to use the same old config file that was used
     * with Pine. The Pine version numbers made it up to 4.64 and we
     * want Alpine's 1.0 to be larger than 4.64 so we keep a separate
     * internal version number which is the real version number
     * plus 4. That's what gets written in LAST_VERS_USED.
     */
    strncpy(ps->vers_internal, ALPINE_VERSION, sizeof(ps->vers_internal));
    ps->vers_internal[sizeof(ps->vers_internal)-1] = '\0';
    if(isdigit(ps->vers_internal[0]) && ps->vers_internal[0] < '6')
      ps->vers_internal[0] = ps->vers_internal[0] + 4;

    set_current_val(&vars[V_LAST_VERS_USED], TRUE, TRUE);
    /* Check for special cases first */
    if(VAR_LAST_VERS_USED
       && (isdigit(ps->vers_internal[0])
	   && ps->vers_internal[1] == '.'
	   && isdigit((unsigned char)ps->vers_internal[2])
	   && isdigit((unsigned char)ps->vers_internal[3])
	   && isalpha((unsigned char)ps->vers_internal[4])
	   && strncmp(VAR_LAST_VERS_USED, ps->vers_internal, 4) >= 0)){
	ps->show_new_version = 0;
    }
    /* Otherwise just do lexicographic comparision... */
    else if(VAR_LAST_VERS_USED
	    && strcmp(VAR_LAST_VERS_USED, ps->vers_internal) >= 0){
	ps->show_new_version = 0;
    }
    else{
#ifdef	_WINDOWS
	/*
	 * If this is the first time we've run a version > 4.40, and there
	 * is evidence that the config file has not been used by unix pine,
	 * then we convert color008 to colorlgr, color009 to colormgr, and
	 * color010 to colordgr. If the config file is being used by
	 * unix pine then color009 may really supposed to be red, etc.
	 * Same if we've already run 4.41 or higher. We don't have to do
	 * anything if we are new to alpine.
	 */
	ps->pre441 = (VAR_LAST_VERS_USED
		      && strcmp(VAR_LAST_VERS_USED, "4.40") <= 0);
#endif	/* _WINDOWS */

	/*
	 * Don't offer the new version message if we're told not to.
	 */
	set_current_val(&vars[V_NEW_VER_QUELL], TRUE, TRUE);
	ps->show_new_version = !(VAR_NEW_VER_QUELL
			         && strcmp(ps->vers_internal,
					   VAR_NEW_VER_QUELL) < 0);

#ifdef _WINDOWS
	if(!ps_global->install_flag)
#endif /* _WINDOWS */
	{
	if(VAR_LAST_VERS_USED){
	    strncpy(ps_global->pine_pre_vers, VAR_LAST_VERS_USED,
		    sizeof(ps_global->pine_pre_vers));
	    ps_global->pine_pre_vers[sizeof(ps_global->pine_pre_vers)-1] = '\0';
	}

	set_variable(V_LAST_VERS_USED, ps->vers_internal, 1, 1,
		     ps_global->ew_for_except_vars);
	}
    }

    /* Obsolete, backwards compatibility */
    set_current_val(&vars[V_ELM_STYLE_SAVE], TRUE, TRUE);
    /* Also obsolete */
    set_current_val(&vars[V_SAVE_BY_SENDER], TRUE, TRUE);
    if(!strucmp(VAR_ELM_STYLE_SAVE, "yes"))
      set_variable(V_SAVE_BY_SENDER, "yes", 1, 1, Main);
    obs_save_by_sender = !strucmp(VAR_SAVE_BY_SENDER, "yes");

    set_current_pattern_vals(ps);

    set_current_val(&vars[V_INDEX_FORMAT], TRUE, TRUE);
    init_index_format(VAR_INDEX_FORMAT, &ps->index_disp_format);

    /* this should come after pre441 is set or not */
    set_current_color_vals(ps);

    set_current_val(&vars[V_RSS_NEWS], TRUE, TRUE);
    set_current_val(&vars[V_RSS_WEATHER], TRUE, TRUE);
    set_current_val(&vars[V_WP_INDEXHEIGHT], TRUE, TRUE);
    set_current_val(&vars[V_WP_INDEXLINES], TRUE, TRUE);
    set_current_val(&vars[V_WP_AGGSTATE], TRUE, TRUE);
    set_current_val(&vars[V_WP_STATE], TRUE, TRUE);
    set_current_val(&vars[V_WP_COLUMNS], TRUE, TRUE);

    set_current_val(&vars[V_PRUNED_FOLDERS], TRUE, TRUE);
    set_current_val(&vars[V_ARCHIVED_FOLDERS], TRUE, TRUE);
    set_current_val(&vars[V_INCOMING_FOLDERS], TRUE, TRUE);
    set_current_val(&vars[V_SORT_KEY], TRUE, TRUE);
    if(decode_sort(VAR_SORT_KEY, &ps->def_sort, &def_sort_rev) == -1){
	snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Sort type \"%.200s\" is invalid", VAR_SORT_KEY);
	init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
	ps->def_sort = SortArrival;
	ps->def_sort_rev = 0;
    }
    else
      ps->def_sort_rev = def_sort_rev;

    cur_rule_value(&vars[V_SAVED_MSG_NAME_RULE], TRUE, TRUE);
    {NAMEVAL_S *v; int i;
    for(i = 0; (v = save_msg_rules(i)); i++)
      if(v->value == ps_global->save_msg_rule)
	break;
     
     /* if save_msg_rule is not default, or is explicitly set to default */
     if((ps_global->save_msg_rule != SAV_RULE_DEFLT) ||
	(v && v->name &&
	 (!strucmp(ps_global->vars[V_SAVED_MSG_NAME_RULE].post_user_val.p,
		   v->name) ||
	  !strucmp(ps_global->vars[V_SAVED_MSG_NAME_RULE].main_user_val.p,
		   v->name))))
       obs_save_by_sender = 0;  /* don't overwrite */
    }

    cur_rule_value(&vars[V_FCC_RULE], TRUE, TRUE);
    cur_rule_value(&vars[V_AB_SORT_RULE], TRUE, TRUE);

#ifndef	_WINDOWS
    cur_rule_value(&vars[V_COLOR_STYLE], TRUE, TRUE);
#endif

    cur_rule_value(&vars[V_INDEX_COLOR_STYLE], TRUE, TRUE);
    cur_rule_value(&vars[V_TITLEBAR_COLOR_STYLE], TRUE, TRUE);
    cur_rule_value(&vars[V_FLD_SORT_RULE], TRUE, TRUE);
    cur_rule_value(&vars[V_INCOMING_STARTUP], TRUE, TRUE);
    cur_rule_value(&vars[V_PRUNING_RULE], TRUE, TRUE);
    cur_rule_value(&vars[V_REOPEN_RULE], TRUE, TRUE);
    cur_rule_value(&vars[V_GOTO_DEFAULT_RULE], TRUE, TRUE);
    cur_rule_value(&vars[V_THREAD_DISP_STYLE], TRUE, TRUE);
    cur_rule_value(&vars[V_THREAD_INDEX_STYLE], TRUE, TRUE);

    set_current_val(&vars[V_THREAD_MORE_CHAR], TRUE, TRUE);
    if(VAR_THREAD_MORE_CHAR[0] && VAR_THREAD_MORE_CHAR[1]){
	init_error(ps, SM_ORDER | SM_DING, 3, 5,
	  _("Only using first character of threading-indicator-character option"));
	VAR_THREAD_MORE_CHAR[1] = '\0';
    }

    set_current_val(&vars[V_THREAD_EXP_CHAR], TRUE, TRUE);
    if(VAR_THREAD_EXP_CHAR[0] && VAR_THREAD_EXP_CHAR[1]){
	init_error(ps, SM_ORDER | SM_DING, 3, 5,
	   _("Only using first character of threading-expanded-character option"));
	VAR_THREAD_EXP_CHAR[1] = '\0';
    }

    set_current_val(&vars[V_THREAD_LASTREPLY_CHAR], TRUE, TRUE);
    if(!VAR_THREAD_LASTREPLY_CHAR[0])
      VAR_THREAD_LASTREPLY_CHAR = cpystr(DF_THREAD_LASTREPLY_CHAR);

    if(VAR_THREAD_LASTREPLY_CHAR[0] && VAR_THREAD_LASTREPLY_CHAR[1]){
	init_error(ps, SM_ORDER | SM_DING, 3, 5,
	  _("Only using first character of threading-lastreply-character option"));
	VAR_THREAD_LASTREPLY_CHAR[1] = '\0';
    }

    set_current_val(&vars[V_MAXREMSTREAM], TRUE, TRUE);
    ps->s_pool.max_remstream = i = atoi(DF_MAXREMSTREAM);
    if(SVAR_MAXREMSTREAM(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
    else
      ps->s_pool.max_remstream = i;
    
    set_current_val(&vars[V_PERMLOCKED], TRUE, TRUE);

    set_current_val(&vars[V_NMW_WIDTH], TRUE, TRUE);
    ps->nmw_width = i = atoi(DF_NMW_WIDTH);
    if(SVAR_NMW_WIDTH(ps, i, tmp_20k_buf, SIZEOF_20KBUF))
      init_error(ps, SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
    else
      ps->nmw_width = i;

    /* backwards compatibility */
    if(obs_save_by_sender){
        ps->save_msg_rule = SAV_RULE_FROM;
	set_variable(V_SAVED_MSG_NAME_RULE, "by-from", 1, 1, Main);
    }

    /* this should come after process_feature_list because of use_fkeys */
    if(!ps->start_in_index)
        set_current_val(&vars[V_INIT_CMD_LIST], FALSE, TRUE);
    if(VAR_INIT_CMD_LIST && VAR_INIT_CMD_LIST[0] && VAR_INIT_CMD_LIST[0][0])
      if(cmds_f)
        (*cmds_f)(ps, VAR_INIT_CMD_LIST);

#ifdef	_WINDOWS
    mswin_set_quit_confirm (F_OFF(F_QUIT_WO_CONFIRM, ps_global));
#endif	/* _WINDOWS */

#ifdef DEBUG
    dump_configuration(0);
#endif /* DEBUG */
}


void
convert_configvars_to_utf8(struct variable *vars, char *fromcharset)
{
    struct variable *v;

    /*
     * Make sure that everything is UTF-8.
     */
    for(v = vars; v->name; v++)
      convert_configvar_to_utf8(v, fromcharset);
}


void
convert_configvar_to_utf8(struct variable *v, char *fromcharset)
{
    char **p, *conv, **valptr;
    int i;

    /*
     * Make sure that everything is UTF-8.
     */
    if(v->is_list){
	for(i = 0; i < 7; i++){
	    switch(i){
	      case 1: valptr = v->current_val.l; break;
	      case 0: valptr = v->main_user_val.l; break;
	      case 2: valptr = v->changed_val.l; break;
	      case 3: valptr = v->post_user_val.l; break;
	      case 4: valptr = v->global_val.l; break;
	      case 5: valptr = v->fixed_val.l; break;
	      case 6: valptr = v->cmdline_val.l; break;
	      default: panic("bad case in convert_configvar");
	    }

	    if(valptr){
		for(p = valptr; *p; p++){
		    if(**p){
			conv = convert_to_utf8(*p, fromcharset, 0);
			if(conv){
			    fs_give((void **) p);
			    *p = conv;
			}
		    }
		}
	    }
	}
    }
    else{
	for(i = 0; i < 7; i++){
	    switch(i){
	      case 1: valptr = &v->current_val.p; break;
	      case 0: valptr = &v->main_user_val.p; break;
	      case 2: valptr = &v->changed_val.p; break;
	      case 3: valptr = &v->post_user_val.p; break;
	      case 4: valptr = &v->global_val.p; break;
	      case 5: valptr = &v->fixed_val.p; break;
	      case 6: valptr = &v->cmdline_val.p; break;
	      default: panic("bad case in convert_configvar");
	    }

	    if(valptr && *valptr && (*valptr)[0]){
		conv = convert_to_utf8(*valptr, fromcharset, 0);
		if(conv){
		    fs_give((void **) valptr);
		    *valptr = conv;
		}
	    }
	}
    }
}



/*
 * Standard feature name sections
 */
char *
feature_list_section(FEATURE_S *feature)
{
#define	PREF_NONE      -1
    static char *feat_sect[] = {
#define PREF_MISC	0
	/* TRANSLATORS: section heading in configuration screen */
	N_("Advanced User Preferences"),
#define PREF_FLDR	1
	/* TRANSLATORS: section heading in configuration screen */
	N_("Folder Preferences"),
#define PREF_ADDR	2
	/* TRANSLATORS: section heading in configuration screen */
	N_("Address Book Preferences"),
#define PREF_COMP	3
	/* TRANSLATORS: section heading in configuration screen */
	N_("Composer Preferences"),
#define PREF_NEWS	4
	/* TRANSLATORS: section heading in configuration screen */
	N_("News Preferences"),
#define PREF_VIEW	5
	/* TRANSLATORS: section heading in configuration screen */
	N_("Viewer Preferences"),
#define PREF_ACMD	6
	/* TRANSLATORS: section heading in configuration screen */
	N_("Advanced Command Preferences"),
#define PREF_PRNT	7
	/* TRANSLATORS: section heading in configuration screen */
	N_("Printer Preferences"),
#define	PREF_RPLY	8
	/* TRANSLATORS: section heading in configuration screen */
	N_("Reply Preferences"),
#define	PREF_SEND	9
	/* TRANSLATORS: section heading in configuration screen */
	N_("Sending Preferences"),
#define	PREF_INDX	10
	/* TRANSLATORS: section heading in configuration screen */
	N_("Message Index Preferences"),
#define	PREF_HIDDEN	11
	HIDDEN_PREF
};

    return((feature && feature->section > PREF_NONE
	    && feature->section < (sizeof(feat_sect)/sizeof(feat_sect[0])))
	   ? _(feat_sect[feature->section]) : NULL);
}


/* any os-specific exclusions */
#if	defined(DOS) || defined(OS2)
#define	PREF_OS_LWSD	PREF_NONE
#define	PREF_OS_LCLK	PREF_NONE
#define	PREF_OS_STSP	PREF_NONE
#define	PREF_OS_SPWN	PREF_NONE
#define	PREF_OS_XNML	PREF_NONE
#define	PREF_OS_USFK	PREF_MISC
#define	PREF_OS_MOUSE	PREF_NONE
#else
#define	PREF_OS_LWSD	PREF_MISC
#define	PREF_OS_LCLK	PREF_COMP
#define	PREF_OS_STSP	PREF_MISC
#define	PREF_OS_SPWN	PREF_MISC
#define	PREF_OS_XNML	PREF_MISC
#define	PREF_OS_USFK	PREF_NONE
#define	PREF_OS_MOUSE	PREF_MISC
#endif


/*
 * Standard way to get at feature list members...
 */
FEATURE_S *
feature_list(int index)
{
    /*
     * This list is alphabatized by feature string, but the 
     * macro values need not be ordered.
     */
    static FEATURE_S feat_list[] = {
/* Composer prefs */
	{"allow-changing-from", NULL,
	 F_ALLOW_CHANGING_FROM, h_config_allow_chg_from, PREF_COMP, 1},
	{"alternate-compose-menu", NULL,
	 F_ALT_COMPOSE_MENU, h_config_alt_compose_menu, PREF_COMP, 0},
	{"alternate-role-menu", "Alternate Role (#) Menu",
	 F_ALT_ROLE_MENU, h_config_alt_role_menu, PREF_COMP, 0},
	{"compose-cancel-confirm-uses-yes", NULL,
	 F_CANCEL_CONFIRM, h_config_cancel_confirm, PREF_COMP, 0},
	{"compose-rejects-unqualified-addrs", "Compose Rejects Unqualified Addresses",
	 F_COMPOSE_REJECTS_UNQUAL, h_config_compose_rejects_unqual, PREF_COMP, 0},
	{"compose-send-offers-first-filter", NULL,
	 F_FIRST_SEND_FILTER_DFLT, h_config_send_filter_dflt, PREF_COMP, 0},
	{"compose-cut-from-cursor", "Ctrl-K Cuts From Cursor",
	 F_DEL_FROM_DOT, h_config_del_from_dot, PREF_COMP, 0},
	{"compose-maps-delete-key-to-ctrl-d", "Delete Key Maps to Ctrl-D",
	 F_COMPOSE_MAPS_DEL, h_config_compose_maps_del, PREF_COMP, 0},
	{"quell-dead-letter-on-cancel", "Do Not Save to Deadletter on Cancel",
	 F_QUELL_DEAD_LETTER, h_config_quell_dead_letter, PREF_COMP, 0},
	{"enable-alternate-editor-cmd", "Enable Alternate Editor Command",
	 F_ENABLE_ALT_ED, h_config_enable_alt_ed, PREF_COMP, 1},
	{"enable-alternate-editor-implicitly", NULL,
	 F_ALT_ED_NOW, h_config_alt_ed_now, PREF_COMP, 0},
	{"enable-search-and-replace", "Enable Search and Replace",
	 F_ENABLE_SEARCH_AND_REPL, h_config_enable_search_and_repl, PREF_COMP, 1},
	{"enable-sigdashes", NULL,
	 F_ENABLE_SIGDASHES, h_config_sigdashes, PREF_COMP, 0},
	{"quell-mailchecks-composing-except-inbox", "Prevent Mailchecks While Composing Except for INBOX",
	 F_QUELL_PINGS_COMPOSING, h_config_quell_checks_comp, PREF_COMP, 0},
	{"quell-mailchecks-composing-inbox", "Prevent Mailchecks While Composing for INBOX",
	 F_QUELL_PINGS_COMPOSING_INBOX, h_config_quell_checks_comp_inbox, PREF_COMP, 0},
	{"quell-user-lookup-in-passwd-file", "Prevent User Lookup in Password File",
	 F_QUELL_LOCAL_LOOKUP, h_config_quell_local_lookup, PREF_OS_LCLK, 0},
	{"spell-check-before-sending", NULL,
	 F_ALWAYS_SPELL_CHECK, h_config_always_spell_check, PREF_COMP, 0},

/* Reply Prefs */
	{"copy-to-address-to-from-if-it-is-us", "Copy To Address to From if it is Us",
	 F_COPY_TO_TO_FROM, h_config_copy_to_to_from, PREF_RPLY, 0},
	{"enable-reply-indent-string-editing", NULL,
	 F_ENABLE_EDIT_REPLY_INDENT, h_config_prefix_editing, PREF_RPLY, 0},
	{"include-attachments-in-reply", "Include Attachments in Reply",
	 F_ATTACHMENTS_IN_REPLY, h_config_attach_in_reply, PREF_RPLY, 0},
	{"include-header-in-reply", "Include Header in Reply",
	 F_INCLUDE_HEADER, h_config_include_header, PREF_RPLY, 0},
	{"include-text-in-reply", "Include Text in Reply",
	 F_AUTO_INCLUDE_IN_REPLY, h_config_auto_include_reply, PREF_RPLY, 0},
	{"reply-always-uses-reply-to", "Reply Always Uses Reply-To",
	 F_AUTO_REPLY_TO, h_config_auto_reply_to, PREF_RPLY, 0},
	{"signature-at-bottom", "Signature at Bottom",
	 F_SIG_AT_BOTTOM, h_config_sig_at_bottom, PREF_RPLY, 0},
	{"strip-from-sigdashes-on-reply", "Strip From Sigdashes on Reply",
	 F_ENABLE_STRIP_SIGDASHES, h_config_strip_sigdashes, PREF_RPLY, 0},
	{"forward-as-attachment", "Forward messages as attachments",
	 F_FORWARD_AS_ATTACHMENT, h_config_forward_as_attachment, PREF_RPLY, 0},

/* Sending Prefs */
	{"disable-sender", "Do Not Generate Sender Header",
	 F_DISABLE_SENDER, h_config_disable_sender, PREF_SEND, 0},
	{"use-sender-not-x-sender", "Use Sender Instead of X-X-Sender",
	 F_USE_SENDER_NOT_X, h_config_use_sender_not_x, PREF_SEND, 0},
	{"quell-flowed-text", "Do Not Send Flowed Text",
	 F_QUELL_FLOWED_TEXT, h_config_quell_flowed_text, PREF_SEND, 0},
	{"downgrade-multipart-to-text", "Downgrade Multipart to Text",
	 F_COMPOSE_ALWAYS_DOWNGRADE, h_downgrade_multipart_to_text, PREF_SEND, 0},
	{"enable-8bit-esmtp-negotiation", "Enable 8bit ESMTP Negotiation",
	 F_ENABLE_8BIT, h_config_8bit_smtp, PREF_SEND, 1},
#ifdef	BACKGROUND_POST
	{"enable-background-sending", NULL,
	 F_BACKGROUND_POST, h_config_compose_bg_post, PREF_SEND, 0},
#endif
	{"enable-delivery-status-notification", NULL,
	 F_DSN, h_config_compose_dsn, PREF_SEND, 0},
	{"enable-verbose-smtp-posting", "Enable Verbose SMTP Posting",
	 F_VERBOSE_POST, h_config_verbose_post, PREF_SEND, 0},
	{"fcc-without-attachments", "Fcc Does Not Include Attachments",
	 F_NO_FCC_ATTACH, h_config_no_fcc_attach, PREF_SEND, 0},
	{"fcc-on-bounce", "Include Fcc When Bouncing Messages",
	 F_FCC_ON_BOUNCE, h_config_fcc_on_bounce, PREF_SEND, 0},
	{"mark-fcc-seen", NULL,
	 F_MARK_FCC_SEEN, h_config_mark_fcc_seen, PREF_SEND, 0},
	{"fcc-only-without-confirm", "Send to Fcc Only Without Confirming",
	 F_AUTO_FCC_ONLY, h_config_auto_fcc_only, PREF_SEND, 0},
	{"send-without-confirm", "Send Without Confirming",
	 F_SEND_WO_CONFIRM, h_config_send_wo_confirm, PREF_SEND, 0},
	{"strip-whitespace-before-send", "Strip Whitespace Before Sending",
	 F_STRIP_WS_BEFORE_SEND, h_config_strip_ws_before_send, PREF_SEND, 0},
	{"warn-if-blank-fcc", "Warn if Blank Fcc",
	 F_WARN_ABOUT_NO_FCC, h_config_warn_if_fcc_blank, PREF_SEND, 0},
	{"warn-if-blank-subject", "Warn if Blank Subject",
	 F_WARN_ABOUT_NO_SUBJECT, h_config_warn_if_subj_blank, PREF_SEND, 0},
	{"warn-if-blank-to-and-cc-and-newsgroups", "Warn if Blank To and CC and Newsgroups",
	 F_WARN_ABOUT_NO_TO_OR_CC, h_config_warn_if_no_to_or_cc, PREF_SEND, 0},

/* Folder */
	{"combined-folder-display", NULL,
	 F_CMBND_FOLDER_DISP, h_config_combined_folder_display, PREF_FLDR, 0},
	{"combined-subdirectory-display", NULL,
	 F_CMBND_SUBDIR_DISP, h_config_combined_subdir_display, PREF_FLDR, 0},
	{"enable-lame-list-mode", "Compensate for Deficient IMAP servers",
	 F_FIX_BROKEN_LIST, h_config_lame_list_mode, PREF_FLDR, 0},
	{"enable-dot-folders", "Enable Hidden Folders",
	 F_ENABLE_DOT_FOLDERS, h_config_enable_dot_folders, PREF_FLDR, 0},
	{"enable-incoming-folders", "Enable Incoming Folders Collection",
	 F_ENABLE_INCOMING, h_config_enable_incoming, PREF_FLDR, 0},
	{"enable-incoming-folders-checking", NULL,
	 F_ENABLE_INCOMING_CHECKING, h_config_enable_incoming_checking, PREF_FLDR, 0},
	{"incoming-checking-includes-total", NULL,
	 F_INCOMING_CHECKING_TOTAL, h_config_incoming_checking_total, PREF_FLDR, 0},
	{"incoming-checking-uses-recent", NULL,
	 F_INCOMING_CHECKING_RECENT, h_config_incoming_checking_recent, PREF_FLDR, 0},
	{"expanded-view-of-folders", "Expanded View of Folders",
	 F_EXPANDED_FOLDERS, h_config_expanded_folders, PREF_FLDR, 0},
	{"quell-empty-directories", "Hide Empty Directories",
	 F_QUELL_EMPTY_DIRS, h_config_quell_empty_dirs, PREF_FLDR, 0},
	{"separate-folder-and-directory-entries", "Separate Folder and Directory Entries",
	 F_SEPARATE_FLDR_AS_DIR, h_config_separate_fold_dir_view, PREF_FLDR, 0},
	{"single-column-folder-list", NULL,
	 F_SINGLE_FOLDER_LIST, h_config_single_list, PREF_FLDR, 0},
	{"sort-default-fcc-alpha", "Sort Default Fcc Folder Alphabetically",
	 F_SORT_DEFAULT_FCC_ALPHA, h_config_sort_fcc_alpha, PREF_FLDR, 0},
	{"sort-default-save-alpha", "Sort Default Save Folder Alphabetically",
	 F_SORT_DEFAULT_SAVE_ALPHA, h_config_sort_save_alpha, PREF_FLDR, 0},
	{"vertical-folder-list", "Use Vertical Folder List",
	 F_VERTICAL_FOLDER_LIST, h_config_vertical_list, PREF_FLDR, 0},

/* Addr book */
	{"combined-addrbook-display", "Combined Address Book Display",
	 F_CMBND_ABOOK_DISP, h_config_combined_abook_display, PREF_ADDR, 0},
	{"expanded-view-of-addressbooks", "Expanded View of Address Books",
	 F_EXPANDED_ADDRBOOKS, h_config_expanded_addrbooks, PREF_ADDR, 0},
	{"expanded-view-of-distribution-lists", "Expanded View of Distribution Lists",
	 F_EXPANDED_DISTLISTS, h_config_expanded_distlists, PREF_ADDR, 0},
#ifdef	ENABLE_LDAP
	{"ldap-result-to-addrbook-add", "LDAP Result to Addressbook Add",
	 F_ADD_LDAP_TO_ABOOK, h_config_add_ldap, PREF_ADDR, 0},
#endif

/* Index prefs */
	{"auto-open-next-unread", NULL,
	 F_AUTO_OPEN_NEXT_UNREAD, h_config_auto_open_unread, PREF_INDX, 0},
	{"continue-tab-without-confirm", "Continue NextNew Without Confirming",
	 F_TAB_NO_CONFIRM, h_config_tab_no_prompt, PREF_INDX, 0},
	{"convert-dates-to-localtime", NULL,
	 F_DATES_TO_LOCAL, h_config_dates_to_local, PREF_INDX, 0},
	{"delete-skips-deleted", NULL,
	 F_DEL_SKIPS_DEL, h_config_del_skips_del, PREF_INDX, 1},
	{"disable-index-locale-dates", NULL,
	 F_DISABLE_INDEX_LOCALE_DATES, h_config_disable_index_locale_dates, PREF_INDX, 0},
	{"enable-cruise-mode", NULL,
	 F_ENABLE_SPACE_AS_TAB, h_config_cruise_mode, PREF_INDX, 0},
	{"enable-cruise-mode-delete", "Enable Cruise Mode With Deleting",
	 F_ENABLE_TAB_DELETES, h_config_cruise_mode_delete, PREF_INDX, 0},
	{"mark-for-cc", "Mark for CC",
	 F_MARK_FOR_CC, h_config_mark_for_cc, PREF_INDX, 1},
	{"next-thread-without-confirm", "Read Next Thread Without Confirming",
	 F_NEXT_THRD_WO_CONFIRM, h_config_next_thrd_wo_confirm, PREF_INDX, 0},
	{"return-to-inbox-without-confirm", "Return to INBOX Without Confirming",
	 F_RET_INBOX_NO_CONFIRM, h_config_inbox_no_confirm, PREF_INDX, 0},
	{"show-sort", "Show Sort in Titlebar",
	 F_SHOW_SORT, h_config_show_sort, PREF_INDX, 0},
	{"tab-uses-unseen-for-next-folder", "Tab Uses Unseen for Next Folder",
	 F_TAB_USES_UNSEEN, h_config_tab_uses_unseen, PREF_INDX, 0},
	{"tab-visits-next-new-message-only", NULL,
	 F_TAB_TO_NEW, h_config_tab_new_only, PREF_INDX, 0},
	{"thread-index-shows-important-color", NULL,
	 F_COLOR_LINE_IMPORTANT, h_config_color_thrd_import, PREF_INDX, 0},
	{"thread-sorts-by-arrival", "Thread Sorts by Arrival",
	 F_THREAD_SORTS_BY_ARRIVAL, h_config_thread_sorts_by_arrival, PREF_INDX, 0},

/* Viewer prefs */
	{"enable-msg-view-addresses", "Enable Message View Address Links",
	 F_SCAN_ADDR, h_config_enable_view_addresses, PREF_VIEW, 0},
	{"enable-msg-view-attachments", "Enable Message View Attachment Links",
	 F_VIEW_SEL_ATTACH, h_config_enable_view_attach, PREF_VIEW, 0},
	{"enable-msg-view-urls", "Enable Message View URL Links",
	 F_VIEW_SEL_URL, h_config_enable_view_url, PREF_VIEW, 1},
	{"enable-msg-view-web-hostnames", "Enable Message View Web Hostname Links",
	 F_VIEW_SEL_URL_HOST, h_config_enable_view_web_host, PREF_VIEW, 1},
	{"enable-msg-view-forced-arrows", "Enable Message View Forced Arrows",
	 F_FORCE_ARROWS, h_config_enable_view_arrows, PREF_VIEW, 0},
	/* set to TRUE for windows */
	{"pass-c1-control-characters-as-is", NULL,
	 F_PASS_C1_CONTROL_CHARS, h_config_pass_c1_control, PREF_VIEW, 0},
	{"pass-control-characters-as-is", NULL,
	 F_PASS_CONTROL_CHARS, h_config_pass_control, PREF_VIEW, 0},
	{"prefer-plain-text", NULL,
	 F_PREFER_PLAIN_TEXT, h_config_prefer_plain_text, PREF_VIEW, 0},
	{"quell-charset-warning", "Suppress Character Set Warning",
	 F_QUELL_CHARSET_WARNING, h_config_quell_charset_warning, PREF_VIEW, 0},
	{"quell-server-after-link-in-html", "Suppress Server After Link in HTML",
	 F_QUELL_HOST_AFTER_URL, h_config_quell_host_after_url, PREF_VIEW, 0},

/* News */
	{"compose-sets-newsgroup-without-confirm", "Compose Sets Newsgroup Without Confirming",
	 F_COMPOSE_TO_NEWSGRP, h_config_compose_news_wo_conf, PREF_NEWS, 0},
	{"enable-8bit-nntp-posting", "Enable 8bit NNTP Posting",
	 F_ENABLE_8BIT_NNTP, h_config_8bit_nntp, PREF_NEWS, 0},
	{"enable-multiple-newsrcs", NULL,
	 F_ENABLE_MULNEWSRCS, h_config_enable_mulnewsrcs, PREF_NEWS, 0},
	{"mult-newsrc-hostnames-as-typed", "Multiple Newsrc Hostnames as Typed",
	 F_MULNEWSRC_HOSTNAMES_AS_TYPED, h_config_mulnews_as_typed, PREF_NEWS, 0},
	{"hide-nntp-path", "Hide NNTP Path",
	 F_HIDE_NNTP_PATH, h_config_hide_nntp_path, PREF_NEWS, 0},
	{"news-approximates-new-status", NULL,
	 F_FAKE_NEW_IN_NEWS, h_config_news_uses_recent, PREF_NEWS, 1},
	{"news-deletes-across-groups", NULL,
	 F_NEWS_CROSS_DELETE, h_config_news_cross_deletes, PREF_NEWS, 0},
	{"news-offers-catchup-on-close", "News Offers Catchup on Close",
	 F_NEWS_CATCHUP, h_config_news_catchup, PREF_NEWS, 0},
	{"news-post-without-validation", NULL,
	 F_NO_NEWS_VALIDATION, h_config_post_wo_validation, PREF_NEWS, 0},
	{"news-read-in-newsrc-order", "News Read in Newsrc Order",
	 F_READ_IN_NEWSRC_ORDER, h_config_read_in_newsrc_order, PREF_NEWS, 0},
	{"nntp-search-uses-overview", "NNTP Search Uses Overview",
	 F_NNTP_SEARCH_USES_OVERVIEW, h_config_nntp_search_uses_overview, PREF_NEWS, 1},
	{"predict-nntp-server", "Predict NNTP Server",
	 F_PREDICT_NNTP_SERVER, h_config_predict_nntp_server, PREF_NEWS, 0},
	{"quell-extra-post-prompt", "Suppress Extra Posting Prompt",
	 F_QUELL_EXTRA_POST_PROMPT, h_config_quell_post_prompt, PREF_NEWS, 0},

/* Print */
	{"enable-print-via-y-command", NULL,
	 F_ENABLE_PRYNT, h_config_enable_y_print, PREF_PRNT, 0},
	{"print-formfeed-between-messages", NULL,
	 F_AGG_PRINT_FF, h_config_ff_between_msgs, PREF_PRNT, 0},
	{"print-includes-from-line", NULL,
	 F_FROM_DELIM_IN_PRINT, h_config_print_from, PREF_PRNT, 0},
	{"print-index-enabled", NULL,
	 F_PRINT_INDEX, h_config_print_index, PREF_PRNT, 0},
	{"print-offers-custom-cmd-prompt", "Print Offers Custom Command Prompt",
	 F_CUSTOM_PRINT, h_config_custom_print, PREF_PRNT, 0},

/* adv cmd prefs */
	{"enable-aggregate-command-set", NULL,
	 F_ENABLE_AGG_OPS, h_config_enable_agg_ops, PREF_ACMD, 1},
	{"enable-arrow-navigation", NULL,
	 F_ARROW_NAV, h_config_arrow_nav, PREF_ACMD, 1},
	{"enable-arrow-navigation-relaxed", NULL,
	 F_RELAXED_ARROW_NAV, h_config_relaxed_arrow_nav, PREF_ACMD, 1},
	{"enable-bounce-cmd", "Enable Bounce Command",
	 F_ENABLE_BOUNCE, h_config_enable_bounce, PREF_ACMD, 1},
	{"enable-exit-via-lessthan-command", NULL,
	 F_ENABLE_LESSTHAN_EXIT, h_config_enable_lessthan_exit, PREF_ACMD, 1},
	{"enable-flag-cmd", "Enable Flag Command",
	 F_ENABLE_FLAG, h_config_enable_flag, PREF_ACMD, 1},
	{"enable-flag-screen-implicitly", NULL,
	 F_FLAG_SCREEN_DFLT, h_config_flag_screen_default, PREF_ACMD, 0},
	{"enable-flag-screen-keyword-shortcut", NULL,
	 F_FLAG_SCREEN_KW_SHORTCUT, h_config_flag_screen_kw_shortcut,PREF_ACMD, 1},
	{"enable-full-header-and-text", "Enable Full Header and Text",
	 F_ENABLE_FULL_HDR_AND_TEXT, h_config_enable_full_hdr_and_text, PREF_ACMD, 0},
	{"enable-full-header-cmd", "Enable Full Header Command",
	 F_ENABLE_FULL_HDR, h_config_enable_full_hdr, PREF_ACMD, 1},
	{"enable-goto-in-file-browser", "Enable Goto in File Browser",
	 F_ALLOW_GOTO, h_config_allow_goto, PREF_ACMD, 1},
	{"enable-jump-shortcut", NULL,
	 F_ENABLE_JUMP, h_config_enable_jump, PREF_ACMD, 1},
	{"enable-partial-match-lists", NULL,
	 F_ENABLE_SUB_LISTS, h_config_sub_lists, PREF_ACMD, 1},
	{"enable-tab-completion", NULL,
	 F_ENABLE_TAB_COMPLETE, h_config_enable_tab_complete, PREF_ACMD, 1},
	{"enable-unix-pipe-cmd", "Enable Unix Pipe Command",
	 F_ENABLE_PIPE, h_config_enable_pipe, PREF_ACMD, 1},
	{"quell-full-header-auto-reset", "Suppress Full Header Auto Reset",
	 F_QUELL_FULL_HDR_RESET, h_config_quell_full_hdr_reset, PREF_ACMD, 0},

/* Adv user prefs */
#if !defined(DOS) && !defined(OS2)
	{"allow-talk", NULL,
	 F_ALLOW_TALK, h_config_allow_talk, PREF_MISC, 0},
#endif
	{"assume-slow-link", NULL,
	 F_FORCE_LOW_SPEED, h_config_force_low_speed, PREF_OS_LWSD, 0},
	{"auto-move-read-msgs", "Auto Move Read Messages",
	 F_AUTO_READ_MSGS, h_config_auto_read_msgs, PREF_MISC, 0},
	{"auto-unselect-after-apply", NULL,
	 F_AUTO_UNSELECT, h_config_auto_unselect, PREF_MISC, 0},
	{"auto-unzoom-after-apply", NULL,
	 F_AUTO_UNZOOM, h_config_auto_unzoom, PREF_MISC, 1},
	{"auto-zoom-after-select", NULL,
	 F_AUTO_ZOOM, h_config_auto_zoom, PREF_MISC, 1},
	{"busy-cue-spinner-only", NULL,
	 F_USE_BORING_SPINNER, h_config_use_boring_spinner, PREF_MISC, 0},
	{"check-newmail-when-quitting", NULL,
	 F_CHECK_MAIL_ONQUIT, h_config_check_mail_onquit, PREF_MISC, 0},
	{"confirm-role-even-for-default", "Confirm Role Even for Default",
	 F_ROLE_CONFIRM_DEFAULT, h_config_confirm_role, PREF_MISC, 0},
	{"disable-keymenu", NULL,
	 F_BLANK_KEYMENU, h_config_blank_keymenu, PREF_MISC, 0},
	{"disable-password-caching", NULL,
	 F_DISABLE_PASSWORD_CACHING, h_config_disable_password_caching,
	 PREF_MISC, 0},
	{"disable-regular-expression-matching-for-alternate-addresses", NULL,
	 F_DISABLE_REGEX, h_config_disable_regex, PREF_MISC, 0},
	{"disable-save-input-history", NULL,
	 F_DISABLE_SAVE_INPUT_HISTORY, h_config_input_history, PREF_MISC, 0},
	{"disable-take-fullname-in-addresses", "Disable Take Fullname in Addresses",
	 F_DISABLE_TAKE_FULLNAMES, h_config_take_fullname, PREF_MISC, 0},
	{"disable-take-last-comma-first", NULL,
	 F_DISABLE_TAKE_LASTFIRST, h_config_take_lastfirst, PREF_MISC, 0},
	{"disable-terminal-reset-for-display-filters", "Disable Terminal Reset for Display Filters",
	 F_DISABLE_TERM_RESET_DISP, h_config_disable_reset_disp, PREF_MISC, 0},
	{"enable-dot-files", NULL,
	 F_ENABLE_DOT_FILES, h_config_enable_dot_files, PREF_MISC, 0},
	{"enable-fast-recent-test", NULL,
	 F_ENABLE_FAST_RECENT, h_config_fast_recent, PREF_MISC, 0},
	{"enable-mail-check-cue", NULL,
	 F_SHOW_DELAY_CUE, h_config_show_delay_cue, PREF_MISC, 0},
	{"enable-mailcap-param-substitution", "Enable Mailcap Parameter Substitution",
	 F_DO_MAILCAP_PARAM_SUBST, h_config_mailcap_params, PREF_MISC, 0},
	{"enable-mouse-in-xterm", "Enable Mouse in Xterm",
	 F_ENABLE_MOUSE, h_config_enable_mouse, PREF_OS_MOUSE, 0},
	{"enable-newmail-in-xterm-icon", "Enable Newmail in Xterm Icon",
	 F_ENABLE_XTERM_NEWMAIL, h_config_enable_xterm_newmail, PREF_OS_XNML, 0},
	{"enable-newmail-short-text-in-icon", "Enable Newmail Short Text in Icon",
	 F_ENABLE_NEWMAIL_SHORT_TEXT, h_config_enable_newmail_short_text, PREF_OS_XNML, 0},
	{"enable-suspend", NULL,
	 F_CAN_SUSPEND, h_config_can_suspend, PREF_MISC, 0},
	{"enable-take-export", NULL,
	 F_ENABLE_TAKE_EXPORT, h_config_enable_take_export, PREF_MISC, 0},
	{"enable-rules-under-take", "Enable Take Rules",
	 F_ENABLE_ROLE_TAKE, h_config_enable_role_take, PREF_MISC, 0},
#ifdef	_WINDOWS
	{"enable-tray-icon", NULL,
	 F_ENABLE_TRAYICON, h_config_tray_icon, PREF_MISC, 0},
#endif
	{"expose-hidden-config", NULL,
	 F_EXPOSE_HIDDEN_CONFIG, h_config_expose_hidden_config, PREF_MISC, 0},
	{"expunge-only-manually", NULL,
	 F_EXPUNGE_MANUALLY, h_config_expunge_manually, PREF_MISC, 0},
	{"expunge-without-confirm", "Expunge Without Confirming",
	 F_AUTO_EXPUNGE, h_config_auto_expunge, PREF_MISC, 0},
	{"expunge-without-confirm-everywhere", "Expunge Without Confirming Everywhere",
	 F_FULL_AUTO_EXPUNGE, h_config_full_auto_expunge, PREF_MISC, 0},
	{"force-arrow-cursor", NULL,
	 F_FORCE_ARROW, h_config_force_arrow, PREF_MISC, 0},
	{"maildrops-preserve-state", NULL,
	 F_MAILDROPS_PRESERVE_STATE, h_config_maildrops_preserve_state,
	 PREF_MISC, 0},
	{"offer-expunge-of-inbox", "Offer Expunge of INBOX",
	 F_EXPUNGE_INBOX, h_config_expunge_inbox, PREF_MISC, 0},
	{"offer-expunge-of-stayopen-folders", "Offer Expunge of Stayopen Folders",
	 F_EXPUNGE_STAYOPENS, h_config_expunge_stayopens, PREF_MISC, 0},
	{"preopen-stayopen-folders", NULL,
	 F_PREOPEN_STAYOPENS, h_config_preopen_stayopens, PREF_MISC, 0},
	{"preserve-start-stop-characters", "Preserve Start/Stop Characters",
	 F_PRESERVE_START_STOP, h_config_preserve_start_stop, PREF_OS_STSP, 0},
	{"quell-folder-internal-msg", "Prevent Folder Internal Message",
	 F_QUELL_INTERNAL_MSG, h_config_quell_folder_internal_msg, PREF_MISC, 0},
	{"quell-partial-fetching", "Prevent Partial Fetching",
	 F_QUELL_PARTIAL_FETCH, h_config_quell_partial, PREF_MISC, 0},
	{"prune-uses-yyyy-mm", "Prune Uses YYYY-MM",
	 F_PRUNE_USES_ISO, h_config_prune_uses_iso, PREF_MISC, 0},
	{"quit-without-confirm", "Quit Without Confirming",
	 F_QUIT_WO_CONFIRM, h_config_quit_wo_confirm, PREF_MISC, 0},
	{"quote-replace-nonflowed", NULL,
	 F_QUOTE_REPLACE_NOFLOW, h_config_quote_replace_noflow, PREF_MISC, 0},
	{"save-aggregates-copy-sequence", "Save Combines Copies (may be out of order)",
	 F_AGG_SEQ_COPY, h_config_save_aggregates, PREF_MISC, 1},
	{"save-partial-msg-without-confirm", "Save Partial Message Without Confirming",
	 F_SAVE_PARTIAL_WO_CONFIRM, h_config_save_part_wo_confirm, PREF_MISC, 0},
	{"save-will-advance", NULL,
	 F_SAVE_ADVANCES, h_config_save_advances, PREF_MISC, 0},
	{"save-will-not-delete", NULL,
	 F_SAVE_WONT_DELETE, h_config_save_wont_delete, PREF_MISC, 0},
	{"save-will-quote-leading-froms", NULL,
	 F_QUOTE_ALL_FROMS, h_config_quote_all_froms, PREF_MISC, 0},
	{"scramble-message-id", "Scramble the Message-ID When Sending",
	 F_ROT13_MESSAGE_ID, h_config_scramble_message_id, PREF_MISC, 0},
	{"select-without-confirm", "Select Ctrl-T Foldername Without Confirming",
	 F_SELECT_WO_CONFIRM, h_config_select_wo_confirm, PREF_MISC, 0},
	{"show-cursor", NULL,
	 F_SHOW_CURSOR, h_config_show_cursor, PREF_MISC, 0},
	{"show-plain-text-internally", NULL,
	 F_SHOW_TEXTPLAIN_INT, h_config_textplain_int, PREF_MISC, 0},
	{"show-selected-in-boldface", "Show Selected in Boldface",
	 F_SELECTED_SHOWN_BOLD, h_config_select_in_bold, PREF_MISC, 0},
	{"slash-collapses-entire-thread", NULL,
	 F_SLASH_COLL_ENTIRE, h_config_slash_coll_entire, PREF_MISC, 0},
#ifdef	_WINDOWS
	{"store-window-position-in-config", "Store Window Position in Config",
	 F_STORE_WINPOS_IN_CONFIG, h_config_winpos_in_config, PREF_MISC, 0},
#endif
	{"suppress-asterisks-in-password-prompt", "Suppress Asterisks in Password Prompt",
	 F_QUELL_ASTERISKS, h_config_quell_asterisks,
	 PREF_MISC, 0},
	{"quell-attachment-extension-warn", "Suppress Attachment Extension Warning",
	 F_QUELL_ATTACH_EXT_WARN, h_config_quell_attach_ext_warn,
	 PREF_MISC, 0},
	{"quell-attachment-extra-prompt", "Suppress Attachment Extra Prompt",
	 F_QUELL_ATTACH_EXTRA_PROMPT, h_config_quell_attach_extra_prompt,
	 PREF_MISC, 0},
	{"quell-berkeley-format-timezone", "Suppress Berkeley Format Timezone",
	 F_QUELL_BEZERK_TIMEZONE, h_config_no_bezerk_zone, PREF_MISC, 0},
	{"quell-content-id", "Suppress Content-ID",
	 F_QUELL_CONTENT_ID, h_config_quell_content_id, PREF_MISC, 0},
	{"quell-filtering-done-message", "Suppress Filtering Done Message",
	 F_QUELL_FILTER_DONE_MSG, h_config_quell_filtering_done_message,
	 PREF_MISC, 0},
	{"quell-filtering-messages", "Suppress Filtering Messages",
	 F_QUELL_FILTER_MSGS, h_config_quell_filtering_messages,
	 PREF_MISC, 0},
	{"quell-imap-envelope-update", "Suppress IMAP Envelope Update",
	 F_QUELL_IMAP_ENV_CB, h_config_quell_imap_env, PREF_MISC, 0},
	{"quell-lock-failure-warnings", "Suppress Lock Failure Warnings",
	 F_QUELL_LOCK_FAILURE_MSGS, h_config_quell_lock_failure_warnings,
	 PREF_MISC, 0},
	{"quell-maildomain-warning", "Suppress Maildomain Warning",
	 F_QUELL_MAILDOMAIN_WARNING, h_config_quell_domain_warn, PREF_MISC, 0},
	{"quell-news-envelope-update", "Suppress News Envelope Update",
	 F_QUELL_NEWS_ENV_CB, h_config_quell_news_env, PREF_MISC, 0},
#ifdef	_WINDOWS
	{"quell-ssl-largeblocks", "Prevent SSL Largeblocks",
	 F_QUELL_SSL_LARGEBLOCKS, h_config_quell_ssl_largeblocks, PREF_MISC, 0},
#endif
	{"quell-status-message-beeping", "Suppress Status Message Beeping",
	 F_QUELL_BEEPS, h_config_quell_beeps, PREF_MISC, 0},
	{"quell-timezone-comment-when-sending", "Suppress Timezone Comment When Sending",
	 F_QUELL_TIMEZONE, h_config_quell_tz_comment, PREF_MISC, 0},
	{"suppress-user-agent-when-sending", NULL,
	 F_QUELL_USERAGENT, h_config_suppress_user_agent, PREF_MISC, 0},
	{"tab-checks-recent", "Tab Checks for Recent Messages",
	 F_TAB_CHK_RECENT, h_config_tab_checks_recent, PREF_MISC, 0},
	{"termdef-takes-precedence", NULL,
	 F_TCAP_WINS, h_config_termcap_wins, PREF_MISC, 0},
	{"try-alternative-authentication-driver-first", NULL,
	 F_PREFER_ALT_AUTH, h_config_alt_auth, PREF_MISC, 0},
	{"unselect-will-not-advance", NULL,
	 F_UNSELECT_WONT_ADVANCE, h_config_unsel_wont_advance, PREF_MISC, 0},
	{"use-current-dir", "Use Current Directory",
	 F_USE_CURRENT_DIR, h_config_use_current_dir, PREF_MISC, 0},
	{"use-function-keys", NULL,
	 F_USE_FK, h_config_use_fk, PREF_OS_USFK, 0},
	{"use-regular-startup-rule-for-stayopen-folders", "Use Regular Startup Rule for Stayopen Folders",
	 F_STARTUP_STAYOPEN, h_config_use_reg_start_for_stayopen, PREF_MISC, 0},
	{"use-resent-to-in-rules", "Use Resent-To in Rules",
	 F_USE_RESENTTO, h_config_use_resentto, PREF_MISC, 0},
	{"use-subshell-for-suspend", "Use Subshell for Suspend",
	 F_SUSPEND_SPAWNS, h_config_suspend_spawns, PREF_OS_SPWN, 0},
#ifndef	_WINDOWS
	{"use-system-translation", NULL,
	 F_USE_SYSTEM_TRANS, h_config_use_system_translation, PREF_MISC, 0},
#endif

/* Hidden Features */
	{"old-growth", NULL,
	 F_OLD_GROWTH, NO_HELP, PREF_NONE, 0},
	{"disable-config-cmd", NULL,
	 F_DISABLE_CONFIG_SCREEN, h_config_disable_config_cmd, PREF_HIDDEN, 0},
	{"disable-keyboard-lock-cmd", NULL,
	 F_DISABLE_KBLOCK_CMD, h_config_disable_kb_lock, PREF_HIDDEN, 0},
	{"disable-password-cmd", NULL,
	 F_DISABLE_PASSWORD_CMD, h_config_disable_password_cmd, PREF_HIDDEN, 0},
	{"disable-pipes-in-sigs", NULL,
	 F_DISABLE_PIPES_IN_SIGS, h_config_disable_pipes_in_sigs, PREF_HIDDEN, 0},
	{"disable-pipes-in-templates", NULL,
	 F_DISABLE_PIPES_IN_TEMPLATES, h_config_disable_pipes_in_templates,
	 PREF_HIDDEN, 0},
	{"disable-roles-setup-cmd", NULL,
	 F_DISABLE_ROLES_SETUP, h_config_disable_roles_setup, PREF_HIDDEN, 0},
	{"disable-roles-sig-edit", NULL,
	 F_DISABLE_ROLES_SIGEDIT, h_config_disable_roles_sigedit, PREF_HIDDEN, 0},
	{"disable-roles-template-edit", NULL,
	 F_DISABLE_ROLES_TEMPLEDIT, h_config_disable_roles_templateedit,
	 PREF_HIDDEN, 0},
	{"disable-setlocale-collate", NULL,
	 F_DISABLE_SETLOCALE_COLLATE, h_config_disable_collate, PREF_HIDDEN, 0},
	{"disable-shared-namespaces", NULL,
	 F_DISABLE_SHARED_NAMESPACES, h_config_disable_shared, PREF_HIDDEN, 0},
	{"disable-signature-edit-cmd", NULL,
	 F_DISABLE_SIGEDIT_CMD, h_config_disable_signature_edit, PREF_HIDDEN, 0},
	{"quell-personal-name-prompt", NULL,
	 F_QUELL_PERSONAL_NAME_PROMPT, h_config_quell_personal_name_prompt, PREF_HIDDEN, 0},
	{"quell-user-id-prompt", "Quell User ID Prompt",
	 F_QUELL_USER_ID_PROMPT, h_config_quell_user_id_prompt, PREF_HIDDEN, 0},
#ifdef SMIME
	{"smime-dont-do-smime", "S/MIME -- Turn off S/MIME",
	 F_DONT_DO_SMIME, h_config_smime_dont_do_smime, PREF_HIDDEN, 0},
	{"smime-encrypt-by-default", "S/MIME -- Encrypt by Default",
	 F_ENCRYPT_DEFAULT_ON, h_config_smime_encrypt_by_default, PREF_HIDDEN, 0},
	{"smime-remember-passphrase", "S/MIME -- Remember S/MIME Passphrase",
	 F_REMEMBER_SMIME_PASSPHRASE, h_config_smime_remember_passphrase, PREF_HIDDEN, 0},
	{"smime-sign-by-default", "S/MIME -- Sign by Default",
	 F_SIGN_DEFAULT_ON, h_config_smime_sign_by_default, PREF_HIDDEN, 0},
#ifdef APPLEKEYCHAIN
	{"publiccerts-in-keychain", "S/MIME -- Public Certs in MacOS Keychain",
	 F_PUBLICCERTS_IN_KEYCHAIN, h_config_smime_pubcerts_in_keychain, PREF_HIDDEN, 0},
#endif
#endif
	{"selectable-item-nobold", NULL,
	 F_SLCTBL_ITEM_NOBOLD, NO_HELP, PREF_NONE, 0},
	{"send-confirms-only-expanded", NULL,	/* exposed in Web Alpine */
	 F_SEND_CONFIRM_ON_EXPAND, h_config_send_confirms_only_expanded, PREF_HIDDEN, 0},
	{"enable-jump-cmd", NULL,		/* exposed in Web Alpine */
	 F_ENABLE_JUMP_CMD, h_config_enable_jump_command, PREF_HIDDEN, 0},
	{"enable-newmail-sound", NULL,		/* exposed in Web Alpine */
	 F_ENABLE_NEWMAIL_SOUND, h_config_enable_newmail_sound, PREF_HIDDEN, 0},
	{"render-html-internally", NULL,		/* exposed in Web Alpine */
	 F_RENDER_HTML_INTERNALLY, h_config_render_html_internally, PREF_HIDDEN, 0}
    };

    return((index >= 0 && index < (sizeof(feat_list)/sizeof(feat_list[0])))
	   ? &feat_list[index] : NULL);
}


/*
 * feature_list_index -- return index of given feature id in
 *			 feature list
 */
int
feature_list_index(int id)
{
    FEATURE_S *feature;
    int	       i;

    for(i = 0; (feature = feature_list(i)); i++)
      if(id == feature->id)
	return(i);

    return(-1);
}


/*
 * feature_list_name -- return the given feature id's corresponding name
 */
char *
feature_list_name(int id)
{
    FEATURE_S *f;

    return((f = feature_list(feature_list_index(id))) ? f->name : "");
}


int
feature_list_id(char *name)
{
    FEATURE_S *f;
    int i;

    for(i = 0; (f = feature_list(i)); i++)
      if(!strucmp(f->name, name))
        return(f->id);

    return(-1);
}


/*
 * feature_list_help -- return the given feature id's corresponding help
 */
HelpType
feature_list_help(int id)
{
    FEATURE_S *f;

    return((f = feature_list(feature_list_index(id))) ? f->help : NO_HELP);
}


/*
 * All the arguments past "list" are the backwards compatibility hacks.
 */
void
process_feature_list(struct pine *ps, char **list, int old_growth, int hir, int osr)
{
    register char            *q;
    char                    **p,
                             *lvalue[BM_SIZE * 8];
    int                       i,
                              yorn;
    long                      l;
    FEATURE_S		     *feat;


    /* clear all previous settings and reset them to default */
    for(i = 0; (feat = feature_list(i)) != NULL; i++)
      F_SET(feat->id, ps, feat->defval);

    /* backwards compatibility */
    if(hir)
	F_TURN_ON(F_INCLUDE_HEADER, ps);

    /* ditto */
    if(osr)
	F_TURN_ON(F_SIG_AT_BOTTOM, ps);

    /* ditto */
    if(old_growth)
        set_old_growth_bits(ps, 0);

    /* now run through the list (global, user, and cmd_line lists are here) */
    if(list){
      for(p = list; (q = *p) != NULL; p++){
	if(struncmp(q, "no-", 3) == 0){
	  yorn = 0;
	  q += 3;
	}else{
	  yorn = 1;
	}

	for(i = 0; (feat = feature_list(i)) != NULL; i++){
	  if(strucmp(q, feat->name) == 0){
	    if(feat->id == F_OLD_GROWTH){
	      set_old_growth_bits(ps, yorn);
	    }else{
	      F_SET(feat->id, ps, yorn);
	    }
	    break;
	  }
	}

	/* if it wasn't in that list */
	if(feat == NULL)
          dprint((1,"Unrecognized feature in feature-list (%s%s)\n",
		     (yorn ? "" : "no-"), q ? q : "?"));
      }
    }

    /*
     * Turn on gratuitous '>From ' quoting, if requested...
     */
    mail_parameters(NULL, SET_FROMWIDGET,
		    F_ON(F_QUOTE_ALL_FROMS, ps) ? VOIDT : NIL);

    /*
     * Turn off .lock creation complaints...
     */
    if(F_ON(F_QUELL_LOCK_FAILURE_MSGS, ps))
      mail_parameters(NULL, SET_LOCKEACCESERROR, (void *) 0);

    /*
     * Turn on quelling of pseudo message.
     */
    if(F_ON(F_QUELL_INTERNAL_MSG,ps_global))
      mail_parameters(NULL, SET_USERHASNOLIFE, (void *) 1);

    l = F_ON(F_MULNEWSRC_HOSTNAMES_AS_TYPED,ps_global) ? 0L : 1L;
    mail_parameters(NULL, SET_NEWSRCCANONHOST, (void *) l);

    ps->pass_ctrl_chars = F_ON(F_PASS_CONTROL_CHARS,ps_global) ? 1 : 0;
    ps->pass_c1_ctrl_chars = F_ON(F_PASS_C1_CONTROL_CHARS,ps_global) ? 1 : 0;

#ifndef	_WINDOWS
    if(F_ON(F_QUELL_BEZERK_TIMEZONE,ps_global))
      mail_parameters(NULL, SET_NOTIMEZONES, (void *) 1);
#endif

    if(F_ON(F_USE_FK, ps))
      ps->orig_use_fkeys = 1;

    /* Will we have to build a new list? */
    if(!(old_growth || hir || osr))
	return;

    /*
     * Build a new list for feature-list.  The only reason we ever need to
     * do this is if one of the obsolete options is being converted
     * into a feature-list item, and it isn't already included in the user's
     * feature-list.
     */
    i = 0;
    for(p = LVAL(&ps->vars[V_FEATURE_LIST], Main);
	p && (q = *p); p++){
      /* already have it or cancelled it, don't need to add later */
      if(hir && (strucmp(q, "include-header-in-reply") == 0 ||
                             strucmp(q, "no-include-header-in-reply") == 0)){
	hir = 0;
      }else if(osr && (strucmp(q, "signature-at-bottom") == 0 ||
                             strucmp(q, "no-signature-at-bottom") == 0)){
	osr = 0;
      }else if(old_growth && (strucmp(q, "old-growth") == 0 ||
                             strucmp(q, "no-old-growth") == 0)){
	old_growth = 0;
      }
      lvalue[i++] = cpystr(q);
    }

    /* check to see if we still need to build a new list */
    if(!(old_growth || hir || osr))
	return;

    if(hir)
      lvalue[i++] = "include-header-in-reply";
    if(osr)
      lvalue[i++] = "signature-at-bottom";
    if(old_growth)
      lvalue[i++] = "old-growth";
    lvalue[i] = NULL;
    set_variable_list(V_FEATURE_LIST, lvalue, TRUE, Main);
}


void
set_current_pattern_vals(struct pine *ps)
{
    struct variable *vars = ps->vars;

    set_current_val(&vars[V_PATTERNS], TRUE, TRUE);
    set_current_val(&vars[V_PAT_ROLES], TRUE, TRUE);
    set_current_val(&vars[V_PAT_FILTS], TRUE, TRUE);
    set_current_val(&vars[V_PAT_FILTS_OLD], TRUE, TRUE);
    set_current_val(&vars[V_PAT_SCORES], TRUE, TRUE);
    set_current_val(&vars[V_PAT_SCORES_OLD], TRUE, TRUE);
    set_current_val(&vars[V_PAT_INCOLS], TRUE, TRUE);
    set_current_val(&vars[V_PAT_OTHER], TRUE, TRUE);
    set_current_val(&vars[V_PAT_SRCH], TRUE, TRUE);

    /*
     * If old pattern variable (V_PATTERNS) is set and the new ones aren't
     * in the config file, then convert the old data into the new variables.
     * It isn't quite that simple, though, because we don't store unset
     * variables in remote pinercs. Check for the variables but if we
     * don't find any of them, also check the version number. This change was
     * made in version 4.30. We could just check that except that we're
     * worried somebody will make an incompatible version number change in
     * their local version, and will break this. So we check both the
     * version # and the var_in_pinerc things to be safer.
     */
    if(vars[V_PATTERNS].current_val.l
       && vars[V_PATTERNS].current_val.l[0]
       && !var_in_pinerc(vars[V_PAT_ROLES].name)
       && !var_in_pinerc(vars[V_PAT_FILTS].name)
       && !var_in_pinerc(vars[V_PAT_FILTS_OLD].name)
       && !var_in_pinerc(vars[V_PAT_SCORES].name)
       && !var_in_pinerc(vars[V_PAT_SCORES_OLD].name)
       && !var_in_pinerc(vars[V_PAT_INCOLS].name)
       && isdigit((unsigned char) ps->pine_pre_vers[0])
       && ps->pine_pre_vers[1] == '.'
       && isdigit((unsigned char) ps->pine_pre_vers[2])
       && isdigit((unsigned char) ps->pine_pre_vers[3])
       && strncmp(ps->pine_pre_vers, "4.30", 4) < 0){
	convert_pattern_data();
    }

    /*
     * Otherwise, if FILTS_OLD is set and FILTS isn't in the config file,
     * convert FILTS_OLD to FILTS. Same for SCORES.
     * The reason FILTS was changed was so we could change the
     * semantics of how rules work when there are pieces in the rule that
     * we don't understand. At the same time as the FILTS change we added
     * a rule to detect 8bitSubjects. So a user might have a filter that
     * deletes messages with 8bitSubjects. The problem is that that same
     * filter in a FILTS_OLD pine would match because it would ignore the
     * 8bitSubject part of the pattern and match on the rest. So we changed
     * the semantics so that rules with unknown bits would be ignored
     * instead of used. We had to change variable names at the same time
     * because we were adding the 8bit thing and the old pines are still
     * out there. Filters and Scores can both be dangerous. Roles, Colors,
     * and Other seem less dangerous so not worth adding a new variable.
     * This was changed in 4.50.
     */
    else{
	if(vars[V_PAT_FILTS_OLD].current_val.l
	   && vars[V_PAT_FILTS_OLD].current_val.l[0]
	   && !var_in_pinerc(vars[V_PAT_FILTS].name)
	   && !var_in_pinerc(vars[V_PAT_SCORES].name)
	   && isdigit((unsigned char) ps->pine_pre_vers[0])
	   && ps->pine_pre_vers[1] == '.'
	   && isdigit((unsigned char) ps->pine_pre_vers[2])
	   && isdigit((unsigned char) ps->pine_pre_vers[3])
	   && strncmp(ps->pine_pre_vers, "4.50", 4) < 0){
	    convert_filts_pattern_data();
	}

	if(vars[V_PAT_SCORES_OLD].current_val.l
	   && vars[V_PAT_SCORES_OLD].current_val.l[0]
	   && !var_in_pinerc(vars[V_PAT_FILTS].name)
	   && !var_in_pinerc(vars[V_PAT_SCORES].name)
	   && isdigit((unsigned char) ps->pine_pre_vers[0])
	   && ps->pine_pre_vers[1] == '.'
	   && isdigit((unsigned char) ps->pine_pre_vers[2])
	   && isdigit((unsigned char) ps->pine_pre_vers[3])
	   && strncmp(ps->pine_pre_vers, "4.50", 4) < 0){
	    convert_scores_pattern_data();
	}
    }

    if(vars[V_PAT_ROLES].post_user_val.l)
      ps_global->ew_for_role_take = Post;
    else
      ps_global->ew_for_role_take = Main;

    if(vars[V_PAT_FILTS].post_user_val.l)
      ps_global->ew_for_filter_take = Post;
    else
      ps_global->ew_for_filter_take = Main;

    if(vars[V_PAT_SCORES].post_user_val.l)
      ps_global->ew_for_score_take = Post;
    else
      ps_global->ew_for_score_take = Main;

    if(vars[V_PAT_INCOLS].post_user_val.l)
      ps_global->ew_for_incol_take = Post;
    else
      ps_global->ew_for_incol_take = Main;

    if(vars[V_PAT_OTHER].post_user_val.l)
      ps_global->ew_for_other_take = Post;
    else
      ps_global->ew_for_other_take = Main;

    if(vars[V_PAT_SRCH].post_user_val.l)
      ps_global->ew_for_srch_take = Post;
    else
      ps_global->ew_for_srch_take = Main;
}


/*
 * Foreach of the config files;
 * transfer the data to the new variables.
 */
void
convert_pattern_data(void)
{
    convert_pinerc_patterns(PAT_USE_MAIN);
    convert_pinerc_patterns(PAT_USE_POST);
}


void
convert_filts_pattern_data(void)
{
    convert_pinerc_filts_patterns(PAT_USE_MAIN);
    convert_pinerc_filts_patterns(PAT_USE_POST);
}


void
convert_scores_pattern_data(void)
{
    convert_pinerc_scores_patterns(PAT_USE_MAIN);
    convert_pinerc_scores_patterns(PAT_USE_POST);
}


/*
 * Foreach of the four variables, transfer the data for this config file
 * from the old patterns variable. We don't have to convert OTHER patterns
 * or SRCH patterns because they didn't exist in pines without patterns-other.
 *
 * If the original variable had patlines with type File then we convert
 * all of the individual patterns to type Lit, because each pattern can
 * be of any category. Lit patterns are better tested, anyway.
 */
void
convert_pinerc_patterns(long int use_flags)
{
    long      old_rflags;
    long      rflags;
    PAT_S    *pat;
    PAT_STATE pstate;
    ACTION_S *act;

    old_rflags = (ROLE_OLD_PAT | use_flags);

    rflags = 0L;
    if(any_patterns(old_rflags, &pstate)){
	dprint((2, "converting old patterns to new (%s)\n", (use_flags == PAT_USE_MAIN) ? "Main" : "Post"));
	for(pat = first_pattern(&pstate); 
	    pat;
	    pat = next_pattern(&pstate)){
	    if((act = pat->action) != NULL){
		if(act->is_a_role &&
		   add_to_pattern(pat, ROLE_DO_ROLES | use_flags))
		  rflags |= ROLE_DO_ROLES;
		if(act->is_a_incol &&
		   add_to_pattern(pat, ROLE_DO_INCOLS | use_flags))
		  rflags |= ROLE_DO_INCOLS;
		if(act->is_a_score &&
		   add_to_pattern(pat, ROLE_DO_SCORES | use_flags))
		  rflags |= ROLE_DO_SCORES;
		if(act->is_a_filter &&
		   add_to_pattern(pat, ROLE_DO_FILTER | use_flags))
		  rflags |= ROLE_DO_FILTER;
	    }
	}
	
	if(rflags)
	  if(write_patterns(rflags | use_flags))
	    dprint((1,
		   "Trouble converting patterns to new variable\n"));
    }
}


/*
 * If the original variable had patlines with type File then we convert
 * all of the individual patterns to type Lit, because each pattern can
 * be of any category. Lit patterns are better tested, anyway.
 */
void
convert_pinerc_filts_patterns(long int use_flags)
{
    long      old_rflags;
    long      rflags;
    PAT_S    *pat;
    PAT_STATE pstate;
    ACTION_S *act;

    old_rflags = (ROLE_OLD_FILT | use_flags);

    rflags = 0L;
    if(any_patterns(old_rflags, &pstate)){
	dprint((2, "converting old filter patterns to new (%s)\n", (use_flags == PAT_USE_MAIN) ? "Main" : "Post"));
	for(pat = first_pattern(&pstate); 
	    pat;
	    pat = next_pattern(&pstate)){
	    if((act = pat->action) != NULL){
		if(act->is_a_filter &&
		   add_to_pattern(pat, ROLE_DO_FILTER | use_flags))
		  rflags |= ROLE_DO_FILTER;
	    }
	}
	
	if(rflags)
	  if(write_patterns(rflags | use_flags))
	    dprint((1,
		   "Trouble converting filter patterns to new variable\n"));
    }
}


/*
 * If the original variable had patlines with type File then we convert
 * all of the individual patterns to type Lit, because each pattern can
 * be of any category. Lit patterns are better tested, anyway.
 */
void
convert_pinerc_scores_patterns(long int use_flags)
{
    long      old_rflags;
    long      rflags;
    PAT_S    *pat;
    PAT_STATE pstate;
    ACTION_S *act;

    old_rflags = (ROLE_OLD_SCORE | use_flags);

    rflags = 0L;
    if(any_patterns(old_rflags, &pstate)){
	dprint((2, "converting old scores patterns to new (%s)\n", (use_flags == PAT_USE_MAIN) ? "Main" : "Post"));
	for(pat = first_pattern(&pstate); 
	    pat;
	    pat = next_pattern(&pstate)){
	    if((act = pat->action) != NULL){
		if(act->is_a_score &&
		   add_to_pattern(pat, ROLE_DO_SCORES | use_flags))
		  rflags |= ROLE_DO_SCORES;
	    }
	}
	
	if(rflags)
	  if(write_patterns(rflags | use_flags))
	    dprint((1,
		   "Trouble converting scores patterns to new variable\n"));
    }
}


/*
 * set_old_growth_bits - Command used to set or unset old growth set
 *			 of features
 */
void
set_old_growth_bits(struct pine *ps, int val)
{
    int i;

    for(i = 1; i <= F_FEATURE_LIST_COUNT; i++)
      if(test_old_growth_bits(ps, i))
	F_SET(i, ps, val);
}



/*
 * test_old_growth_bits - Test to see if all the old growth bits are on,
 *			  *or* if a particular feature index is in the old
 *			  growth set.
 *
 * WEIRD ALERT: if index == F_OLD_GROWTH bit values are tested
 *              otherwise a bits existence in the set is tested!!!
 *
 * BUG: this will break if an old growth feature number is ever >= 32.
 */
int
test_old_growth_bits(struct pine *ps, int index)
{
    /*
     * this list defines F_OLD_GROWTH set
     */
    static unsigned long old_growth_bits = ((1 << F_ENABLE_FULL_HDR)     |
					    (1 << F_ENABLE_PIPE)         |
					    (1 << F_ENABLE_TAB_COMPLETE) |
					    (1 << F_QUIT_WO_CONFIRM)     |
					    (1 << F_ENABLE_JUMP)         |
					    (1 << F_ENABLE_ALT_ED)       |
					    (1 << F_ENABLE_BOUNCE)       |
					    (1 << F_ENABLE_AGG_OPS)	 |
					    (1 << F_ENABLE_FLAG)         |
					    (1 << F_CAN_SUSPEND));
    if(index >= 32)
	return(0);

    if(index == F_OLD_GROWTH){
	for(index = 1; index <= F_FEATURE_LIST_COUNT; index++)
	  if(((1 << index) & old_growth_bits) && F_OFF(index, ps))
	    return(0);

	return(1);
    }
    else
      return((1 << index) & old_growth_bits);
}


/*
 * Side effect is that the appropriate global variable is set, and the
 * appropriate current_val is set.
 */
void
cur_rule_value(struct variable *var, int expand, int cmdline)
{
    int i;
    NAMEVAL_S *v;

    set_current_val(var, expand, cmdline);

    if(var == &ps_global->vars[V_SAVED_MSG_NAME_RULE]){
      if(ps_global->VAR_SAVED_MSG_NAME_RULE)
	for(i = 0; (v = save_msg_rules(i)); i++)
	  if(!strucmp(ps_global->VAR_SAVED_MSG_NAME_RULE, S_OR_L(v))){
	      ps_global->save_msg_rule = v->value;
	      break;
	  }
    }
#ifndef	_WINDOWS
    else if(var == &ps_global->vars[V_COLOR_STYLE]){
      if(ps_global->VAR_COLOR_STYLE)
	for(i = 0; (v = col_style(i)); i++)
	  if(!strucmp(ps_global->VAR_COLOR_STYLE, S_OR_L(v))){
	      ps_global->color_style = v->value;
	      break;
	  }
    }
#endif
    else if(var == &ps_global->vars[V_INDEX_COLOR_STYLE]){
      if(ps_global->VAR_INDEX_COLOR_STYLE)
	for(i = 0; (v = index_col_style(i)); i++)
	  if(!strucmp(ps_global->VAR_INDEX_COLOR_STYLE, S_OR_L(v))){
	      ps_global->index_color_style = v->value;
	      break;
	  }
    }
    else if(var == &ps_global->vars[V_TITLEBAR_COLOR_STYLE]){
      if(ps_global->VAR_TITLEBAR_COLOR_STYLE)
	for(i = 0; (v = titlebar_col_style(i)); i++)
	  if(!strucmp(ps_global->VAR_TITLEBAR_COLOR_STYLE, S_OR_L(v))){
	      ps_global->titlebar_color_style = v->value;
	      break;
	  }
    }
    else if(var == &ps_global->vars[V_FCC_RULE]){
      if(ps_global->VAR_FCC_RULE)
	for(i = 0; (v = fcc_rules(i)); i++)
	  if(!strucmp(ps_global->VAR_FCC_RULE, S_OR_L(v))){
	      ps_global->fcc_rule = v->value;
	      break;
	  }
    }
    else if(var == &ps_global->vars[V_GOTO_DEFAULT_RULE]){
      if(ps_global->VAR_GOTO_DEFAULT_RULE)
	for(i = 0; (v = goto_rules(i)); i++)
	  if(!strucmp(ps_global->VAR_GOTO_DEFAULT_RULE, S_OR_L(v))){
	      ps_global->goto_default_rule = v->value;
	      break;
	  }
    }
    else if(var == &ps_global->vars[V_INCOMING_STARTUP]){
      if(ps_global->VAR_INCOMING_STARTUP)
	for(i = 0; (v = incoming_startup_rules(i)); i++)
	  if(!strucmp(ps_global->VAR_INCOMING_STARTUP, S_OR_L(v))){
	      ps_global->inc_startup_rule = v->value;
	      break;
	  }
    }
    else if(var == &ps_global->vars[V_PRUNING_RULE]){
      if(ps_global->VAR_PRUNING_RULE)
	for(i = 0; (v = pruning_rules(i)); i++)
	  if(!strucmp(ps_global->VAR_PRUNING_RULE, S_OR_L(v))){
	      ps_global->pruning_rule = v->value;
	      break;
	  }
    }
    else if(var == &ps_global->vars[V_REOPEN_RULE]){
      if(ps_global->VAR_REOPEN_RULE)
	for(i = 0; (v = reopen_rules(i)); i++)
	  if(!strucmp(ps_global->VAR_REOPEN_RULE, S_OR_L(v))){
	      ps_global->reopen_rule = v->value;
	      break;
	  }
    }
    else if(var == &ps_global->vars[V_FLD_SORT_RULE]){
      if(ps_global->VAR_FLD_SORT_RULE)
	for(i = 0; (v = fld_sort_rules(i)); i++)
	  if(!strucmp(ps_global->VAR_FLD_SORT_RULE, S_OR_L(v))){
	      ps_global->fld_sort_rule = v->value;
	      break;
	  }
    }
    else if(var == &ps_global->vars[V_AB_SORT_RULE]){
      if(ps_global->VAR_AB_SORT_RULE)
	for(i = 0; (v = ab_sort_rules(i)); i++)
	  if(!strucmp(ps_global->VAR_AB_SORT_RULE, S_OR_L(v))){
	      ps_global->ab_sort_rule = v->value;
	      break;
	  }
    }
    else if(var == &ps_global->vars[V_THREAD_DISP_STYLE]){
      if(ps_global->VAR_THREAD_DISP_STYLE)
	for(i = 0; (v = thread_disp_styles(i)); i++)
	  if(!strucmp(ps_global->VAR_THREAD_DISP_STYLE, S_OR_L(v))){
	      ps_global->thread_disp_style = v->value;
	      break;
	  }
    }
    else if(var == &ps_global->vars[V_THREAD_INDEX_STYLE]){
      if(ps_global->VAR_THREAD_INDEX_STYLE)
	for(i = 0; (v = thread_index_styles(i)); i++)
	  if(!strucmp(ps_global->VAR_THREAD_INDEX_STYLE, S_OR_L(v))){
	      ps_global->thread_index_style = v->value;
	      break;
	  }
    }
}


/*
 * Standard way to get at save message rules...
 */
NAMEVAL_S *
save_msg_rules(int index)
{
    static NAMEVAL_S save_rules[] = {
      {"by-from",			      NULL, SAV_RULE_FROM},
      {"by-nick-of-from",		      NULL, SAV_RULE_NICK_FROM_DEF},
      {"by-nick-of-from-then-from",	      NULL, SAV_RULE_NICK_FROM},
      {"by-fcc-of-from",		      NULL, SAV_RULE_FCC_FROM_DEF},
      {"by-fcc-of-from-then-from",	      NULL, SAV_RULE_FCC_FROM},
      {"by-realname-of-from",	 	      NULL, SAV_RULE_RN_FROM_DEF},
      {"by-realname-of-from-then-from",	      NULL, SAV_RULE_RN_FROM},
      {"by-sender",			      NULL, SAV_RULE_SENDER},
      {"by-nick-of-sender",		      NULL, SAV_RULE_NICK_SENDER_DEF},
      {"by-nick-of-sender-then-sender",	      NULL, SAV_RULE_NICK_SENDER},
      {"by-fcc-of-sender",		      NULL, SAV_RULE_FCC_SENDER_DEF},
      {"by-fcc-of-sender-then-sender",	      NULL, SAV_RULE_FCC_SENDER},
      {"by-realname-of-sender",		      NULL, SAV_RULE_RN_SENDER_DEF},
      {"by-realname-of-sender-then-sender",   NULL, SAV_RULE_RN_SENDER},
      {"by-recipient",			      NULL, SAV_RULE_RECIP},
      {"by-nick-of-recip",		      NULL, SAV_RULE_NICK_RECIP_DEF},
      {"by-nick-of-recip-then-recip",	      NULL, SAV_RULE_NICK_RECIP},
      {"by-fcc-of-recip",		      NULL, SAV_RULE_FCC_RECIP_DEF},
      {"by-fcc-of-recip-then-recip",	      NULL, SAV_RULE_FCC_RECIP},
      {"by-realname-of-recip",		      NULL, SAV_RULE_RN_RECIP_DEF},
      {"by-realname-of-recip-then-recip",     NULL, SAV_RULE_RN_RECIP},
      {"by-replyto",			      NULL, SAV_RULE_REPLYTO},
      {"by-nick-of-replyto",		      NULL, SAV_RULE_NICK_REPLYTO_DEF},
      {"by-nick-of-replyto-then-replyto",     NULL, SAV_RULE_NICK_REPLYTO},
      {"by-fcc-of-replyto",		      NULL, SAV_RULE_FCC_REPLYTO_DEF},
      {"by-fcc-of-replyto-then-replyto",      NULL, SAV_RULE_FCC_REPLYTO},
      {"by-realname-of-replyto",	      NULL, SAV_RULE_RN_REPLYTO_DEF},
      {"by-realname-of-replyto-then-replyto", NULL, SAV_RULE_RN_REPLYTO},
      {"last-folder-used",		      NULL, SAV_RULE_LAST}, 
      {"default-folder",		      NULL, SAV_RULE_DEFLT}
    };

    return((index >= 0 && index < (sizeof(save_rules)/sizeof(save_rules[0])))
	   ? &save_rules[index] : NULL);
}


/*
 * Standard way to get at fcc rules...
 */
NAMEVAL_S *
fcc_rules(int index)
{
    static NAMEVAL_S f_rules[] = {
	{"default-fcc",        NULL, FCC_RULE_DEFLT}, 
	{"last-fcc-used",      NULL, FCC_RULE_LAST}, 
	{"by-recipient",       NULL, FCC_RULE_RECIP},
	{"by-nickname",        NULL, FCC_RULE_NICK},
	{"by-nick-then-recip", NULL, FCC_RULE_NICK_RECIP},
	{"current-folder",     NULL, FCC_RULE_CURRENT}
    };

    return((index >= 0 && index < (sizeof(f_rules)/sizeof(f_rules[0])))
	   ? &f_rules[index] : NULL);
}


/*
 * Standard way to get at addrbook sort rules...
 */
NAMEVAL_S *
ab_sort_rules(int index)
{
    static NAMEVAL_S ab_rules[] = {
	{"fullname-with-lists-last",  NULL, AB_SORT_RULE_FULL_LISTS},
	{"fullname",                  NULL, AB_SORT_RULE_FULL}, 
	{"nickname-with-lists-last",  NULL, AB_SORT_RULE_NICK_LISTS},
	{"nickname",                  NULL, AB_SORT_RULE_NICK},
	{"dont-sort",                 NULL, AB_SORT_RULE_NONE}
    };

    return((index >= 0 && index < (sizeof(ab_rules)/sizeof(ab_rules[0])))
	   ? &ab_rules[index] : NULL);
}


/*
 * Standard way to get at color styles.
 */
NAMEVAL_S *
col_style(int index)
{
    static NAMEVAL_S col_styles[] = {
	{"no-color",			NULL, COL_NONE}, 
	{"use-termdef",			NULL, COL_TERMDEF},
	{"force-ansi-8color",		NULL, COL_ANSI8},
	{"force-ansi-16color",		NULL, COL_ANSI16},
	{"force-xterm-256color",	NULL, COL_ANSI256}
    };

    return((index >= 0 && index < (sizeof(col_styles)/sizeof(col_styles[0])))
	   ? &col_styles[index] : NULL);
}


/*
 * Standard way to get at index color styles.
 */
NAMEVAL_S *
index_col_style(int index)
{
    static NAMEVAL_S ind_col_styles[] = {
	{"flip-colors",			NULL, IND_COL_FLIP}, 
	{"reverse",			NULL, IND_COL_REV}, 
	{"reverse-fg",			NULL, IND_COL_FG},
	{"reverse-fg-no-ambiguity",	NULL, IND_COL_FG_NOAMBIG},
	{"reverse-bg",			NULL, IND_COL_BG},
	{"reverse-bg-no-ambiguity",	NULL, IND_COL_BG_NOAMBIG}
    };

    return((index >= 0 && index < (sizeof(ind_col_styles)/sizeof(ind_col_styles[0]))) ? &ind_col_styles[index] : NULL);
}


/*
 * Standard way to get at titlebar color styles.
 */
NAMEVAL_S *
titlebar_col_style(int index)
{
    static NAMEVAL_S tbar_col_styles[] = {
	{"default",			NULL, TBAR_COLOR_DEFAULT}, 
	{"indexline",			NULL, TBAR_COLOR_INDEXLINE}, 
	{"reverse-indexline",		NULL, TBAR_COLOR_REV_INDEXLINE}
    };

    return((index >= 0 && index < (sizeof(tbar_col_styles)/sizeof(tbar_col_styles[0]))) ? &tbar_col_styles[index] : NULL);
}


/*
 * Standard way to get at folder sort rules...
 */
NAMEVAL_S *
fld_sort_rules(int index)
{
    static NAMEVAL_S fdl_rules[] = {
	{"alphabetical",          NULL, FLD_SORT_ALPHA}, 
	{"alpha-with-dirs-last",  NULL, FLD_SORT_ALPHA_DIR_LAST},
	{"alpha-with-dirs-first", NULL, FLD_SORT_ALPHA_DIR_FIRST}
    };

    return((index >= 0 && index < (sizeof(fdl_rules)/sizeof(fdl_rules[0])))
	   ? &fdl_rules[index] : NULL);
}


/*
 * Standard way to get at incoming startup rules...
 */
NAMEVAL_S *
incoming_startup_rules(int index)
{
    static NAMEVAL_S is_rules[] = {
	{"first-unseen",		NULL, IS_FIRST_UNSEEN},
	{"first-recent",		NULL, IS_FIRST_RECENT}, 
	{"first-important",		NULL, IS_FIRST_IMPORTANT}, 
	{"first-important-or-unseen",	NULL, IS_FIRST_IMPORTANT_OR_UNSEEN}, 
	{"first-important-or-recent",	NULL, IS_FIRST_IMPORTANT_OR_RECENT}, 
	{"first",			NULL, IS_FIRST},
	{"last",			NULL, IS_LAST}
    };

    return((index >= 0 && index < (sizeof(is_rules)/sizeof(is_rules[0])))
	   ? &is_rules[index] : NULL);
}


NAMEVAL_S *
startup_rules(int index)
{
    static NAMEVAL_S is2_rules[] = {
	{"first-unseen",		NULL, IS_FIRST_UNSEEN},
	{"first-recent",		NULL, IS_FIRST_RECENT}, 
	{"first-important",		NULL, IS_FIRST_IMPORTANT}, 
	{"first-important-or-unseen",	NULL, IS_FIRST_IMPORTANT_OR_UNSEEN}, 
	{"first-important-or-recent",	NULL, IS_FIRST_IMPORTANT_OR_RECENT}, 
	{"first",			NULL, IS_FIRST},
	{"last",			NULL, IS_LAST},
	{"default",			NULL, IS_NOTSET}
    };

    return((index >= 0 && index < (sizeof(is2_rules)/sizeof(is2_rules[0])))
	   ? &is2_rules[index] : NULL);
}


/*
 * Standard way to get at pruning-rule values.
 */
NAMEVAL_S *
pruning_rules(int index)
{
    static NAMEVAL_S pr_rules[] = {
	{"ask about rename, ask about deleting","ask-ask", PRUNE_ASK_AND_ASK},
	{"ask about rename, don't delete",	"ask-no",  PRUNE_ASK_AND_NO},
	{"always rename, ask about deleting",	"yes-ask", PRUNE_YES_AND_ASK}, 
	{"always rename, don't delete",		"yes-no",  PRUNE_YES_AND_NO}, 
	{"don't rename, ask about deleting",	"no-ask",  PRUNE_NO_AND_ASK}, 
	{"don't rename, don't delete",		"no-no",   PRUNE_NO_AND_NO} 
    };

    return((index >= 0 && index < (sizeof(pr_rules)/sizeof(pr_rules[0])))
	   ? &pr_rules[index] : NULL);
}


/*
 * Standard way to get at reopen-rule values.
 */
NAMEVAL_S *
reopen_rules(int index)
{
    static NAMEVAL_S ro_rules[] = {
	/* TRANSLATORS: short description of a feature option */
	{"Always reopen",					"yes-yes",
							    REOPEN_YES_YES},
	/* TRANSLATORS: short description of a feature option, default in brackets */
	{"Yes for POP/NNTP, Ask about other remote [Yes]",	"yes-ask-y",
							    REOPEN_YES_ASK_Y},
	/* TRANSLATORS: short description of a feature option, default in brackets */
	{"Yes for POP/NNTP, Ask about other remote [No]",	"yes-ask-n",
							    REOPEN_YES_ASK_N},
	/* TRANSLATORS: short description of a feature option */
	{"Yes for POP/NNTP, No for other remote",		"yes-no",
							    REOPEN_YES_NO},
	/* TRANSLATORS: short description of a feature option, default in brackets */
	{"Always ask [Yes]",					"ask-ask-y",
							    REOPEN_ASK_ASK_Y},
	/* TRANSLATORS: short description of a feature option, default in brackets */
	{"Always ask [No]",					"ask-ask-n",
							    REOPEN_ASK_ASK_N},
	/* TRANSLATORS: short description of a feature option, default in brackets */
	{"Ask about POP/NNTP [Yes], No for other remote",	"ask-no-y",
							    REOPEN_ASK_NO_Y},
	/* TRANSLATORS: short description of a feature option, default in brackets */
	{"Ask about POP/NNTP [No], No for other remote",	"ask-no-n",
							    REOPEN_ASK_NO_N},
	/* TRANSLATORS: short description of a feature option */
	{"Never reopen",					"no-no",
							    REOPEN_NO_NO},
    };

    return((index >= 0 && index < (sizeof(ro_rules)/sizeof(ro_rules[0])))
	   ? &ro_rules[index] : NULL);
}


/*
 * Standard way to get at thread_disp_style values.
 */
NAMEVAL_S *
thread_disp_styles(int index)
{
    static NAMEVAL_S td_styles[] = {
	{"none",			"none",		THREAD_NONE},
	{"show-thread-structure",	"struct",	THREAD_STRUCT},
	{"mutt-like",			"mutt",		THREAD_MUTTLIKE},
	{"indent-subject-1",		"subj1",	THREAD_INDENT_SUBJ1},
	{"indent-subject-2",		"subj2",	THREAD_INDENT_SUBJ2},
	{"indent-from-1",		"from1",	THREAD_INDENT_FROM1},
	{"indent-from-2",		"from2",	THREAD_INDENT_FROM2},
	{"show-structure-in-from",	"struct-from",	THREAD_STRUCT_FROM}
    };

    return((index >= 0 && index < (sizeof(td_styles)/sizeof(td_styles[0])))
	   ? &td_styles[index] : NULL);
}


/*
 * Standard way to get at thread_index_style values.
 */
NAMEVAL_S *
thread_index_styles(int index)
{
    static NAMEVAL_S ti_styles[] = {
	{"regular-index-with-expanded-threads",	"exp",	THRDINDX_EXP},
	{"regular-index-with-collapsed-threads","coll",	THRDINDX_COLL},
	{"separate-index-screen-always",	"sep",	THRDINDX_SEP},
	{"separate-index-screen-except-for-single-messages","sep-auto",
							THRDINDX_SEP_AUTO}
    };

    return((index >= 0 && index < (sizeof(ti_styles)/sizeof(ti_styles[0])))
	   ? &ti_styles[index] : NULL);
}


/*
 * Standard way to get at goto default rules...
 */
NAMEVAL_S *
goto_rules(int index)
{
    static NAMEVAL_S g_rules[] = {
	{"folder-in-first-collection",		 NULL, GOTO_FIRST_CLCTN},
	{"inbox-or-folder-in-first-collection",	 NULL, GOTO_INBOX_FIRST_CLCTN},
	{"inbox-or-folder-in-recent-collection", NULL, GOTO_INBOX_RECENT_CLCTN},
	{"first-collection-with-inbox-default",	 NULL, GOTO_FIRST_CLCTN_DEF_INBOX},
	{"most-recent-folder",			 NULL, GOTO_LAST_FLDR}
    };

    return((index >= 0 && index < (sizeof(g_rules)/sizeof(g_rules[0])))
	   ? &g_rules[index] : NULL);
}


NAMEVAL_S *
pat_fldr_types(int index)
{
    static NAMEVAL_S pat_fldr_list[] = {
	{"Any",			"ANY",		FLDR_ANY},
	{"News",		"NEWS",		FLDR_NEWS},
	{"Email",		"EMAIL",	FLDR_EMAIL},
	{"Specific (Enter Incoming Nicknames or use ^T)", "SPEC", FLDR_SPECIFIC}
    };

    return((index >= 0 &&
	    index < (sizeof(pat_fldr_list)/sizeof(pat_fldr_list[0])))
		   ? &pat_fldr_list[index] : NULL);
}


NAMEVAL_S *
inabook_fldr_types(int indexarg)
{
    static NAMEVAL_S inabook_fldr_list[] = {
	{"Don't care, always matches",			"E",	IAB_EITHER},
	{"Yes, in any address book",			"YES",	IAB_YES},
	{"No, not in any address book",			"NO",	IAB_NO},
	{"Yes, in specific address books",		"SYES",	IAB_SPEC_YES},
	{"No, not in any of specific address books",	"SNO",	IAB_SPEC_NO}
    };

    int index = indexarg & IAB_TYPE_MASK;

    return((index >= 0 &&
	   index < (sizeof(inabook_fldr_list)/sizeof(inabook_fldr_list[0])))
		   ? &inabook_fldr_list[index] : NULL);
}


NAMEVAL_S *
filter_types(int index)
{
    static NAMEVAL_S filter_type_list[] = {
	{"Just Set Message Status",	"NONE",		FILTER_STATE},
	{"Delete",			"DEL",		FILTER_KILL},
	{"Move (Enter folder name(s) in primary collection, or use ^T)",
						    "FLDR", FILTER_FOLDER}
    };

    return((index >= 0 &&
	    index < (sizeof(filter_type_list)/sizeof(filter_type_list[0])))
		   ? &filter_type_list[index] : NULL);
}


NAMEVAL_S *
role_repl_types(int index)
{
    static NAMEVAL_S role_repl_list[] = {
	{"Never",			"NO",	ROLE_REPL_NO},
	{"With confirmation",		"YES",	ROLE_REPL_YES},
	{"Without confirmation",	"NC",	ROLE_REPL_NOCONF}
    };

    return((index >= 0 &&
	    index < (sizeof(role_repl_list)/sizeof(role_repl_list[0])))
		   ? &role_repl_list[index] : NULL);
}


NAMEVAL_S *
role_forw_types(int index)
{
    static NAMEVAL_S role_forw_list[] = {
	{"Never",		  	"NO",	ROLE_FORW_NO},
	{"With confirmation",		"YES",	ROLE_FORW_YES},
	{"Without confirmation",	"NC",	ROLE_FORW_NOCONF}
    };

    return((index >= 0 &&
	    index < (sizeof(role_forw_list)/sizeof(role_forw_list[0])))
		   ? &role_forw_list[index] : NULL);
}


NAMEVAL_S *
role_comp_types(int index)
{
    static NAMEVAL_S role_comp_list[] = {
	{"Never",		  	"NO",	ROLE_COMP_NO},
	{"With confirmation",		"YES",	ROLE_COMP_YES},
	{"Without confirmation",	"NC",	ROLE_COMP_NOCONF}
    };

    return((index >= 0 &&
	    index < (sizeof(role_comp_list)/sizeof(role_comp_list[0])))
		   ? &role_comp_list[index] : NULL);
}


NAMEVAL_S *
role_status_types(int index)
{
    static NAMEVAL_S role_status_list[] = {
	{"Don't care, always matches",	"E",	PAT_STAT_EITHER},
	{"Yes",				"YES",	PAT_STAT_YES},
	{"No",				"NO",	PAT_STAT_NO}
    };

    return((index >= 0 &&
	    index < (sizeof(role_status_list)/sizeof(role_status_list[0])))
		   ? &role_status_list[index] : NULL);
}


NAMEVAL_S *
msg_state_types(int index)
{
    static NAMEVAL_S msg_state_list[] = {
	{"Don't change it",		"LV",	ACT_STAT_LEAVE},
	{"Set this state",		"SET",	ACT_STAT_SET},
	{"Clear this state",		"CLR",	ACT_STAT_CLEAR}
    };

    return((index >= 0 &&
	    index < (sizeof(msg_state_list)/sizeof(msg_state_list[0])))
		   ? &msg_state_list[index] : NULL);
}


#ifdef	ENABLE_LDAP
NAMEVAL_S *
ldap_search_rules(int index)
{
    static NAMEVAL_S ldap_search_list[] = {
	{"contains",		NULL, LDAP_SRCH_CONTAINS},
	{"equals",		NULL, LDAP_SRCH_EQUALS},
	{"begins-with",		NULL, LDAP_SRCH_BEGINS},
	{"ends-with",		NULL, LDAP_SRCH_ENDS}
    };

    return((index >= 0 &&
	    index < (sizeof(ldap_search_list)/sizeof(ldap_search_list[0])))
		   ? &ldap_search_list[index] : NULL);
}


NAMEVAL_S *
ldap_search_types(int index)
{
    static NAMEVAL_S ldap_types_list[] = {
	{"name",				NULL, LDAP_TYPE_CN},
	{"surname",				NULL, LDAP_TYPE_SUR},
	{"givenname",				NULL, LDAP_TYPE_GIVEN},
	{"email",				NULL, LDAP_TYPE_EMAIL},
	{"name-or-email",			NULL, LDAP_TYPE_CN_EMAIL},
	{"surname-or-givenname",		NULL, LDAP_TYPE_SUR_GIVEN},
	{"sur-or-given-or-name-or-email",	NULL, LDAP_TYPE_SEVERAL}
    };

    return((index >= 0 &&
	    index < (sizeof(ldap_types_list)/sizeof(ldap_types_list[0])))
		   ? &ldap_types_list[index] : NULL);
}


NAMEVAL_S *
ldap_search_scope(int index)
{
    static NAMEVAL_S ldap_scope_list[] = {
	{"base",		NULL, LDAP_SCOPE_BASE},
	{"onelevel",		NULL, LDAP_SCOPE_ONELEVEL},
	{"subtree",		NULL, LDAP_SCOPE_SUBTREE}
    };

    return((index >= 0 &&
	    index < (sizeof(ldap_scope_list)/sizeof(ldap_scope_list[0])))
		   ? &ldap_scope_list[index] : NULL);
}
#endif


/*
 * Choose from the global default, command line args, pinerc values to set
 * the actual value of the variable that we will use.  Start at the top
 * and work down from higher to lower precedence.
 * For lists, we may inherit values from lower precedence
 * versions if that's the way the user specifies it.
 * The user can put INHERIT_DEFAULT as the first entry in a list and that
 * means it will inherit the current values, for example the values
 * from the global_val, or the value from the main_user_val could be
 * inherited in the post_user_val.
 */
void    
set_current_val(struct variable *var, int expand, int cmdline)
{
    int    is_set[5], is_inherit[5];
    int    i, j, k, cnt, start;
    char **tmp, **t, **list[5];
    char  *p;

    dprint((9,
	       "set_current_val(var=%s%s, expand=%d, cmdline=%d)\n",
	       (var && var->name) ? var->name : "?",
	       (var && var->is_list) ? " (list)" : "",
	       expand, cmdline));

    if(!var)
      return;

    if(var->is_list){			  /* variable is a list */

	for(j = 0; j < 5; j++){
	    t = j==0 ? var->global_val.l :
		j==1 ? var->main_user_val.l :
		j==2 ? var->post_user_val.l :
		j==3 ? ((cmdline) ? var->cmdline_val.l : NULL) :
		       var->fixed_val.l;

	    is_set[j] = is_inherit[j] = 0;
	    list[j] = NULL;

	    if(t){
		if(!expand){
		    is_set[j]++;
		    list[j] = t;
		}
		else{
		    for(i = 0; t[i]; i++){
			if(expand_variables(tmp_20k_buf, SIZEOF_20KBUF, t[i],
					    0)){
			    /* successful expand */
			    is_set[j]++;
			    list[j] = t;
			    break;
			}
		    }
		}

		if(list[j] && list[j][0] && !strcmp(list[j][0],INHERIT))
		  is_inherit[j]++;
	    }
	}

	cnt = 0;
	start = 0;
	/* count how many items in current_val list */
	/* Admin wants default, which is global_val. */
	if(var->is_fixed && var->fixed_val.l == NULL){
	    cnt = 0;
	    if(is_set[0]){
		for(; list[0][cnt]; cnt++)
		  ;
	    }
	}
	else{
	    for(j = 0; j < 5; j++){
		if(is_set[j]){
		    if(!is_inherit[j]){
			cnt = 0;	/* reset */
			start = j;
		    }

		    for(i = is_inherit[j] ? 1 : 0; list[j][i]; i++)
		      cnt++;
		}
	    }
	}

	free_list_array(&var->current_val.l);	 /* clean up any old values */

	/* check to see if anything is set */
	if(is_set[0] + is_set[1] + is_set[2] + is_set[3] + is_set[4] > 0){
	    var->current_val.l = (char **)fs_get((cnt+1)*sizeof(char *));
	    tmp = var->current_val.l;
	    if(var->is_fixed && var->fixed_val.l == NULL){
		if(is_set[0]){
		    for(i = 0; list[0][i]; i++){
			if(!expand)
			  *tmp++ = cpystr(list[0][i]);
			else if(expand_variables(tmp_20k_buf, SIZEOF_20KBUF,
						 list[0][i], 0))
			  *tmp++ = cpystr(tmp_20k_buf);
		    }
		}
	    }
	    else{
		for(j = start; j < 5; j++){
		    if(is_set[j]){
			for(i = is_inherit[j] ? 1 : 0; list[j][i]; i++){
			    if(!expand)
			      *tmp++ = cpystr(list[j][i]);
			    else if(expand_variables(tmp_20k_buf,SIZEOF_20KBUF,
						     list[j][i], 0))
			      *tmp++ = cpystr(tmp_20k_buf);
			}
		    }
		}
	    }

	    *tmp = NULL;
	}
	else
	  var->current_val.l = NULL;
    }
    else{  /* variable is not a list */
	char *strvar = NULL;

	for(j = 0; j < 5; j++){

	    p = j==0 ? var->fixed_val.p :
		j==1 ? ((cmdline) ? var->cmdline_val.p : NULL) :
		j==2 ? var->post_user_val.p :
		j==3 ? var->main_user_val.p :
		       var->global_val.p;

	    is_set[j] = 0;

	    if(p){
		if(!expand){
		    is_set[j]++;
		    if(!strvar)
			strvar = p;
		}
		else if(expand_variables(tmp_20k_buf, SIZEOF_20KBUF, p,
				(var == &ps_global->vars[V_MAILCAP_PATH] ||
				 var == &ps_global->vars[V_MIMETYPE_PATH]))){
		    is_set[j]++;
		    if(!strvar)
			strvar = p;
		}
	    }
	}

	/* Admin wants default, which is global_val. */
	if(var->is_fixed && var->fixed_val.p == NULL)
	  strvar = var->global_val.p;

	if(var->current_val.p)		/* free previous value */
	  fs_give((void **)&var->current_val.p);

	if(strvar){
	    if(!expand)
	      var->current_val.p = cpystr(strvar);
	    else{
		expand_variables(tmp_20k_buf, SIZEOF_20KBUF, strvar,
				 (var == &ps_global->vars[V_MAILCAP_PATH] ||
				  var == &ps_global->vars[V_MIMETYPE_PATH]));
		var->current_val.p = cpystr(tmp_20k_buf);
	    }
	}
	else
	  var->current_val.p = NULL;
    }

    if(var->is_fixed && !is_inherit[4]){
	char **flist;
	int fixed_len, user_len;

	/*
	 * sys mgr fixed this variable and user is trying to change it
	 */
	for(k = 1; !(ps_global->give_fixed_warning &&
		     ps_global->fix_fixed_warning) && k <= 3; k++){
	    if(is_set[k]){
		if(var->is_list){
		    t = k==1 ? ((cmdline) ? var->cmdline_val.l : NULL) :
			k==2 ? var->post_user_val.l :
			       var->main_user_val.l;

		    /* If same length and same contents, don't warn. */
		    for(flist=var->fixed_val.l; flist && *flist; flist++)
		      ;/* just counting */

		    fixed_len = var->fixed_val.l ? (flist - var->fixed_val.l)
						 : 0;
		    for(flist=t; flist && *flist; flist++)
		      ;/* just counting */

		    user_len = t ? (flist - t) : 0;
		    if(user_len == fixed_len){
		      for(i=0; i < user_len; i++){
			for(j=0; j < user_len; j++)
			  if(!strucmp(t[i], var->fixed_val.l[j]))
			    break;
			  
			if(j == user_len){
			  ps_global->give_fixed_warning = 1;
			  if(k != 1)
			    ps_global->fix_fixed_warning = 1;

			  break;
			}
		      }
		    }
		    else{
			ps_global->give_fixed_warning = 1;
			if(k != 1)
			  ps_global->fix_fixed_warning = 1;
		    }
		}
		else{
		    p = k==1 ? ((cmdline) ? var->cmdline_val.p : NULL) :
			k==2 ? var->post_user_val.p :
			       var->main_user_val.p;
		    
		    if((var->fixed_val.p && !p) ||
		       (!var->fixed_val.p && p) ||
		       (var->fixed_val.p && p && strucmp(var->fixed_val.p, p))){
			ps_global->give_fixed_warning = 1;
			if(k != 1)
			  ps_global->fix_fixed_warning = 1;
		    }
		}
	    }
	}
    }
}


void
set_news_spec_current_val(int expand, int cmdline)
{
    struct variable *newsvar = &ps_global->vars[V_NEWS_SPEC];
    struct variable *fvar    = &ps_global->vars[V_FOLDER_SPEC];

    /* check to see if it has a value */
    set_current_val(newsvar, expand, cmdline);

    /*
     * If no value, we might want to fake a value. We'll do that if
     * there is no news collection already defined in FOLDER_SPEC and if
     * there is also an NNTP_SERVER defined.
     */
    if(!newsvar->current_val.l && ps_global->VAR_NNTP_SERVER &&
       ps_global->VAR_NNTP_SERVER[0] && ps_global->VAR_NNTP_SERVER[0][0] &&
       !news_in_folders(fvar)){
	char buf[MAXPATH];

	newsvar->global_val.l = (char **)fs_get(2 * sizeof(char *));
	snprintf(buf, sizeof(buf), "{%.*s/nntp}#news.[]", sizeof(buf)-20,
		ps_global->VAR_NNTP_SERVER[0]);
	newsvar->global_val.l[0] = cpystr(buf);
	newsvar->global_val.l[1] = NULL;
	set_current_val(newsvar, expand, cmdline);
	/*
	 * But we're going to get rid of the fake global_val in case
	 * things change.
	 */
	free_list_array(&newsvar->global_val.l);
    }
}


/*
 * Feature-list has to be handled separately from the other variables
 * because it is additive.  The other variables choose one of command line,
 * or pine.conf, or pinerc.  Feature list adds them.  This could easily be
 * converted to a general purpose routine if we add more additive variables.
 *
 * This works by replacing earlier values with later ones.  That is, command
 * line settings have higher precedence than global settings and that is
 * accomplished by putting the command line features after the global
 * features in the list.  When they are processed, the last one wins.
 *
 * Feature-list also has a backwards compatibility hack.
 */
void    
set_feature_list_current_val(struct variable *var)
{
    char **list;
    char **list_fixed;
    char   no_allow[50];
    int    i, j, k, m,
	   elems = 0;

    /* count the lists so we can allocate */
    for(m = 0; m < 6; m++){
	list = m==0 ? var->global_val.l :
		m==1 ? var->main_user_val.l :
		 m==2 ? var->post_user_val.l :
		  m==3 ? ps_global->feat_list_back_compat :
		   m==4 ? var->cmdline_val.l :
		           var->fixed_val.l;
	if(list)
	  for(i = 0; list[i]; i++)
	    elems++;
    }

    list_fixed = var->fixed_val.l;

    if(var->current_val.l)
      free_list_array(&var->current_val.l);

    var->current_val.l = (char **)fs_get((elems+1) * sizeof(char *));

    /*
     * We need to warn the user if the sys mgr has restricted him or her
     * from changing a feature that he or she is trying to change.
     *
     * We're not catching the old-growth macro since we're just comparing
     * strings. That is, it works correctly, but the user won't be warned
     * if the user old-growth and the mgr says no-quit-without-confirm.
     */

    j = 0;
    strncpy(no_allow, "no-", 3);
    strncpy(no_allow+3, feature_list_name(F_ALLOW_CHANGING_FROM), sizeof(no_allow)-3-1);
    no_allow[sizeof(no_allow)-1] = '\0';

    for(m = 0; m < 6; m++){
	list = m==0 ? var->global_val.l :
		m==1 ? var->main_user_val.l :
		 m==2 ? var->post_user_val.l :
		  m==3 ? ps_global->feat_list_back_compat :
		   m==4 ? var->cmdline_val.l :
		           var->fixed_val.l;
	if(list)
	  for(i = 0; list[i]; i++){
	      var->current_val.l[j++] = cpystr(list[i]);

	      /* this is the warning section */
	      if(m >= 1 && m <= 4){
		  for(k = 0; list_fixed && list_fixed[k]; k++){
		      char *p, *q;
		      p = list[i];
		      q = list_fixed[k];
		      if(!struncmp(p, "no-", 3))
			p += 3;
		      if(!struncmp(q, "no-", 3))
			q += 3;
		      if(!strucmp(q, p) && strucmp(list[i], list_fixed[k])){
			  ps_global->give_fixed_warning = 1;
			  if(m <= 2)
			    ps_global->fix_fixed_warning = 1;
		      }
		  }
	      }
	      else if(m == 5 && !strucmp(list[i], no_allow))
	        ps_global->never_allow_changing_from = 1;
	  }
    }

#ifdef	NEVER_ALLOW_CHANGING_FROM
    ps_global->never_allow_changing_from = 1;
#endif

    var->current_val.l[j] = NULL;
}
                                                     


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

	Expand Metacharacters/variables in file-names

   Read input line and expand shell-variables/meta-characters

	<input>		<replaced by>
	$variable	getenv("variable")
	${variable}	getenv("variable")
	${variable:-defvalue} is getenv("variable") if variable is defined and
	                      is defvalue otherwise
	~		getenv("HOME")
	\c		c
	<others>	<just copied>

NOTE handling of braces in ${name} doesn't check much or do error recovery

   If colon_path is set, then we expand ~ not only at the start of linein,
   but also after each : in the path.
	
  ----*/

char *
expand_variables(char *lineout, size_t lineoutlen, char *linein, int colon_path)
{
    char *src = linein, *dest = lineout, *p;
    char *limit = lineout + lineoutlen;
    int   envexpand = 0;

    if(!linein)
      return(NULL);

    while(*src ){			/* something in input string */
        if(*src == '$' && *(src+1) == '$'){
	    /*
	     * $$ to escape chars we're interested in, else
	     * it's up to the user of the variable to handle the 
	     * backslash...
	     */
	    if(dest < limit)
              *dest++ = *++src;		/* copy next as is */
        }else
#if !(defined(DOS) || defined(OS2))
        if(*src == '\\' && *(src+1) == '$'){
	    /*
	     * backslash to escape chars we're interested in, else
	     * it's up to the user of the variable to handle the 
	     * backslash...
	     */
	    if(dest < limit)
              *dest++ = *++src;		/* copy next as is */
        }else if(*src == '~' &&
		 (src == linein || (colon_path && *(src-1) == ':'))){
	    char buf[MAXPATH];
	    int  i;

	    for(i = 0; i < sizeof(buf)-1 && src[i] && src[i] != '/'; i++)
	      buf[i] = src[i];

	    src    += i;		/* advance src pointer */
	    buf[i]  = '\0';		/* tie off buf string */
	    fnexpand(buf, sizeof(buf));	/* expand the path */

	    for(p = buf; dest < limit && (*dest = *p); p++, dest++)
	      ;

	    continue;
        }else
#endif
	if(*src == '$'){		/* shell variable */
	    char word[128+1], *colon = NULL, *rbrace = NULL;

	    envexpand++;		/* signal that we've expanded a var */
	    src++;			/* skip dollar */
	    if(*src == '{'){		/* starts with brace? */
		src++;        
		rbrace = strindex(src, '}');
		if(rbrace){
		    /* look for default value */
		    colon = strstr(src, ":-");
		    if(colon && (rbrace < colon))
		      colon = NULL;
		}
	    }

	    p = word;

	    /* put the env variable to be looked up in word */
	    if(rbrace){
		while(*src
		      && (p-word < sizeof(word)-1)
		      && ((colon && src < colon) || (!colon && src < rbrace))){
		    if(isspace((unsigned char) *src)){
			/*
			 * Illegal input. This should be an error of some
			 * sort but instead of that we'll just backup to the
			 * $ and treat it like it wasn't there.
			 */
			while(*src != '$')
			  src--;
			
			envexpand--;
			goto just_copy;
		    }
		    else
		      *p++ = *src++;
		}

		/* adjust src for next char */
		src = rbrace + 1;
	    }
	    else{
		while(*src && !isspace((unsigned char) *src)
		      && (p-word < sizeof(word)-1))
		  *p++ = *src++;
	    }

	    *p = '\0';

	    if((p = getenv(word)) != NULL){ /* check for word in environment */
		while(*p && dest < limit)
		  *dest++ = *p++;
	    }
	    else if(colon){		    /* else possible default value */
		p = colon + 2;
		while(*p && p < rbrace && dest < limit)
		  *dest++ = *p++;
	    }

	    continue;
	}else{				/* other cases: just copy */
just_copy:
	    if(dest < limit)
	      *dest++ = *src;
	}

        if(*src)			/* next character (if any) */
	  src++;
    }

    if(dest < limit)
      *dest = '\0';
    else
      lineout[lineoutlen-1] = '\0';

    return((envexpand && lineout[0] == '\0') ? NULL : lineout);
}


/*----------------------------------------------------------------------
    Sets  login, full_username and home_dir

   Args: ps -- The Pine structure to put the user name, etc in

  Result: sets the fullname, login and home_dir field of the pine structure
          returns 0 on success, -1 if not.
  ----*/
#define	MAX_INIT_ERRS	10
void
init_error(struct pine *ps, int flags, int min_time, int max_time, char *message)
{
    int    i;

    if(!ps->init_errs){
	ps->init_errs = (INIT_ERR_S *)fs_get((MAX_INIT_ERRS + 1) *
					     sizeof(*ps->init_errs));
	memset(ps->init_errs, 0, (MAX_INIT_ERRS + 1) * sizeof(*ps->init_errs));
    }

    for(i = 0; i < MAX_INIT_ERRS; i++)
      if(!(ps->init_errs)[i].message){
	  (ps->init_errs)[i].message  = cpystr(message);
	  (ps->init_errs)[i].min_time = min_time;
	  (ps->init_errs)[i].max_time = max_time;
	  (ps->init_errs)[i].flags    = flags;
	  dprint((2, "%s\n", message ? message : "?"));
	  break;
      }
}


/*----------------------------------------------------------------------
         Read and parse a pinerc file
  
   Args:  Filename   -- name of the .pinerc file to open and read
          vars       -- The vars structure to store values in
          which_vars -- Whether the local or global values are being read

   Result: 

 This may be the local file or the global file.  The values found are
merged with the values currently in vars.  All values are strings and
are malloced; and existing values will be freed before the assignment.
Those that are <unset> will be left unset; their values will be NULL.
  ----*/
void
read_pinerc(PINERC_S *prc, struct variable *vars, ParsePinerc which_vars)
{
    char               *filename, *file, *value, **lvalue, *line, *error;
    char               *p, *p1, *free_file = NULL;
    struct variable    *v;
    PINERC_LINE        *pline = NULL;
    int                 line_count, was_quoted;
    int			i;

    if(!prc)
      return;

    dprint((2, "reading_pinerc \"%s\"\n",
	   prc->name ? prc->name : "?"));

    if(prc->type == Loc){
	filename = prc->name ? prc->name : "";
	file = free_file = read_file(filename, 0);

	/*
	 * This is questionable. In case the user edits the pinerc
	 * in Windows and adds a UTF-8 BOM, we skip it here. If the
	 * user adds a Unicode BOM we're in trouble. We could write it
	 * with the BOM ourselves but so far we leave it BOMless in
	 * order that it's the same on Unix and Windows.
	 */
	if(BOM_UTF8(file))
	  file += 3;
    }
    else{
	if((file = read_remote_pinerc(prc, which_vars)) != NULL)
	  ps_global->c_client_error[0] = '\0';

	free_file = file;
    }

    if(file == NULL || *file == '\0'){
#ifdef	DEBUG
	if(file == NULL){
          dprint((2, "Open failed: %s\n", error_description(errno)));
	}
	else{
	    if(prc->type == Loc){
	      dprint((1, "Read_pinerc: empty pinerc (new?)\n"));
	    }
	    else{
	      dprint((1, "Read_pinerc: new remote pinerc\n"));
	    }
	}
#endif /* DEBUG */

	if(which_vars == ParsePers){
	    /* problems getting remote config */
	    if(file == NULL && prc->type == RemImap){
		if(!pith_opt_remote_pinerc_failure
		   || !(*pith_opt_remote_pinerc_failure)())
		  exceptional_exit(_("Unable to read or write remote configuration"), -1);
	    }

	    ps_global->first_time_user = 1;
	    prc->outstanding_pinerc_changes = 1;
	}

        return;
    }
    else{
	if(prc->type == Loc &&
	   (which_vars == ParseFixed || which_vars == ParseGlobal ||
	    (can_access(filename, ACCESS_EXISTS) == 0 &&
	     can_access(filename, EDIT_ACCESS) != 0))){
	    prc->readonly = 1;
	    if(prc == ps_global->prc)
	      ps_global->readonly_pinerc = 1;
	}

	/*
	 * accept CRLF or LF newlines
	 */
	for(p = file; *p && *p != '\012'; p++)
	  ;

	if(p > file && *p && *(p-1) == '\015')	/* cvt crlf to lf */
	  for(p1 = p - 1; (*p1 = *p) != '\0'; p++)
	    if(!(*p == '\015' && *(p+1) == '\012'))
	      p1++;
    }

    dprint((2, "Read %d characters:\n", strlen(file)));

    if(which_vars == ParsePers || which_vars == ParsePersPost){
	/*--- Count up lines and allocate structures */
	for(line_count = 0, p = file; *p != '\0'; p++)
          if(*p == '\n')
	    line_count++;

	prc->pinerc_lines = (PINERC_LINE *)
			       fs_get((3 + line_count) * sizeof(PINERC_LINE));
	memset((void *)prc->pinerc_lines, 0,
	       (3 + line_count) * sizeof(PINERC_LINE));
	pline = prc->pinerc_lines;
    }

    for(p = file, line = file; *p != '\0';){
        /*----- Grab the line ----*/
        line = p;
        while(*p && *p != '\n')
          p++;
        if(*p == '\n'){
            *p++ = '\0';
        }

        /*----- Comment Line -----*/
        if(*line == '#'){
	    /* no comments in remote pinercs */
            if(pline && prc->type == Loc){
                pline->is_var = 0;
                pline->line = cpystr(line);
                pline++;
            }
            continue;
        }

	if(*line == '\0' || *line == '\t' || *line == ' '){
            p1 = line;
            while(*p1 == '\t' || *p1 == ' ')
               p1++;
            if(pline){
		/*
		 * This could be a continuation line from some future
		 * version of pine, or it could be a continuation line
		 * from a PC-Pine variable we don't know about in unix.
		 */
	        if(*p1 != '\0')
                    pline->line = cpystr(line);
	        else
                    pline->line = cpystr("");
               pline->is_var = 0;
               pline++;
            }
            continue;
	}

        /*----- look up matching 'v' and leave "value" after '=' ----*/
        for(v = vars; *line && v->name; v++)
	  if((i = strlen(v->name)) < strlen(line) && !struncmp(v->name,line,i)){
	      int j;

	      for(j = i; line[j] == ' ' || line[j] == '\t'; j++)
		;

	      if(line[j] == '='){	/* bingo! */
		  for(value = &line[j+1];
		      *value == ' ' || *value == '\t';
		      value++)
		    ;

		  break;
	      }
	      /* else either unrecognized var or bogus line */
	  }

        /*----- Didn't match any variable or bogus format -----*/
	/*
	 * This could be a variable from some future
	 * version of pine, or it could be a PC-Pine variable
	 * we don't know about in unix. Either way, we want to preserve
	 * it in the file.
	 */
        if(!v->name){
            if(pline){
                pline->is_var = 0;
                pline->line = cpystr(line);
                pline++;
            }
            continue;
        }

	/*
	 * Previous versions have caused duplicate pinerc data to be
	 * written to pinerc files. This clause erases the duplicate
	 * information when we read it, and it will be removed from the file
	 * if we call write_pinerc. We test to see if the same variable
	 * appears later in the file, if so, we skip over it here.
	 * We don't care about duplicates if this isn't a pinerc we might
	 * write out, so include pline in the conditional.
	 * Note that we will leave all of the duplicate comments and blank
	 * lines in the file unless it is a remote pinerc. Luckily, the
	 * bug that caused the duplicates only applied to remote pinercs,
	 * so we should have that case covered.
	 *
	 * If we find a duplicate, we point p to the start
	 * of the next line that should be considered, and then skip back
	 * to the top of the loop.
	 */
	if(pline && var_is_in_rest_of_file(v->name, p)){
	    if(v->is_list)
	      p = skip_over_this_var(line, p);

	    continue;
	}

	
        /*----- Obsolete variable, read it anyway below, might use it -----*/
        if(v->is_obsolete){
            if(pline){
                pline->obsolete_var = 1;
                pline->line = cpystr(line);
                pline->var = v;
            }
        }

        /*----- Variable is in the list but unused for some reason -----*/
        if(!v->is_used){
            if(pline){
                pline->is_var = 0;
                pline->line = cpystr(line);
                pline++;
            }
            continue;
        }

        /*--- Var is not user controlled, leave it alone for back compat ---*/
        if(!v->is_user && pline){
	    pline->is_var = 0;
	    pline->line = cpystr(line);
	    pline++;
	    continue;
        }

	if(which_vars == ParseFixed)
	  v->is_fixed = 1;

        /*---- variable is unset, or it's global but expands to nothing ----*/
        if(!*value
	   || (which_vars == ParseGlobal
	       && !expand_variables(tmp_20k_buf, SIZEOF_20KBUF, value,
				    (v == &ps_global->vars[V_MAILCAP_PATH] ||
				     v == &ps_global->vars[V_MIMETYPE_PATH])))){
            if(v->is_user && pline){
                pline->is_var   = 1;
                pline->var = v;
                pline++;
            }
            continue;
        }

        /*--value is non-empty, store it handling quotes and trailing space--*/
        if(*value == '"' && !v->is_list && v->del_quotes){
            was_quoted = 1;
            value++;
            for(p1 = value; *p1 && *p1 != '"'; p1++);
            if(*p1 == '"')
              *p1 = '\0';
            else
              removing_trailing_white_space(value);
        }else
          was_quoted = 0;

	/*
	 * List Entry Parsing
	 *
	 * The idea is to parse a comma separated list of 
	 * elements, preserving quotes, and understanding
	 * continuation lines (that is ',' == "\n ").
	 * Quotes must be balanced within elements.  Space 
	 * within elements is preserved, but leading and trailing 
	 * space is trimmed.  This is a generic function, and it's 
	 * left to the the functions that use the lists to make sure
	 * they contain valid data...
	 */
	if(v->is_list){

	    was_quoted = 0;
	    line_count = 0;
	    p1         = value;
	    while(1){			/* generous count of list elements */
		if(*p1 == '"')		/* ignore ',' if quoted   */
		  was_quoted = (was_quoted) ? 0 : 1 ;

		if((*p1 == ',' && !was_quoted) || *p1 == '\n' || *p1 == '\0')
		  line_count++;		/* count this element */

		if(*p1 == '\0' || *p1 == '\n'){	/* deal with EOL */
		    if(p1 < p || *p1 == '\n'){
			*p1++ = ','; 	/* fix null or newline */

			if(*p1 != '\t' && *p1 != ' '){
			    *(p1-1) = '\0'; /* tie off list */
			    p       = p1;   /* reset p */
			    break;
			}
		    }else{
			p = p1;		/* end of pinerc */
			break;
		    }
		}else
		  p1++;
	    }

	    error  = NULL;
	    lvalue = parse_list(value, line_count,
				v->del_quotes ? PL_REMSURRQUOT : PL_NONE,
			        &error);
	    if(error){
		dprint((1,
		       "read_pinerc: ERROR: %s in %s = \"%s\"\n", 
			   error ? error : "?",
			   v->name ? v->name : "?",
			   value ? value : "?"));
	    }
	    /*
	     * Special case: turn "" strings into empty strings.
	     * This allows users to turn off default lists.  For example,
	     * if smtp-server is set then a user could override smtp-server
	     * with smtp-server="".
	     */
	    for(i = 0; lvalue[i]; i++)
		if(lvalue[i][0] == '"' &&
		   lvalue[i][1] == '"' &&
		   lvalue[i][2] == '\0')
		     lvalue[i][0] = '\0';
	}

        if(pline){
            if(v->is_user && (which_vars == ParsePers || !v->is_onlymain)){
		if(v->is_list){
		    char ***l;

		    l = (which_vars == ParsePers) ? &v->main_user_val.l
						  : &v->post_user_val.l;
		    free_list_array(l);
		    *l = lvalue;
		}
		else{
		    char **p;

		    p = (which_vars == ParsePers) ? &v->main_user_val.p
						  : &v->post_user_val.p;
		    if(p && *p != NULL)
		      fs_give((void **)p);

		    *p = cpystr(value);
		}

		if(pline){
		    pline->is_var    = 1;
		    pline->var       = v;
		    pline->is_quoted = was_quoted;
		    pline++;
		}
            }
        }
	else if(which_vars == ParseGlobal){
            if(v->is_global){
		if(v->is_list){
		    free_list_array(&v->global_val.l);
		    v->global_val.l = lvalue;
		}
		else{
		    if(v->global_val.p != NULL)
		      fs_give((void **) &(v->global_val.p));

		    v->global_val.p = cpystr(value);
		}
            }
        }
	else{  /* which_vars == ParseFixed */
            if(v->is_user || v->is_global){
		if(v->is_list){
		    free_list_array(&v->fixed_val.l);
		    v->fixed_val.l = lvalue;
		}
		else{
		    if(v->fixed_val.p != NULL)
		      fs_give((void **) &(v->fixed_val.p));

		    v->fixed_val.p = cpystr(value);
		}
	    }
	}

#ifdef DEBUG
	if(v->is_list){
	    char **l;
	    l =   (which_vars == ParsePers)     ? v->main_user_val.l :
	           (which_vars == ParsePersPost) ? v->post_user_val.l :
	            (which_vars == ParseGlobal)   ? v->global_val.l :
						     v->fixed_val.l;
	    if(l && *l && **l){
                dprint((5, " %20.20s : %s\n",
		       v->name ? v->name : "?",
		       *l ? *l : "?"));
	        while(++l && *l && **l)
                    dprint((5, " %20.20s : %s\n", "",
			   *l ? *l : "?"));
	    }
	}else{
	    char *p;
	    p =   (which_vars == ParsePers)     ? v->main_user_val.p :
	           (which_vars == ParsePersPost) ? v->post_user_val.p :
	            (which_vars == ParseGlobal)   ? v->global_val.p :
						     v->fixed_val.p;
	    if(p && *p)
                dprint((5, " %20.20s : %s\n",
		       v->name ? v->name : "?",
		       p ? p : "?"));
	}
#endif /* DEBUG */
    }

    if(pline){
        pline->line = NULL;
        pline->is_var = 0;
	if(!prc->pinerc_written && prc->type == Loc){
	    prc->pinerc_written = name_file_mtime(filename);
	    dprint((5, "read_pinerc: time_pinerc_written = %ld\n",
		       (long) prc->pinerc_written));
	}
    }

    if(free_file)
      fs_give((void **) &free_file);
}


/*
 * Args   varname   The variable name we're looking for
 *        begin     Begin looking here
 *
 * Returns 1   if variable varname appears in the rest of the file
 *         0   if not
 */
int
var_is_in_rest_of_file(char *varname, char *begin)
{
    char *p;

    if(!(varname && *varname && begin && *begin))
      return 0;

    p = begin;

    while((p = srchstr(p, varname)) != NULL){
	/* beginning of a line? */
	if(p > begin && (*(p-1) != '\n' && *(p-1) != '\r')){
	    p++;
	    continue;
	}

	/* followed by [ SPACE ] < = > ? */
	p += strlen(varname);
	while(*p == ' ' || *p == '\t')
	  p++;
	
	if(*p == '=')
	  return 1;
    }
    
    return 0;
}


/*
 * Args   begin    Variable to skip starts here.
 *        nextline This is where the next line starts. We need to know this
 *                 because the input has been mangled a little. A \0 has
 *                 replaced the \n at the end of the first line, but we can
 *                 use nextline to help us out of that quandry.
 *
 * Return a pointer to the start of the first line after this variable
 *        and all of its continuation lines.
 */
char *
skip_over_this_var(char *begin, char *nextline)
{
    char *p;

    p = begin;

    while(1){
	if(*p == '\0' || *p == '\n'){		/* EOL */
	    if(p < nextline || *p == '\n'){	/* there may be another line */
		p++;
		if(*p != ' ' && *p != '\t')	/* no continuation line */
		  return(p);
	    }
	    else				/* end of file */
	      return(p);
	}
	else
	  p++;
    }
}


static char quotes[3] = {'"', '"', '\0'};
/*----------------------------------------------------------------------
    Write out the .pinerc state information

   Args: ps -- The pine structure to take state to be written from
      which -- Which pinerc to write
      flags -- If bit WRP_NOUSER is set, then assume that there is
                not a user present to answer questions.

  This writes to a temporary file first, and then renames that to 
 be the new .pinerc file to protect against disk error.  This has the 
 problem of possibly messing up file protections, ownership and links.
  ----*/
int
write_pinerc(struct pine *ps, EditWhich which, int flags)
{
    char               *p, *dir, *tmp = NULL, *pinrc;
    char               *pval, **lval;
    int                 bc = 1;
    PINERC_LINE        *pline;
    struct variable    *var;
    time_t		mtime;
    char               *filename;
    REMDATA_S          *rd = NULL;
    PINERC_S           *prc = NULL;
    STORE_S            *so = NULL;

    dprint((2,"---- write_pinerc(%s) ----\n",
	    (which == Main) ? "Main" : "Post"));

    switch(which){
      case Main:
	prc = ps ? ps->prc : NULL;
	break;
      case Post:
	prc = ps ? ps->post_prc : NULL;
	break;
      default:
	break;
    }

    if(!prc)
      return(-1);
    
    if(prc->quit_to_edit){
	if(!(flags & WRP_NOUSER))
	  quit_to_edit_msg(prc);

	return(-1);
    }

    if(prc->type != Loc && !prc->readonly){

	bc = 0;			/* don't do backcompat conversion */
	rd = prc->rd;
	if(!rd)
	  return(-1);
	
	rd_check_remvalid(rd, -10L);

	if(rd->flags & REM_OUTOFDATE){
	    if((flags & WRP_NOUSER) || unexpected_pinerc_change()){
		prc->outstanding_pinerc_changes = 1;
		if(!(flags & WRP_NOUSER))
		  q_status_message1(SM_ORDER | SM_DING, 3, 3,
				    "Pinerc \"%.200s\" NOT saved",
				    prc->name ? prc->name : "");
		dprint((2, "write_pinerc: remote pinerc changed\n"));
		return(-1);
	    }
	    else
	      rd->flags &= ~REM_OUTOFDATE;
	}

	rd_open_remote(rd);

	if(rd->access == ReadWrite){
	    int ro;

	    if((ro=rd_remote_is_readonly(rd)) || rd->flags & REM_OUTOFDATE){
		if(ro == 1){
		    if(!(flags & WRP_NOUSER))
		      q_status_message(SM_ORDER | SM_DING, 5, 15,
			     _("Can't access remote config, changes NOT saved!"));
		    dprint((1,
	    "write_pinerc: Can't write to remote pinerc %s, aborting write\n",
			   rd->rn ? rd->rn : "?"));
		}
		else if(ro == 2){
		    if(!(rd->flags & NO_META_UPDATE)){
			unsigned long save_chk_nmsgs;

			switch(rd->type){
			  case RemImap:
			    save_chk_nmsgs = rd->t.i.chk_nmsgs;
			    rd->t.i.chk_nmsgs = 0;
			    rd_write_metadata(rd, 0);
			    rd->t.i.chk_nmsgs = save_chk_nmsgs;
			    break;

			  default:
			    q_status_message(SM_ORDER | SM_DING, 3, 5,
					 "Write_pinerc: Type not supported");
			    break;
			}
		    }

		    if(!(flags & WRP_NOUSER))
		      q_status_message1(SM_ORDER | SM_DING, 5, 15,
	    _("No write permission for remote config %.200s, changes NOT saved!"),
				    rd->rn);
		}
		else{
		    if(!(flags & WRP_NOUSER))
		      q_status_message(SM_ORDER | SM_DING, 5, 15,
		 _("Remote config changed, aborting our change to avoid damage..."));
		    dprint((1,
			    "write_pinerc: remote config %s changed since we started pine, aborting write\n",
			    prc->name ? prc->name : "?"));
		}

		rd->flags &= ~DO_REMTRIM;
		return(-1);
	    }

	    filename = rd->lf;
	}
	else{
	    prc->readonly = 1;
	    if(prc == ps->prc)
	      ps->readonly_pinerc = 1;
	}
    }
    else
      filename = prc->name ? prc->name : "";

    pinrc = prc->name ? prc->name : "";

    if(prc->type == Loc){
	mtime = name_file_mtime(filename);
	if(prc->pinerc_written
	   && prc->pinerc_written != mtime
	   && ((flags & WRP_NOUSER) || unexpected_pinerc_change())){
	    prc->outstanding_pinerc_changes = 1;

	    if(!(flags & WRP_NOUSER))
	      q_status_message1(SM_ORDER | SM_DING, 3, 3,
				"Pinerc \"%.200s\" NOT saved", pinrc);

	    dprint((2,"write_pinerc: mtime mismatch: \"%s\": %ld != %ld\n",
		    filename ? filename : "?",
		    (long) prc->pinerc_written, (long) mtime));
	    return(-1);
	}
    }

    /* don't write if pinerc is read-only */
    if(prc->readonly ||
         (filename &&
	  can_access(filename, ACCESS_EXISTS) == 0 &&
          can_access(filename, EDIT_ACCESS) != 0)){
	prc->readonly = 1;
	if(prc == ps->prc)
	  ps->readonly_pinerc = 1;

	if(!(flags & WRP_NOUSER))
	  q_status_message1(SM_ORDER | SM_DING, 0, 5,
		      _("Can't modify configuration file \"%.200s\": ReadOnly"),
			    pinrc);
	dprint((2, "write_pinerc: fail because can't access pinerc\n"));

	if(rd)
	  rd->flags &= ~DO_REMTRIM;

	return(-1);
    }

    if(rd && rd->flags & NO_FILE){
	so = rd->sonofile;
	so_truncate(rd->sonofile, 0L);		/* reset storage object */
    }
    else{
	dir = ".";
	if((p = last_cmpnt(filename)) != NULL){
	    *--p = '\0';
	    dir = filename;
	}

#if	defined(DOS) || defined(OS2)
	if(!(isalpha((unsigned char)dir[0]) && dir[1] == ':' && dir[2] == '\0')
	   && (can_access(dir, EDIT_ACCESS) < 0 &&
	       our_mkdir(dir, 0700) < 0))
	{
	    if(!(flags & WRP_NOUSER))
	      q_status_message2(SM_ORDER | SM_DING, 3, 5,
			      /* TRANSLATORS: first argument is a filename, second
			         arg is the text of the error message */
			      _("Error creating \"%.200s\" : %.200s"), dir,
			      error_description(errno));
	    if(rd)
	      rd->flags &= ~DO_REMTRIM;

	    return(-1);
	}

	tmp = temp_nam(dir, "rc");

	if(*dir && tmp && !in_dir(dir, tmp)){
	    our_unlink(tmp);
	    fs_give((void **)&tmp);
	}

	if(p)
	  *p = '\\';

	if(tmp == NULL)
	  goto io_err;

#else  /* !DOS */
	tmp = temp_nam((*dir) ? dir : "/", "pinerc");

	/*
	 * If temp_nam can't write in dir it puts the temp file in a
	 * temp directory, which won't help us when we go to rename.
	 */
	if(*dir && tmp && !in_dir(dir, tmp)){
	    our_unlink(tmp);
	    fs_give((void **)&tmp);
	}

	if(p)
	  *p = '/';

	if(tmp == NULL)
	  goto io_err;

#endif  /* !DOS */

	if((so = so_get(FileStar, tmp, WRITE_ACCESS)) == NULL)
	  goto io_err;
    }

    if(!(flags & WRP_PRESERV_WRITTEN))
      for(var = ps->vars; var->name != NULL; var++) 
	var->been_written = 0;

    if(prc->type == Loc && ps->first_time_user &&
       !so_puts(so, native_nl(cf_text_comment)))
      goto io_err;

    /* Write out what was in the .pinerc */
    for(pline = prc->pinerc_lines;
	pline && (pline->is_var || pline->line); pline++){
	if(pline->is_var){
	    var = pline->var;

	    if(var->is_list)
	      lval = LVAL(var, which);
	    else
	      pval = PVAL(var, which);

	    /* variable is not set */
	    if((var->is_list && (!lval || !lval[0])) ||
	       (!var->is_list && !pval)){
		/* leave null variables out of remote pinerc */
		if(prc->type == Loc &&
		   (!so_puts(so, var->name) || !so_puts(so, "=") ||
		    !so_puts(so, NEWLINE)))
		  goto io_err;
	    }
	    /* var is set to empty string */
	    else if((var->is_list && lval[0][0] == '\0') ||
		    (!var->is_list && pval[0] == '\0')){
		if(!so_puts(so, var->name) || !so_puts(so, "=") ||
		   !so_puts(so, quotes) || !so_puts(so, NEWLINE))
		  goto io_err;
	    }
	    else{
		if(var->is_list){
		    int i = 0;

		    for(i = 0; lval[i]; i++){
			snprintf(tmp_20k_buf, 10000, "%s%s%s%s%s",
				(i) ? "\t" : var->name,
				(i) ? "" : "=",
				lval[i][0] ? lval[i] : quotes,
				lval[i+1] ? "," : "", NEWLINE);
			tmp_20k_buf[10000-1] = '\0';
			if(!so_puts(so, bc ? backcompat_convert_from_utf8(tmp_20k_buf+10000, SIZEOF_20KBUF-10000, tmp_20k_buf) : tmp_20k_buf))
			  goto io_err;
		    }
		}
		else{
		    snprintf(tmp_20k_buf, 10000, "%s=%s%s%s%s",
			    var->name,
			    (pline->is_quoted && pval[0] != '\"')
			      ? "\"" : "",
			    pval,
			    (pline->is_quoted && pval[0] != '\"')
			      ? "\"" : "", NEWLINE);
		    tmp_20k_buf[10000-1] = '\0';
		    if(!so_puts(so, bc ? backcompat_convert_from_utf8(tmp_20k_buf+10000, SIZEOF_20KBUF-10000, tmp_20k_buf) : tmp_20k_buf))
		      goto io_err;
		}
	    }

	    var->been_written = 1;

	}else{
	    /*
	     * The description text should be changed into a message
	     * about the variable being obsolete when a variable is
	     * moved to obsolete status.  We add that message before
	     * the variable unless it is already there.  However, we
	     * leave the variable itself in case the user runs an old
	     * version of pine again.  Note that we have read in the
	     * value of the variable in read_pinerc and translated it
	     * into a new variable if appropriate.
	     */
	    if(pline->obsolete_var && prc->type == Loc){
		if(pline <= prc->pinerc_lines || (pline-1)->line == NULL ||
		   strlen((pline-1)->line) < 3 ||
		   strucmp((pline-1)->line+2, pline->var->descrip) != 0)
		  if(!so_puts(so, "# ") ||
		     !so_puts(so, native_nl(pline->var->descrip)) ||
		     !so_puts(so, NEWLINE))
		    goto io_err;
	    }

	    /* remove comments from remote pinercs */
	    if((prc->type == Loc ||
		(pline->line[0] != '#' && pline->line[0] != '\0')) &&
	        (!so_puts(so, pline->line) || !so_puts(so, NEWLINE)))
	      goto io_err;
	}
    }

    /* Now write out all the variables not in the .pinerc */
    for(var = ps->vars; var->name != NULL; var++){
	if(!var->is_user || var->been_written || !var->is_used ||
	   var->is_obsolete || (var->is_onlymain && which != Main))
	  continue;

	if(var->is_list)
	  lval = LVAL(var, which);
	else
	  pval = PVAL(var, which);

	/*
	 * set description to NULL to eliminate preceding
	 * blank and comment line.
	 */
	if(prc->type == Loc && var->descrip && *var->descrip &&
	   (!so_puts(so, NEWLINE) || !so_puts(so, "# ") ||
	    !so_puts(so, native_nl(var->descrip)) || !so_puts(so, NEWLINE)))
	  goto io_err;

	/* variable is not set */
	/** Don't know what the global_val thing is for. SH, Mar 00 **/
	if((var->is_list && (!lval || (!lval[0] && !var->global_val.l))) ||
	   (!var->is_list && !pval)){
	    /* leave null variables out of remote pinerc */
	    if(prc->type == Loc &&
	       (!so_puts(so, var->name) || !so_puts(so, "=") ||
	        !so_puts(so, NEWLINE)))
	      goto io_err;
	}
	/* var is set to empty string */
	else if((var->is_list && (!lval[0] || !lval[0][0]))
		|| (!var->is_list && pval[0] == '\0')){
	    if(!so_puts(so, var->name) || !so_puts(so, "=") ||
	       !so_puts(so, quotes) || !so_puts(so, NEWLINE))
	      goto io_err;
	}
	else if(var->is_list){
	    int i = 0;

	    for(i = 0; lval[i] ; i++){
		snprintf(tmp_20k_buf, 10000, "%s%s%s%s%s",
			(i) ? "\t" : var->name,
			(i) ? "" : "=",
			lval[i],
			lval[i+1] ? "," : "", NEWLINE);
		tmp_20k_buf[10000-1] = '\0';
		if(!so_puts(so, bc ? backcompat_convert_from_utf8(tmp_20k_buf+10000, SIZEOF_20KBUF-10000, tmp_20k_buf) : tmp_20k_buf))
		  goto io_err;
	    }
	}
	else{
	    char *pconverted;

	    pconverted = bc ? backcompat_convert_from_utf8(tmp_20k_buf, SIZEOF_20KBUF, pval) : pval;

	    if(!so_puts(so, var->name) || !so_puts(so, "=") ||
	       !so_puts(so, pconverted) || !so_puts(so, NEWLINE))
	      goto io_err;
	}
    }

    if(!(rd && rd->flags & NO_FILE)){
	if(so_give(&so))
	  goto io_err;

	file_attrib_copy(tmp, filename);
	if(rename_file(tmp, filename) < 0)
	  goto io_err;
    }
    
    if(prc->type != Loc){
	int   e, we_cancel;
	char datebuf[200];

	datebuf[0] = '\0';

	if(!(flags & WRP_NOUSER))
	  we_cancel = busy_cue(_("Copying to remote config"), NULL, 1);

	if((e = rd_update_remote(rd, datebuf)) != 0){
	    dprint((1,
		   "write_pinerc: error copying from %s to %s\n",
		   rd->lf ? rd->lf : "<memory>", rd->rn ? rd->rn : "?"));
	    if(!(flags & WRP_NOUSER)){
		q_status_message2(SM_ORDER | SM_DING, 3, 5,
				_("Error copying to %.200s: %.200s"),
				rd->rn, error_description(errno));
		
		q_status_message(SM_ORDER | SM_DING, 5, 5,
       _("Copy of config to remote folder failed, changes NOT saved remotely"));
	    }
	}
	else{
	    rd_update_metadata(rd, datebuf);
	    rd->read_status = 'W';
	    rd_trim_remdata(&rd);
	    rd_close_remote(rd);
	}

	if(we_cancel)
	  cancel_busy_cue(-1);
    }

    prc->outstanding_pinerc_changes = 0;

    if(prc->type == Loc){
	prc->pinerc_written = name_file_mtime(filename);
	dprint((2, "wrote pinerc: %s: time_pinerc_written = %ld\n",
		   pinrc ? pinrc : "?", (long) prc->pinerc_written));
    }
    else{
	dprint((2, "wrote pinerc: %s\n", pinrc ? pinrc : "?"));
    }

    if(tmp){
	our_unlink(tmp);
	fs_give((void **)&tmp);
    }

    return(0);

  io_err:
    if(!(flags & WRP_NOUSER))
      q_status_message2(SM_ORDER | SM_DING, 3, 5,
		        _("Error saving configuration in \"%.200s\": %.200s"),
		        pinrc, error_description(errno));

    dprint((1, "Error writing %s : %s\n", pinrc ? pinrc : "?",
	       error_description(errno)));
    if(rd)
      rd->flags &= ~DO_REMTRIM;
    if(tmp){
	our_unlink(tmp);
	fs_give((void **)&tmp);
    }

    return(-1);
}


/*
 * The srcstr is UTF-8. In order to help the user with
 * running this pine and an old pre-alpine pine on the same config
 * file we attempt to convert the values of the config variables
 * to the user's character set before writing.
 */
char *
backcompat_convert_from_utf8(char *buf, size_t buflen, char *srcstr)
{
    char *converted = NULL;
    char *p;
    int its_ascii = 1;


    for(p = srcstr; *p && its_ascii; p++)
      if(*p & 0x80)
	its_ascii = 0;

    /* if it is ascii, go with that */
    if(its_ascii)
      converted = srcstr;
    else{
	char *trythischarset = NULL;

	/*
	 * If it is possible to translate the UTF-8
	 * string into the user's character set then
	 * do that. For backwards compatibility with
	 * old pines.
	 */
	if(ps_global->keyboard_charmap && ps_global->keyboard_charmap[0])
	  trythischarset = ps_global->keyboard_charmap;
	else if(ps_global->display_charmap && ps_global->display_charmap[0])
	  trythischarset = ps_global->display_charmap;

	if(trythischarset){
	    SIZEDTEXT src, dst;

	    src.data = (unsigned char *) srcstr;
	    src.size = strlen(srcstr);
	    memset(&dst, 0, sizeof(dst));
	    if(utf8_cstext(&src, trythischarset, &dst, 0)){
		if(dst.data){
		    strncpy(buf, (char *) dst.data, buflen);
		    buf[buflen-1] = '\0';
		    fs_give((void **) &dst.data);
		    converted = buf;
		}
	    }
	}

	if(!converted)
	  converted = srcstr;
    }

    return(converted);
}


/*
 * Given a unix-style source string which may contain LFs,
 * convert those to CRLFs if appropriate.
 *
 * Returns a pointer to the converted string. This will be a string
 * stored in tmp_20k_buf.
 *
 * This is just used for the variable descriptions in the pinerc file. It
 * could certainly be fancier. It simply converts all \n to NEWLINE.
 */
char *
native_nl(char *src)
{ 
    char *q, *p;

    tmp_20k_buf[0] = '\0';

    if(src){
	for(q = (char *)tmp_20k_buf; *src; src++){
	    if(*src == '\n'){
		for(p = NEWLINE; *p; p++)
		  *q++ = *p;
	    }
	    else
	      *q++ = *src;
	}

	*q = '\0';
    }

    return((char *)tmp_20k_buf);
}


void
quit_to_edit_msg(PINERC_S *prc)
{
    /* TRANSLATORS: The %s is either "Postload " or nothing. A Postload config file
       is a type of config file. */
    q_status_message1(SM_ORDER, 3, 4, _("Must quit Alpine to change %sconfig file."),
		      (prc == ps_global->post_prc) ? "Postload " : "");
}


/*------------------------------------------------------------
  Return TRUE if the given string was a feature name present in the
  pinerc as it was when pine was started...
  ----*/
int
var_in_pinerc(char *s)
{
    PINERC_LINE *pline;

    for(pline = ps_global->prc ? ps_global->prc->pinerc_lines : NULL;
	pline && (pline->var || pline->line); pline++)
      if(pline->var && pline->var->name && !strucmp(s, pline->var->name))
	return(1);

    for(pline = ps_global->post_prc ? ps_global->post_prc->pinerc_lines : NULL;
	pline && (pline->var || pline->line); pline++)
      if(pline->var && pline->var->name && !strucmp(s, pline->var->name))
	return(1);

    return(0);
}


/*------------------------------------------------------------
  Free resources associated with pinerc_lines data
 ----*/
void
free_pinerc_lines(PINERC_LINE **pinerc_lines)
{
    PINERC_LINE *pline;

    if(pinerc_lines && *pinerc_lines){
	for(pline = *pinerc_lines; pline->var || pline->line; pline++)
	  if(pline->line)
	    fs_give((void **)&pline->line);

	fs_give((void **)pinerc_lines);
    }
}


/*------------------------------------------------------------
    Dump out a global pine.conf on the standard output with fresh
    comments.  Preserves variables currently set in SYSTEM_PINERC, if any.
  ----*/
void
dump_global_conf(void)
{
     FILE            *f;
     struct variable *var;
     PINERC_S        *prc;

     prc = new_pinerc_s(SYSTEM_PINERC);
     read_pinerc(prc, variables, ParseGlobal);
     if(prc)
       free_pinerc_s(&prc);

     f = stdout;
     if(f == NULL) 
       goto io_err;

     fprintf(f, "#      %s -- system wide pine configuration\n#\n",
	     SYSTEM_PINERC);
     fprintf(f, "# Values here affect all pine users unless they've overridden the values\n");
     fprintf(f, "# in their .pinerc files.  A copy of this file with current comments may\n");
     fprintf(f, "# be obtained by running \"pine -conf\". It will be printed to standard output.\n#\n");
     fprintf(f,"# For a variable to be unset its value must be null/blank.  This is not the\n");
     fprintf(f,"# same as the value of \"empty string\", which can be used to effectively\n");
     fprintf(f,"# \"unset\" a variable that has a default or previously assigned value.\n");
     fprintf(f,"# To set a variable to the empty string its value should be \"\".\n");
     fprintf(f,"# Switch variables are set to either \"yes\" or \"no\", and default to \"no\".\n");
     fprintf(f,"# Except for feature-list items, which are additive, values set in the\n");
     fprintf(f,"# .pinerc file replace those in pine.conf, and those in pine.conf.fixed\n");
     fprintf(f,"# over-ride all others.  Features can be over-ridden in .pinerc or\n");
     fprintf(f,"# pine.conf.fixed by pre-pending the feature name with \"no-\".\n#\n");
     fprintf(f,"# (These comments are automatically inserted.)\n");

     for(var = variables; var->name != NULL; var++){
         if(!var->is_global || !var->is_used || var->is_obsolete)
           continue;

         if(var->descrip && *var->descrip){
           if(fprintf(f, "\n# %s\n", var->descrip) == EOF)
             goto io_err;
	 }

	 if(var->is_list){
	     if(var->global_val.l == NULL){
		 if(fprintf(f, "%s=\n", var->name) == EOF)
		   goto io_err;
	     }else{
		 int i;

		 for(i=0; var->global_val.l[i]; i++)
		   if(fprintf(f, "%s%s%s%s\n", (i) ? "\t" : var->name,
			      (i) ? "" : "=", var->global_val.l[i],
			      var->global_val.l[i+1] ? ",":"") == EOF)
		     goto io_err;
	     }
	 }else{
	     if(var->global_val.p == NULL){
		 if(fprintf(f, "%s=\n", var->name) == EOF)
		   goto io_err;
	     }else if(strlen(var->global_val.p) == 0){
		 if(fprintf(f, "%s=\"\"\n", var->name) == EOF)
               goto io_err;
	     }else{
		 if(fprintf(f,"%s=%s\n",var->name,var->global_val.p) == EOF)
		   goto io_err;
	     }
	 }
     }
     exit(0);


   io_err:
     fprintf(stderr, "Error writing config to stdout: %s\n",
             error_description(errno));
     exit(-1);
}


/*------------------------------------------------------------
    Dump out a pinerc to filename with fresh
    comments.  Preserves variables currently set in pinerc, if any.
  ----*/
void
dump_new_pinerc(char *filename)
{
    FILE            *f;
    struct variable *var;
    char             buf[MAXPATH], *p;
    PINERC_S        *prc;


    p = ps_global->pinerc;

#if defined(DOS) || defined(OS2)
    if(!ps_global->pinerc){
	char *p;

	if(p = getenv("PINERC")){
	    ps_global->pinerc = cpystr(p);
	}else{
	    char buf2[MAXPATH];
	    build_path(buf2, ps_global->home_dir, DF_PINEDIR, sizeof(buf2));
	    build_path(buf, buf2, SYSTEM_PINERC, sizeof(buf));
	}

	p = buf;
    }
#else	/* !DOS */
    if(!ps_global->pinerc){
	build_path(buf, ps_global->home_dir, ".pinerc", sizeof(buf));
	p = buf;
    }
#endif	/* !DOS */

    prc = new_pinerc_s(p);
    read_pinerc(prc, variables, ParsePers);
    if(prc)
      free_pinerc_s(&prc);

    f = NULL;;
    if(filename[0] == '\0'){
	fprintf(stderr, "Missing argument to \"-pinerc\".\n");
    }else if(!strcmp(filename, "-")){
	f = stdout;
    }else{
	f = our_fopen(filename, "wb");
    }

    if(f == NULL) 
	goto io_err;

    if(fprintf(f, "%s", cf_text_comment) == EOF)
	goto io_err;

    for(var = variables; var->name != NULL; var++){
	dprint((7,"write_pinerc: %s = %s\n",
	       var->name ? var->name : "?",
	       var->main_user_val.p ? var->main_user_val.p : "<not set>"));
        if(!var->is_user || !var->is_used || var->is_obsolete)
	    continue;

	/*
	 * set description to NULL to eliminate preceding
	 * blank and comment line.
	 */
         if(var->descrip && *var->descrip){
           if(fprintf(f, "\n# %s\n", var->descrip) == EOF)
             goto io_err;
	 }

	if(var->is_list){
	    if(var->main_user_val.l == NULL){
		if(fprintf(f, "%s=\n", var->name) == EOF)
		    goto io_err;
	    }else{
		int i;

		for(i=0; var->main_user_val.l[i]; i++)
		    if(fprintf(f, "%s%s%s%s\n", (i) ? "\t" : var->name,
			      (i) ? "" : "=", var->main_user_val.l[i],
			      var->main_user_val.l[i+1] ? ",":"") == EOF)
		    goto io_err;
	    }
	}else{
	    if(var->main_user_val.p == NULL){
		if(fprintf(f, "%s=\n", var->name) == EOF)
		    goto io_err;
	    }else if(strlen(var->main_user_val.p) == 0){
		if(fprintf(f, "%s=\"\"\n", var->name) == EOF)
		    goto io_err;
	    }else{
		if(fprintf(f,"%s=%s\n",var->name,var->main_user_val.p) == EOF)
		    goto io_err;
	    }
	}
    }
    exit(0);


io_err:
    snprintf(buf, sizeof(buf), "Error writing config to %s: %s\n",
	    filename, error_description(errno));
    exceptional_exit(buf, -1);
}


/*----------------------------------------------------------------------
      Set a user variable and save the .pinerc
   
  Args:  var -- The index of the variable to set from conftype.h (V_....)
         value -- The string to set the value to

 Result: -1 is returned on failure and 0 is returned on success

 The vars data structure is updated and the pinerc saved.
 ----*/ 
int
set_variable(int var, char *value, int expand, int commit, EditWhich which)
{
    struct variable *v;
    char           **apval;
    PINERC_S        *prc;

    v = &ps_global->vars[var];

    if(!v->is_user) 
      panic1("Trying to set non-user variable %s", v->name);
    
    /* Override value of which, at most one of these should be set */
    if(v->is_onlymain)
      which = Main;
    else if(v->is_outermost)
      which = ps_global->ew_for_except_vars;

    apval = APVAL(v, which);

    if(!apval)
      return(-1);

    if(*apval)
      fs_give((void **)apval);

    *apval = value ? cpystr(value) : NULL;
    set_current_val(v, expand, FALSE);

    switch(which){
      case Main:
	prc = ps_global->prc;
	break;
      case Post:
	prc = ps_global->post_prc;
	break;
      default:
	break;
    }

    if(prc)
      prc->outstanding_pinerc_changes = 1;

    return(commit ? write_pinerc(ps_global, which, WRP_NONE) : 0);
}


/*----------------------------------------------------------------------
      Set a user variable list and save the .pinerc
   
  Args:  var -- The index of the variable to set from conftype.h (V_....)
         lvalue -- The list to set the value to

 Result: -1 is returned on failure and 0 is returned on success

 The vars data structure is updated and if write_it, the pinerc is saved.
 ----*/ 
int
set_variable_list(int var, char **lvalue, int write_it, EditWhich which)
{
    char          ***alval;
    int              i;
    struct variable *v = &ps_global->vars[var];
    PINERC_S        *prc;

    if(!v->is_user || !v->is_list)
      panic1("BOTCH: Trying to set non-user or non-list variable %s", v->name);

    /* Override value of which, at most one of these should be set */
    if(v->is_onlymain)
      which = Main;
    else if(v->is_outermost)
      which = ps_global->ew_for_except_vars;

    alval = ALVAL(v, which);
    if(!alval)
      return(-1);

    if(*alval)
      free_list_array(alval);

    if(lvalue){
	for(i = 0; lvalue[i] ; i++)	/* count elements */
	  ;

	*alval = (char **) fs_get((i+1) * sizeof(char *));

	for(i = 0; lvalue[i] ; i++)
	  (*alval)[i] = cpystr(lvalue[i]);

	(*alval)[i]         = NULL;
    }

    set_current_val(v, TRUE, FALSE);

    switch(which){
      case Main:
	prc = ps_global->prc;
	break;
      case Post:
	prc = ps_global->post_prc;
	break;
      default:
	break;
    }

    if(prc)
      prc->outstanding_pinerc_changes = 1;

    return(write_it ? write_pinerc(ps_global, which, WRP_NONE) : 0);
}
           

void
set_current_color_vals(struct pine *ps)
{
    struct variable *vars = ps->vars;
    int later_color_is_set = 0;

    set_current_val(&vars[V_NORM_FORE_COLOR], TRUE, TRUE);
    set_current_val(&vars[V_NORM_BACK_COLOR], TRUE, TRUE);
    pico_nfcolor(VAR_NORM_FORE_COLOR);
    pico_nbcolor(VAR_NORM_BACK_COLOR);

    set_current_val(&vars[V_REV_FORE_COLOR], TRUE, TRUE);
    set_current_val(&vars[V_REV_BACK_COLOR], TRUE, TRUE);
    pico_rfcolor(VAR_REV_FORE_COLOR);
    pico_rbcolor(VAR_REV_BACK_COLOR);

    set_color_val(&vars[V_TITLE_FORE_COLOR], 1);
    set_color_val(&vars[V_TITLECLOSED_FORE_COLOR], 0);
    set_color_val(&vars[V_STATUS_FORE_COLOR], 1);
    set_color_val(&vars[V_KEYLABEL_FORE_COLOR], 1);
    set_color_val(&vars[V_KEYNAME_FORE_COLOR], 1);
    set_color_val(&vars[V_SLCTBL_FORE_COLOR], 1);
    set_color_val(&vars[V_METAMSG_FORE_COLOR], 1);
    set_color_val(&vars[V_PROMPT_FORE_COLOR], 1);
    set_color_val(&vars[V_HEADER_GENERAL_FORE_COLOR], 1);
    set_color_val(&vars[V_IND_PLUS_FORE_COLOR], 0);
    set_color_val(&vars[V_IND_IMP_FORE_COLOR], 0);
    set_color_val(&vars[V_IND_DEL_FORE_COLOR], 0);
    set_color_val(&vars[V_IND_HIPRI_FORE_COLOR], 0);
    set_color_val(&vars[V_IND_LOPRI_FORE_COLOR], 0);
    set_color_val(&vars[V_IND_ANS_FORE_COLOR], 0);
    set_color_val(&vars[V_IND_NEW_FORE_COLOR], 0);
    set_color_val(&vars[V_IND_REC_FORE_COLOR], 0);
    set_color_val(&vars[V_IND_FWD_FORE_COLOR], 0);
    set_color_val(&vars[V_IND_UNS_FORE_COLOR], 0);
    set_color_val(&vars[V_IND_ARR_FORE_COLOR], 0);
    set_color_val(&vars[V_IND_SUBJ_FORE_COLOR], 0);
    set_color_val(&vars[V_IND_FROM_FORE_COLOR], 0);
    set_color_val(&vars[V_IND_OP_FORE_COLOR], 0);
    set_color_val(&vars[V_INCUNSEEN_FORE_COLOR], 0);
    set_color_val(&vars[V_SIGNATURE_FORE_COLOR], 0);

    set_current_val(&ps->vars[V_VIEW_HDR_COLORS], TRUE, TRUE);
    set_current_val(&ps->vars[V_KW_COLORS], TRUE, TRUE);
    set_custom_spec_colors(ps);

    /*
     * Set up the quoting colors. If a later color is set but not an earlier
     * color we set the earlier color to Normal to make it easier when
     * we go to use the colors. However, if the only quote colors set are
     * Normal that is the same as no settings, so delete them.
     */
    set_color_val(&vars[V_QUOTE1_FORE_COLOR], 0);
    set_color_val(&vars[V_QUOTE2_FORE_COLOR], 0);
    set_color_val(&vars[V_QUOTE3_FORE_COLOR], 0);

    if((!(VAR_QUOTE3_FORE_COLOR && VAR_QUOTE3_BACK_COLOR) ||
	(!strucmp(VAR_QUOTE3_FORE_COLOR, VAR_NORM_FORE_COLOR) &&
	 !strucmp(VAR_QUOTE3_BACK_COLOR, VAR_NORM_BACK_COLOR)))   &&
       (!(VAR_QUOTE2_FORE_COLOR && VAR_QUOTE2_BACK_COLOR) ||
	(!strucmp(VAR_QUOTE2_FORE_COLOR, VAR_NORM_FORE_COLOR) &&
	 !strucmp(VAR_QUOTE2_BACK_COLOR, VAR_NORM_BACK_COLOR)))   &&
       (!(VAR_QUOTE1_FORE_COLOR && VAR_QUOTE1_BACK_COLOR) ||
	(!strucmp(VAR_QUOTE1_FORE_COLOR, VAR_NORM_FORE_COLOR) &&
	 !strucmp(VAR_QUOTE1_BACK_COLOR, VAR_NORM_BACK_COLOR)))){
	/*
	 * They are all either Normal or not set. Delete them all.
	 */
	if(VAR_QUOTE3_FORE_COLOR)
	  fs_give((void **)&VAR_QUOTE3_FORE_COLOR);
	if(VAR_QUOTE3_BACK_COLOR)
	  fs_give((void **)&VAR_QUOTE3_BACK_COLOR);
	if(VAR_QUOTE2_FORE_COLOR)
	  fs_give((void **)&VAR_QUOTE2_FORE_COLOR);
	if(VAR_QUOTE2_BACK_COLOR)
	  fs_give((void **)&VAR_QUOTE2_BACK_COLOR);
	if(VAR_QUOTE1_FORE_COLOR)
	  fs_give((void **)&VAR_QUOTE1_FORE_COLOR);
	if(VAR_QUOTE1_BACK_COLOR)
	  fs_give((void **)&VAR_QUOTE1_BACK_COLOR);
    }
    else{			/* something is non-Normal */
	if(VAR_QUOTE3_FORE_COLOR && VAR_QUOTE3_BACK_COLOR)
	  later_color_is_set++;

	/* if 3 is set but not 2, set 2 to Normal */
	if(VAR_QUOTE2_FORE_COLOR && VAR_QUOTE2_BACK_COLOR)
	  later_color_is_set++;
	else if(later_color_is_set)
	  set_color_val(&vars[V_QUOTE2_FORE_COLOR], 1);

	/* if 3 or 2 is set but not 1, set 1 to Normal */
	if(VAR_QUOTE1_FORE_COLOR && VAR_QUOTE1_BACK_COLOR)
	  later_color_is_set++;
	else if(later_color_is_set)
	  set_color_val(&vars[V_QUOTE1_FORE_COLOR], 1);
    }

#ifdef	_WINDOWS
    if(ps->pre441){
	int conv_main = 0, conv_post = 0;

	ps->pre441 = 0;
	if(ps->prc && !unix_color_style_in_pinerc(ps->prc)){
	    conv_main = convert_pc_gray_names(ps, ps->prc, Main);
	    if(conv_main)
	      ps->prc->outstanding_pinerc_changes = 1;
	}
	

	if(ps->post_prc && !unix_color_style_in_pinerc(ps->post_prc)){
	    conv_post = convert_pc_gray_names(ps, ps->post_prc, Post);
	    if(conv_post)
	      ps->post_prc->outstanding_pinerc_changes = 1;
	}
	
	if(conv_main || conv_post){
	    if(conv_main)
	      write_pinerc(ps, Main, WRP_NONE);

	    if(conv_post)
	      write_pinerc(ps, Post, WRP_NONE);

	    set_current_color_vals(ps);
	}
    }
#endif	/* _WINDOWS */

    pico_set_normal_color();
}


/*
 * Set current_val for the foreground and background color vars, which
 * are assumed to be in order. If a set_current_val on them doesn't
 * produce current_vals, then use the colors from defvar to set those
 * current_vals.
 */
void
set_color_val(struct variable *v, int use_default)
{
    set_current_val(v, TRUE, TRUE);
    set_current_val(v+1, TRUE, TRUE);

    if(!(v->current_val.p && v->current_val.p[0] &&
         (v+1)->current_val.p && (v+1)->current_val.p[0])){
	struct variable *defvar;

	if(v->current_val.p)
	  fs_give((void **)&v->current_val.p);
	if((v+1)->current_val.p)
	  fs_give((void **)&(v+1)->current_val.p);

	if(!use_default)
	  return;

	if(var_defaults_to_rev(v))
	  defvar = &ps_global->vars[V_REV_FORE_COLOR];
	else
	  defvar = &ps_global->vars[V_NORM_FORE_COLOR];

	/* use default vars values instead */
	if(defvar && defvar->current_val.p && defvar->current_val.p[0] &&
           (defvar+1)->current_val.p && (defvar+1)->current_val.p[0]){
	    v->current_val.p = cpystr(defvar->current_val.p);
	    (v+1)->current_val.p = cpystr((defvar+1)->current_val.p);
	}
    }
}


int
var_defaults_to_rev(struct variable *v)
{
    return(v == &ps_global->vars[V_REV_FORE_COLOR] ||
	   v == &ps_global->vars[V_TITLE_FORE_COLOR] ||
	   v == &ps_global->vars[V_STATUS_FORE_COLOR] ||
	   v == &ps_global->vars[V_KEYNAME_FORE_COLOR] ||
	   v == &ps_global->vars[V_PROMPT_FORE_COLOR]);
}



/*
 * Each item in the list looks like:
 *
 *  /HDR=<header>/FG=<foreground color>/BG=<background color>
 *
 * We separate the three pieces into an array of structures to make
 * it easier to deal with later.
 */
void
set_custom_spec_colors(struct pine *ps)
{
    if(ps->hdr_colors)
      free_spec_colors(&ps->hdr_colors);

    ps->hdr_colors = spec_colors_from_varlist(ps->VAR_VIEW_HDR_COLORS, 1);

    /* fit keyword colors into the same structures for code re-use */
    if(ps->kw_colors)
      free_spec_colors(&ps->kw_colors);

    ps->kw_colors = spec_colors_from_varlist(ps->VAR_KW_COLORS, 1);
}


/*
 * Input is one item from config variable.
 *
 * Return value must be freed by caller. The return is a single SPEC_COLOR_S,
 * not a list.
 */
SPEC_COLOR_S *
spec_color_from_var(char *t, int already_expanded)
{
    char        *p, *spec, *fg, *bg;
    PATTERN_S   *val;
    SPEC_COLOR_S *new_hcolor = NULL;

    if(t && t[0] && !strcmp(t, INHERIT)){
	new_hcolor = (SPEC_COLOR_S *)fs_get(sizeof(*new_hcolor));
	memset((void *)new_hcolor, 0, sizeof(*new_hcolor));
	new_hcolor->inherit = 1;
    }
    else if(t && t[0]){
	char tbuf[10000];

	if(!already_expanded){
	    tbuf[0] = '\0';
	    if(expand_variables(tbuf, sizeof(tbuf), t, 0))
	      t = tbuf;
	}

	spec = fg = bg = NULL;
	val = NULL;
	if((p = srchstr(t, "/HDR=")) != NULL)
	  spec = remove_backslash_escapes(p+5);
	if((p = srchstr(t, "/FG=")) != NULL)
	  fg = remove_backslash_escapes(p+4);
	if((p = srchstr(t, "/BG=")) != NULL)
	  bg = remove_backslash_escapes(p+4);
	val = parse_pattern("VAL", t, 0);
	
	if(spec && *spec){
	    /* remove colons */
	    if((p = strindex(spec, ':')) != NULL)
	      *p = '\0';

	    new_hcolor = (SPEC_COLOR_S *)fs_get(sizeof(*new_hcolor));
	    memset((void *)new_hcolor, 0, sizeof(*new_hcolor));
	    new_hcolor->spec = spec;
	    new_hcolor->fg   = fg;
	    new_hcolor->bg   = bg;
	    new_hcolor->val  = val;
	}
	else{
	    if(spec)
	      fs_give((void **)&spec);
	    if(fg)
	      fs_give((void **)&fg);
	    if(bg)
	      fs_give((void **)&bg);
	    if(val)
	      free_pattern(&val);
	}
    }

    return(new_hcolor);
}


/*
 * Input is a list from config file.
 *
 * Return value may be a list of SPEC_COLOR_S and must be freed by caller.
 */
SPEC_COLOR_S *
spec_colors_from_varlist(char **varlist, int already_expanded)
{
    char        **s, *t;
    SPEC_COLOR_S *new_hc = NULL;
    SPEC_COLOR_S *new_hcolor, **nexthc;

    nexthc = &new_hc;
    if(varlist){
	for(s = varlist; (t = *s) != NULL; s++){
	    if(t[0]){
		new_hcolor = spec_color_from_var(t, already_expanded);
		if(new_hcolor){
		    *nexthc = new_hcolor;
		    nexthc = &new_hcolor->next;
		}
	    }
	}
    }

    return(new_hc);
}


/*
 * Returns allocated charstar suitable for config var for a single
 * SPEC_COLOR_S.
 */
char *
var_from_spec_color(SPEC_COLOR_S *hc)
{
    char *ret_val = NULL;
    char *p, *spec = NULL, *fg = NULL, *bg = NULL, *val = NULL;
    size_t len;

    if(hc && hc->inherit)
      ret_val = cpystr(INHERIT);
    else if(hc){
	if(hc->spec)
	  spec = add_viewerhdr_escapes(hc->spec);
	if(hc->fg)
	  fg = add_viewerhdr_escapes(hc->fg);
	if(hc->bg)
	  bg = add_viewerhdr_escapes(hc->bg);
	if(hc->val){
	    p = pattern_to_string(hc->val);
	    if(p){
		val = add_viewerhdr_escapes(p);
		fs_give((void **)&p);
	    }
	}

	len = strlen("/HDR=/FG=/BG=") + strlen(spec ? spec : "") +
	      strlen(fg ? fg : "") + strlen(bg ? bg : "") +
	      strlen(val ? "/VAL=" : "") + strlen(val ? val : "");
	ret_val = (char *) fs_get(len + 1);
	snprintf(ret_val, len+1, "/HDR=%s/FG=%s/BG=%s%s%s",
		spec ? spec : "", fg ? fg : "", bg ? bg : "",
		val ? "/VAL=" : "", val ? val : "");

	if(spec)
	  fs_give((void **)&spec);
	if(fg)
	  fs_give((void **)&fg);
	if(bg)
	  fs_give((void **)&bg);
	if(val)
	  fs_give((void **)&val);
    }

    return(ret_val);
}


/*
 * Returns allocated charstar suitable for config var for a single
 * SPEC_COLOR_S.
 */
char **
varlist_from_spec_colors(SPEC_COLOR_S *hcolors)
{
    SPEC_COLOR_S *hc;
    char       **ret_val = NULL;
    int          i;

    /* count how many */
    for(hc = hcolors, i = 0; hc; hc = hc->next, i++)
      ;
    
    ret_val = (char **)fs_get((i+1) * sizeof(*ret_val));
    memset((void *)ret_val, 0, (i+1) * sizeof(*ret_val));
    for(hc = hcolors, i = 0; hc; hc = hc->next, i++)
      ret_val[i] = var_from_spec_color(hc);
    
    return(ret_val);
}


void
update_posting_charset(struct pine *ps, int revert)
{
#ifndef	_WINDOWS
    if(F_ON(F_USE_SYSTEM_TRANS, ps)){
	if(!revert)
	  q_status_message(SM_ORDER, 5, 5, _("This change has no effect because feature Use-System-Translation is on"));
    }
    else{
#endif	/* ! _WINDOWS */
	if(ps->posting_charmap)
	  fs_give((void **) &ps->posting_charmap);

	if(ps->VAR_POST_CHAR_SET){
	    ps->posting_charmap = cpystr(ps->VAR_POST_CHAR_SET);
	    if(!posting_charset_is_supported(ps->posting_charmap)){
		snprintf(tmp_20k_buf, SIZEOF_20KBUF,
			 _("Posting-Character set \"%s\" is unsupported, using UTF-8"),
			 ps->posting_charmap);
		q_status_message(SM_ORDER | SM_DING, 3, 5, tmp_20k_buf);
		fs_give((void **) &ps->posting_charmap);
		ps->posting_charmap = cpystr("UTF-8");
	    }
	}
	else
	  ps->posting_charmap = cpystr("UTF-8");
#ifndef	_WINDOWS
    }
#endif	/* ! _WINDOWS */
}


#define FIXED_COMMENT		_("(fixed)")
#define DEFAULT_COMMENT		_("(default)")
#define OVERRIDE_COMMENT	_("(overridden)")

int
feature_gets_an_x(struct pine *ps, struct variable *var, FEATURE_S *feature,
		  char **comment, EditWhich ew)
{
    char           **lval, **lvalexc, **lvalnorm;
    char            *def = DEFAULT_COMMENT;
    int              j, done = 0;
    int              feature_fixed_on = 0, feature_fixed_off = 0;

    if(comment)
      *comment = NULL;

    lval  = LVAL(var, ew);
    lvalexc  = LVAL(var, ps->ew_for_except_vars);
    lvalnorm = LVAL(var, Main);
  
    /* feature value is administratively fixed */
    if((j = feature_in_list(var->fixed_val.l, feature->name)) != 0){
	if(j == 1)
	  feature_fixed_on++;
	else if(j == -1)
	  feature_fixed_off++;

	done++;
	if(comment)
	  *comment = FIXED_COMMENT;
    }

    /*
     * We have an exceptions config setting which overrides anything
     * we do here, in the normal config.
     */
    if(!done &&
       ps->ew_for_except_vars != Main && ew == Main &&
       feature_in_list(lvalexc, feature->name)){
	done++;
	if(comment)
	  *comment = OVERRIDE_COMMENT;
    }

    /*
     * Feature is set On in default but not set here.
     */
    if(!done &&
       !feature_in_list(lval, feature->name) &&
       ((feature_in_list(var->global_val.l, feature->name) == 1) ||
        ((ps->ew_for_except_vars != Main &&
          ew == ps->ew_for_except_vars &&
          feature_in_list(lvalnorm, feature->name) == 1)))){
	done = 17;
	if(comment)
	  *comment = def;
    }

    if(!done &&
       feature->defval &&
       !feature_in_list(lval, feature->name) &&
       !feature_in_list(var->global_val.l, feature->name) &&
       (ps->ew_for_except_vars == Main ||
        ew != ps->ew_for_except_vars ||
        !feature_in_list(lvalnorm, feature->name))){
	done = 17;
	if(comment)
	  *comment = def;
    }

    return(feature_fixed_on ||
	   (!feature_fixed_off &&
	    (done == 17 ||
	     test_feature(lval, feature->name,
			  test_old_growth_bits(ps, feature->id)))));
}


int
longest_feature_comment(struct pine *ps, EditWhich ew)
{
    int lc = 0;

    lc = MAX(lc, utf8_width(FIXED_COMMENT));
    lc = MAX(lc, utf8_width(DEFAULT_COMMENT));
    if(ps->ew_for_except_vars != Main && ew == Main)
      lc = MAX(lc, utf8_width(OVERRIDE_COMMENT));

    return(lc);
}


void
toggle_feature(struct pine *ps, struct variable *var, FEATURE_S *f,
	       int just_flip_value, EditWhich ew)
{
    char      **vp, *p, **lval, ***alval;
    int		og, on_before, was_set;
    char       *err;
    long	l;

    og = test_old_growth_bits(ps, f->id);

    /*
     * if this feature is in the fixed set, or old-growth is in the fixed
     * set and this feature is in the old-growth set, don't alter it...
     */
    for(vp = var->fixed_val.l; vp && *vp; vp++){
	p = (struncmp(*vp, "no-", 3)) ? *vp : *vp + 3;
	if(!strucmp(p, f->name) || (og && !strucmp(p, "old-growth"))){
	    q_status_message(SM_ORDER, 3, 3,
	    /* TRANSLATORS: In the configuration screen, telling the user we
	       can't change this option because the system administrator
	       prohibits it. */
			     _("Can't change value fixed by sys-admin."));
	    return;
	}
    }

    on_before = F_ON(f->id, ps);

    lval  = LVAL(var, ew);
    alval = ALVAL(var, ew);
    if(just_flip_value)
      was_set = test_feature(lval, f->name, og);
    else
      was_set = feature_gets_an_x(ps, var, f, NULL, ew);

    if(alval)
      set_feature(alval, f->name, !was_set);

    set_feature_list_current_val(var);
    process_feature_list(ps, var->current_val.l, 0, 0, 0);
    
    /*
     * Handle any features that need special attention here...
     */
    if(on_before != F_ON(f->id, ps))
     switch(f->id){
      case F_QUOTE_ALL_FROMS :
	mail_parameters(NULL,SET_FROMWIDGET,F_ON(f->id,ps) ? VOIDT : NIL);
	break;

      case F_FAKE_NEW_IN_NEWS :
        if(IS_NEWS(ps->mail_stream))
	  q_status_message(SM_ORDER | SM_DING, 3, 4,
	       "news-approximates-new-status won't affect current newsgroup until next open");

	break;

      case F_COLOR_LINE_IMPORTANT :
      case F_DATES_TO_LOCAL :
	clear_index_cache(ps->mail_stream, 0);
	break;

      case F_DISABLE_INDEX_LOCALE_DATES :
	reset_index_format();
	clear_index_cache(ps->mail_stream, 0);
	break;

      case F_MARK_FOR_CC :
	clear_index_cache(ps->mail_stream, 0);
	if(THREADING() && sp_viewing_a_thread(ps->mail_stream))
	  unview_thread(ps, ps->mail_stream, ps->msgmap);

	break;

      case F_HIDE_NNTP_PATH :
	mail_parameters(NULL, SET_NNTPHIDEPATH,
			F_ON(f->id, ps) ? VOIDT : NIL);
	break;

      case F_MAILDROPS_PRESERVE_STATE :
	mail_parameters(NULL, SET_SNARFPRESERVE,
			F_ON(f->id, ps) ? VOIDT : NIL);
	break;

      case F_DISABLE_SHARED_NAMESPACES :
	mail_parameters(NULL, SET_DISABLEAUTOSHAREDNS,
			F_ON(f->id, ps) ? VOIDT : NIL);
	break;

      case F_QUELL_LOCK_FAILURE_MSGS :
	mail_parameters(NULL, SET_LOCKEACCESERROR,
			F_ON(f->id, ps) ? VOIDT : NIL);
	break;

      case F_MULNEWSRC_HOSTNAMES_AS_TYPED :
	l = F_ON(f->id, ps) ? 0L : 1L;
	mail_parameters(NULL, SET_NEWSRCCANONHOST, (void *) l);
	break;

      case F_QUELL_INTERNAL_MSG :
	mail_parameters(NULL, SET_USERHASNOLIFE,
			F_ON(f->id, ps) ? VOIDT : NIL);
	break;

      case F_DISABLE_SETLOCALE_COLLATE :
	set_collation(F_OFF(F_DISABLE_SETLOCALE_COLLATE, ps), 1);
	break;

#ifndef	_WINDOWS
      case F_USE_SYSTEM_TRANS :
	err = NULL;
	reset_character_set_stuff(&err);
	if(err){
	    q_status_message(SM_ORDER | SM_DING, 3, 4, err);
	    fs_give((void **) &err);
	}

	break;
#endif	/* ! _WINDOWS */

      case F_ENABLE_INCOMING_CHECKING :
	if(!on_before && F_OFF(F_ENABLE_INCOMING, ps))
	  q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders"));

	clear_incoming_valid_bits();
	break;

      case F_INCOMING_CHECKING_TOTAL :
      case F_INCOMING_CHECKING_RECENT :
	if(!on_before && F_OFF(F_ENABLE_INCOMING_CHECKING, ps))
	  q_status_message(SM_ORDER, 0, 3, _("This option has no effect without Enable-Incoming-Folders-Checking"));

	clear_incoming_valid_bits();
	break;

      case F_THREAD_SORTS_BY_ARRIVAL :
	clear_index_cache(ps->mail_stream, 0);
	refresh_sort(ps->mail_stream, sp_msgmap(ps->mail_stream), SRT_NON);
	break;

#ifdef SMIME
      case F_DONT_DO_SMIME :
	smime_deinit();
	break;

#ifdef APPLEKEYCHAIN
      case F_PUBLICCERTS_IN_KEYCHAIN :
	smime_deinit();
	break;
#endif
#endif

      default :
	break;
     }
}


/*
 * Returns 1 -- Feature is in the list and positive
 *         0 -- Feature is not in the list at all
 *        -1 -- Feature is in the list and negative (no-)
 */
int
feature_in_list(char **l, char *f)
{
    char *p;
    int   rv = 0, forced_off;

    for(; l && *l; l++){
	p = (forced_off = !struncmp(*l, "no-", 3)) ? *l + 3 : *l;
	if(!strucmp(p, f))
	  rv = forced_off ? -1 : 1;
    }

    return(rv);
}


/*
 * test_feature - runs thru a feature list, and returns:
 *                 1 if feature explicitly set and matches 'v'
 *                 0 if feature not explicitly set *or* doesn't match 'v'
 */
int
test_feature(char **l, char *f, int g)
{
    char *p;
    int   rv = 0, forced_off;

    for(; l && *l; l++){
	p = (forced_off = !struncmp(*l, "no-", 3)) ? *l + 3 : *l;
	if(!strucmp(p, f))
	  rv = !forced_off;
	else if(g && !strucmp(p, "old-growth"))
	  rv = !forced_off;
    }

    return(rv);
}


void
set_feature(char ***l, char *f, int v)
{
    char **list = l ? *l : NULL, newval[256];
    int    count = 0;

    snprintf(newval, sizeof(newval), "%s%s", v ? "" : "no-", f);
    for(; list && *list; list++, count++)
      if((**list == '\0')                       /* anything can replace an empty value */
	 || !strucmp(((!struncmp(*list, "no-", 3)) ? *list + 3 : *list), f)){
	  fs_give((void **)list);		/* replace with new value */
	  *list = cpystr(newval);
	  return;
      }

    /*
     * if we got here, we didn't find it in the list, so grow the list
     * and add it..
     */
    if(!*l)
      *l = (char **)fs_get((count + 2) * sizeof(char *));
    else
      fs_resize((void **)l, (count + 2) * sizeof(char *));

    (*l)[count]     = cpystr(newval);
    (*l)[count + 1] = NULL;
}


int
reset_character_set_stuff(char **err)
{
    int use_system = 0;
    char buf[1000];

    if(err)
      *err = NULL;

    if(ps_global->display_charmap)
      fs_give((void **) &ps_global->display_charmap);

    if(ps_global->keyboard_charmap)
      fs_give((void **) &ps_global->keyboard_charmap);

    if(ps_global->posting_charmap)
      fs_give((void **) &ps_global->posting_charmap);

#ifdef	_WINDOWS
    ps_global->display_charmap = cpystr("UTF-8");
#else	/* UNIX */
    if(ps_global->VAR_CHAR_SET)
      ps_global->display_charmap = cpystr(ps_global->VAR_CHAR_SET);
    else{
#if HAVE_LANGINFO_H && defined(CODESET)
      ps_global->display_charmap = cpystr(nl_langinfo_codeset_wrapper());
#else
      ps_global->display_charmap = cpystr("UTF-8");
#endif
    }
#endif	/* UNIX */

    if(!ps_global->display_charmap)
      ps_global->display_charmap = cpystr("US-ASCII");

#ifdef	_WINDOWS
    ps_global->keyboard_charmap = cpystr("UTF-8");
#else	/* UNIX */
    if(ps_global->VAR_KEY_CHAR_SET)
      ps_global->keyboard_charmap = cpystr(ps_global->VAR_KEY_CHAR_SET);
    else
      ps_global->keyboard_charmap = cpystr(ps_global->display_charmap);

    if(!ps_global->keyboard_charmap)
      ps_global->keyboard_charmap = cpystr("US-ASCII");

    if(F_ON(F_USE_SYSTEM_TRANS, ps_global)){
#if	PREREQ_FOR_SYS_TRANSLATION
	use_system++;
	/* This modifies its arguments */
	if(setup_for_input_output(use_system, &ps_global->display_charmap,
				  &ps_global->keyboard_charmap,
				  &ps_global->input_cs, (err && *err) ? NULL : err) == -1)
	  return -1;
#endif
    }
#endif	/* UNIX */

    if(!use_system){
	if(setup_for_input_output(use_system, &ps_global->display_charmap,
				  &ps_global->keyboard_charmap,
				  &ps_global->input_cs, (err && *err) ? NULL : err) == -1)
	  return -1;
    }

    if(!use_system && ps_global->VAR_POST_CHAR_SET){
	ps_global->posting_charmap = cpystr(ps_global->VAR_POST_CHAR_SET);
	if(!posting_charset_is_supported(ps_global->posting_charmap)){
	    if(err && !*err){
		snprintf(buf, sizeof(buf),
			 _("Posting-Character-Set \"%s\" is unsupported, using UTF-8"),
			 ps_global->posting_charmap);
		*err = cpystr(buf);
	    }

	    fs_give((void **) &ps_global->posting_charmap);
	    ps_global->posting_charmap = cpystr("UTF-8");
	}
    }
    else{
	if(use_system && ps_global->VAR_POST_CHAR_SET
	   && strucmp(ps_global->VAR_POST_CHAR_SET, "UTF-8"))
	    if(err && !*err)
	      *err = cpystr(_("Posting-Character-Set is ignored with Use-System-Translation turned on"));

	ps_global->posting_charmap = cpystr("UTF-8");
    }

    set_locale_charmap(ps_global->keyboard_charmap);

    return(0);
}


/*
 * Given a single printer string from the config file, returns pointers
 * to alloc'd strings containing the printer nickname, the command,
 * the init string, the trailer string, everything but the nickname string,
 * and everything but the command string.  All_but_cmd includes the trailing
 * space at the end (the one before the command) but all_but_nick does not
 * include the leading space (the one before the [).
 * If you pass in a pointer it is guaranteed to come back pointing to an
 * allocated string, even if it is just an empty string.  It is ok to pass
 * NULL for any of the six return strings.
 */
void
parse_printer(char *input, char **nick, char **cmd, char **init, char **trailer,
	      char **all_but_nick, char **all_but_cmd)
{
    char *p, *q, *start, *saved_options = NULL;
    int tmpsave, cnt;

    if(!input)
      input = "";

    if(nick || all_but_nick){
	if((p = srchstr(input, " [")) != NULL){
	    if(all_but_nick)
	      *all_but_nick = cpystr(p+1);

	    if(nick){
		while(p-1 > input && isspace((unsigned char)*(p-1)))
		  p--;

		tmpsave = *p;
		*p = '\0';
		*nick = cpystr(input);
		*p = tmpsave;
	    }
	}
	else{
	    if(nick)
	      *nick = cpystr("");

	    if(all_but_nick)
	      *all_but_nick = cpystr(input);
	}
    }

    if((p = srchstr(input, "] ")) != NULL){
	do{
	    ++p;
	}while(isspace((unsigned char)*p));

	tmpsave = *p;
	*p = '\0';
	saved_options = cpystr(input);
	*p = tmpsave;
    }
    else
      p = input;
    
    if(cmd)
      *cmd = cpystr(p);

    if(init){
	if(saved_options && (p = srchstr(saved_options, "INIT="))){
	    start = p + strlen("INIT=");
	    for(cnt=0, p = start; *p && *(p+1) && isxpair(p); p += 2)
	      cnt++;
	    
	    q = *init = (char *)fs_get((cnt + 1) * sizeof(char));
	    for(p = start; *p && *(p+1) && isxpair(p); p += 2)
	      *q++ = read_hex(p);
	    
	    *q = '\0';
	}
	else
	  *init = cpystr("");
    }

    if(trailer){
	if(saved_options && (p = srchstr(saved_options, "TRAILER="))){
	    start = p + strlen("TRAILER=");
	    for(cnt=0, p = start; *p && *(p+1) && isxpair(p); p += 2)
	      cnt++;
	    
	    q = *trailer = (char *)fs_get((cnt + 1) * sizeof(char));
	    for(p = start; *p && *(p+1) && isxpair(p); p += 2)
	      *q++ = read_hex(p);
	    
	    *q = '\0';
	}
	else
	  *trailer = cpystr("");
    }

    if(all_but_cmd){
	if(saved_options)
	  *all_but_cmd = saved_options;
	else
	  *all_but_cmd = cpystr("");
    }
    else if(saved_options)
      fs_give((void **)&saved_options);
}


int
copy_pinerc(char *local, char *remote, char **err_msg)
{
    return(copy_localfile_to_remotefldr(RemImap, local, remote,
					REMOTE_PINERC_SUBTYPE,
					err_msg));
}


int
copy_abook(char *local, char *remote, char **err_msg)
{
    return(copy_localfile_to_remotefldr(RemImap, local, remote,
					REMOTE_ABOOK_SUBTYPE,
					err_msg));
}


/*
 * Copy local file to remote folder.
 *
 * Args remotetype -- type of remote folder
 *           local -- name of local file
 *          remote -- name of remote folder
 *         subtype --
 *
 * Returns 0 on success.
 */
int
copy_localfile_to_remotefldr(RemType remotetype, char *local, char *remote,
			     char *subtype, char **err_msg)
{
    int        retfail = -1;
    unsigned   flags;
    REMDATA_S *rd;

    dprint((9, "copy_localfile_to_remotefldr(%s,%s)\n",
	       local ? local : "<null>",
	       remote ? remote : "<null>"));

    *err_msg = (char *)fs_get(MAXPATH * sizeof(char));

    if(!local || !*local){
	snprintf(*err_msg, MAXPATH, _("No local file specified"));
	return(retfail);
    }

    if(!remote || !*remote){
	snprintf(*err_msg, MAXPATH, _("No remote folder specified"));
	return(retfail);
    }

    if(!IS_REMOTE(remote)){
	snprintf(*err_msg, MAXPATH, _("Remote folder name \"%s\" %s"), remote,
		(*remote != '{') ? _("must begin with \"{\"") : _("not valid"));
	return(retfail);
    }

    if(IS_REMOTE(local)){
	snprintf(*err_msg, MAXPATH, _("First argument \"%s\" must be a local filename"),
	        local);
	return(retfail);
    }

    if(can_access(local, ACCESS_EXISTS) != 0){
	snprintf(*err_msg, MAXPATH, _("Local file \"%s\" does not exist"), local);
	return(retfail);
    }

    if(can_access(local, READ_ACCESS) != 0){
	snprintf(*err_msg, MAXPATH, _("Can't read local file \"%s\": %s"),
	        local, error_description(errno));
	return(retfail);
    }

    /*
     * Check if remote folder exists and create it if it doesn't.
     */
    flags = 0;
    rd = rd_create_remote(remotetype, remote, subtype,
			  &flags, _("Error: "), _("Can't copy to remote folder."));
    
    if(!rd || rd->access == NoExists){
	snprintf(*err_msg, MAXPATH, _("Can't create \"%s\""), remote);
	if(rd)
	  rd_free_remdata(&rd);

	return(retfail);
    }

    if(rd->access == MaybeRorW)
      rd->access = ReadWrite;

    rd->flags |= (NO_META_UPDATE | DO_REMTRIM);
    rd->lf = cpystr(local);

    rd_open_remote(rd);
    if(!rd_stream_exists(rd)){
	snprintf(*err_msg, MAXPATH, _("Can't open remote folder \"%s\""), rd->rn);
	rd_free_remdata(&rd);
	return(retfail);
    }

    if(rd_remote_is_readonly(rd)){
	snprintf(*err_msg, MAXPATH, _("Remote folder \"%s\" is readonly"), rd->rn);
	rd_free_remdata(&rd);
	return(retfail);
    }

    switch(rd->type){
      case RemImap:
	/*
	 * Empty folder, add a header msg.
	 */
	if(rd->t.i.stream->nmsgs == 0){
	    if(rd_init_remote(rd, 1) != 0){
		snprintf(*err_msg, MAXPATH,
		  _("Failed initializing remote folder \"%s\", check debug file"),
		  rd->rn);
		rd_free_remdata(&rd);
		return(retfail);
	    }
	}

	fs_give((void **)err_msg);
	*err_msg = NULL;
	if(rd_chk_for_hdr_msg(&(rd->t.i.stream), rd, err_msg)){
		rd_free_remdata(&rd);
		return(retfail);
	}

	break;

      default:
	break;
    }

    if(rd_update_remote(rd, NULL) != 0){
	snprintf(*err_msg, MAXPATH, _("Error copying to remote folder \"%s\""), rd->rn);
	rd_free_remdata(&rd);
	return(retfail);
    }

    rd_update_metadata(rd, NULL);
    rd_close_remdata(&rd);
    
    fs_give((void **)err_msg);
    return(0);
}


/*----------------------------------------------------------------------
    Panic pine - call on detected programmatic errors to exit pine, with arg

  Input: message --  printf styule string for panic message (see above)
         arg     --  argument for printf string

 Result: The various tty modes are restored
         If debugging is active a core dump will be generated
         Exits Pine
  ----*/
void
panic1(char *message, char *arg)
{
    char buf1[1001], buf2[1001];

    snprintf(buf1, sizeof(buf1), "%.*s", MAX(sizeof(buf1) - 1 - strlen(message), 0), arg);
    snprintf(buf2, sizeof(buf2), message, buf1);
    panic(buf2);
}


/*
 *
 */
HelpType
config_help(int var, int feature)
{
    switch(var){
      case V_FEATURE_LIST :
	return(feature_list_help(feature));
	break;

      case V_PERSONAL_NAME :
	return(h_config_pers_name);
      case V_USER_ID :
	return(h_config_user_id);
      case V_USER_DOMAIN :
	return(h_config_user_dom);
      case V_SMTP_SERVER :
	return(h_config_smtp_server);
      case V_NNTP_SERVER :
	return(h_config_nntp_server);
      case V_INBOX_PATH :
	return(h_config_inbox_path);
      case V_PRUNED_FOLDERS :
	return(h_config_pruned_folders);
      case V_DEFAULT_FCC :
	return(h_config_default_fcc);
      case V_DEFAULT_SAVE_FOLDER :
	return(h_config_def_save_folder);
      case V_POSTPONED_FOLDER :
	return(h_config_postponed_folder);
      case V_READ_MESSAGE_FOLDER :
	return(h_config_read_message_folder);
      case V_FORM_FOLDER :
	return(h_config_form_folder);
      case V_ARCHIVED_FOLDERS :
	return(h_config_archived_folders);
      case V_SIGNATURE_FILE :
	return(h_config_signature_file);
      case V_LITERAL_SIG :
	return(h_config_literal_sig);
      case V_INIT_CMD_LIST :
	return(h_config_init_cmd_list);
      case V_COMP_HDRS :
	return(h_config_comp_hdrs);
      case V_CUSTOM_HDRS :
	return(h_config_custom_hdrs);
      case V_VIEW_HEADERS :
	return(h_config_viewer_headers);
      case V_VIEW_MARGIN_LEFT :
	return(h_config_viewer_margin_left);
      case V_VIEW_MARGIN_RIGHT :
	return(h_config_viewer_margin_right);
      case V_QUOTE_SUPPRESSION :
	return(h_config_quote_suppression);
      case V_SAVED_MSG_NAME_RULE :
	return(h_config_saved_msg_name_rule);
      case V_FCC_RULE :
	return(h_config_fcc_rule);
      case V_SORT_KEY :
	return(h_config_sort_key);
      case V_AB_SORT_RULE :
	return(h_config_ab_sort_rule);
      case V_FLD_SORT_RULE :
	return(h_config_fld_sort_rule);
      case V_POST_CHAR_SET :
	return(h_config_post_char_set);
      case V_UNK_CHAR_SET :
	return(h_config_unk_char_set);
#ifndef	_WINDOWS
      case V_KEY_CHAR_SET :
	return(h_config_key_char_set);
      case V_CHAR_SET :
	return(h_config_char_set);
#endif	/* ! _WINDOWS */
      case V_EDITOR :
	return(h_config_editor);
      case V_SPELLER :
	return(h_config_speller);
      case V_DISPLAY_FILTERS :
	return(h_config_display_filters);
      case V_SEND_FILTER :
	return(h_config_sending_filter);
      case V_ALT_ADDRS :
	return(h_config_alt_addresses);
      case V_KEYWORDS :
	return(h_config_keywords);
      case V_KW_BRACES :
	return(h_config_kw_braces);
      case V_OPENING_SEP :
	return(h_config_opening_sep);
      case V_KW_COLORS :
	return(h_config_kw_color);
      case V_ABOOK_FORMATS :
	return(h_config_abook_formats);
      case V_INDEX_FORMAT :
	return(h_config_index_format);
      case V_INCCHECKTIMEO :
	return(h_config_incoming_timeo);
      case V_INCCHECKINTERVAL :
	return(h_config_incoming_interv);
      case V_INC2NDCHECKINTERVAL :
	return(h_config_incoming_second_interv);
      case V_INCCHECKLIST :
	return(h_config_incoming_list);
      case V_OVERLAP :
	return(h_config_viewer_overlap);
      case V_MAXREMSTREAM :
	return(h_config_maxremstream);
      case V_PERMLOCKED :
	return(h_config_permlocked);
      case V_MARGIN :
	return(h_config_scroll_margin);
      case V_DEADLETS :
	return(h_config_deadlets);
      case V_FILLCOL :
	return(h_config_composer_wrap_column);
      case V_TCPOPENTIMEO :
	return(h_config_tcp_open_timeo);
      case V_TCPREADWARNTIMEO :
	return(h_config_tcp_readwarn_timeo);
      case V_TCPWRITEWARNTIMEO :
	return(h_config_tcp_writewarn_timeo);
      case V_TCPQUERYTIMEO :
	return(h_config_tcp_query_timeo);
      case V_RSHOPENTIMEO :
	return(h_config_rsh_open_timeo);
      case V_SSHOPENTIMEO :
	return(h_config_ssh_open_timeo);
      case V_USERINPUTTIMEO :
	return(h_config_user_input_timeo);
      case V_REMOTE_ABOOK_VALIDITY :
	return(h_config_remote_abook_validity);
      case V_REMOTE_ABOOK_HISTORY :
	return(h_config_remote_abook_history);
      case V_INCOMING_FOLDERS :
	return(h_config_incoming_folders);
      case V_FOLDER_SPEC :
	return(h_config_folder_spec);
      case V_NEWS_SPEC :
	return(h_config_news_spec);
      case V_ADDRESSBOOK :
	return(h_config_address_book);
      case V_GLOB_ADDRBOOK :
	return(h_config_glob_addrbook);
      case V_LAST_VERS_USED :
	return(h_config_last_vers);
      case V_SENDMAIL_PATH :
	return(h_config_sendmail_path);
      case V_OPER_DIR :
	return(h_config_oper_dir);
      case V_RSHPATH :
	return(h_config_rshpath);
      case V_RSHCMD :
	return(h_config_rshcmd);
      case V_SSHPATH :
	return(h_config_sshpath);
      case V_SSHCMD :
	return(h_config_sshcmd);
      case V_NEW_VER_QUELL :
	return(h_config_new_ver_quell);
      case V_DISABLE_DRIVERS :
	return(h_config_disable_drivers);
      case V_DISABLE_AUTHS :
	return(h_config_disable_auths);
      case V_REMOTE_ABOOK_METADATA :
	return(h_config_abook_metafile);
      case V_REPLY_STRING :
	return(h_config_reply_indent_string);
      case V_WORDSEPS :
	return(h_config_wordseps);
      case V_QUOTE_REPLACE_STRING :
	return(h_config_quote_replace_string);
      case V_REPLY_INTRO :
	return(h_config_reply_intro);
      case V_EMPTY_HDR_MSG :
	return(h_config_empty_hdr_msg);
      case V_STATUS_MSG_DELAY :
	return(h_config_status_msg_delay);
      case V_ACTIVE_MSG_INTERVAL :
	return(h_config_active_msg_interval);
      case V_MAILCHECK :
	return(h_config_mailcheck);
      case V_MAILCHECKNONCURR :
	return(h_config_mailchecknoncurr);
      case V_MAILDROPCHECK :
	return(h_config_maildropcheck);
      case V_NNTPRANGE :
	return(h_config_nntprange);
      case V_NEWS_ACTIVE_PATH :
	return(h_config_news_active);
      case V_NEWS_SPOOL_DIR :
	return(h_config_news_spool);
      case V_IMAGE_VIEWER :
	return(h_config_image_viewer);
      case V_USE_ONLY_DOMAIN_NAME :
	return(h_config_domain_name);
      case V_LAST_TIME_PRUNE_QUESTION :
	return(h_config_prune_date);
      case V_UPLOAD_CMD:
	return(h_config_upload_cmd);
      case V_UPLOAD_CMD_PREFIX:
	return(h_config_upload_prefix);
      case V_DOWNLOAD_CMD:
	return(h_config_download_cmd);
      case V_DOWNLOAD_CMD_PREFIX:
	return(h_config_download_prefix);
      case V_GOTO_DEFAULT_RULE:
	return(h_config_goto_default);
      case V_INCOMING_STARTUP:
	return(h_config_inc_startup);
      case V_PRUNING_RULE:
	return(h_config_pruning_rule);
      case V_REOPEN_RULE:
	return(h_config_reopen_rule);
      case V_THREAD_DISP_STYLE:
	return(h_config_thread_disp_style);
      case V_THREAD_INDEX_STYLE:
	return(h_config_thread_index_style);
      case V_THREAD_MORE_CHAR:
	return(h_config_thread_indicator_char);
      case V_THREAD_EXP_CHAR:
	return(h_config_thread_exp_char);
      case V_THREAD_LASTREPLY_CHAR:
	return(h_config_thread_lastreply_char);
      case V_MAILCAP_PATH :
	return(h_config_mailcap_path);
      case V_MIMETYPE_PATH :
	return(h_config_mimetype_path);
#if !defined(DOS) && !defined(OS2) && !defined(LEAVEOUTFIFO)
      case V_FIFOPATH :
	return(h_config_fifopath);
#endif
      case V_NMW_WIDTH :
	return(h_config_newmailwidth);
      case V_NEWSRC_PATH :
	return(h_config_newsrc_path);
      case V_BROWSER :
	return(h_config_browser);
#if defined(DOS) || defined(OS2)
      case V_FILE_DIR :
	return(h_config_file_dir);
#endif
      case V_NORM_FORE_COLOR :
      case V_NORM_BACK_COLOR :
	return(h_config_normal_color);
      case V_REV_FORE_COLOR :
      case V_REV_BACK_COLOR :
	return(h_config_reverse_color);
      case V_TITLE_FORE_COLOR :
      case V_TITLE_BACK_COLOR :
	return(h_config_title_color);
      case V_TITLECLOSED_FORE_COLOR :
      case V_TITLECLOSED_BACK_COLOR :
	return(h_config_titleclosed_color);
      case V_STATUS_FORE_COLOR :
      case V_STATUS_BACK_COLOR :
	return(h_config_status_color);
      case V_SLCTBL_FORE_COLOR :
      case V_SLCTBL_BACK_COLOR :
	return(h_config_slctbl_color);
      case V_QUOTE1_FORE_COLOR :
      case V_QUOTE2_FORE_COLOR :
      case V_QUOTE3_FORE_COLOR :
      case V_QUOTE1_BACK_COLOR :
      case V_QUOTE2_BACK_COLOR :
      case V_QUOTE3_BACK_COLOR :
	return(h_config_quote_color);
      case V_INCUNSEEN_FORE_COLOR :
      case V_INCUNSEEN_BACK_COLOR :
	return(h_config_incunseen_color);
      case V_SIGNATURE_FORE_COLOR :
      case V_SIGNATURE_BACK_COLOR :
	return(h_config_signature_color);
      case V_PROMPT_FORE_COLOR :
      case V_PROMPT_BACK_COLOR :
	return(h_config_prompt_color);
      case V_HEADER_GENERAL_FORE_COLOR :
      case V_HEADER_GENERAL_BACK_COLOR :
	return(h_config_header_general_color);
      case V_IND_PLUS_FORE_COLOR :
      case V_IND_IMP_FORE_COLOR :
      case V_IND_DEL_FORE_COLOR :
      case V_IND_ANS_FORE_COLOR :
      case V_IND_NEW_FORE_COLOR :
      case V_IND_UNS_FORE_COLOR :
      case V_IND_REC_FORE_COLOR :
      case V_IND_FWD_FORE_COLOR :
      case V_IND_PLUS_BACK_COLOR :
      case V_IND_IMP_BACK_COLOR :
      case V_IND_DEL_BACK_COLOR :
      case V_IND_ANS_BACK_COLOR :
      case V_IND_NEW_BACK_COLOR :
      case V_IND_UNS_BACK_COLOR :
      case V_IND_REC_BACK_COLOR :
      case V_IND_FWD_BACK_COLOR :
	return(h_config_index_color);
      case V_IND_OP_FORE_COLOR :
      case V_IND_OP_BACK_COLOR :
	return(h_config_index_opening_color);
      case V_IND_SUBJ_FORE_COLOR :
      case V_IND_SUBJ_BACK_COLOR :
	return(h_config_index_subject_color);
      case V_IND_FROM_FORE_COLOR :
      case V_IND_FROM_BACK_COLOR :
	return(h_config_index_from_color);
      case V_IND_HIPRI_FORE_COLOR :
      case V_IND_HIPRI_BACK_COLOR :
      case V_IND_LOPRI_FORE_COLOR :
      case V_IND_LOPRI_BACK_COLOR :
	return(h_config_index_pri_color);
      case V_IND_ARR_FORE_COLOR :
      case V_IND_ARR_BACK_COLOR :
	return(h_config_index_arrow_color);
      case V_KEYLABEL_FORE_COLOR :
      case V_KEYLABEL_BACK_COLOR :
	return(h_config_keylabel_color);
      case V_KEYNAME_FORE_COLOR :
      case V_KEYNAME_BACK_COLOR :
	return(h_config_keyname_color);
      case V_METAMSG_FORE_COLOR :
      case V_METAMSG_BACK_COLOR :
	return(h_config_metamsg_color);
      case V_VIEW_HDR_COLORS :
	return(h_config_customhdr_color);
      case V_PRINTER :
	return(h_config_printer);
      case V_PERSONAL_PRINT_CATEGORY :
	return(h_config_print_cat);
      case V_PERSONAL_PRINT_COMMAND :
	return(h_config_print_command);
      case V_PAT_ROLES :
	return(h_config_pat_roles);
      case V_PAT_FILTS :
	return(h_config_pat_filts);
      case V_PAT_SCORES :
	return(h_config_pat_scores);
      case V_PAT_INCOLS :
	return(h_config_pat_incols);
      case V_PAT_OTHER :
	return(h_config_pat_other);
      case V_PAT_SRCH :
	return(h_config_pat_srch);
      case V_INDEX_COLOR_STYLE :
	return(h_config_index_color_style);
      case V_TITLEBAR_COLOR_STYLE :
	return(h_config_titlebar_color_style);
#ifdef	_WINDOWS
      case V_FONT_NAME :
	return(h_config_font_name);
      case V_FONT_SIZE :
	return(h_config_font_size);
      case V_FONT_STYLE :
	return(h_config_font_style);
      case V_FONT_CHAR_SET :
	return(h_config_font_char_set);
      case V_PRINT_FONT_NAME :
	return(h_config_print_font_name);
      case V_PRINT_FONT_SIZE :
	return(h_config_print_font_size);
      case V_PRINT_FONT_STYLE :
	return(h_config_print_font_style);
      case V_PRINT_FONT_CHAR_SET :
	return(h_config_print_font_char_set);
      case V_WINDOW_POSITION :
	return(h_config_window_position);
      case V_CURSOR_STYLE :
	return(h_config_cursor_style);
#else
      case V_COLOR_STYLE :
	return(h_config_color_style);
#endif
#ifdef	ENABLE_LDAP
      case V_LDAP_SERVERS :
	return(h_config_ldap_servers);
#endif
#ifdef	SMIME
      case V_PUBLICCERT_DIR :
	return(h_config_smime_pubcertdir);
      case V_PUBLICCERT_CONTAINER :
	return(h_config_smime_pubcertcon);
      case V_PRIVATEKEY_DIR :
	return(h_config_smime_privkeydir);
      case V_PRIVATEKEY_CONTAINER :
	return(h_config_smime_privkeycon);
      case V_CACERT_DIR :
	return(h_config_smime_cacertdir);
      case V_CACERT_CONTAINER :
	return(h_config_smime_cacertcon);
#endif
      case V_RSS_NEWS :
	return(h_config_rss_news);
      case V_RSS_WEATHER :
	return(h_config_rss_weather);
      case V_WP_INDEXHEIGHT :
	return(h_config_wp_indexheight);
      case V_WP_INDEXLINES :
	return(h_config_wp_indexlines);
      case V_WP_AGGSTATE :
	return(h_config_wp_aggstate);
      case V_WP_STATE :
	return(h_config_wp_state);
      case V_WP_COLUMNS :
	return(h_config_wp_columns);
      default :
	return(NO_HELP);
    }
}


/*
 * We don't want the user to be able to edit their pinerc and set
 * printer to whatever they want if personal-print-command is fixed.
 * So make sure printer is set to something legitimate. If it isn't,
 * set it to something standard and return non-zero.
 */
int
printer_value_check_and_adjust(void)
{
    char **tt;
    char   aname[100], wname[100];
    int    ok = 0;
    struct variable *vars = ps_global->vars;

    if(vars[V_PERSONAL_PRINT_COMMAND].is_fixed && !vars[V_PRINTER].is_fixed){
	strncpy(aname, ANSI_PRINTER, sizeof(aname));
	aname[sizeof(aname)-1] = '\0';
	strncat(aname, "-no-formfeed", sizeof(aname)-strlen(aname)-1);
	strncpy(wname, WYSE_PRINTER, sizeof(wname));
	wname[sizeof(wname)-1] = '\0';
	strncat(wname, "-no-formfeed", sizeof(wname)-strlen(wname)-1);
	if(strucmp(VAR_PRINTER, ANSI_PRINTER) == 0
	  || strucmp(VAR_PRINTER, aname) == 0
	  || strucmp(VAR_PRINTER, WYSE_PRINTER) == 0
	  || strucmp(VAR_PRINTER, wname) == 0)
	  ok++;
	else if(VAR_STANDARD_PRINTER && VAR_STANDARD_PRINTER[0]){
	    for(tt = VAR_STANDARD_PRINTER; *tt; tt++)
	      if(strucmp(VAR_PRINTER, *tt) == 0)
		break;
	    
	    if(*tt)
	      ok++;
	}

	if(!ok){
	    char            *val;
	    struct variable *v;

	    if(VAR_STANDARD_PRINTER && VAR_STANDARD_PRINTER[0])
	      val = VAR_STANDARD_PRINTER[0];
	    else
	      val = ANSI_PRINTER;
	    
	    v = &vars[V_PRINTER];
	    if(v->main_user_val.p)
	      fs_give((void **)&v->main_user_val.p);
	    if(v->post_user_val.p)
	      fs_give((void **)&v->post_user_val.p);
	    if(v->current_val.p)
	      fs_give((void **)&v->current_val.p);
	    
	    v->main_user_val.p = cpystr(val);
	    v->current_val.p = cpystr(val);
	}
    }

    return(!ok);
}


char **
get_supported_options(void)
{
    char         **config;
    DRIVER        *d;
    AUTHENTICATOR *a;
    char          *title = _("Supported features in this Alpine");
    char           sbuf[MAX_SCREEN_COLS+1];
    int            cnt, alcnt, len, cols, disabled, any_disabled = 0;;

    /*
     * Line count:
     *   Title + blank			= 2
     *   SSL Title + SSL lines + blank	= 4
     *   Auth title + blank		= 2
     *   Driver title + blank		= 2
     *   LDAP title + LDAP line 	= 2
     *   Disabled explanation + blank line = 4
     *   end				= 1
     */
    cnt = 17;
    for(a = mail_lookup_auth(1); a; a = a->next)
      cnt++;
    for(d = (DRIVER *)mail_parameters(NIL, GET_DRIVERS, NIL);
	d; d = d->next)
      cnt++;

    alcnt = cnt;
    config = (char **) fs_get(alcnt * sizeof(char *));
    memset(config, 0, alcnt * sizeof(char *));

    cols = ps_global->ttyo ? ps_global->ttyo->screen_cols : 0;
    len = utf8_width(title);
    snprintf(sbuf, sizeof(sbuf), "%*s%s", cols > len ? (cols-len)/2 : 0, "", title);

    cnt = 0;
    if(cnt < alcnt)
      config[cnt] = cpystr(sbuf);

    if(++cnt < alcnt)
      config[cnt] = cpystr("");

    if(++cnt < alcnt)
      /* TRANSLATORS: headings */
      config[cnt] = cpystr(_("Encryption:"));

    if(++cnt < alcnt && mail_parameters(NIL, GET_SSLDRIVER, NIL))
      config[cnt] = cpystr(_("  TLS and SSL"));
    else
      config[cnt] = cpystr(_("  None (no TLS or SSL)"));
#ifdef SMIME
    if(++cnt < alcnt)
      config[cnt] = cpystr("  S/MIME");
#endif

    if(++cnt < alcnt)
      config[cnt] = cpystr("");

    if(++cnt < alcnt)
      config[cnt] = cpystr(_("Authenticators:"));

    for(a = mail_lookup_auth(1); a; a = a->next){
	disabled = (a->client == NULL && a->server == NULL);
	any_disabled += disabled;
	snprintf(sbuf, sizeof(sbuf), "  %s%s", a->name, disabled ? " (disabled)" : "");
	if(++cnt < alcnt)
	  config[cnt] = cpystr(sbuf);
    }

    if(++cnt < alcnt)
      config[cnt] = cpystr("");

    if(++cnt < alcnt)
      config[cnt] = cpystr(_("Mailbox drivers:"));

    for(d = (DRIVER *)mail_parameters(NIL, GET_DRIVERS, NIL);
	d; d = d->next){
	disabled = (d->flags & DR_DISABLE);
	any_disabled += disabled;
	snprintf(sbuf, sizeof(sbuf), "  %s%s", d->name, disabled ? " (disabled)" : "");
	if(++cnt < alcnt)
	  config[cnt] = cpystr(sbuf);
    }

    if(++cnt < alcnt)
      config[cnt] = cpystr("");

    if(++cnt < alcnt)
      config[cnt] = cpystr(_("Directories:"));

#ifdef	ENABLE_LDAP
    if(++cnt < alcnt)
      config[cnt] = cpystr("  LDAP");
#else
    if(++cnt < alcnt)
      config[cnt] = cpystr("  None (no LDAP)");
#endif

    if(any_disabled){
	if(++cnt < alcnt)
	  config[cnt] = cpystr("");

	if(ps_global->ttyo){
	  if(++cnt < alcnt)
	    config[cnt] = cpystr(_("Authenticators may be disabled because of the \"disable-these-authenticators\" hidden config option. Mailbox drivers may be disabled because of the \"disable-these-drivers\" hidden config option."));
	}
	else{
	    if(++cnt < alcnt)
	      config[cnt] = cpystr(_("Authenticators may be disabled because of the \"disable-these-authenticators\""));
	    if(++cnt < alcnt)
	      config[cnt] = cpystr(_("hidden config option. Mailbox drivers may be disabled because of the"));
	    if(++cnt < alcnt)
	      config[cnt] = cpystr(_("\"disable-these-drivers\" hidden config option."));
	}
    }

    if(++cnt < alcnt)
      config[cnt] = NULL;

    return(config);
}


unsigned
reset_startup_rule(MAILSTREAM *stream)
{
    long rflags = ROLE_DO_OTHER;
    PAT_STATE     pstate;
    PAT_S        *pat;
    unsigned      startup_rule;

    startup_rule = IS_NOTSET;

    if(stream && nonempty_patterns(rflags, &pstate)){
	for(pat = first_pattern(&pstate); pat; pat = next_pattern(&pstate)){
	    if(match_pattern(pat->patgrp, stream, NULL, NULL, NULL,
			     SE_NOSERVER|SE_NOPREFETCH))
	      break;
	}

	if(pat && pat->action && !pat->action->bogus)
	  startup_rule = pat->action->startup_rule;
    }

    return(startup_rule);
}


#ifdef	_WINDOWS

char *
transformed_color(old)
    char *old;
{
    if(!old)
      return("");

    if(!struncmp(old, "color008", 8))
      return("colorlgr");
    else if(!struncmp(old, "color009", 8))
      return("colormgr");
    else if(!struncmp(old, "color010", 8))
      return("colordgr");

    return("");
}


/*
 * If this is the first time we've run a version > 4.40, and there
 * is evidence that the config file has not been used by unix pine,
 * then we convert color008 to colorlgr, color009 to colormgr, and
 * color010 to colordgr. If the config file is being used by
 * unix pine then color008 may really supposed to be color008, color009
 * may really supposed to be red, and color010 may really supposed to be
 * green. Same if we've already run 4.41 or higher previously.
 *
 * Returns 0 if no changes, > 0 if something was changed.
 */
int
convert_pc_gray_names(ps, prc, which)
    struct pine *ps;
    PINERC_S    *prc;
    EditWhich    which;
{
    struct variable *v;
    int              ret = 0, ic = 0;
    char           **s, *t, *p, *pstr, *new, *pval, **apval, **lval;

    for(v = ps->vars; v->name; v++){
	if(!color_holding_var(ps, v) || v == &ps->vars[V_KW_COLORS])
	  continue;
	
	if(v == &ps->vars[V_VIEW_HDR_COLORS]){

	    if((lval = LVAL(v,which)) != NULL){
		/* fix these in place */
		for(s = lval; (t = *s) != NULL; s++){
		    if((p = srchstr(t, "FG=color008")) ||
		       (p = srchstr(t, "FG=color009")) ||
		       (p = srchstr(t, "FG=color010"))){
			strncpy(p+3, transformed_color(p+3), 8);
			ret++;
		    }

		    if((p = srchstr(t, "BG=color008")) ||
		       (p = srchstr(t, "BG=color009")) ||
		       (p = srchstr(t, "BG=color010"))){
			strncpy(p+3, transformed_color(p+3), 8);
			ret++;
		    }
		}
	    }
	}
	else{
	    if((pval = PVAL(v,which)) != NULL){
		apval = APVAL(v,which);
		if(apval && (!strucmp(pval, "color008") ||
		             !strucmp(pval, "color009") ||
		             !strucmp(pval, "color010"))){
		    new = transformed_color(pval);
		    if(*apval)
		      fs_give((void **)apval);

		    *apval = cpystr(new);
		    ret++;
		}
	    }
	}
    }

    v = &ps->vars[V_PAT_INCOLS];
    if((lval = LVAL(v,which)) != NULL){
	for(s = lval; (t = *s) != NULL; s++){
	    if((pstr = srchstr(t, "action=")) != NULL){
		if((p = srchstr(pstr, "FG=color008")) ||
		   (p = srchstr(pstr, "FG=color009")) ||
		   (p = srchstr(pstr, "FG=color010"))){
		    strncpy(p+3, transformed_color(p+3), 8);
		    ic++;
		}

		if((p = srchstr(pstr, "BG=color008")) ||
		   (p = srchstr(pstr, "BG=color009")) ||
		   (p = srchstr(pstr, "BG=color010"))){
		    strncpy(p+3, transformed_color(p+3), 8);
		    ic++;
		}
	    }
	}
    }

    if(ic)
      set_current_val(&ps->vars[V_PAT_INCOLS], TRUE, TRUE);

    return(ret+ic);
}


int
unix_color_style_in_pinerc(prc)
    PINERC_S *prc;
{
    PINERC_LINE *pline;

    for(pline = prc ? prc->pinerc_lines : NULL;
	pline && (pline->var || pline->line); pline++)
      if(pline->line && !struncmp("color-style=", pline->line, 12))
	return(1);
    
    return(0);
}

char *
pcpine_general_help(titlebuf)
    char *titlebuf;
{
    if(titlebuf)
      strcpy(titlebuf, "PC Alpine For Windows");

    return(pcpine_help(h_pine_for_windows));
}

#endif	/* _WINDOWS */
