/*
 *	Copyright (C) 1984, 1985  SRI International
 *	Copyright (C) 1989, 1990, 1991, 1993  TGV, Incorporated
 *
 *	Read in the INIT file (mm.init)
 *
 */
#include "comnd.h"
#include <stdio.h>
#include "vax-mm.h"  /* must _follow_ stdio.h for local_printf to be used! */

static Do_Init_File1();
static char *savestr();
static int Init_Key(), Init_String_Extended_Lines(), Set_Personal_Name(),
	   Setup_Delivery_To_MM();

extern Setup_More_Processing();

int Set_Changes = 0;		/* Has someone changed any variables? */


/*
 *	Init keyword data (used to parse what follows a given keyword)
 */
static struct init_data {
	int code;				/* Data Type		 */
#define NUMBER		0				/* A number	 */
#define STRING		1				/* A string	 */
#define ROUTINE		2				/* A routine	 */
	int data1;				/* Data1		 */
	int *data2;				/* Data2		 */
	char *Help;				/* Help string		 */
	}

#define SIZE(string) (sizeof(string)-1)

Init_Bboard_Dont_Type_Headers =
	{ROUTINE,	(int)&Bboard_Suppress_Headers,	(int *)Init_Key,
"SET BBOARD-DONT-TYPE-HEADERS takes a keyword list as an argument, and\n\
specifies a list of header keywords which should be suppressed by\n\
TYPE and related commands when a BBOARD is being read.\n"},

Init_Bboard_Only_Type_Headers =
	{ROUTINE,	(int)&Bboard_Only_Type_Headers,(int *)Init_Key,
"SET BBOARD-ONLY-TYPE-HEADERS takes a keyword list as an argument, and\n\
specifies a list of headers that are the only ones to be typed\n\
out by TYPE and related commands when a BBOARD is being read.\n"},

Init_Blank_Screen_Startup =
	{NUMBER,	0,			&Do_Blank_Screen,
"SET BLANK-SCREEN-STARTUP takes a numeric argument.  If non-zero,\n\
the default, the screen is cleared at startup and before each\n\
message typed out when in READ mode.\n"},

Init_Control_E_Editor =
	{NUMBER,	0,			&Control_E_Editor,
"SET CONTROL-E-EDITOR takes a numeric argument.  If negative, never\n\
enter the editor on ^E; if zero, ask if should enter the editor; if\n\
positive, the default, always enter the editor.\n"},

Init_Control_N_Abort =
	{NUMBER,	0,			&Control_N_Abort,
"SET CONTROL-N-ABORT takes a numeric argument.  If negative, never\n\
abort on ^N; if zero, the default, ask if should abort; if\n\
positive, always abort.\n"},

Init_Dead_Letter_File =
	{STRING,	SIZE(Dead_Letter_File),	(int *)Dead_Letter_File,
"SET DEAD_LETTER_FILE takes a file name argument, and specifies a\n\
new file into which an outgoing message is copied on a mail submission\n\
failure.  This is useful for backup purposes if you didn't save a copy\n\
of a message which the mail system rejected for submission.  The default\n\
is DEAD.LETTER in your login directory.\n"},

Init_Default_Bboard =
	{STRING,	SIZE(Default_Bboard),	(int *)Default_Bboard,
"SET DEFAULT-BBOARD takes a string of up to 47 characters, which is\n\
used as the default argument to the BBOARD command.  If no string\n\
is specified, this defaults to BBOARD:MAIL.TXT\n"},

Init_Default_BCC_List =
	{STRING,	SIZE(Default_BCC_List), (int *)Default_BCC_List,
"SET DEFAULT-BCC-LIST takes a list of addresses as an argument,\n\
and specifies a default list to always bcc your outgoing messages\n\
to.\n"},

Init_Default_CC_List =
	{STRING,	SIZE(Default_CC_List),	(int *)Default_CC_List,
"SET DEFAULT-CC-LIST takes a list of addresses as an argument, and\n\
specifies a default list to always cc your outgoing messages to.\n"},

Init_Delivery_To_MM =
	{NUMBER,	0,			&Delivery_To_MM,
"SET DELIVERY-TO-MM takes a numeric argument.  If one, the default,\n\
the MultiNet SMTP delivery system will deliver all incoming mail to MM.\n\
If zero, all incoming mail will be sent to your VMS MAIL mailbox.\n\
Setting this option to zero allows users to be able to send mail via MM,\n\
but causes all inbound mail to be delivered via VMS MAIL.\n"},

Init_Dont_Complete_Usernames =
	{NUMBER,	0,			&Dont_Complete_Usernames,
"SET DONT-COMPLETE-USERNAMES takes a single numeric argument.  If\n\
non-zero, MM will not attempt to complete a partially specified local\n\
username.  On machines with large numbers of users, this may make MM\n\
significantly faster.\n"},

Init_Dont_Display_Restored_Draft =
	{NUMBER,	0,			&Dont_Display_Restored_Draft,
"SET DONT-DISPLAY-RESTORED-DRAFT takes a single numeric argument.  If\n\
non-zero, MM will not display a draft letter restored with the RESTORED-DRAFT\n\
command.\n"},

Init_Dont_Do_Locking =
	{NUMBER,	0,			&Dont_Do_Locking,
"SET DONT-DO-LOCKING takes a numeric argument.  If zero, the default,\n\
MM will do locking to prevent a user from running MM under a single userid\n\
more than once on a system (or within a VAXcluster).  If non-zero, MM will\n\
not do any locking.\n"},

Init_Dont_Ignore_Bad_Addresses =
	{NUMBER,	0,			&Dont_Ignore_Bad_Addresses,
"SET DONT-IGNORE-BAD-ADDRESSES takes a single numeric argument.  If\n\
non-zero, MM will completely reject lines containing ANY bad address.\n\
If zero, the default, MM will reject just the bad address in the line.\n"},

Init_Dont_Insert_Message_ID =
	{NUMBER,	0,			&Dont_Insert_Message_ID,
"SET DONT-INSERT-MESSAGE-ID takes a single numeric argument.  If\n\
non-zero, MM does not insert the \"Message-ID:\" field in outgoing\n\
messages.  Zero, the default, inserts the \"Message-ID:\" field in\n\
outgoing messages\n"},

Init_Dont_Load_System_Init_File =
	{NUMBER,	0,			&Dont_Load_System_Init_File,
"SET DONT-LOAD-SYSTEM-INIT-FILE takes a single numeric argument.  If\n\
non-zero, the system-wide MM initialization file is NOT loaded.\n"},

Init_Dont_Type_Headers =
	{ROUTINE,	(int)&Suppress_Headers, (int *)Init_Key,
"SET DONT-TYPE-HEADERS takes a keyword list as an argument, and\n\
specifies a list of header keywords which should be suppressed by\n\
TYPE and related commands.\n"},

