/* -*- mode: C; mode: fold; -*- */
/* Copyright (c) 1998 John E. Davis (davis@space.mit.edu)
 *
 * This file is part of slrn.
 *
 * Slrn is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 * 
 * Slrn is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Slrn; see the file COPYING.  If not, write to the Free
 * Software Foundation, 59 Temple Place - Suite 330, 
 * Boston, MA  02111-1307, USA.
 */

/* Read startup .slrnrc file */

#include "config.h"
#include "slrnfeat.h"

/*{{{ Include Files */

#include <stdio.h>
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif

#include <string.h>
#include <slang.h>

#include "jdmacros.h"

#include "slrn.h"
#include "group.h"
#include "misc.h"
#include "art.h"
#include "post.h"
#include "startup.h"
#include "score.h"
#include "util.h"
#include "uudecode.h"
#if SLRN_HAS_MIME
# include "mime.h"
#endif
#if SLRN_HAS_GROUPLENS
# include "grplens.h"
#endif
#if SLRN_HAS_SLANG
# include "interp.h"
#endif
#include "server.h"
#include "chmap.h"
#include "print.h"

#ifdef VMS
# include "vms.h"
#endif
/*}}}*/

/*{{{ Forward Function Declarations */

static int unsetkey_fun (int, SLcmd_Cmd_Table_Type *);
static int setkey_fun (int, SLcmd_Cmd_Table_Type *);
static int server_fun (int, SLcmd_Cmd_Table_Type *);
static int color_fun (int, SLcmd_Cmd_Table_Type *);
static int mono_fun (int, SLcmd_Cmd_Table_Type *);
static int user_data_fun (int, SLcmd_Cmd_Table_Type *);
static int ignore_quote_fun (int, SLcmd_Cmd_Table_Type *);
static int autobaud_fun (int, SLcmd_Cmd_Table_Type *);
static int set_variable_fun (int, SLcmd_Cmd_Table_Type *);
static int nnrp_fun (int, SLcmd_Cmd_Table_Type *);
static int grouplens_fun (int, SLcmd_Cmd_Table_Type *);
static int interpret_fun (int, SLcmd_Cmd_Table_Type *);
static int include_file_fun (int, SLcmd_Cmd_Table_Type *);
static int set_header_format_fun (int, SLcmd_Cmd_Table_Type *);
static int set_visible_headers_fun (int, SLcmd_Cmd_Table_Type *);

/*}}}*/
/*{{{ Static Global Variables */

static int This_Line_Num;	       /* current line number in startup file */
static char *This_File;
static char *This_Line;		       /* line being parsed */

char *Server_Object;
char *Post_Object;

static SLcmd_Cmd_Table_Type Slrn_Cmd_Table;
static SLcmd_Cmd_Type Slrn_Startup_File_Cmds[] = /*{{{*/
{
     {unsetkey_fun, "unsetkey", "SS"},
     {setkey_fun, "setkey", "SSS"},
     {server_fun, "server", "SS"},
     {color_fun, "color", "SSS"},
     {mono_fun, "mono", "SSsss"},
     {set_variable_fun, "set", "SG"},
     {user_data_fun, "hostname", "S"},
     {nnrp_fun, "nnrpaccess", "SSS" },
#define SLRN_MAX_QUOTE_REGEXP 5
     {ignore_quote_fun, "ignore_quotes", "Sssss"},
     {autobaud_fun, "autobaud", ""},
     {grouplens_fun, "grouplens_add", "S"},
     {interpret_fun, "interpret", "S"},
     {include_file_fun, "include", "S"},
     {set_header_format_fun, "header_display_format", "IS"},
     {user_data_fun, "scorefile", "S"},
     {set_visible_headers_fun, "visible_headers", "S"},

   /* The following are considered obsolete */
     {user_data_fun, "username", "S"},
     {user_data_fun, "replyto", "S"},
     {user_data_fun, "organization", "S"},
     {user_data_fun, "signature", "S"},
     {user_data_fun, "realname", "S"},
     {user_data_fun, "followup", "S"},
     {user_data_fun, "cc_followup_string", "S"},
     {user_data_fun, "quote_string", "S"},
#if SLRN_HAS_DECODE
     {user_data_fun, "decode_directory", "S"},
#endif
     {user_data_fun, "editor_command", "S"},
     {NULL, "", ""}
};

/*}}}*/

/*}}}*/
/*{{{ Public Global Variables */

SLRegexp_Type *Slrn_Ignore_Quote_Regexp [SLRN_MAX_QUOTE_REGEXP + 1];
int Slrn_Autobaud = 0;
char *Slrn_Score_File;
int Slrn_Scroll_By_Page;

/*}}}*/

/*{{{ Utility Functions */