Init_Editor_Invocation_Command =
	{STRING,	SIZE(Editor_Invocation_Command),
						(int *)Editor_Invocation_Command,
"SET EDITOR-INVOCATION-COMMAND takes a string which specifies the command\n\
that will invoke the editor.  \"%s\" should be placed in the string in the\n\
position where the temporary file name is to be inserted.\n"},

Init_Escape_Automatic_Send =
	{NUMBER,	0,			&Escape_Automatic_Send,
"SET ESCAPE-AUTOMATIC-SEND takes a numeric argument.  If zero, the\n\
default, then both escape and ^Z in message text input mode will\n\
return to send level unless MM was invoked from DCL via a command\n\
such as \"MM SEND\", in which case escape enters send level and ^Z\n\
sends the message.  If positive, then escape sends the message and\n\
^Z returns to send level.  If negative, then ^Z sends the message and\n\
escape returns to send level.\n"},

Init_Flagged_Messages_Autotype =
	{NUMBER,	0,			&Flagged_Autotype_Suppress,
"SET FLAGGED-MESSAGES-AUTOTYPE-SUPPRESS takes a numeric\n\
argument.  If non-zero, flagged messages are not automatically\n\
shown when an automatic headers list of recent messages is done\n\
(e.g. when reading in a mail file or if new messages come in).\n\
The default is zero.\n"},

Init_Header_Options =
	{ROUTINE,	(int)User_Header_Str,	(int *)Init_String_Extended_Lines,
"SET HEADER-OPTIONS takes a text line as an argument and specifies\n\
a header to be inserted by default in a message.\n"},

Init_Keywords =
	{ROUTINE,	(int)&Key_Table,	(int *)Init_Key,
"SET KEYWORDS takes a keyword list as an argument, and specifies a\n\
list of keywords by which you wish to tag your messages using the\n\
KEYWORD command.\n"},

Init_List_Confirm_Suppress =
	{NUMBER,	0,			&List_Confirm_Suppress,
"SET LIST-CONFIRM-SUPPRESS take a single numeric argument.  If\n\
zero, the default, LIST commands require a confirmation before\n\
outputting to the list device (typically the lineprinter).  If\n\
non-zero no confirmation is required.\n"},

Init_List_Device =
	{STRING,	SIZE(List_Device),	(int *)List_Device,
"SET LIST-DEVICE takes a device name and specifies the device to\n\
use for the LIST command.  The default is LPT:.\n"
},

Init_Spool_To_List_Device =
	{NUMBER,	0,			&Spool_To_List_Device,
"SET SPOOL-TO-LIST-DEVICE takes a numberic argument.  If non-zero,\n\
the \"SPL\" bit is set in the FAB options word when creating a listing\n\
file.  This causes the file to be spooled to the SYS$PRINT queue when it\n\
is closed.  DO NOT set this flag non-zero if the device specified by\n\
LIST-DEVICE is itself set spooled.\n"
},

Init_List_Include_Headers =
	{NUMBER,	0,			&List_Include_Headers,
"SET LIST-INCLUDE-HEADERS takes a numeric argument.  If non-zero,\n\
the default, output a list of headers at the beginning of a\n\
listing made by the LIST command.\n"},

Init_List_On_Separate_Pages =
	{NUMBER,	0,			&List_On_Separate_Pages,
"SET LIST-ON-SEPARATE-PAGES takes a numeric argument.  If\n\
non-zero, each message is listed on a separate page.  The default\n\
is zero.\n"},

Init_Local_Host_Name =
	{STRING,	SIZE(This_Hosts_Name),	(int *)This_Hosts_Name,
"SET LOCAL-HOST-NAME takes a string which specifies the official name of\n\
the local host.\n"},

Init_Mail_Copy_File =
	{STRING,	SIZE(Mail_Copy_File),	(int *)Mail_Copy_File,
"SET MAIL-COPY-FILE takes a file name argument, and specifies a\n\
new file into which the text of an outgoing message is copied.\n\
This differs from a SAVED-MESSAGES-FILE in that a mail copy file is\n\
a temporary file, consists solely of the text of the message text\n\
(e.g. does not include the message header), and an individual\n\
copy is made for each message.  This is useful for backup purposes\n\
or for sending the same message to multiple recipients under\n\
separate cover.  A common value for this filename SYS$LOGIN:MAIL.CPY\n\
a null name disables this feature.\n"},

Init_Mark_Deleted_Messages =
	{NUMBER,	0,			&Mark_Deleted_Messages,
"SET MARK-DELETED-MESSAGES takes a number.  If non-zero, when a deleted,\n\
unseen message is attempted to be read, it will be marked as being seen\n\
even though it will not be displayed.\n"},

Init_Message_Sequence_Prompt =
	{STRING,	SIZE(Msg_Seq_Prompt),	(int *)Msg_Seq_Prompt,
"SET MESSAGE-SEQUENCE-PROMPT takes a string argument and specifies\n\
the prompt meaning you're in msg-sequence mode.  The default is\n\
M>.\n"},

Init_More_Processing =
	{NUMBER,	0,			&More_Processing,
"SET MORE-PROCESSING takes a number.  If non-zero, more processing\n\
(stopping after each page is full and waiting for a <space> to be typed) is\n\
turned on.\n"},

Init_New_File_Protection =
	{NUMBER,	0,			&Mail_File_Mode,
"SET NEW-FILE-PROTECTION takes a decimal UNIX protection code as an\n\
argument and specifies the default protection to be given to text\n\
files created by MOVE, COPY, etc.  The default is the system\n\
default protection.\n"},

Init_New_Style_Parsing =
	{NUMBER,	0,			&New_Style_Parsing,
"SET NEW-STYLE-PARSING determines whether the old TOPS-style address\n\
parsing should be used (value zero) or whether the new address parsing\n\
routines should be used (non-zero value).\n"},

Init_Only_Type_Headers =
	{ROUTINE,	(int)&Only_Type_Headers,(int *)Init_Key,
"SET ONLY-TYPE-HEADERS takes a keyword list as an argument, and\n\
specifies a list of headers that are the only ones to be typed\n\
out by TYPE and related commands.\n"},

Init_Personal_Name =
	{ROUTINE,	(int)&Personal_Name,	(int *)Set_Personal_Name,
"SET PERSONAL-NAME takes a string argument and specifies a personal\n\
name to be included in the From: item in outgoing mail messages.  If\n\
this string is not specified in valid RFC 822 format, MM will quote\n\
the personal name as appropriate.  The default is no personal name.\n"},

Init_POP3_Check_Interval =
	{NUMBER,	0,			&POP3_Check_Interval,
"POP3-CHECK-INTERVAL takes a single numeric argument.  If less than zero,\n\
MM will do a one time check of POP3-SERVER-HOST for new mail during startup\n\
of the MM session.  If greater than zero, POP-CHECK-INTERVAL specifies, in\n\
minutes, the time interval to automatically check for new mail on\n\
POP3-SERVER-HOST.  If zero, the default, no automatic POP3 mail check is\n\
performed.\n"},

Init_POP3_Debug =
	{NUMBER,	0,			&POP3_Debug,
"POP3-DEBUG takes a single numeric argument.  If non-zero, the dialogue\n\
between the POP3 client and server is displayed.\n"},

Init_POP3_No_Delete =
	{NUMBER,	0,			&POP3_No_Delete,
"POP3-NO-DELETE take single numeric argument.  If non-zero, messages\n\
retrieved via POP3 will NOT be deleted on the remote host.  If\n\
POP3-NO-DELETE is zero (the default), the messages will be deleted from\n\
the remote POP3 mailbox.\n"},

Init_POP3_Server_Host =
	{STRING,	SIZE(POP3_Server_Host), (int *)POP3_Server_Host,
"POP3-SERVER-HOST takes a string which specifies the name of the remote\n\
POP3 server host.  Mail will be downloaded from the specified host via\n\
POP3 (Post Office Protocol Version 3)\n"},

Init_POP3_User_Name =
	{STRING,	SIZE(POP3_User_Name),	(int *)POP3_User_Name,
"POP3-USER-NAME takes a string which specifies the remote username to use\n\
when retrieving mail from host specified by POP3-SERVER-HOST.  If\n\
POP3-USER-NAME is not specified, the lowercase VMS username is the default.\n"},

Init_Print_Debugging_Info =
	{NUMBER,	0,			&Print_Debugging_Info,
"SET PRINT-DEBUGGING-INFORMATION takes a numeric argument.  If non-zero,\n\
then debugging information will be printed as MM executes.\n"},

Init_Print_Jobs_Immed_Info =
	{NUMBER,	0,			&Print_Jobs_Immediately,
"SET PRINT-JOBS-IMMEDIATELY takes a numeric argument.  If non-zero,\n\
then all print jobs will be immediately submitted.  Otherwise, all\n\
print jobs are batched to print at exit.\n"},

Init_Print_Queue =
	{STRING,	SIZE(Print_Queue),	(int *)Print_Queue,
"SET PRINT-QUEUE takes a string argument and specifies the default\n\
queue to use if none is specified in a PRINT command.\n"},

Init_Print_Form =
	{STRING,	SIZE(Print_Form),	(int *)Print_Form,
"SET PRINT-FORM takes a string argument and specifies the default\n\
form to use if none is specified in a PRINT command.\n"},

Init_Prompt_For_BCC =
	{NUMBER,	0,			&Prompt_For_BCC,
"SET PROMPT-FOR-BCC takes a numeric argument.  If non-zero, then\n\
bcc recipients will be prompted for in the SEND command.\n"},

Init_Push_On_Control_C =
	{NUMBER,	0,			&Push_On_Control_C,
"SET PUSH-ON-CONTROL-C takes a number.  If non-zero, MM will do a \"PUSH\"\n\
on receipt of a ^C interrupt rather than quitting\n"},

Init_Quit_Is_Synonym_For_Push =
	{NUMBER,	0,			&Quit_Is_Synonym_For_Push,
"SET QUIT-IS-SYNONYM-FOR-PUSH takes a number.  If non-zero, the \"QUIT\"\n\
command becomes a synonym for the \"PUSH\" command.\n"},

Init_Read_Prompt =
	{STRING,	SIZE(Read_Prompt),	(int *)Read_Prompt,
"SET READ-PROMPT takes a string argument and specifies the prompt\n\
meaning you're in read mode.  The default is R>.\n"},

Init_Read_Receipt_Reply =
	{NUMBER,	0,			&Read_Receipt_Reply,
"SET READ-RECEIPT-REPLY takes a numeric argument.  If zero, the default,\n\
when a message with a read receipt requested header in it is read, MM\n\
will ask whether or not you wish to have a read receipt notification\n\
message sent to the sender.  If greater than zero, MM will automatically\n\
send a read receipt notification message back to the sender of the message.\n\
If less than zero, MM will never send read receipt notification messages.\n"},

Init_Reply_CC_Others =
	{NUMBER,	0,			&Reply_CC_Others,
"SET REPLY-CC-OTHERS takes a numeric argument.  If non-zero, the\n\
default, REPLY to ALL cc's everyone other than from.  If zero,\n\
then people in the to-list are to'd, not cc'd.	Most people find\n\
it confusing to receive a reply when the to-list has other than\n\
the from address being replied to.\n"},

Init_Reply_Include_Me =
	{NUMBER,	0,			&Reply_Include_Me,
"SET REPLY-INCLUDE-ME takes a numeric argument.  If non-zero,\n\
your username will always be included in replies.  If zero, the\n\
default, you aren't included in replies.\n"},

Init_Reply_Initial_Display =
	{NUMBER,	0,			&Reply_Initial_Display,
"SET REPLY-INITIAL-DISPLAY takes a numeric argument.  If non-zero\n\
then display text of reply initially.  The default is zero.\n"},

Init_Reply_InsCurMsg_Default =
	{NUMBER,	0,			&Reply_Insert_Current_Msg,
"SET REPLY-INSERT-CURRENT-MESSAGE-DEFAULT takes a numeric\n\
argument.  If non-zero then insert the current message into a\n\
reply by default.  The default is zero.\n"},

Init_Reply_Leading_String =
	{STRING,	SIZE(Reply_Leading_String), (int *)Reply_Leading_String,
"SET REPLY-LEADING-STRING takes a string argument, and specifies the\n\
string that you want to have inserted at the beginning of each line of\n\
the INCLUDEd message to which you are REPLYing.  Defaults to a tab.\n"},

Init_Reply_Sender_Only_Default =
	{NUMBER,	0,			&Reply_Sender_Only_Default,
"SET REPLY-SENDER-ONLY-DEFAULT takes a numeric argument.  If\n\
non-zero, the default, then default to replying only to the\n\
sender of the message.\n"},

Init_Saved_Messages_File =
	{STRING,	SIZE(Saved_Messages_File), (int *)Saved_Messages_File,
"SET SAVED-MESSAGES-FILE takes a file name argument, and specifies\n\
a file to receive copies of your outgoing messages.  The file is\n\
written in mail file format; you can use MM's GET command to read\n\
a SAVED-MESSAGES-FILE.	If the file does not already exist MM\n\
will ask if you want to create it.\n"},

Init_Send_Prompt =
	{STRING,	SIZE(Send_Prompt),	(int *)Send_Prompt,
"SET SEND-PROMPT takes a string argument and specifies the prompt\n\
meaning you're in send mode.  The default is S>.\n"},

Init_Send_Return_Sends =
	{NUMBER,	0,			&Send_Return_Sends,
"SET SEND-RETURN-SENDS takes a numeric argument.  If zero, the default,\n\
there is no default command at SEND level so an explicit SEND command\n\
must be done to send the message.  If non-zero, the default command at\n\
SEND level is SEND, so that just return will send the message.\n"},