static void exit_malloc_error (void) /*{{{*/
{
   if (This_File == NULL)
     slrn_exit_error ("Memory Allocation Failure");
   
   slrn_exit_error ("%s: Line %d\n%sMemory Allocation Failure",
		    This_File, This_Line_Num, This_Line);
}

/*}}}*/

static char *safe_malloc (unsigned int n) /*{{{*/
{
   char *s;
   s = (char *) SLMALLOC (n);
   if (s == NULL) exit_malloc_error ();
   return s;
}

/*}}}*/


static void exit_unknown_object (void) /*{{{*/
{
   slrn_exit_error ("%s: Error encountered processing line %d\n%s",
		    This_File, This_Line_Num, This_Line);
}

/*}}}*/

static void issue_obsolete_message (void) /*{{{*/
{
   slrn_message ("%s: Command is obsolete on line %d:\n%s",
		 This_File, This_Line_Num, This_Line);
   slrn_message ("The new usage is:\nset %s\n", This_Line);
}

/*}}}*/

   
/*}}}*/
/*{{{ Set/Unset Key Functions */

static int setkey_fun (int argc, SLcmd_Cmd_Table_Type *table) /*{{{*/
{
   char *map = table->string_args[1];
   char *fun = table->string_args[2];
   char *key = table->string_args[3];
   SLKeyMap_List_Type *kmap = NULL;
   
   (void) argc;

   if (!strcmp (map, "group")) kmap = Slrn_Group_Keymap;
   else if (!strcmp (map, "article")) kmap = Slrn_Article_Keymap;
   else if (!strcmp (map, "readline")) kmap = Slrn_RLine_Keymap;
   else slrn_exit_error ("%s: line %d:\n%sNo such keymap: %s", This_File, This_Line_Num, This_Line, map);
   
   if (SLang_define_key (key, fun, kmap) != 0)
     {
	slrn_exit_error ("%s: line %d:\n%serror defining key.", This_File, This_Line_Num, This_Line);
     }
   return 0;
}

/*}}}*/

static int unsetkey_fun (int argc, SLcmd_Cmd_Table_Type *table) /*{{{*/
{
   char *map = table->string_args[1];
   char *key = table->string_args[2];
   SLKeyMap_List_Type *kmap = NULL;
   
   (void) argc;
   
   if (!strcmp (map, "group")) kmap = Slrn_Group_Keymap;
   else if (!strcmp (map, "article")) kmap = Slrn_Article_Keymap;
   else slrn_exit_error ("%s: line %d:\n%sNo such keymap: %s",
			 This_File, This_Line_Num, This_Line, map);
   
   SLang_undefine_key (key, kmap);
   return 0;
}

/*}}}*/

/*}}}*/

static int autobaud_fun (int argc, SLcmd_Cmd_Table_Type *table) /*{{{*/
{
   (void) argc; (void) table;
   Slrn_Autobaud = 1;
   return 0;
}

/*}}}*/

static SLRegexp_Type *compile_quote_regexp (char *str) /*{{{*/
{
   unsigned char *compiled_pattern_buf;
   SLRegexp_Type *r;
   
   compiled_pattern_buf = (unsigned char *) safe_malloc (512);
   r = (SLRegexp_Type *) safe_malloc (sizeof (SLRegexp_Type));
   
   r->pat = (unsigned char *) str;
   r->buf = compiled_pattern_buf;
   r->case_sensitive = 1;
   r->buf_len = 512;
   
   if (SLang_regexp_compile (r))
     {
	slrn_exit_error ("%s: line %d:\n%sInvalid regular expression.",
			 This_File, This_Line_Num, This_Line);
     }
   
   return r;
}

/*}}}*/
static int ignore_quote_fun (int argc, SLcmd_Cmd_Table_Type *table) /*{{{*/
{
   unsigned int i;
   SLRegexp_Type *r;
   
   if (argc > SLRN_MAX_QUOTE_REGEXP + 1)
     {
	slrn_exit_error ("%s: line %d:\n%sToo many expressions specified.",
			 This_File, This_Line_Num, This_Line);
     }
   
   for (i = 0; i < SLRN_MAX_QUOTE_REGEXP; i++)
     {
	r = Slrn_Ignore_Quote_Regexp[i];
	if (r != NULL)
	  {
	     slrn_free ((char *) r->buf);
	     SLFREE (r);
	     Slrn_Ignore_Quote_Regexp [i] = NULL;
	  }
     }
	
   for (i = 1; i < (unsigned int) argc; i++)
     {
	Slrn_Ignore_Quote_Regexp[i - 1] 
	  = compile_quote_regexp (table->string_args[i]);
     }
   return 0;
}

/*}}}*/