Init_Short_Message_Length =
	{NUMBER,	0,			&Short_Message_Length,
"SET SHORT-MESSAGE-LENGTH takes a decimal numeric argument and specifies\n\
the default message length in characters separating \"short\" and \"long\"\n\
messages.  The default is 1500 characters.\n"},

Init_Signature_File =
	{STRING,	SIZE(Signature_File),	(int *)Signature_File,
"SET SIGNATURE-FILE takes a file name argument, and specifies\n\
a file to be included at the end of each message that you send.\n\
Normally, this file will contain signature information along with\n\
information on how the recipient can reach you (electronic mail\n\
address, phone number, postal address, etc).\n"},

Init_Simple_Editor =
	{NUMBER,	0,			&Simple_Editor,
"SET SIMPLE-EDITOR takes a single numeric argument.  If non-zero,\n\
the editor invoked by EDITOR-INVOCATION-COMMAND is a simple editor,\n\
such as \"vi\", enabling the simple editor interface.  Zero, the default,\n\
indicates that a programmable editor with an appropriate MACRO package,\n\
like \"emacs\" with MM MACROS, is to be invoked.\n"},

Init_Spell_Invocation_Command =
	{STRING,	SIZE(Spell_Invocation_Command),
						(int *)Spell_Invocation_Command,
"SET SPELL-INVOCATION-COMMAND takes a string which specifies the command\n\
that will invoke a spell checker on the current input text.  \"%s\" should\n\
be placed in the string in the position where the temporary file name is to\n\
be inserted.\n"},

Init_Terse_Text_Prompt =
	{NUMBER,	0,			&Terse_Text_Prompt,
"SET TERSE-TEXT-PROMPT takes a single numeric argument.  If zero,\n\
the default, MM prompts for message text input with a list of the\n\
various control characters to exit text input and what they do.\n\
If non-zero, MM simply prompts with \"Msg:\".\n"},

Init_Top_Level_Prompt =
	{STRING,	SIZE(Top_Level_Prompt), (int *)Top_Level_Prompt,
"SET TOP-LEVEL-PROMPT takes a string argument and specifies the\n\
prompt meaning you're at top level.  The default is MM>.\n"},

Init_Use_Editor_Automatically =
	{NUMBER,	0,			&Use_Editor_Automatically,
"SET USE-EDITOR-AUTOMATICALLY takes a numeric argument.  If\n\
non-zero, then go straight into the editor on any message text\n\
input.	If zero, the default, go into normal text input allowing\n\
the editor by command.\n"},

Init_User_Headers =
	{ROUTINE,	(int)&User_Headers,	(int *)Init_Key,
"SET USER-HEADERS takes a keyword list as an argument, and\n\
specifies a list of special headers you may want to generate.\n\
The send-mode USER-HEADER command will add it to the current\n\
message.\n"},

Init_User_Name =
	{STRING,	SIZE(User_Name),	(int *)User_Name,
"SET USER-NAME takes a user name string and defaults to your\n\
logged-in user name.  This variable is MM's internal idea of your\n\
\"login user name\".  You are not allowed to set this variable to\n\
other than your \"real\" user name (your logged-in name or as\n\
established by ALIAS).	It is acceptable to use SET USER-NAME to\n\
specify how your user name should be cased in outgoing mail\n\
(e.g. user SMITH may want to do \"SET USER-NAME Smith\").\n"};

#undef	SIZE


/*
 *	Init Keyword table
 */