static int grouplens_fun (int argc, SLcmd_Cmd_Table_Type *table) /*{{{*/
{
   (void) argc;
#if SLRN_HAS_GROUPLENS
   (void) slrn_grouplens_add_group (table->string_args[1]);
#else 
   (void) table;
#endif
   return 0;
}

/*}}}*/


static int set_visible_headers_fun (int argc, SLcmd_Cmd_Table_Type *table) 
{
   (void) argc;
   return slrn_set_visible_headers (table->string_args[1]);
}

static int set_header_format_fun (int argc, SLcmd_Cmd_Table_Type *table) 
{
   (void) argc;
   return slrn_set_header_format (table->int_args[1], table->string_args[2]);
}

/*{{{ Setting/Getting Variable Functions */

typedef struct /*{{{*/
{
   char *what;
   int *valuep;
}

/*}}}*/
Set_Int_Type;

static Set_Int_Type Int_Things_To_Set [] = /*{{{*/
{
     {"auto_mark_article_as_read", &Slrn_Del_Article_Upon_Read},
     {"simulate_graphic_chars", &Slrn_Simulate_Graphic_Chars},
#if 0 /* This does not work yet */
     {"article_window_page_overlap", &Slrn_Article_Window_Border},
#endif
     {"new_subject_breaks_threads",	&Slrn_New_Subject_Breaks_Threads},
     {"scroll_by_page", &Slrn_Scroll_By_Page},
     {"use_color", &SLtt_Use_Ansi_Colors},
     {"ignore_signature", &Slrn_Sig_Is_End_Of_Article},
     {"reject_long_lines", &Slrn_Reject_Long_Lines},
     {"generate_message_id", &Slrn_Generate_Message_Id},
     {"display_cursor_bar", &Slrn_Display_Cursor_Bar},
#if SLRN_HAS_NNTP_SUPPORT
     {"query_reconnect", &Slrn_Query_Reconnect},
#else
     {"query_reconnect", NULL},
#endif
#if SLRN_HAS_SORT_BY_SCORE
     {"display_score", &Slrn_Display_Score},
#else
     {"display_score", NULL},
#endif
     {"use_xgtitle", &Slrn_Use_Xgtitle},
     {"show_article", &Slrn_Startup_With_Article},
     {"author_display", NULL},
     {"display_author_realname", NULL},
     {"show_descriptions", &Slrn_Group_Display_Descriptions},
     {"no_backups", &Slrn_No_Backups},
     {"beep", &SLtt_Ignore_Beep},
     {"unsubscribe_new_groups", &Slrn_Unsubscribe_New_Groups},
     {"show_thread_subject", &Slrn_Show_Thread_Subject},
     {"mouse", &Slrn_Use_Mouse},
     {"query_next_group", &Slrn_Query_Next_Group},
     {"query_next_article", &Slrn_Query_Next_Article},
     {"confirm_actions", &Slrn_User_Wants_Confirmation},
     {"cc_followup", &Slrn_Auto_CC_To_Poster},
     {"use_tmpdir", &Slrn_Use_Tmpdir},
     {"sorting_method", &Slrn_Sorting_Mode},
     {"uncollapse_threads", &Slrn_Threads_Visible},
     {"read_active", &Slrn_List_Active_File},
     {"use_metamail", &Slrn_Use_Meta_Mail},
     {"group_dsc_start_column", &Slrn_Group_Description_Column},
     {"lines_per_update", &Slrn_Reads_Per_Update},
     {"min_high_score", &Slrn_High_Score_Min},
     {"max_low_score", &Slrn_Low_Score_Max},
     {"kill_score", &Slrn_Kill_Score_Max},
#if !defined(IBMPC_SYSTEM)
     {"use_blink", &SLtt_Blink_Mode},
#endif
     {"wrap_flags", &Slrn_Wrap_Mode},
     {"write_newsrc_flags", &Slrn_Write_Newsrc_Flags},
     {"query_read_group_cutoff", &Slrn_Query_Group_Cutoff},
     {"prompt_next_group", &Slrn_Prompt_Next_Group},
     {"use_header_numbers", &Slrn_Use_Header_Numbers},
#if SLRN_HAS_SPOILERS
     {"spoiler_char", &Slrn_Spoiler_Char},
     {"spoiler_display_mode", &Slrn_Spoiler_Display_Mode},
#else
     {"spoiler_start_new_page", NULL},
     {"spoiler_char", NULL},
#endif
#if SLRN_HAS_MIME
     {"use_mime", &Slrn_Use_Mime},
#else
     {"use_mime", NULL},
#endif
#if SLRN_HAS_GROUPLENS
     {"use_grouplens", &Slrn_Use_Group_Lens},
     {"grouplens_port", &Slrn_GroupLens_Port},
#else
     {"use_grouplens", NULL},
#endif
#if 0
#if SLRN_HAS_INEWS_SUPPORT
     {"use_inews", &Slrn_Use_Inews},
#else
     {"use_inews", NULL},
#endif
#endif
#if SLRN_HAS_PULL_SUPPORT
     {"use_slrnpull", &Slrn_Use_Pull_Post},
#else
     {"use_slrnpull", NULL},
#endif
#if SLRN_HAS_TILDE_FEATURE
     {"use_tilde", &Slrn_Use_Tildes},
#else
     {"use_tilde", NULL},
#endif
#if SLRN_HAS_SPOOL_SUPPORT
     {"spool_check_up_on_nov", &Slrn_Spool_Check_Up_On_Nov},
#else
     {"spool_check_up_on_nov", NULL},
#endif
     {NULL, NULL}
};

/*}}}*/

typedef struct /*{{{*/
{
   char *what;
   char **svaluep;
}

/*}}}*/
Set_String_Type;

static Set_String_Type String_Things_To_Set [] = /*{{{*/
{
     {"art_help_line", &Slrn_Art_Help_Line},
     {"header_help_line", &Slrn_Header_Help_Line},
     {"group_help_line", &Slrn_Group_Help_Line},
     {"quote_string", &Slrn_Quote_String},
     {"realname", &Slrn_User_Info.realname},
     {"username", &Slrn_User_Info.username},
     {"replyto", &Slrn_User_Info.replyto},
     {"organization", &Slrn_User_Info.org},
     {"followup", &Slrn_User_Info.followup_string},   /* obsolete */
     {"followup_string", &Slrn_User_Info.followup_string},
     {"reply_string", &Slrn_User_Info.reply_string},
     {"cc_followup_string", &Slrn_Courtesy_CC_Message},
     {"editor_command", &Slrn_Editor},
     {"post_editor_command", &Slrn_Editor_Post},
     {"score_editor_command", &Slrn_Editor_Score},
     {"mail_editor_command", &Slrn_Editor_Mail},
     {"non_Xbrowser", &Slrn_NonX_Browser},
     {"Xbrowser", &Slrn_X_Browser},
     {"save_posts", &Slrn_Save_Posts_File},
     {"save_replies", &Slrn_Save_Replies_File},
     {"save_directory", &Slrn_Save_Directory},
     {"postpone_directory", &Slrn_Postpone_Dir},
     {"signature", &Slrn_User_Info.signature},
     {"custom_headers", &Slrn_Post_Custom_Headers},
     {"followup_custom_headers", &Slrn_Followup_Custom_Headers},
     {"reply_custom_headers", &Slrn_Reply_Custom_Headers},
#if SLRN_HAS_GROUPLENS
     {"grouplens_pseudoname", &Slrn_GroupLens_Pseudoname},
     {"grouplens_host", &Slrn_GroupLens_Host},
#else
     {"grouplens_pseudoname", NULL},
     {"grouplens_host", NULL},
#endif
     {"decode_directory", 
#if SLRN_HAS_DECODE
	  &Slrn_Decode_Directory
#else
	  NULL
#endif
     },
   
     {"inews_program",
#if SLRN_HAS_INEWS_SUPPORT && SLRN_HAS_USER_INEWS
	  &Slrn_Inews_Pgm
#else
	  NULL
#endif
     },
     
#if SLRN_HAS_MIME
     {"mime_charset", &Slrn_Mime_Display_Charset},
     {"metamail_command", &Slrn_MetaMail_Cmd},
#else
     {"mime_charset", NULL},
     {"metamail_command", NULL},
#endif
#if SLRN_HAS_CHARACTER_MAP
     {"charset", &Slrn_Charset},
#else
     {"charset", NULL},
#endif
#ifndef VMS
     {"sendmail_command", &Slrn_SendMail_Command},
#endif
     {"spool_inn_root", 
#if SLRN_HAS_SPOOL_SUPPORT
     &Slrn_Inn_Root
#else
     NULL
#endif
     },
     {"spool_root",
#if SLRN_HAS_SPOOL_SUPPORT
     &Slrn_Spool_Root
#else
     NULL
#endif
     },
     {"spool_nov_root",
#if SLRN_HAS_SPOOL_SUPPORT
     &Slrn_Nov_Root
#else
     NULL
#endif
     },
     {"spool_nov_file",
#if SLRN_HAS_SPOOL_SUPPORT
     &Slrn_Nov_File
#else
     NULL
#endif
     },
     {"spool_active_file",
#if SLRN_HAS_SPOOL_SUPPORT
     &Slrn_Active_File
#else
     NULL
#endif
     },
     {"spool_activetimes_file",
#if SLRN_HAS_SPOOL_SUPPORT
     &Slrn_ActiveTimes_File
#else
     NULL
#endif
     },
     {"spool_newsgroups_file",
#if SLRN_HAS_SPOOL_SUPPORT
     &Slrn_Newsgroups_File
#else
     NULL
#endif
     },
     {"macro_directory",
#if SLRN_HAS_SLANG
	&Slrn_Macro_Dir
#else
	  NULL
#endif
     },
     {"server_object", &Server_Object},
     {"post_object", &Post_Object},
     {"printer_name", &Slrn_Printer_Name},
     {NULL, NULL}
};