struct {
	int current_entries;
	int maximum_entries;
	struct tbluk_keyword keywords[68];
	} Init_Table = {
	68,68,
	{{0,	"BBOARD-DONT-TYPE-HEADERS",	(int)&Init_Bboard_Dont_Type_Headers},
	 {0,	"BBOARD-ONLY-TYPE-HEADERS",	(int)&Init_Bboard_Only_Type_Headers},
	 {0,	"BLANK-SCREEN-STARTUP",	(int)&Init_Blank_Screen_Startup},
	 {COMND_INVISIBLE,	"CONTROL-E-EDITOR",	(int)&Init_Control_E_Editor},
	 {COMND_INVISIBLE,	"CONTROL-N-ABORT",	(int)&Init_Control_N_Abort},
	 {0,	"DEAD-LETTER-FILE",	(int)&Init_Dead_Letter_File},
	 {0,	"DEFAULT-BBOARD",	(int)&Init_Default_Bboard},
	 {0,	"DEFAULT-BCC-LIST",	(int)&Init_Default_BCC_List},
	 {0,	"DEFAULT-CC-LIST",	(int)&Init_Default_CC_List},
	 {0,	"DELIVERY-TO-MM",	(int)&Init_Delivery_To_MM},
	 {0,	"DONT-COMPLETE-USERNAMES",	(int)&Init_Dont_Complete_Usernames},
	 {0,	"DONT-DISPLAY-RESTORED-DRAFT",	(int)&Init_Dont_Display_Restored_Draft},
	 {0,	"DONT-DO-LOCKING",	(int)&Init_Dont_Do_Locking},
	 {0,	"DONT-IGNORE-BAD-ADDRESSES",	(int)&Init_Dont_Ignore_Bad_Addresses},
	 {0,	"DONT-INSERT-MESSAGE-ID",	(int)&Init_Dont_Insert_Message_ID},
	 {(COMND_INVISIBLE),	"DONT-LOAD-SYSTEM-INIT-FILE",	(int)&Init_Dont_Load_System_Init_File},
	 {0,	"DONT-TYPE-HEADERS",	(int)&Init_Dont_Type_Headers},
	 {0,	"EDITOR-INVOCATION-COMMAND",	(int)&Init_Editor_Invocation_Command},
	 {0,	"ESCAPE-AUTOMATIC-SEND",	(int)&Init_Escape_Automatic_Send},
	 {0,	"FLAGGED-MESSAGES-AUTOTYPE-SUPPRESS",	(int)&Init_Flagged_Messages_Autotype},
	 {0,	"HEADER-OPTIONS",	(int)&Init_Header_Options},
	 {0,	"KEYWORDS",	(int)&Init_Keywords},
	 {0,	"LIST-CONFIRM-SUPPRESS",	(int)&Init_List_Confirm_Suppress},
	 {0,	"LIST-DEVICE",	(int)&Init_List_Device},
	 {0,	"LIST-INCLUDE-HEADERS",	(int)&Init_List_Include_Headers},
	 {0,	"LIST-ON-SEPARATE-PAGES",	(int)&Init_List_On_Separate_Pages},
	 {(COMND_INVISIBLE),	"LOCAL-HOST-NAME",	(int)&Init_Local_Host_Name},
	 {0,	"MAIL-COPY-FILE",	(int)&Init_Mail_Copy_File},
	 {0,	"MARK-DELETED-MESSAGES",	(int)&Init_Mark_Deleted_Messages},
	 {0,	"MESSAGE-SEQUENCE-PROMPT",	(int)&Init_Message_Sequence_Prompt},
	 {0,	"MORE-PROCESSING",	(int)&Init_More_Processing},
	 {0,	"NEW-FILE-PROTECTION",	(int)&Init_New_File_Protection},
	 {0,	"NEW-STYLE-PARSING",	(int)&Init_New_Style_Parsing},
	 {0,	"ONLY-TYPE-HEADERS",	(int)&Init_Only_Type_Headers},
	 {0,	"PERSONAL-NAME",	(int)&Init_Personal_Name},
	 {0,	"POP3-CHECK-INTERVAL",	(int)&Init_POP3_Check_Interval},
	 {0,	"POP3-DEBUG",	(int)&Init_POP3_Debug},
	 {0,	"POP3-NO-DELETE",	(int)&Init_POP3_No_Delete},
	 {0,	"POP3-SERVER-HOST",	(int)&Init_POP3_Server_Host},
	 {0,	"POP3-USER-NAME",	(int)&Init_POP3_User_Name},
	 {0,	"PRINT-DEBUGGING-INFORMATION",	(int)&Init_Print_Debugging_Info},
	 {0,	"PRINT-FORM",	(int)&Init_Print_Form},
	 {0,	"PRINT-JOBS-IMMEDIATELY",	(int)&Init_Print_Jobs_Immed_Info},
	 {0,	"PRINT-QUEUE",	(int)&Init_Print_Queue},
	 {0,	"PROMPT-FOR-BCC",	(int)&Init_Prompt_For_BCC},
	 {0,	"PUSH-ON-CONTROL-C",	(int)&Init_Push_On_Control_C},
	 {0,	"QUIT-IS-SYNONYM-FOR-PUSH",	(int)&Init_Quit_Is_Synonym_For_Push},
	 {0,	"READ-PROMPT",	(int)&Init_Read_Prompt},
	 {0,	"READ-RECEIPT-REPLY",	(int)&Init_Read_Receipt_Reply},
	 {0,	"REPLY-CC-OTHERS",	(int)&Init_Reply_CC_Others},
	 {0,	"REPLY-INCLUDE-ME",	(int)&Init_Reply_Include_Me},
	 {0,	"REPLY-INITIAL-DISPLAY",	(int)&Init_Reply_Initial_Display},
	 {0,	"REPLY-INSERT-CURRENT-MESSAGE-DEFAULT",	(int)&Init_Reply_InsCurMsg_Default},
	 {0,	"REPLY-LEADING-STRING",	(int)&Init_Reply_Leading_String},
	 {0,	"REPLY-SENDER-ONLY-DEFAULT",	(int)&Init_Reply_Sender_Only_Default},
	 {0,	"SAVED-MESSAGES-FILE",	(int)&Init_Saved_Messages_File},
	 {0,	"SEND-PROMPT",	(int)&Init_Send_Prompt},
	 {0,	"SEND-RETURN-SENDS",	(int)&Init_Send_Return_Sends},
	 {0,	"SHORT-MESSAGE-LENGTH",	(int)&Init_Short_Message_Length},
	 {0,	"SIGNATURE-FILE",	(int)&Init_Signature_File},
	 {0,	"SIMPLE-EDITOR",	(int)&Init_Simple_Editor},
	 {0,	"SPELL-INVOCATION-COMMAND",	(int)&Init_Spell_Invocation_Command},
	 {0,	"SPOOL-TO-LIST-DEVICE",	(int)&Init_Spool_To_List_Device},
	 {0,	"TERSE-TEXT-PROMPT",	(int)&Init_Terse_Text_Prompt},
	 {0,	"TOP-LEVEL-PROMPT",	(int)&Init_Top_Level_Prompt},
	 {0,	"USE-EDITOR-AUTOMATICALLY",	(int)&Init_Use_Editor_Automatically},
	 {0,	"USER-HEADERS",	(int)&Init_User_Headers},
	 {0,	"USER-NAME",	(int)&Init_User_Name}}};

/*
 *
 *	Initialize world
 *
 */
Init()
{
	char *cp;

	/*
	 *	Set the default options
	 */
	Do_Blank_Screen = -1;		/* Blank screen on startup	*/
	List_Include_Headers = -1;	/* Output headers in listings	*/
	Escape_Automatic_Send = 0;	/* No escape send automatically */
	Reply_Sender_Only_Default = -1; /* repl<cr> = just reply to from*/
	Delivery_To_MM = 1;		/* Do mail delivery to MM	*/
	Dont_Complete_Usernames = -1;	/* Don't complete from SYSUAF	*/
	Dont_Do_Locking = 0;		/* Don't do locking		*/
	Second_MM_Invocation = 0;	/* 2nd or greater MM?		*/
	Send_Return_Sends = 0;		/* Don't make <CR> send automatically */
	Mark_Deleted_Messages = 0;	/* Don't mark deleted messages	*/

	Personal_Name[0] = '\0';

	Reply_Leading_String[0] = '\t';

	Top_Level_Prompt[0] = 'M';
	Top_Level_Prompt[1] = 'M';
	Top_Level_Prompt[2] = '>';

	Msg_Seq_Prompt[0] = 'M';
	Msg_Seq_Prompt[1] = '>';

	Send_Prompt[0] = 'S';
	Send_Prompt[1] = '>';

	Read_Prompt[0] = 'R';
	Read_Prompt[1] = '>';
	bzero(POP3_Server_Host, sizeof(POP3_Server_Host));
	bzero(POP3_User_Name, sizeof(POP3_User_Name));
	POP3_Debug = 0;
    	New_Style_Parsing = 0;

	User_From_String[0] = '\0';
	User_Reply_To_String[0] = '\0';

	Print_Form[0] = '\0';
	Print_Queue[0] = '\0';

	strcpy(List_Device,"LPA0:MM.LIS");

	/*
	 *	Default dead letter filename
	 */
	strcpy(Dead_Letter_File, "SYS$LOGIN:DEAD.LETTER");

	/*
	 *	Using an alternate newmail file?
	 */
	cp = (char *)getenv("MULTINET_MM_MAIL_FILE");
	if (cp)
		strcpy(New_Mail_File, cp);
	else
		New_Mail_File[0] = '\0';
}


/*
 *
 *	Read in the MM init file
 *
 */
Do_Init_File()
{
	/*
	 *	Read the User's init file
	 */
	Do_Init_File1(Home_File(MM_INIT_FILE));
	/*
	 *	Read in the System's init file
	 */
	if (!Dont_Load_System_Init_File) {
		Do_Init_File1("sys$manager:mm.sys");
		Do_Init_File1("multinet:mm.sys");
	}
	/*
	 *	Get the login name
	 */
	strcpy(Real_User_Name,(char *)Get_Username());
	/*
	 *	If the USERNAME hasn't been filled in, get it
	 */
	if (User_Name[0] == 0)
		strcpy(User_Name,Real_User_Name);
	/*
	 *	If the Personal Name hasn't been filled in, get it
	 */
	if (Personal_Name[0])
		strcpy(Personal_Name,
		       (char *)rfc822_string((char *)Get_Personal_Name()));
	/*
	 *	If the default file protection is 0, set it to 0600
	 */
	if (Mail_File_Mode == 0) Mail_File_Mode = 0600;
}