/*}}}*/

int slrn_set_string_variable (char *name, char *value) /*{{{*/
{
   Set_String_Type *sp = String_Things_To_Set;
	
   while (sp->what != NULL)
     {
	if (!strcmp (sp->what, name))
	  {
	     char *ss;
		  
	     if (sp->svaluep == NULL) return 0;
	     
	     ss = *sp->svaluep;
		  
	     slrn_free (ss);
	     if (NULL == (ss = SLmake_string (value)))
	       exit_malloc_error ();
		  
	     *sp->svaluep = ss;
	     return 0;
	  }
	sp++;
     }
   return -1;
}

/*}}}*/

int slrn_set_integer_variable (char *name, int value) /*{{{*/
{
   Set_Int_Type *ip = Int_Things_To_Set;
   
   while (ip->what != NULL)
     {
	if (!strcmp (ip->what, name))
	  {
	     if (ip->valuep == NULL) return 0;
	     *ip->valuep = value;
	     return 0;
	  }
	ip++;
     }
   return -1;
}

/*}}}*/

int slrn_get_variable_value (char *name, int *type, char ***sval, int **ival) /*{{{*/
{
   Set_String_Type *sp;
   Set_Int_Type *ip;
   
   sp = String_Things_To_Set;
   while (sp->what != NULL)
     {
	if (!strcmp (sp->what, name))
	  {
	     *sval = sp->svaluep;
	     *type = STRING_TYPE;
	     return 0;
	  }
	sp++;
     }
   
   ip = Int_Things_To_Set;
   while (ip->what != NULL)
     {
	if (!strcmp (ip->what, name))
	  {
	     *ival = ip->valuep;
	     *type = INT_TYPE;
	     return 0;
	  }
	ip++;
     }
   
   return -1;
}

/*}}}*/

static int set_variable_fun (int argc, SLcmd_Cmd_Table_Type *table) /*{{{*/
{
   int ret;
   char *what = table->string_args[1];
   int ivalue = table->int_args[2];
   char *svalue = table->string_args[2];
   int type = table->arg_type[2];
   
   (void) argc;
   
   if (type == STRING_TYPE)
     ret = slrn_set_string_variable (what, svalue);
   else if (type == INT_TYPE) 
     ret = slrn_set_integer_variable (what, ivalue);
   else ret = -1;
   
   if (ret != 0) exit_unknown_object ();
   return 0;
}

/*}}}*/


/*}}}*/

/*{{{ Setting Color/Mono Attributes */

typedef struct /*{{{*/
{
   char *name;
   int value;
   char *fg, *bg;
   SLtt_Char_Type mono;
}

/*}}}*/
Color_Handle_Type;

/* default colors -- suitable for a color xterm */
   
static Color_Handle_Type Color_Handles[] = /*{{{*/
{
     {"normal",		0,		"black",	"white", 0},
     {"status",		STATUS_COLOR,	"yellow",	"blue", SLTT_REV_MASK},
     {"menu",		MENU_COLOR,	"yellow",	"blue", SLTT_REV_MASK},
     {"menu_press",	MENU_PRESS_COLOR,"blue",	"yellow", 0},
     {"headers",	HEADER_COLOR,	"brightcyan",	"white", 0},
     {"group",		GROUP_COLOR,	"blue",		"white", 0},
     {"subject",	SUBJECT_COLOR,	"black",	"white", 0},
     {"author",		AUTHOR_COLOR,	"magenta",	"white", 0},
     {"error",		ERROR_COLOR,	"red",		"white", SLTT_BLINK_MASK},
     {"cursor",		CURSOR_COLOR,	"brightgreen",	"white", SLTT_REV_MASK},
     {"article",	ARTICLE_COLOR,	"blue",		"white", 0},
     {"tree",		TREE_COLOR,	"red",		"white", 0},
     {"quotes",		QUOTE_COLOR,	"red",		"white", 0},
     {"signature",	SIGNATURE_COLOR,"red",		"white", 0},
     {"thread_number",	THREAD_NUM_COLOR,"blue",	"white", SLTT_BOLD_MASK},
     {"header_number",	HEADER_NUMBER_COLOR,"green",	"white", 0},
     {"high_score",	HIGH_SCORE_COLOR,"red",		"white", SLTT_BOLD_MASK},
     {"description",	GROUP_DESCR_COLOR,"magenta",	"white", 0},
     {"grouplens_display",GROUPLENS_DISPLAY_COLOR,"blue","white", 0},
     {"tilde",		SLRN_TILDE_COLOR,"green",	"white", SLTT_BOLD_MASK},
     {"header_name",SLRN_HEADER_KEYWORD_COLOR,"green", "white", SLTT_BOLD_MASK},
     {"response_char",RESPONSE_CHAR_COLOR,"green", "white", SLTT_BOLD_MASK},
     {"box", BOX_COLOR,"black", "white", 0},
     {"frame", FRAME_COLOR,"yellow", "blue", SLTT_REV_MASK},
     {"selection", SELECT_COLOR,"yellow", "blue", SLTT_BOLD_MASK},
   
     {NULL, -1, NULL, NULL, 0}
};

/*}}}*/

int slrn_set_object_color (char *name, char *fg, char *bg)
{
   Color_Handle_Type *ct = Color_Handles;

   while (ct->name != NULL)
     {
	if (!strcmp (ct->name, name))
	  {
	     SLtt_set_color (ct->value, name, fg, bg);
	     return 0;
	  }
	ct++;
     }
   
   slrn_error ("%s is not a color object", name);
   return -1;
}

static int color_fun (int argc, SLcmd_Cmd_Table_Type *table) /*{{{*/
{
   char *what = table->string_args[1];
   char *fg = table->string_args[2];
   char *bg = table->string_args[3];
   
   (void) argc;   
   if (-1 == slrn_set_object_color (what, fg, bg))
     exit_unknown_object ();
   return 0;
}

/*}}}*/

static int mono_fun (int argc, SLcmd_Cmd_Table_Type *table) /*{{{*/
{
   char *what = table->string_args[1];
   char *attr;
   int i;
   
   Color_Handle_Type *ct = Color_Handles;
   
   while (ct->name != NULL)
     {
	if (!strcmp (ct->name, what))
	  {
	     SLtt_Char_Type mono_attr = 0;
	     for (i = 2; i < argc; i++)
	       {
		  attr = table->string_args[i];
		  if (!strcmp (attr, "bold")) mono_attr |= SLTT_BOLD_MASK;
		  else if (!strcmp (attr, "blink")) mono_attr |= SLTT_BLINK_MASK;
		  else if (!strcmp (attr, "underline")) mono_attr |= SLTT_ULINE_MASK;
		  else if (!strcmp (attr, "reverse")) mono_attr |= SLTT_REV_MASK;
		  else if (!strcmp (attr, "none")) mono_attr = 0;
		  else exit_unknown_object ();
	       }
	     SLtt_set_mono (ct->value, NULL, mono_attr);
	     return 0;
	  }
	ct++;
     }
   exit_unknown_object ();
   return 0;
}

/*}}}*/

/*}}}*/

/*{{{ User Info Data (Hostname, etc) */

/*----------------------------------------------------------------------*\
* static int user_data_fun ();
 *
 * convenient mechanism to set Slrn_User_Info fields without adding
 * extra environment variables
 *
 * recognized fields
 *
 *   replyto		- alternative name for replies
 *   organization	- use double quotes if there are spaces!
 *   signature		- an alternate to ~/.signature (for news posting)
 *   hostname		- full name of the current host
\*----------------------------------------------------------------------*/

typedef struct /*{{{*/
{
   char *name;
   char **addr;
   unsigned int size;
}

/*}}}*/
User_Info_Variable_Type;

static User_Info_Variable_Type User_Info_Variables[] = /*{{{*/
{
     {"hostname", (char **)Slrn_User_Info.host, MAX_HOST_NAME_LEN},
     {"scorefile", &Slrn_Score_File, 0},

#define USER_INFO_OBSOLETE_STARTS_HERE 2
   /* The following are obsolete and will not be supported in the future. */
     {"username", &Slrn_User_Info.username, 0},
     {"realname", &Slrn_User_Info.realname, 0},
     {"replyto", &Slrn_User_Info.replyto, 0},
     {"organization", &Slrn_User_Info.org, 0},
     {"followup", &Slrn_User_Info.followup_string, 0},
     {"signature", &Slrn_User_Info.signature, 0},
     {"cc_followup_string", &Slrn_Courtesy_CC_Message, 0},
#if SLRN_HAS_DECODE
     {"decode_directory", &Slrn_Decode_Directory, 0},
#endif
     {"editor_command", &Slrn_Editor, 0},
     {"quote_string", NULL, 0},
     {NULL, NULL, 0}
};

/*}}}*/