/*
 *	Read in the specified init file
 */
static Do_Init_File1(Filename)
char *Filename;
{
	FILE *f;
	char Line[1024];
	int line_error = 0, file_error = 0;
	int count = 0;
	int flags;
	int i;
	int Negative;
	struct tbluk_keyword *t;
	register struct init_data *Data;
	register char *cp,*cp1;

	/*
	 *	Open the init file
	 */
	f = fopen(Filename,"r");
	if (!f) return;
	/*
	 *	Read through the init file:
	 *	Lines are of the form <variable> <value>\n
	 */
	while(fgets(Line,1024,f) != NULL) {
		/*
		 *	Extract the keyword
		 */
		count++;
		cp = Line;
		while(*cp) {
			if (*cp == '\n') {
				*cp = 0;
				line_error = 1;
				goto check_error;
			}
			if ((*cp == ' ') || (*cp == '\t')) break;
			cp++;
		}
		*cp++ = 0;
		/*
		 *	Go to the beginning of the <value> token
		 */
		while(*cp) {
			if ((*cp != ' ') && (*cp != '\t') && (*cp != '\n'))
								break;
			cp++;
		}
		/*
		 *	Look up the keyword in the keyword table
		 */
		t = tbluk_jsys(Line,&Init_Table,0,&flags);
		/*
		 *	Check for errors
		 */
		if (flags & (TBLUK_NOMATCH | TBLUK_AMBIGUOUS)) {
			line_error = 1;
			goto check_error;
		}
		/*
		 *	Process it appropriately
		 */
		Data = (struct init_data *)t->user_data;
		switch(Data->code) {
			/*
			 *	A decimal number
			 */
			case NUMBER:
				/*
				 *	Initialize
				 */
				i = 0;
				Negative = 0;
				/*
				 *	Check for negative number
				 */
				if (*cp == '-') {
					cp++;
					Negative = 1;
				}
				/*
				 *	There had BETTER be something there!
				 */
				if (!*cp || (*cp == '\n')) {
					line_error = 1;
					goto check_error;
				}
				/*
				 *	Decode the number
				 */
				while(*cp) {
					/*
					 *	On EOL we are done
					 */
					if (*cp == '\n') break;
					/*
					 *	On legal digit we update
					 *	the number.
					 */
					if ((*cp >= '0') && (*cp <= '9')) {
						i *= 10;
						i += (*cp++ - '0');
						continue;
					}
					/*
					 *	Anything else is an error
					 */
					line_error = 1;
					goto check_error;
				}
				/*
				 *	Make the number negative if necessary
				 */
				if (Negative)i = -i;
				/*
				 *	Store the value
				 */
				*Data->data2 = i;
				/*
				 *	Done
				 */
				break;
			/*
			 *	A string
			 */
			case STRING:
				/*
				 *	Initialize
				 */
				i = Data->data1;
				cp1 = (char *)Data->data2;
				/*
				 *	Copy the string
				 */
				while(--i >= 0) {
					if (*cp == '\n') {*cp1 = 0; break;}
					if ((*cp1++ = *cp++) == 0) break;
				}
				/*
				 *	Check for string overflow
				 */
				if (i < 0) {
					line_error = 1;
					goto check_error;
				}
				/*
				 *	Done
				 */
				break;
			/*
			 *	Call routine to do the work
			 */
			case ROUTINE:
				/*
				 *	Call the routine
				 */
				i = (*(int (*)())Data->data2)
							(Data->data1,cp,f);
				/*
				 *	Process errors
				 */
				if (i < 0) {
					line_error = 1;
					goto check_error;
				}
				/*
				 *	Done:
				 */
				break;
		}
check_error:
		if (line_error) {
			line_error = 0;
			file_error++;
			printf("%s: Syntax error at line %d, keyword %s\n",
			       Home_File(MM_INIT_FILE), count, Line);
		}
	}
	/*
	 *	Done
	 */
	fclose(f);

	/*
	 *	Syntax error in Init File
	 */
	if (file_error) {
		fclose(f);
		printf("\nYour current MM profile file contains errors.  It was probably created by an\n");
		printf("older version of MM.  It will now be updated to remove the lines in error.\n");
		Do_Create_Init();
		printf("\n%s updated.\n\n", Home_File(MM_INIT_FILE));
		Do_Blank_Screen = 0;	/* Keep msg from being erased!! */
	}
	return;
}


/*
 *
 *	Init Routine to parse a string and construct a keyword table
 *
 */
static int Init_Key(Table,String,File)
register struct option_keyword_table *Table;
register char *String;
FILE *File;
{
	register char *cp,*cp1;
	struct tbluk_keyword t;
	register int i;
	char Keyword[100];

	/*
	 *	Free up any dynamic strings already in the table
	 */
	for(i = 0; i < Table->current_entries; i++) {
		if (Table->keywords[i].keyword)
				mm_free(Table->keywords[i].keyword);
		Table->keywords[i].keyword = 0;
	}
	/*
	 *	Initialize the table "MAX ENTRIES" (current entries = 0)
	 */
	Table->maximum_entries = OPTION_KEYWORD_TABLE_SIZE;
	Table->current_entries = 0;
	/*
	 *	Run through the "," separated strings
	 */
	cp = String;
	while(*cp && (*cp != '\n')) {
		/*
		 *	Get the next string, first skip whitespace
		 */
		while((*cp == ' ') || (*cp == '\t')) cp++;
		cp1 = Keyword;
		while(*cp && (*cp != '\n') && (*cp != ',')) *cp1++ = *cp++;
		/*
		 *	Add this keyword to the table
		 */
		if (cp1 != Keyword) {
			/*
			 *	Null terminate the keyword
			 */
			*cp1++ = 0;
			/*
			 *	Setup the keyword structure
			 */
			t.flags = 0;
			t.user_data = 0;
			t.keyword = savestr(Keyword);
			/*
			 *	Add the keyword
			 */
			i = tbadd_jsys(&t,Table);
			/*
			 *	Check for errors
			 */
			if (i < 0) return(-1);
		}
		/*
		 *	Get rid of trailing ','
		 */
		if (*cp == ',') cp++;
	}
	/*
	 *	Done
	 */
	return(0);
}


/*
 *
 *	Init Routine to ???
 *
 */
static int Init_String_Extended_Lines(String_Area,String,File)
char *String_Area;
char *String;
FILE *File;
{

	/*
	 *	Concatenate the string (and \n) to String Area
	 */
	strcat(String_Area,String);
	if (strchr(String,'\n') == 0) strcat(String_Area,"\n");
}


/*
 *
 *	Init Routine to parse a string and construct a keyword table
 *
 */