static int user_data_fun (int argc, SLcmd_Cmd_Table_Type *table) /*{{{*/
{
   char *what = table->string_args[0];
   char *field = table->string_args[1];
   User_Info_Variable_Type *u = User_Info_Variables;
   char **ptr, *contents;
   unsigned int n;
   
   (void) argc;
   
   while (u->name != NULL)
     {
	if (!strcmp (u->name, what))
	  {
	     n = strlen (field);
	     
	     if (u->size)
	       {
		  contents = (char *) u->addr;
		  strncpy (contents, field, u->size);
		  contents [u->size - 1] = 0;
	       }
	     else if (NULL != (ptr = u->addr))
	       {
		  contents = safe_malloc (n + 1);
		  strcpy (contents, field);
		  
		  slrn_free (*ptr);
		  *ptr = contents;
	       }

	     if (u >= User_Info_Variables + USER_INFO_OBSOLETE_STARTS_HERE)
	       issue_obsolete_message ();
	     
	     return 0;
	  }
	u++;
     }
   exit_unknown_object ();
   return -1;
}

/*}}}*/

/*}}}*/

/*{{{ Server Newsrc Mapping Functions */

typedef struct Server_List_Type /*{{{*/
{
   struct Server_List_Type *next;
   char *file;
   char *host;
   char *username;
   char *password;
}

/*}}}*/
Server_List_Type;

static Server_List_Type *Server_List;

static Server_List_Type *find_server (char *host) /*{{{*/
{
   Server_List_Type *s;
   char *port;

   /* host may contain information about the port in the form "address:port".
    * First try to find a match with the port information.  If that fails, 
    * find a match without it.
    */
   host = slrn_safe_strmalloc (host);
   port = slrn_strchr (host, ':');

   while (1)
     {
	s = Server_List;
	while (s != NULL)
	  {
	     if (0 == slrn_case_strcmp ((unsigned char *)host, 
					(unsigned char *) s->host))
	       break;
	     s = s->next;
	  }

	if (s != NULL)
	  break;

	if (port == NULL)
	  break;
	
	/* Try again without port information */
	*port = 0;
	port = NULL;
     }

   slrn_free (host);
   return s;
}

/*}}}*/

static int add_to_server_list (char *host, char *file, char *username, char *password) /*{{{*/
{
   Server_List_Type *s;
   
   if (NULL == (s = find_server (host)))
     {
	s = (Server_List_Type *) safe_malloc (sizeof (Server_List_Type));
	memset ((char *) s, 0, sizeof (Server_List_Type));
	s->next = Server_List;
	Server_List = s;
	s->host = slrn_safe_strmalloc (host);
     }
   
   if (file != NULL)
     {
	slrn_free (s->file);
	s->file = slrn_safe_strmalloc (file);
     }

   if (username != NULL)
     {
	slrn_free (s->username);
	s->username = slrn_safe_strmalloc (username);
     }

   if (password != NULL)
     {
	slrn_free (s->password);
	s->password = slrn_safe_strmalloc (password);
     }
   
   return 0;
}

/*}}}*/

static int server_fun (int argc, SLcmd_Cmd_Table_Type *table) /*{{{*/
{
   char *the_file = table->string_args[2], *the_host = table->string_args[1];
      
   (void) argc;
   
   return add_to_server_list (the_host, the_file, NULL, NULL);
}

/*}}}*/

char *slrn_map_file_to_host (char *host) /*{{{*/
{
   Server_List_Type *s;
   
   if (NULL == (s = find_server (host)))
     return NULL;
   
   return s->file;
}

/*}}}*/

/*}}}*/

/*{{{ Server Authorization Information */

/*----------------------------------------------------------------------*\
* static int nnrp_fun ();
 *
 * convenient mechanism to set nnrp Slrn_User_Info fields without adding
 * extra environment variables
 *
 * recognized fields
 *
 *   nnrpaccess         - used to log in to a server using authinfo
 *                        it has the following format.
 *                         "host  username  password"
\*----------------------------------------------------------------------*/

static int nnrp_fun (int argc, SLcmd_Cmd_Table_Type *table) /*{{{*/
{
#if SLRN_HAS_NNTP_SUPPORT
   char *server = table->string_args[1];
   char *name = table->string_args[2];
   char *pass = table->string_args[3];

   (void) argc;
   return add_to_server_list (server, NULL, name, pass);
#else
   (void) argc;
   (void) table;
   return 0;
#endif   
}
/*}}}*/