static int Set_Personal_Name(Name,String,File)
register char *Name;
register char *String;
FILE *File;
{
	register char *cp,*cp1;
	char buf[256];

	cp = String;
	cp1 = buf;

	while( (*cp != '\n') && (*cp != 0) ) *cp1++ = *cp++;
	*cp1 = 0;

	strcpy(Personal_Name, (char *)rfc822_string(buf));
}

/*
 *
 *	Routine to save a string in dynamically allocated memory
 *
 */
char *savestr(String)
char *String;
{
	register char *cp,*cp1;
	register char *Return_String;
	register int i;

	/*
	 *	Get the string size
	 */
	i = 0;
	cp = String;
	while(*cp++) i++;
	i++;
	/*
	 *	Allocate some memory
	 */
	Return_String = (char *) mm_malloc(i);
	/*
	 *	Copy the string
	 */
	cp  = String;
	cp1 = Return_String;
	while(*cp1++ = *cp++);
	/*
	 *	Done
	 */
	return(Return_String);
}


/*
 *
 *	Help routine for SET
 *
 */
Help_Set_Routine()
{
	static struct comnd_function confirm = {COMND_CONFIRM};
	static struct comnd_function keyword =
		{COMND_KEYWORD,
		 0,
		 &confirm,
		 (int)&Init_Table};
	struct tbluk_keyword *t;
	struct comnd_function *f;
	int Status,i;
	struct init_data *Init_Data;
	struct option_keyword_table *keyword_table;

	/*
	 *	Get the SET keyword
	 */
	Status = comnd_jsys(&Command_State,&keyword,&t,&f);
	if (Status < 0) {
		printf("***Parse error***\n");
		longjmp(Goto_Top_Level,0);
	}
	/*
	 *	If confirm, just do general SET information
	 */
	if (f->code == COMND_CONFIRM) {
		printf(
"The SET command is used to change variables initialized from the MM.INIT\n\
file on your user directory.  The changed variables can be written to\n\
your MM.INIT file with the CREATE-INIT command.  The PROFILE command is\n\
used to create a basic environment and guides you through some of the\n\
set options.  The HELP SET command takes a third argument which is a\n\
variable name, resulting in individual help messages being printed for\n\
each set variable, as well as displaying the current value.  The SHOW\n\
command lists the current settings for all variables.\n");
		return;
	}
	/*
	 *	Otherwise, print the appropriate help entry
	 */
	Confirm();
	Init_Data = (struct init_data *)t->user_data;
	printf("%s",Init_Data->Help);
	printf("\nThis variable is currently set to:\n");
	switch(((struct init_data *)t->user_data)->code) {
		case NUMBER:
			printf("%s %d\n",t->keyword,*Init_Data->data2);
			break;
		case STRING:
			printf("%s %s\n",t->keyword,(char *)Init_Data->data2);
			break;
		case ROUTINE:
			if (((int (*)())Init_Data->data2) == Init_Key) {
				printf("%s ",t->keyword);
				keyword_table =
					(struct option_keyword_table *)
						Init_Data->data1;
				for(i = 0;
				    i < keyword_table->current_entries;
				    i++) {
					if (i != 0) printf(",");
					printf("%s",
						keyword_table->
							keywords[i].
								keyword);
				}
				printf("\n");
				break;
			}
			if (((int (*)())Init_Data->data2) ==
						Init_String_Extended_Lines) {
				char *cp,*cp1;

				cp = (char *)Init_Data->data1;
				while(1) {
					cp1 = (char *)strchr(cp,'\n');
					if (cp1 == 0) {
						printf("%s %s\n",t->keyword,cp);
						break;
					}
					*cp1 = 0;
					printf("%s %s\n",t->keyword,cp);
					*cp1 = '\n';
					cp = cp1 + 1;
					if (*cp == 0) break;
				}
				break;
			}
			if (((int (*)())Init_Data->data2) ==
						Set_Personal_Name) {
				printf("%s %s\n",t->keyword,Personal_Name);
				break;
			}
			break;
	}
}


/*
 *
 *	Interactive routine to set a variable
 *
 */
CMD_Set()
{
	static struct comnd_function keyword = {COMND_KEYWORD,0,0,(int)&Init_Table};
	static struct comnd_function number = {COMND_NUMBER,0,0,10};
	static struct comnd_function string = {COMND_TEXT};
	struct tbluk_keyword *t;
	register struct init_data *Init_Data;
	int data;
	int Status;
	char buffer[512];

	/*
	 *	Noise
	 */
	Noise("variable");
	/*
	 *	Get the keyword
	 */
	Status = comnd_jsys(&Command_State,&keyword,&t,0);
	if (Status < 0) {
		printf("?Parse error (later)\n");
		return(-1);
	}
	Init_Data = (struct init_data *)t->user_data;
	/*
	 *	Noise
	 */
	Noise("to");
	/*
	 *	Select the variable type
	 */
	switch (Init_Data->code) {
		case NUMBER:
		  /*
		   *	Read in the number
		   */
		  Status = comnd_jsys(&Command_State,&number,&data,0);
		  if (Status < 0) {
			printf("?parse error (later)\n");
			return(-1);
		  }
		  Confirm();
		  /*
		   *	Set the variable
		   */
		  *Init_Data->data2 = data;
		  /*
		   *	If it was MORE-PROCESSING, we need to do something!
		   */
		  if (Init_Data->data2 == &More_Processing)
			  Setup_More_Processing();
		  else if (Init_Data->data2 == &Delivery_To_MM)
			  Setup_Delivery_To_MM(data);
		  else if (Init_Data->data2 == &POP3_Check_Interval)
			  POP3_Check_Interval_Temp = POP3_Check_Interval;
						
		  Set_Changes++;
		  break;

		case STRING:
		  /*
		   *	Read in the string
		   */
		  Command_State.atom_buffer = (char *)Init_Data->data2;
		  Command_State.atom_buffer_size = Init_Data->data1+1;
		  Status = comnd_jsys(&Command_State,&string,0,0);
		  Command_State.atom_buffer = 0;
		  if (Status < 0) {
			printf("?parse error (later)\n");
			return(-1);
		  }
		  Confirm();
		  /*
		   *	Done
		   */
		  Set_Changes++;
		  break;

		case ROUTINE:
		  /*
		   *	Read in the string
		   */
		  Command_State.atom_buffer = buffer;
		  Command_State.atom_buffer_size = sizeof(buffer);
		  Status = comnd_jsys(&Command_State,&string,0,0);
		  Command_State.atom_buffer = 0;
		  if (Status < 0) {
			printf("?parse error (later)\n");
			return(-1);
		  }
		  Confirm();
		  /*
		   *	Call the routine
		   */
		  (*(int (*)())Init_Data->data2)(Init_Data->data1,buffer,0);
		  Set_Changes++;
		  break;
	}
}



/*
 *
 *	Create an INIT file from the current parameters
 *
 */
CMD_Create_Init()
{
	/*
	 *	Confirm
	 */
	Confirm();
	/*
	 *	Create the new init file and reset the number of SET changes to
	 *	zero.
	 */
	Do_Create_Init();
	Set_Changes = 0;
}