int slrn_get_authorization (char *host, char **name, char **pass) /*{{{*/
{
   Server_List_Type *s;
   char buf[256];
   
   *name = NULL;
   *pass = NULL;
   
   s = find_server (host);

   if (s == NULL)
     return 0;
   
   if ((s->username == NULL) || (s->password == NULL))
     return 0;
   
   if (*s->username == 0)
     {
	*buf = 0;
	if (-1 == slrn_read_input ("Username", NULL, buf, 1, 0))
	  return -1;
	SLFREE (s->username);
	s->username = slrn_safe_strmalloc (buf);
     }

   if (*s->password == 0)
     {
	*buf = 0;
	if (-1 == slrn_read_input_no_echo ("Password", NULL, buf, 1, 0))
	  return -1;
	SLFREE (s->password);
	s->password = slrn_safe_strmalloc (buf);
     }

   *name = s->username;
   *pass = s->password;

   return 0;
}

/*}}}*/

/*}}}*/

static void slrn_init_modes (void) /*{{{*/
{
   slrn_init_group_mode ();
   slrn_init_article_mode ();
}

/*}}}*/

void slrn_startup_initialize (void) /*{{{*/
{
   Color_Handle_Type *h;
   
   slrn_init_modes ();
   SLang_init_case_tables ();
   
   Slrn_Ignore_Quote_Regexp[0] = compile_quote_regexp ("^ ?[:>]");
   
   h = Color_Handles;
   while (h->name != NULL)
     {
	SLtt_set_color (h->value, NULL, h->fg, h->bg);
	SLtt_set_mono (h->value, NULL, h->mono);
	h++;
     }

#if !defined(IBMPC_SYSTEM)
   /* We are not using the blink characters (unless in mono) */
   SLtt_Blink_Mode = 0;
#endif

   /* The following are required by GNKSA */
   (void) slrn_set_visible_headers ("From:,Subject:,Newsgroups:,Followup-To:,Reply-To:");
				       
   (void) slrn_set_header_format (0, "%F%-5S%G%-5l:[%12r]%t%s");
   (void) slrn_set_header_format (1, "%F%G%-5l:[%12r]%t%s");
   (void) slrn_set_header_format (2, "%F%-5l:%t%s");
   (void) slrn_set_header_format (3, "%F%-5S%-5l:%t%50s %r");
   
}


/*}}}*/

int slrn_read_startup_file (char *name) /*{{{*/
{
   FILE *fp;
   char file [SLRN_MAX_PATH_LEN];
   char line [512];
   SLPreprocess_Type pt;
   int save_this_line_num;
   char *save_this_file;
   char *save_this_line;

   if (-1 == slrn_init_readline ())
     {
	slrn_exit_error ("Unable to initialize S-Lang readline library.");
     }
   

   if (-1 == SLprep_open_prep (&pt))
     {
	slrn_exit_error ("Error initializing S-Lang preprocessor.");
     }
   
   
   fp = slrn_open_home_file (name, "r", file, 0);
   if (fp == NULL) return -1;
   
   slrn_message ("Reading startup file %s.", file);
   
   save_this_file = This_File;
   save_this_line = This_Line;
   save_this_line_num = This_Line_Num;

   This_File = file;
   This_Line = line;
   This_Line_Num = 0;
   
   Slrn_Cmd_Table.table = Slrn_Startup_File_Cmds;
   
   while (NULL != fgets (line, sizeof(line) - 1, fp))
     {
	This_Line_Num++;
	if (SLprep_line_ok (line, &pt))
	  (void) SLcmd_execute_string (line, &Slrn_Cmd_Table);
	
	if (SLang_Error) exit_unknown_object ();
     }
   slrn_fclose (fp);
   
   SLprep_close_prep (&pt);
   
   if ((Server_Object != NULL)
       && (-1 == (Slrn_Default_Server_Obj = slrn_map_name_to_object_id (0, Server_Object))))
     slrn_exit_error ("Server object '%s' is not supported.", Server_Object);
   
   if ((Post_Object != NULL) 
       && (-1 == (Slrn_Default_Post_Obj = slrn_map_name_to_object_id (1, Post_Object))))
     slrn_exit_error ("Post object '%s' is not supported.", Post_Object);
   
   This_File = save_this_file;
   This_Line = save_this_line;
   This_Line_Num = save_this_line_num;
   return 0;
}

/*}}}*/

static int include_file_fun (int argc, SLcmd_Cmd_Table_Type *table)
{
   char *file;
   
   (void) argc;
   
   file = table->string_args [1];

   if (-1 == slrn_read_startup_file (file))
     slrn_exit_error ("%s: line %d:\n%sFile not opened: %s",
		      This_File, This_Line_Num, This_Line, file);

   return 0;
}

     
static int interpret_fun (int argc, SLcmd_Cmd_Table_Type *table) /*{{{*/
{
#if SLRN_HAS_SLANG
   char *file = table->string_args [1];
   
   (void) argc;
   if (Slrn_Use_Slang == 0) return 0;
   return slrn_eval_slang_file (file);
#else
   (void) argc;
   return 0;
#endif
}

/*}}}*/