int Do_Create_Init()
{
	register struct tbluk_keyword *t;
	register struct init_data *Init_Data;
	register int i,j;
	FILE *f;

	i = Xcreat(Home_File(MM_INIT_FILE),0600,0);
	if (i < 0) {
		printf("?Couldn't creat MM.INIT\n");
		return(-1);
	}
	f = fdopen(i,"w");
	/*
	 *	Loop through the table
	 */
	for(i = 0; i < Init_Table.current_entries; i++) {
		t = &Init_Table.keywords[i];
		Init_Data = (struct init_data *)t->user_data;
		switch(Init_Data->code) {
			case NUMBER:
				Print_Number(f, t, Init_Data);
				break;
			case STRING:
				Print_String(f, t, Init_Data);
				break;
			case ROUTINE:
				Print_Routine(f, t, Init_Data);
				break;
		}
	}
	fclose(f);
}


/*
 *	Show all the init file entries
 */
CMD_Show()
{
	
static struct comnd_function keyword_LOCAL_1 = {
	COMND_TOKEN,
	(COMND_HELP_VALID | COMND_SUPPRESS_DEFAULT_HELP | COMND_DEFAULT_VALID),
	0,
	(int)"*",
	"* to see all variables",
	"*",
	0};

static struct comnd_function keyword = {
	COMND_KEYWORD,
	(COMND_HELP_VALID | COMND_DEFAULT_VALID),
	&keyword_LOCAL_1,
	(int)&Init_Table,
	"MM variable, ",
	"*",
	0};
	register int i, j;
	struct tbluk_keyword *t;
	struct comnd_function *f;
	register struct init_data *Init_Data;
	int Status;

	/*
	 *	Noise
	 */
	Noise("variable");

	/*
	 *	Get the keyword
	 */
	Status = comnd_jsys(&Command_State,&keyword,&t,&f);
	if (Status < 0) {
		printf("?Parse error (later)\n");
		return(-1);
	}

	/*
	 *	Confirm
	 */
	Confirm();

	/*
	 *	Keyword typed?  If so, only print that info.
	 */
	if (f->code == COMND_KEYWORD) {
		Init_Data = (struct init_data *)t->user_data;
		/*
		 *	Dispatch on type
		 */
		switch(Init_Data->code) {
			case NUMBER:
				Print_Number(stdout, t, Init_Data);
				break;
			case STRING:
				Print_String(stdout, t, Init_Data);
				break;
			case ROUTINE:
				Print_Routine(stdout, t, Init_Data);
				break;
		}
	return;
	}

	/*
	 *	Scan the Init keyword table and print out all the entries
	 */
	for(j = 0; j < Init_Table.current_entries; j++) {
		/*
		 *	Ignore abbreviations/invisible entries
		 */
		t = &Init_Table.keywords[j];
		if (t->flags & COMND_ABBREVIATION) continue;
		if (t->flags & COMND_INVISIBLE) continue;
		/*
		 *	Get the data pointer
		 */
		Init_Data = (struct init_data *)
					Init_Table.keywords[j].user_data;
		/*
		 *	Dispatch on type
		 */
		switch(Init_Data->code) {
			case NUMBER:
				Print_Number(stdout, t, Init_Data);
				break;
			case STRING:
				Print_String(stdout, t, Init_Data);
				break;
			case ROUTINE:
				Print_Routine(stdout, t, Init_Data);
				break;
		}
	}
}

Print_Number(f, t, Init_Data)
FILE *f;
struct tbluk_keyword *t;
struct init_data *Init_Data;
{
	if (f == stdout)
		printf("%s %d\n",t->keyword,*Init_Data->data2);
	else
		fprintf(f, "%s %d\n",t->keyword,*Init_Data->data2);
}

Print_String(f, t, Init_Data)
FILE *f;
struct tbluk_keyword *t;
struct init_data *Init_Data;
{
	if (f == stdout)
		printf("%s %s\n",t->keyword,(char *)Init_Data->data2);
	else
		fprintf(f, "%s %s\n",t->keyword,(char *)Init_Data->data2);
}

Print_Routine(f, t, Init_Data)
FILE *f;
struct tbluk_keyword *t;
struct init_data *Init_Data;
{
	int j;

	if (((int (*)())Init_Data->data2) == Init_Key) {
		register struct option_keyword_table *keyword_table;
		keyword_table = (struct option_keyword_table *)Init_Data->data1;
		if (keyword_table->current_entries == 0) return;
		if (f == stdout)
			printf("%s ", t->keyword);
		else
			fprintf(f, "%s ", t->keyword);
		for(j = 0; j < keyword_table->current_entries; j++) {
			if (j != 0) {
				if (f == stdout)
					printf(",");
				else
					fprintf(f, ",");
			}
			if (f == stdout)
				printf("%s", keyword_table->keywords[j].keyword);
			else
				fprintf(f, "%s", keyword_table->keywords[j].keyword);
		}
		if (f == stdout)
			printf("\n");
		else
			fprintf(f, "\n");
	} else
	if (((int (*)())Init_Data->data2) == Init_String_Extended_Lines) {
		char *cp,*cp1;
		cp = (char *)Init_Data->data1;
		if (*cp == 0) return;
		while(1) {
			cp1 = (char *)strchr(cp,'\n');
			if (cp1 == 0) {
				if (f == stdout)
					printf("%s %s\n", t->keyword, cp);
				else
					fprintf(f, "%s %s\n", t->keyword, cp);
				return;
			}
			*cp1 = 0;
			if (f == stdout)
				printf("%s %s\n", t->keyword, cp);
			else
				fprintf(f, "%s %s\n", t->keyword, cp);
			*cp1 = '\n';
			cp = cp1 + 1;
			if (*cp == 0) return;
		}
	} else
	if (((int (*)())Init_Data->data2) == Set_Personal_Name)
		if (f == stdout)
			printf("%s %s\n", t->keyword, Personal_Name);
		else
			fprintf(f, "%s %s\n", t->keyword, Personal_Name);

	return;
}

/*
 *	If running PMDF or ST Mail, we do other things to ensure that mail
 *	does or does not get delivered to MM.
 */
static int Setup_Delivery_To_MM(data)
int data;
{
	register int i;
	FILE *f;

#ifdef PMDF
	if (RUNNING_PMDF) {
    	    pmdf_set_mm_delivery(data);
    	    return;
    	}
#endif /* PMDF */

    	if (RUNNING_MX) return;

	if (RUNNING_STMAIL) {
		i = Xcreat(Home_File("$MAILINTERFACE."),0600,0);
		if (i < 0) {
			printf("?Couldn't creat $MAILINTERFACE.\n");
			return(-1);
		}
		f = fdopen(i,"w");
		if (data)
			fprintf(f, "mm\n");
		else
			fprintf(f, "vmsmail\n");
		fclose(f);
	}
}
