/*
 *	Copyright (C) 1988  SRI International
 *	Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993  TGV, Incorporated
 *
 *	Send commands
 *
 */

#include "comnd.h"
#include <ctype.h>
#include <stdio.h>
#include "vax-mm.h"
#include "gtjfn.h"
#include "address.h"
#include "texti.h"
#include "multinet_root:[multinet.include.sys]types.h"
#include "multinet_root:[multinet.include.netinet]in.h"
#include "multinet_root:[multinet.include]netdb.h"
#include "multinet_root:[multinet.include.arpa]nameser.h"
#include "multinet_root:[multinet.include]resolv.h"
#include <ssdef.h>
#include <stsdef.h>
#include <descrip.h>

#define ADDRESS_INDIRECT    99	    	/* private indirection flag */

extern char MM_Name[];
extern int MM_Edit_Number,MM_Version,MM_Minor_Id_Number;
static Send_Init_No_Default_CC_List(), Erase_All(), Add_Address(),
       Do_Abort(), Generate_Header(), Generate_Address_List(),
       Parse_Return_Addresses();
static int Address_Match(), Send_SubCommand_Mode(), strcmpn();
static char *Save_String();
extern char *Get_Hostname(), *strchr();
#ifndef __ALPHA
#define Topslib_Version topslib_version_040400x
#endif
extern noshare char Topslib_Version[];
extern noshare int (*tops_eof_hook)();
extern int Control_Z();
static int Restored_Draft = 0;

/*
 *	Text/Address space sizes
 */
#define FREE_TEXT_SPACE_SIZE	1000*1024
#define FREE_TEXT_SPACE_INCR	100*1024
#define FREE_ADDRESS_SPACE_SIZE 1280

/*
 *	Control Characters for text input
 */
#define CTRL_B	2		/* ^B: Insert file		*/
#define CTRL_E	5		/* ^E: Enter Editor		*/
#define CTRL_K	11		/* ^K: Retype message text	*/
#define CTRL_L	12		/* ^L: Clear screen and retype	*/
#define CTRL_N	14		/* ^N: Abort			*/
#define CTRL_Z	26		/* ^Z: End of message		*/
#define ESCAPE	27		/* <ESC>: End of message	*/


/*
 *	Module Global symbols
 */
static struct comnd_function confirm = {COMND_CONFIRM};
static int		Send_Can_Be_Continued = 0;
static char		*Substitute_Header;
static jmp_buf		Send_Top_Level;
static int		Not_A_Reply_To_Anyone;
static struct Address	*Address_List;
static struct Address	*ToList;
static struct Address	*CcList;
static struct Address	*BccList;
static struct Address	*LclList;
static struct Address	*FiList;
static struct Address	*NetList;
static struct Address	*UucpList;
static struct Address	*StandByCcList;
static char		*Subject;
static char		*In_Reply_To_String;
static char		*After_Date;
static char		*From_String;
static char		*Reply_To_String;
static int		Delivery_Options;
#define DELIVERY_OPTION_REGISTERED_MAIL (1<<0)
#define DELIVERY_OPTION_READ_RECEIPT (1<<1)
#define DELIVERY_OPTION_DELIVERY_RECEIPT (1<<2)
static int		Doing_Group;
static int		Send_Mode;

static char		Free_Text_Space[FREE_TEXT_SPACE_SIZE];
static int		Free_Text_Space_Size,Saved_Free_Text_Space_Size;
static int		Text_Space_Size;
static int		UserName_Space_Size,Saved_UserName_Space_Size;
static struct Address	Free_Address_Space[FREE_ADDRESS_SPACE_SIZE];
static int		Free_Address_Space_Size,Saved_Free_Address_Space_Size;

/*
 *	Forward declarations needed by GEM C
 */
static Process_FAX_Addresses();
static int CMD_Display_All();
static int CMD_Display_Bcc();
static int CMD_Display_Cc();
static int CMD_Display_From();
static int CMD_Display_Header();
static int CMD_Display_Reply_To();
static int CMD_Display_Sender();
static int CMD_Display_Subject();
static int CMD_Display_Text();
static int CMD_Display_To();
static Add_More_Users_To_List();
static Extract_Mailbox_From_Field();
static int Find_Image_Symbol();
static int SIG_TO_RET();

/*
 *	Send a message
 */
CMD_Send()
{
	int Terminator;

	Send_Mode = 0;
	Restored_Draft = 0;
	/*
	 *	Noise
	 */
	Noise("message to");
	/*
	 *	Initialize send
	 */
	Send_Init_No_Default_CC_List();
	/*
	 *	Get TO list
	 */
	Get_To(0);
	/*
	 *	If there is nothing on the Address List, do prompt
	 */
	Send_Mode = 1;
	if (Address_List == 0) {
		Get_To(1);
		ToList = Address_List;
		Address_List = 0;
		Get_CC(1);
		CcList = Address_List;
		Address_List = 0;
		if (Prompt_For_BCC) {
			Get_BCC(1);
			BccList = Address_List;
			Address_List = 0;
		}
	} else {
		ToList = Address_List;
		Address_List = 0;
	}
	/*
	 *	Add the DEFAULT-CC and DEFAULT-BCC lists
	 */
	if (Default_CC_List[0] != 0) {
		Setup_String_Parse(Default_CC_List);
		Add_More_Users_To_List(&CcList);
	}
	if (Default_BCC_List[0] != 0) {
		Setup_String_Parse(Default_BCC_List);
		Add_More_Users_To_List(&BccList);
	}
	/*
	 *	Get Subject
	 */
	Get_Subject(1);
	/*
	 *	Get the message text
	 *	One way or another
	 */
	if (Use_Editor_Automatically) {
		int i;

		printf("\nInvoking editor...\n");  /* Some want to know */
		i = Edit_Buffer((In_Reply_To_String && !Restored_Draft) ?
					"mm-reply-edit" : "mm-send-edit",
				Free_Text_Space,
				Text_Space_Size,
				Free_Text_Space_Size);
		Text_Space_Size = i;
		/*
		 *	Return as though an ESCAPE was typed
		 */
		Free_Text_Space[Text_Space_Size] = 0;
		Terminator = ((Escape_Automatic_Send > 0) ? CTRL_Z : ESCAPE);
	} else {
		/*
		 *	Disable TOPS EOF hook during Get_Text()
		 */
		tops_eof_hook = 0;
		Terminator = Get_Text(1,1);
		tops_eof_hook = Control_Z;
	}
	/*
	 *	Send Sub-Command Mode:
	 */
	Init_CMD_Help(HELP_FILE_SEND, &Help_Send);
	Send_SubCommand_Mode(Terminator);
	/*
	 *	DEBUG
	 */
	if (Print_Debugging_Info) {
		register struct Address *Address;
		printf("******DEBUGGING INFO******\n");
		printf("To:\n");
		for(Address = ToList; Address; Address = Address->Next_Address) {
			switch(Address->Type) {
				case ADDRESS_LOCAL:
				case ADDRESS_UUCP:
					printf("User = %s",Address->User);
					break;
				case ADDRESS_FILE:
					printf("File = %s",Address->User);
					break;
				case ADDRESS_NETWORK:
					if (Address->Host)
						printf("User = %s@%s ",
						Address->User,Address->Host);
					else
						printf("User = %s",
						Address->User);
					break;
				case ADDRESS_GROUP:
					printf("Group = %s:",
					Address->User);
					break;
				default:
					printf("BAD TYPE CODE %d",Address->Type);
					break;
			}
			printf("%s\n",
				Address->Flags & ADDRESS_INVISIBLE ?
					" [invisible]" : "");
		}
		printf("Cc:\n");
		for(Address = CcList; Address; Address = Address->Next_Address) {
			switch(Address->Type) {
				case ADDRESS_LOCAL:
				case ADDRESS_UUCP:
					printf("User = %s",Address->User);
					break;
				case ADDRESS_FILE:
					printf("User = %s",Address->User);
					break;
				case ADDRESS_NETWORK:
					if (Address->Host)
						printf("User = %s@%s ",
						Address->User,Address->Host);
					else
						printf("User = %s ",
						Address->User);
					break;
				case ADDRESS_GROUP:
					printf("Group = %s:",
					Address->User);
					break;
				default:
					printf("BAD TYPE CODE %d",Address->Type);
					break;
			}
			printf("%s\n",
				Address->Flags & ADDRESS_INVISIBLE ?
					" [invisible]" : "");
		}
		printf("BCC:\n");
		for(Address = BccList; Address; Address = Address->Next_Address) {
			switch(Address->Type) {
				case ADDRESS_LOCAL:
				case ADDRESS_UUCP:
					printf("User = %s",Address->User);
					break;
				case ADDRESS_FILE:
					printf("User = %s",Address->User);
					break;
				case ADDRESS_NETWORK:
					if (Address->Host)
						printf("User = %s@%s ",
						Address->User,Address->Host);
					else
						printf("User = %s ",
						Address->User);
					break;
				case ADDRESS_GROUP:
					printf("Group = %s:",
					Address->User);
					break;
				default:
					printf("BAD TYPE CODE %d",Address->Type);
					break;
			}
			printf("%s\n",
				Address->Flags & ADDRESS_INVISIBLE ?
					" [invisible]" : "");
		}
		printf("****END DEBUGGING INFO****\n");
	}
	/*
	 *	Check for new mail now
	 */
	Init_Mail_Check_Time(0);
}


/*
 *	Routine to initialize send without the default CC list
 */
static Send_Init_No_Default_CC_List()
{

	/*
	 *	Assume not a reply to anyone
	 */
	Not_A_Reply_To_Anyone = 1;
	/*
	 *	Erase everything
	 */
	Erase_All();
}


/*
 *	Erase everything
 */
static Erase_All()
{

	/*
	 *	Reset string pointers
	 */
	Subject		 = 0;
	ToList		 = 0;
	CcList		 = 0;
	BccList		 = 0;
    	StandByCcList	 = 0;
	LclList		 = 0;
	FiList		 = 0;
	NetList		 = 0;
	UucpList	 = 0;
	After_Date	 = 0;
	Delivery_Options = 0;
	Address_List	 = 0;
	Doing_Group	 = 0;
	In_Reply_To_String = 0;

	/*
	 *	Reset free space
	 */
	Free_Text_Space_Size = sizeof(Free_Text_Space);
	Text_Space_Size = 0;
	UserName_Space_Size = 0;
	Free_Address_Space_Size =
			(sizeof(Free_Address_Space)/sizeof(struct Address));

	/*
	 *	Reset the From: and Reply-To: strings
	 */
	From_String = User_From_String;
	Reply_To_String = User_Reply_To_String;
}


/*
 *	Get TO list
 */
Get_To(Do_Prompt)
int Do_Prompt;
{

	if (Do_Prompt) {
		/*
		 *	Save environment in case of rescan
		 */
		Saved_Free_Text_Space_Size = Free_Text_Space_Size;
		Saved_UserName_Space_Size = UserName_Space_Size;
		Saved_Free_Address_Space_Size = Free_Address_Space_Size;
		setjmp(Send_Top_Level);
		/*
		 *	Setup the comnd jsys & initialize
		 */
		Command_State.prompt = " To: ";
		Command_State.atom_buffer = 0;
		COMMAND_PARSE_INIT(&Command_State);
		/*
		 *	Restore environment for rescan
		 */
		Free_Text_Space_Size = Saved_Free_Text_Space_Size;
		UserName_Space_Size = Saved_UserName_Space_Size;
		Free_Address_Space_Size = Saved_Free_Address_Space_Size;
		Address_List = 0;
	}
	/*
	 *	Get Users
	 */
	Get_User(1);
}


/*
 *	Get "CC" list
 */
Get_CC(Do_Prompt)
int Do_Prompt;
{

	if (Do_Prompt) {
		/*
		 *	Save environment in case of rescan
		 */
		Saved_Free_Text_Space_Size = Free_Text_Space_Size;
		Saved_UserName_Space_Size = UserName_Space_Size;
		Saved_Free_Address_Space_Size = Free_Address_Space_Size;
		setjmp(Send_Top_Level);
		/*
		 *	Setup the comnd jsys & initialize
		 */
		Command_State.prompt = " cc: ";
		Command_State.atom_buffer = 0;
		COMMAND_PARSE_INIT(&Command_State);
		/*
		 *	Restore environment for rescan
		 */
		Free_Text_Space_Size = Saved_Free_Text_Space_Size;
		UserName_Space_Size = Saved_UserName_Space_Size;
		Free_Address_Space_Size = Saved_Free_Address_Space_Size;
		Address_List = 0;
	}
	/*
	 *	Get Users
	 */
	Get_User(1);
}


/*
 *	Get Blind "CC" list
 */
Get_BCC(Do_Prompt)
int Do_Prompt;
{

	if (Do_Prompt) {
		/*
		 *	Save environment in case of rescan
		 */
		Saved_Free_Text_Space_Size = Free_Text_Space_Size;
		Saved_UserName_Space_Size = UserName_Space_Size;
		Saved_Free_Address_Space_Size = Free_Address_Space_Size;
		setjmp(Send_Top_Level);
		/*
		 *	Setup the comnd jsys & initialize
		 */
		Command_State.prompt = " bcc: ";
		Command_State.atom_buffer = 0;
		COMMAND_PARSE_INIT(&Command_State);
		/*
		 *	Restore environment for rescan
		 */
		Free_Text_Space_Size = Saved_Free_Text_Space_Size;
		UserName_Space_Size = Saved_UserName_Space_Size;
		Free_Address_Space_Size = Saved_Free_Address_Space_Size;
		Address_List = 0;
	}
	/*
	 *	Get Users
	 */
	Get_User(1);
}


/*
 *	We need to be able to access these in a couple of different routines,
 *	so let's declare them here...
 */

#ifdef	PMDF
static void (*fax_form)() = NULL;
static void (*dispose_vstringl_list)() = NULL;
#endif

/*
 *	Get a User Name
 */
Get_User_New(Eliminate_Redundant_Addresses)
{
	char *cp, *rfc821_address, *personal_name, *fulladdress;
    	char Buffer[2048], username[256], tmp[2048];
    	struct Address *Address;
    	struct ParseCtx {
    	    struct ParseCtx *next;
    	    unsigned int ctx;
    	    unsigned int unit;
    	    char *buf, buffer[1024];
    	} *context;
	int status, i, type, rdlen, question_first;

    static unsigned long Break_Mask[4] =
    	    {0x00002000,0,0,0};
    static struct comnd_function Text = {
    	COMND_TEXT, COMND_SUPPRESS_DEFAULT_HELP|COMND_BREAK,
    	0, 0, 0, 0, Break_Mask};
    static struct comnd_function Conf = {
    	COMND_CONFIRM, 0, 0, 0, 0, 0, 0};

#ifdef	PMDF
	int Found_FAX_Form = 0;
	static int FAX_Initialized = 0;

	/*
	 *	Init the PMDF FAX-FORM routine to call.  If success,
	 *	splice in the special address FAX-FORM.
	 */
	if (!FAX_Initialized) {
		if (!fax_form)
			status = Find_Image_Symbol("PMDF_SHARE_LIBRARY",
						   "FAX_FORM", &fax_form);
		if (!dispose_vstringl_list)
			status = Find_Image_Symbol("PMDF_SHARE_LIBRARY",
						   "DISPOSE_VSTRINGL_LIST",
						   &dispose_vstringl_list);
		FAX_Initialized++;
	}
#endif	/* PMDF */

    	i = question_first = 0;

/*
** HACK! But the TOPS parsing code doesn't transition well from a
** parse that treats ? as a terminator into a parse that wants ?
** literally.
*/
    	if (Command_State.flags & COMND_QUESTION_TYPED &&
    	    *(Command_State.next_field) == '?') {
    	    Command_State.flags &= ~COMND_QUESTION_TYPED;
    	    Command_State.space_left -= 1;
    	    question_first = 1;
    	}
/*
** End of HACK!
*/
    	Command_State.atom_buffer = Buffer+1;
    	Command_State.atom_buffer_size = sizeof(Buffer)-1;
    	status = comnd_jsys(&Command_State, &Text,0,0);
    	if (status < 0) {
    	    Command_State.atom_buffer = 0;
    	    printf("Parse error\n");
    	    longjmp(Send_Mode ? Send_Top_Level : Goto_Top_Level, 0);
    	}
    	Command_State.atom_buffer = 0;
    	status = comnd_jsys(&Command_State, &Conf,0,0);
    	if (status < 0) {
    	    printf("Parse error - not confirmed\n");
    	    longjmp(Send_Mode ? Send_Top_Level : Goto_Top_Level, 0);
    	}
    	context = (struct ParseCtx *) malloc(sizeof(struct ParseCtx));
    	context->next = 0;
    	context->ctx = context->unit = 0;
    	if (question_first) {
    	    Buffer[0] = '?';
    	    context->buf = Buffer;
    	} else {
    	    context->buf = Buffer + 1;
    	}

    	while (1) {
    	    	while (1) {
    	    	    status = parse822(context->buf, &context->ctx, &fulladdress,
    	    	    	    	    &rfc821_address, &personal_name, &type);

    	    	    if (status == SS$_ENDOFFILE) {
    	    	    	if (context->unit) {
    	    	    	    status = file_read(context->unit, context->buffer,
    	    	    	    	    	sizeof(context->buffer)-1, &rdlen);
    	    	    	    if ($VMS_STATUS_SUCCESS(status)) {
    	    	    	    	*(context->buffer+rdlen) = '\0';
    	    	    	    	context->buf = context->buffer;
    	    	    	    	context->ctx = 0;
    	    	    	    	continue;
    	    	    	    }
    	    	    	}
    	    	    	if (context->next) {
    	    	    	    struct ParseCtx *t;
    	    	    	    t = context;
    	    	    	    context = context->next;
    	    	    	    if (t->unit) file_close(t->unit);
    	    	    	    free(t);
    	    	    	} else {
    	    	    	    break;
    	    	    	}
    	    	    } else {
    	    	    	break;
    	    	    }
    	    	}

    	    	if (status == SS$_ENDOFFILE) break;

    	    	if (!(status&1) && strcmp(fulladdress, ".") == 0) {
    	    	    cp = (char *)Get_Username();
    	    	    if (cp) {
    	    	    	strcpy(username, cp);
    	    	    	rfc821_address = username;
    	    	    	fulladdress = username;
    	    	    	personal_name = "";
    	    	    	type = ADDRESS_LOCAL;
    	    	    	status = 1;
    	    	    }
    	    	}

    	    	if (!(status&1)) {
    	    	    printf("?Error parsing: %s\n", fulladdress);
    	    	    continue;
    	    	}

    	    	if (type == ADDRESS_FILE && !*rfc821_address) {
    	    	    	rfc821_address = fulladdress = "MAIL.TXT";
    	    	    	personal_name = "";
    	    	}

    	    	if (type == ADDRESS_INDIRECT) {
    	    	    if (rfc821_address) {
    	    	    	struct ParseCtx *t;
    	    	    	t = (struct ParseCtx *)malloc(sizeof(struct ParseCtx));
    	    	    	if (t) {
    	    	    	    status = file_open(rfc821_address, &(t->unit), 0);
    	    	    	    if ($VMS_STATUS_SUCCESS(status)) {
    	    	    	    	status = file_read(t->unit, t->buffer,
    	    	    	    	    sizeof(t->buffer)-1, &rdlen);
    	    	    	    	if ($VMS_STATUS_SUCCESS(status)) {
    	    	    	    	    *(t->buffer+rdlen) = '\0';
    	    	    	    	    t->buf = t->buffer;
    	    	    	    	    t->ctx = 0;
    	    	    	    	    t->next = context;
    	    	    	    	    context = t;
    	    	    	    	    continue;
    	    	    	    	} else file_close(t->unit);
    	    	    	    }
    	    	    	    printf("?Could not read file: %s\n", rfc821_address);
    	    	    	    free(t);
    	    	    	} else {
    	    	    	    printf("?Memory allocation failure\n");
    	    	    	}
    	    	    } else {
    	    	    	printf("?Filename missing\n");
    	    	    }
    	    	    continue;
    	    	}

#ifdef PMDF
		if (type == ADDRESS_LOCAL && !strcasecmp("fax-form", rfc821_address)) {
			Found_FAX_Form = 1;
			continue;
		}
#endif

		Address = &Free_Address_Space
				[FREE_ADDRESS_SPACE_SIZE-Free_Address_Space_Size];
		Free_Address_Space_Size--;
		Address->Next_Address = 0;
		Address->Host = 0;
    	    	Address->RFC822_Address = 0;
		Address->Flags = 0;
		Address->Type = type;
    	    	if (type == ADDRESS_LOCAL || type == ADDRESS_DECNET) {
    	    	    if (*personal_name) {
    	    	    	sprintf(tmp, "%s%s%s@%s %s",
    	    	    	    (type == ADDRESS_DECNET ? "\"" : ""),
    	    	    	    rfc821_address,
    	    	    	    (type == ADDRESS_DECNET ? "\"" : ""),
    	    	    	    Get_Hostname(), personal_name);
    	    	    } else {
    	    	    	sprintf(tmp, "%s%s%s@%s",
    	    	    	    (type == ADDRESS_DECNET ? "\"" : ""),
    	    	    	    rfc821_address,
    	    	    	    (type == ADDRESS_DECNET ? "\"" : ""),
    	    	    	    Get_Hostname());
    	    	    }
    	    	    Address->Type = type = ADDRESS_LOCAL; /* MM doesn't really grok DECnet */
    	    	    i = strlen(tmp) + 1;
		    if (i > (Free_Text_Space_Size - Text_Space_Size))
			    goto No_Space;
    	    	    Address->RFC822_Address =
    	    	    	Free_Text_Space+(sizeof(Free_Text_Space)-
    	    	    	    	    	    UserName_Space_Size-i);
    	    	    UserName_Space_Size += i;
    	    	    Free_Text_Space_Size -= i;
    	    	    strcpy(Address->RFC822_Address, tmp);
    	    	}

    	    	if (type == ADDRESS_NETWORK) {
    	    	    i = strlen(fulladdress) + 1;
		    if (i > (Free_Text_Space_Size - Text_Space_Size))
			    goto No_Space;
    	    	    Address->RFC822_Address =
    	    	    	Free_Text_Space+(sizeof(Free_Text_Space)-
    	    	    	    	    	    UserName_Space_Size-i);
    	    	    UserName_Space_Size += i;
    	    	    Free_Text_Space_Size -= i;
    	    	    strcpy(Address->RFC822_Address, fulladdress);
    	    	}
    	    	if (type == ADDRESS_NETWORK && *rfc821_address != '<') {
    	    	    char *cp;
    	    	    for (cp = rfc821_address+strlen(rfc821_address)-1;
    	    	    	    cp >= rfc821_address && *cp != '@'; cp--);
    	    	    if (cp > rfc821_address) {
    	    	    	i = cp - rfc821_address + 1;
		    	if (i > (Free_Text_Space_Size - Text_Space_Size))
			    goto No_Space;
    	    	    	Address->User = Free_Text_Space+(sizeof(Free_Text_Space)-
    	    	    	    	    	    UserName_Space_Size-i);
    	    	    	UserName_Space_Size += i;
    	    	    	Free_Text_Space_Size -= i;
    	    	    	strncpy(Address->User, rfc821_address, i-1);
    	    	    	Address->User[i-1] = '\0';
    	    	    	i = strlen(cp);
		    	if (i > (Free_Text_Space_Size - Text_Space_Size))
			    goto No_Space;
    	    	    	Address->Host= Free_Text_Space+(sizeof(Free_Text_Space)-
    	    	    	    	    	    UserName_Space_Size-i);
    	    	    	UserName_Space_Size += i;
    	    	    	Free_Text_Space_Size -= i;
    	    	    	strcpy(Address->Host, cp+1);
    	    	    	for (cp = Address->Host; *cp; cp++) {
    	    	    	    if (islower(*cp)) *cp = toupper(*cp);
    	    	    	}
    	    	    }
    	    	} else {
		/*
		 *	Put the string in string space
		 */
    	    	    i = strlen(rfc821_address) + 1;
		    if (i > (Free_Text_Space_Size - Text_Space_Size))
			goto No_Space;
		    if (i > (Free_Text_Space_Size - Text_Space_Size))
			goto No_Space;
		    Address->User = Free_Text_Space +
					(sizeof(Free_Text_Space) -
						UserName_Space_Size - i);
		    UserName_Space_Size += i;
		    Free_Text_Space_Size -= i;
		    strcpy(Address->User, rfc821_address);
    	    	}
		/*
		 *	Done
		 */
		Add_Address(Address, &Address_List, Eliminate_Redundant_Addresses);

	}

#ifdef	PMDF
	if (Found_FAX_Form)
		Process_FAX_Addresses(Eliminate_Redundant_Addresses);
#endif

    return;

No_Space:
    printf("?Out of text space.\n");
    return;

}

Get_User(e) {

    if (New_Style_Parsing) {
    	Get_User_New(e);
    } else {
    	Get_User_Old(e);
    }
    return;
}
/*
 *	Get a User Name
 */
Get_User_Old(Eliminate_Redundant_Addresses)
{
	static unsigned long int user_mask[4] =
		{0xffffffff,	/* No controls			    */
		 0xdc001305,	/* !, #, $, %, &, ', +, -, ., /,    */
				/* numerics, =			    */
		 0x38000001,	/* Upper case alpha, ^, _	    */
		 0x80000000};	/* Lower case alpha, `, {, |, }, ~  */
	static unsigned long int DECnet_user_mask[4] =
		{0xffffffff,	/* No controls			    */
		 0xd80017c5,	/* "!", ":", "%", "#", "-", ".", numerics*/
		 0x50000001,	/* Upper case alpha, "[", "]", "_"  */
		 0xf8000001};	/* Lower case alpha		    */
	static struct {
		int current_entries;
		int maximum_entries;
		struct tbluk_keyword keywords[1];
		} special = {
			1,
			1,
			{{0,"SYSTEM",-2}}};
	static struct comnd_function field =
		{COMND_FIELD,
		 COMND_HELP_VALID | COMND_BREAK,
		 0,
		 0,
		 "network address",
		 0,
		 user_mask};
	static struct comnd_function quoted_string =
		{COMND_QUOTED_STRING,
		 0,
		 &field};
	static struct comnd_function keyword =
		{COMND_KEYWORD,
		 COMND_HELP_VALID | COMND_BREAK,
		 &quoted_string,
		 (int)&special,
		 "special mailbox, ",
		 0,
		 user_mask};
	static struct comnd_function dot =
		{COMND_TOKEN,
		 COMND_HELP_VALID | COMND_SUPPRESS_DEFAULT_HELP,
		 &keyword,
		 (int)".",
		 "\".\" for yourself \n  or \"@\" to send indirect from a file"};
	static struct comnd_function user =
		{COMND_USERNAME,
		 COMND_BREAK,
		 &dot,
		 0,
		 0,
		 0,
		 user_mask};
	static struct comnd_function star =
		{COMND_TOKEN,
		 COMND_HELP_VALID | COMND_SUPPRESS_DEFAULT_HELP,
		 &user,
		 (int)"*",
		 "\"*\" for sending to a file"};
	static struct comnd_function semi_colon =
		{COMND_TOKEN,
		 COMND_HELP_VALID | COMND_SUPPRESS_DEFAULT_HELP,
		 &star,
		 (int)";",
		 "\";\" to terminate the address group"};
	static struct comnd_function confirm =
		{COMND_CONFIRM,
		 0,
		 &semi_colon};
	static struct comnd_function decnet =
		{COMND_TOKEN,
		 COMND_SUPPRESS_DEFAULT_HELP | COMND_HELP_VALID,
		 &confirm,
		 (int)":",
		 "\":\" for a decnet address"};

#ifdef	PMDF
	static struct {
		int current_entries;
		int maximum_entries;
		struct tbluk_keyword keywords[1];
		} faxspec = {
			1,
			1,
			{{0,"FAX-FORM",-2}}};
	static struct comnd_function faxform =
		{COMND_KEYWORD,
		 COMND_HELP_VALID | COMND_BREAK,
		 0,
		 (int)&faxspec,
		 "PMDF FAX form, ",
		 0,
		 user_mask};

	int Found_FAX_Form = 0;
	static int FAX_Initialized = 0;
#endif

	static struct comnd_function comma = {COMND_COMMA};


	char Buffer[512];
	int Data;
	struct comnd_function *f;
	struct tbluk_keyword *tk;
	int Status;
	char *Address_String;
	int i, j;
	register char *cp,*cp1;
	register struct Address *Address;
	struct Address *Possible_Decnet_Address;
	int Doing_Possible_Decnet_Address;
    	int Bypass_Comma;

	/*
	 *	Splice out the Username parsing (if requested)
	 */
	if (Dont_Complete_Usernames) {
		if (star.next == &user)
			star.next = user.next;
	} else {
		if (star.next != &user)
			star.next = &user;
	}

#ifdef	PMDF
	/*
	 *	Init the PMDF FAX-FORM routine to call.  If success,
	 *	splice in the special address FAX-FORM.
	 */
	if (!FAX_Initialized) {
		if (!fax_form)
			Status = Find_Image_Symbol("PMDF_SHARE_LIBRARY",
						   "FAX_FORM", &fax_form);
		if (!dispose_vstringl_list)
			Status = Find_Image_Symbol("PMDF_SHARE_LIBRARY",
						   "DISPOSE_VSTRINGL_LIST",
						   &dispose_vstringl_list);
		if (fax_form && dispose_vstringl_list)
			if (keyword.next == &quoted_string) {
				faxform.next = &quoted_string;
				keyword.next = &faxform;
			}
		FAX_Initialized++;
	}
#endif

	/*
	 *	Not doing group or decnet now!
	 */
	Doing_Group = 0;
	Doing_Possible_Decnet_Address = 0;
	/*
	 *	Get the user name token
	 *	(if 1st one, disallow <cr>)
	 *	[also enable/disable ";" for address group termination]
	 */
Again:	Command_State.atom_buffer = Buffer;
	Command_State.atom_buffer_size = sizeof(Buffer);
	if (Doing_Group) {
		confirm.next = &semi_colon;
	} else {
		confirm.next = semi_colon.next;
	}
	Status = comnd_jsys(&Command_State,
			    Doing_Possible_Decnet_Address ? &decnet : &confirm,
			    &Data,
			    &f);
	Command_State.atom_buffer = 0;
    	if (Status < 0) {
		printf("?Parse error\n");
		longjmp(Send_Mode ? Send_Top_Level : Goto_Top_Level,0);
	}
	Bypass_Comma = (f->code == COMND_FIELD &&
    	    	    ((Command_State.flags & COMND_ESCAPE_TYPED)||
    	    	     (Command_State.flags & COMND_CTRL_F_TYPED)));
/***    	if (Bypass_Comma) goto Local_User; ***/
	/*
	 *	If attempting to do a DECNET address we either have a ":",
	 *	in which case we go to the DECNET host code or we don't have
	 *	a ":", in which case this is a GROUP specification.
	 */
	if (Doing_Possible_Decnet_Address) {
		Doing_Possible_Decnet_Address = 0;
		Address = Possible_Decnet_Address;
		if (f == &decnet) {
			static struct comnd_function user =
				{COMND_FIELD,
				 COMND_HELP_VALID | COMND_BREAK,
				 0,
				 0,
				 "user name",
				 0,
				 DECnet_user_mask};

			/*
			 *	Get the username
			 */
			Command_State.atom_buffer = Buffer;
			Command_State.atom_buffer_size = sizeof(Buffer);
			Status = comnd_jsys(&Command_State,&user,0,0);
			Command_State.atom_buffer = 0;
			if (Status < 0) {
				printf("?Illegal user name.\n");
				longjmp(Send_Mode ?
					    Send_Top_Level : Goto_Top_Level,
					0);
			}
			Address->Type = ADDRESS_LOCAL;
			i = strlen(Buffer) + strlen(Address->User) + 3;
			if (i > (Free_Text_Space_Size - Text_Space_Size))
				 goto No_Space;
			cp = Free_Text_Space + (sizeof(Free_Text_Space)
					 - UserName_Space_Size - i);
			UserName_Space_Size += i;
			Free_Text_Space_Size -= i;
			strcpy(cp, Address->User);
			strcat(cp,"::");
			strcat(cp, Buffer);
			Address->User = cp;
			Add_Address(Address,&Address_List,Eliminate_Redundant_Addresses);
			goto Get_Comma;
		} else {
			/*
			 *	Mark us as doing a group
			 */
			Doing_Group = 1;
			Address->Type = ADDRESS_GROUP;
			Add_Address(Address,&Address_List,Eliminate_Redundant_Addresses);
			/*
			 *	Fall into the parsing code for the current
			 *	token
			 */
		}
	}
	/*
	 *	If confirmed, just reset Doing_Group and return
	 */
	if (f->code == COMND_CONFIRM) {
		Doing_Group = 0;
#ifdef	PMDF
	if (Found_FAX_Form)
		Process_FAX_Addresses(Eliminate_Redundant_Addresses);
#endif
		return;
	}
	/*
	 *	If quoted string, add quotes back in
	 */
	if (f->code == COMND_QUOTED_STRING) {
		i = strlen(Buffer);
		Buffer[i+1] = '"';
		Buffer[i+2] = 0;
		for(; i > 0; i--)
			Buffer[i] = Buffer[i-1];
		Buffer[0] = '"';
	}
	/*
	 *	If Token = '.', substitute MY name
	 *	If Token = '*', its a file
	 *	If Token = ';', its the end of an address group
	 *	If Token = '<', its a source route
	 */
	if (f->code == COMND_TOKEN) {
		/*
		 *	'*' is a file name
		 */
		if (*((char *)f->data) == '*') {
			static struct comnd_function newfilename = {
				COMND_OUTPUT_FILE,
				COMND_SUPPRESS_DEFAULT_HELP};
			static struct comnd_function filename = {
				COMND_INPUT_FILE,
				COMND_HELP_VALID | COMND_SUPPRESS_DEFAULT_HELP,
				&newfilename,
				0,
				"file name to output message to"};
			static struct gtjfn_block gtjfn;

			/*
			 *	Get the filename
			 */
			gtjfn.default_filename = "MAIL";
			gtjfn.default_extension = "TXT";
			Command_State.gtjfn = &gtjfn;
			if (comnd_jsys(&Command_State,&filename,&i,0) < 0)
				return;
			local_jfns_jsys(Buffer,i);
			tops_free_jfn(i);	/* TEMP */
		}
		/*
		 *	';' is the end of an address group
		 */
		if (*((char *)f->data) == ';') {
			Doing_Group = 0;
			goto Get_Comma;
		}
		/*
		 *	'<' is the start of a source route
		 */
		if (*((char *)f->data) == '<') {
			static unsigned long int source_route_mask[4] =
			{0xffffffff,	/* No controls			    */
			 0x40000000,	/* No ">"			    */
			 0x00000000,	/*				    */
			 0x80000000};	/* No <DEL>			    */
			static struct comnd_function source_route =
			{COMND_FIELD,
			 COMND_SUPPRESS_DEFAULT_HELP | COMND_HELP_VALID | COMND_BREAK,
			 0,
			 0,
			 "RFC-822 \"Source Route\" address terminated by \">\"",
			 0,
			 source_route_mask};
			static struct comnd_function right_arrow =
			{COMND_TOKEN,
			 COMND_SUPPRESS_DEFAULT_HELP,
			 0,
			 (int)">",
			 0};

			/*
			 *	Just take everything up to the closing ">"
			 */
			Command_State.flags |= COMND_NO_INDIRECT_FILE;
			Command_State.atom_buffer = Buffer + 1;
			comnd_jsys(&Command_State, &source_route, 0, 0);
			Command_State.atom_buffer = 0;
			Command_State.flags &= ~COMND_NO_INDIRECT_FILE;
			/*
			 *	Parse the ">"
			 */
			comnd_jsys(&Command_State, &right_arrow, 0, 0);
			/*
			 *	Surround the text with <>
			 */
			Buffer[0] = '<';
			i = strlen(Buffer);
			Buffer[i++] = '>';
			Buffer[i++] = 0;
			/*
			 *	Get an Address structure
			 */
			Address = &Free_Address_Space
					[FREE_ADDRESS_SPACE_SIZE-Free_Address_Space_Size];
			Free_Address_Space_Size--;
			Address->Next_Address = 0;
			Address->Host = 0;
    	    	    	Address->RFC822_Address = 0;
			Address->Flags = Doing_Group ? ADDRESS_INVISIBLE : 0;
			Address->Type = ADDRESS_NETWORK;
			/*
			 *	Put the string in string space
			 */
			if (i > (Free_Text_Space_Size - Text_Space_Size))
				goto No_Space;
			Address->User = Free_Text_Space +
						(sizeof(Free_Text_Space) -
							UserName_Space_Size - i);
			UserName_Space_Size += i;
			Free_Text_Space_Size -= i;
			strcpy(Address->User, Buffer);
			/*
			 *	Done
			 */
			Add_Address(Address, &Address_List, Eliminate_Redundant_Addresses);
			goto Get_Comma;
		}
		/*
		 *	'.' is MY name
		 */
		if (*((char *)f->data) == '.') {
			/*
			 *	Substitute my name
			 */
			cp = (char *)Get_Username();
			if (cp == 0) {
				printf("?Couldn't find your username.\n");
				return;
			}
			cp1 = Buffer;
			while(*cp1++ = *cp++);
			/*
			 *	Make us think that COMND gave back a Username
			 */
			f = &user;
		}
	}
	/*
	 *	See if the FAX-FORM address was specified.
	 */
#ifdef	PMDF
	if (f == &faxform) {
		Found_FAX_Form = 1;
		goto Get_Comma;
	}
#endif
	/*
	 *	Get an Address structure to save the user in
	 */
	if (Free_Address_Space_Size == 0) {
		printf("\n?Too many addresses\n");
		return;
	}
	Address = &Free_Address_Space
			[FREE_ADDRESS_SPACE_SIZE-Free_Address_Space_Size];
	Free_Address_Space_Size--;
	/*
	 *	Structure is not on any lists
	 */
	Address->Next_Address = 0;
	/*
	 *	No user or host names
	 */
	Address->User = 0;
	Address->Host = 0;
    	Address->RFC822_Address = 0;
	/*
	 *	Set Flags
	 */
	Address->Flags = Doing_Group ? ADDRESS_INVISIBLE : 0;
	/*
	 *	Type = LOCAL
	 */
	Address->Type = ADDRESS_LOCAL;
	/*
	 *	Check for FILE
	 */
	if ((f->code == COMND_TOKEN) && (*((char *)f->data) == '*'))
		Address->Type = ADDRESS_FILE;
	/*
	 *	If keyword and complete, use the keyword as a string
	 *	If not, copy the string to string space and use that
	 */
	if ((f->code == COMND_KEYWORD) &&
	    (strlen(((struct tbluk_keyword *)Data)->flags &
						COMND_RELATIVE_ADDRESS ?
		    (char *)f->data +
			(int)((struct tbluk_keyword *)Data)->keyword :
		    ((struct tbluk_keyword *)Data)->keyword) ==
							strlen(Buffer))) {
		Address->User =
		    ((struct tbluk_keyword *)Data)->flags &
						COMND_RELATIVE_ADDRESS ?
		    (char *)f->data +
			(int)((struct tbluk_keyword *)Data)->keyword :
		    ((struct tbluk_keyword *)Data)->keyword;
	} else {
		i = strlen(Buffer)+1;
		if (i > (Free_Text_Space_Size - Text_Space_Size))
			goto No_Space;
		Address->User = Free_Text_Space +
			(sizeof(Free_Text_Space) - UserName_Space_Size - i);
		UserName_Space_Size += i;
		Free_Text_Space_Size -= i;
		strcpy(Address->User,Buffer);
	}
	/*
	 *	Get the delimiter ("," or "@" or ":")
	 *	[or ";" to terminate an address group]
	 */
	{
	  static struct comnd_function token3 =
		{COMND_TOKEN,
		 COMND_SUPPRESS_DEFAULT_HELP,
		 0,
		 (int)":"};
	  static struct comnd_function token2 =
		{COMND_TOKEN,
		 COMND_SUPPRESS_DEFAULT_HELP,
		 &token3,
		 (int)"at"};
	  static struct comnd_function token1 =
		{COMND_TOKEN,
		 COMND_HELP_VALID | COMND_SUPPRESS_DEFAULT_HELP,
		 &token2,
		 (int)"@",
		 "confirm with carriage return\n\
  or \",\" for another address\n\
  or \"@\" for a network host name\n\
  or \":\" to make this a group name or decnet address"};
	  static struct comnd_function semi_colon =
		{COMND_TOKEN,
		 COMND_HELP_VALID | COMND_SUPPRESS_DEFAULT_HELP,
		 &token1,
		 (int)";",
		 "\";\" to terminate the address group"};

	  struct comnd_function *f;

	  /*
	   *	Disable "@" for indirect files
	   */
	  Command_State.flags |= COMND_NO_INDIRECT_FILE;
	  /*
	   *	Get the next token
	   */
	  Command_State.flags &= ~COMND_HANDLE_ERRORS;
	  Status = comnd_jsys(&Command_State,
			      Doing_Group ? &semi_colon : &token1,
			      0,
			      &f);
	  Command_State.flags |=  COMND_HANDLE_ERRORS;
	  Command_State.flags &= ~COMND_NO_INDIRECT_FILE;
	  /*
	   *	If ok it was "@" , "at" or ":"
	   *	process the previous address
	   */
	  if (Status >= 0) {
		/*
		 *	If it was ";", terminate the address group and
		 *	this is a LOCAL address.
		 */
		if (*((char *)f->data) == ';') {
			Doing_Group = 0;
			goto Local_User;
		}
		/*
		 *	If it was ":", it is either a distribution list,
		 *	or a DECNET address.
		 */
		if (*((char *)f->data) == ':') {
			Doing_Possible_Decnet_Address = 1;
			Possible_Decnet_Address = Address;
			goto Again;
		}
		/*
		 *	If it was "@" or "at", it was a net address.
		 */
		if ((*((char *)f->data) == '@') ||
					    (*((char *)f->data) == 'a')) {
			static unsigned long host_mask [4] =
			{0xffffffff,	/* No controls			    */
			 0xfc009bcf,	/* "$", "%", "*", "-", ".", numerics*/
			 0x78000001,	/* Upper case alphabetics, "_"	    */
			 0xf8000001};	/* Lower case alphabetics	    */
			static struct comnd_function host_field =
				{COMND_FIELD,
				 COMND_HELP_VALID | COMND_BREAK,
				 0,
				 0,
				 "host name",
				 0,
				 host_mask };
			static struct comnd_function left_square =
				{COMND_TOKEN,
				 COMND_SUPPRESS_DEFAULT_HELP,
				 &host_field,
				 (int)"[",
				 0};
			static struct comnd_function host =
				{COMND_KEYWORD,
				 COMND_SUPPRESS_DEFAULT_HELP | COMND_BREAK,
				 &left_square,
				 0,	/* table is calculated on the fly */
				 0,
				 0,
				 host_mask };
			static struct comnd_function comma = {COMND_COMMA};
			static struct comnd_function semi_colon =
				{COMND_TOKEN,
				 COMND_HELP_VALID | COMND_SUPPRESS_DEFAULT_HELP,
				 &comma,
				 (int)";",
				 "\";\" to terminate the address group"};
			static struct comnd_function dot =
				{COMND_TOKEN,
				 COMND_HELP_VALID | COMND_SUPPRESS_DEFAULT_HELP,
				 0,
				 (int)".",
				 "Internet address of the form [AA.BB.CC.DD]"};
			static struct comnd_function number =
				{COMND_NUMBER,
				 COMND_HELP_VALID | COMND_SUPPRESS_DEFAULT_HELP,
				 0,
				 10,
				 "Internet address of the form [AA.BB.CC.DD]"};
			static struct comnd_function right_square =
				{COMND_TOKEN,
				 COMND_HELP_VALID | COMND_SUPPRESS_DEFAULT_HELP,
				 0,
				 (int)"]",
				 "Internet address of the form [AA.BB.CC.DD]"};
			struct comnd_function *f;

			/*
			 *	Get the host name lookup table
			 */
			host.data = (int)hosttable_tbluk_table("TCP");
			/*
			 *	Get the hostname
			 */
			Command_State.atom_buffer = Buffer;
			Command_State.atom_buffer_size = sizeof(Buffer);
			Status = comnd_jsys(&Command_State,
					    host.data != 0 ?
							&host : &left_square,
					    &tk,
					    &f);
			Command_State.atom_buffer = 0;

/*  PKARP:BUGFIX	if (Status < 0) {
				printf("?Unrecognized host name.\n");
				longjmp(Send_Mode ?
					    Send_Top_Level : Goto_Top_Level,
					0);
			}                    
*/

			/*
			 *	If we started with "[" then parse
			 *	an internet address
			 */
			if (f->code == COMND_TOKEN) {
				int Address[4];

				for(i = 0; i < 4; i++) {
					if (i != 0)
						comnd_jsys(&Command_State,
							   &dot,
							   0,
							   0);
					comnd_jsys(&Command_State,
						   &number,
						   &Address[i],
						   0);
				}
				/*
				 *	Terminate with "]"
				 */
				comnd_jsys(&Command_State,
					   &right_square,
					   0,
					   0);
				/*
				 *	Reformat the internet address as th
				 *	hostname
				 */
				sprintf(Buffer,"[%d.%d.%d.%d]",
					Address[0],Address[1],Address[2],Address[3]);
			}
			/*
			 *	Save the pointer to the REAL name
			 *	(i.e. resolve aliases first)
			 */
			if (f->code == COMND_KEYWORD) {
				Address->Host = (char *)
					hosttable_real_name(host.data,tk);
			} else {
				i = strlen(Buffer)+1;
				if (i > (Free_Text_Space_Size - Text_Space_Size))
					goto No_Space;
				Address->Host = Free_Text_Space +
					(sizeof(Free_Text_Space)
						 - UserName_Space_Size - i);
				UserName_Space_Size += i;
				Free_Text_Space_Size -= i;
				strcpy(Address->Host, Buffer );
			}
			/*
			 *	Declare this a network address and add to the
			 *	appropriate address list.
			 */
			Address->Type = ADDRESS_NETWORK;
			Add_Address(Address,&Address_List,Eliminate_Redundant_Addresses);
			/*
			 *	Comma expected next
			 */
			Command_State.flags &= ~COMND_HANDLE_ERRORS;
			Status = comnd_jsys(&Command_State,
					    Doing_Group ? &semi_colon : &comma,
					    0,
					    &f);
			if (Status < 0) {
				static struct comnd_function confirm =
					{COMND_CONFIRM};
				Status = comnd_jsys(&Command_State,
						    &confirm,
						    0,
						    0);
				Command_State.flags |=	COMND_HANDLE_ERRORS;
				if (Status < 0)
					printf("?Illegal address specification, comma expected\n");
				return;
			}
			Command_State.flags |=	COMND_HANDLE_ERRORS;
			if ((f->code == COMND_TOKEN) &&
			   (*((char *)f->data) == ';')) {
				/*
				 *	End of address group
				 */
				Doing_Group = 0;
				/*
				 *	Comma expected next
				 */
Get_Comma:			Command_State.flags &= ~COMND_HANDLE_ERRORS;
				Status = comnd_jsys(&Command_State,&comma,0,0);
				Command_State.flags |=	COMND_HANDLE_ERRORS;
				if (Status < 0) {
#ifdef	PMDF
					if (Found_FAX_Form)
						Process_FAX_Addresses(Eliminate_Redundant_Addresses);
#endif
					return;
				}
				goto Again;
			}
			goto Again;
		}
	  }
	}
	/*
	 *	Not ":" or "@", if not a local user, try forwarding
	 *	Allow "!" to specify a UUCP address.
	 */
Local_User:
	/*
	 *	If we have a local address, verify that it is in fact
	 *	a valid local name.  Use forwarding if necessary.
	 */
	if ((f->code != COMND_USERNAME) &&
			(Address->Type != ADDRESS_FILE)) {
		/*
		 *	STMAIL takes care of addresses itself
		 *	ditto for MULTINET mail
		 *	ditto for PMDF
    	    	 *  	ditto for MX
		 */
		if ((!RUNNING_MULTINET) && (!RUNNING_PMDF) && (!RUNNING_MX)) {
			/*
			 *	Check for UUCP address
			 */
			if ((char *)strchr(Address->User,'!') == 0) {
				    printf("\n?No such local user as \"%s\"\n",Address->User);
				   /*
				    *	Ignore Bad Address
				    *	(if necessary)
				    */
				   if (!Dont_Ignore_Bad_Addresses) {
					/*
					 *	Try to parse a comma
					 */
					Command_State.flags &= ~COMND_HANDLE_ERRORS;
					comnd_jsys(&Command_State,
						   Doing_Group ?
						       &semi_colon :
						       &comma,
						   0,
						   &f);
					Command_State.flags |= COMND_HANDLE_ERRORS;
					goto Again;
				    }
				    /*
				     *	Error:
				     */
				    longjmp(Send_Mode ? Send_Top_Level : Goto_Top_Level, 0);
			}
			/*
			 *	Win: A valid UUCP address
			 */
			Address->Type = ADDRESS_UUCP;
		}
	}
	/*
	 *	Add to the address list
	 */
	Add_Address(Address,&Address_List,Eliminate_Redundant_Addresses);
	/*
	 *	Comma expected next (if none, return)
	 */
    	if (Bypass_Comma) goto Again;
	Command_State.flags &= ~COMND_HANDLE_ERRORS;
	Status = comnd_jsys(&Command_State,&comma,0,0);
	Command_State.flags |=	COMND_HANDLE_ERRORS;
	if (Status < 0) {
#ifdef	PMDF
		if (Found_FAX_Form)
			Process_FAX_Addresses(Eliminate_Redundant_Addresses);
#endif
		return;
	}
	goto Again;

	/*
	 *	Out of space
	 */
No_Space:
	printf("?Out of text space.\n");
	return;
}


#ifdef	PMDF

/*
 *	Do the form thing for FAX addresses
 */
static Process_FAX_Addresses(Eliminate_Redundant_Addresses)
{

#define ALFA_SIZE 252

	typedef struct {
		long int	length;
		unsigned char	body[ALFA_SIZE];
	} vstring;

	typedef struct {
		struct vstringl *next;
		struct vstringl *prev;
		long int	index;
		vstring		val;
	} vstringl;

	vstringl *fax_addresses;
	long int zero = 0;
	unsigned char Buffer[ALFA_SIZE+3];
	register struct Address *Address;
	int i;
	char *cp;

    	fax_addresses = NULL;
	(*fax_form)(&zero, &fax_addresses, &zero, &zero);
	if (fax_addresses) {
		vstringl *tmp = fax_addresses;

		while(tmp) {
			/*
			 *	Save the string locally, source route-ifying
			 *	it if necessary.
			 */
			if (tmp->val.body[0] == '@') {
				Buffer[0] = '<';
				strncpy(Buffer+1,
					(char *)&tmp->val.body,
					tmp->val.length);
				Buffer[tmp->val.length+1] = '>';
				Buffer[tmp->val.length+2] = '\0';
			} else {
				strncpy(Buffer,
					(char *)&tmp->val.body,
					tmp->val.length);
				Buffer[tmp->val.length] = '\0';
			}
			/*
			 *	Get an Address structure
			 */
			Address = &Free_Address_Space
					[FREE_ADDRESS_SPACE_SIZE-Free_Address_Space_Size];
			Free_Address_Space_Size--;
			Address->Next_Address = 0;
			Address->Host = 0;
    	    	    	Address->RFC822_Address = 0;
			Address->Flags = 0;
			Address->Type = ADDRESS_NETWORK;
			/*
			 *	Put the string in string space.  If it's a
			 *	source route address, do like in Get_User()
			 *	and stick the whole thing in the user field
			 *	of the Address struct.	Otherwise, split apart
			 *	the user and host parts.
			 */
			if (tmp->val.body[0] == '<') {
				i = tmp->val.length + 3;
				if (i > (Free_Text_Space_Size - Text_Space_Size)) {
					printf("?Out of text space.\n");
					return;
				}
				Address->User = Free_Text_Space +
						(sizeof(Free_Text_Space) -
						UserName_Space_Size - i);
				UserName_Space_Size += i;
				Free_Text_Space_Size -= i;
				strcpy(Address->User, Buffer);
			} else {
				/*
				 *	First the username
				 */
				cp = strchr(Buffer, '@');
				*cp++ = '\0';
				i = strlen(Buffer) + 1;
				if (i > (Free_Text_Space_Size - Text_Space_Size)) {
					printf("?Out of text space.\n");
					return;
				}
				Address->User = Free_Text_Space +
						(sizeof(Free_Text_Space) -
						UserName_Space_Size - i);
				UserName_Space_Size += i;
				Free_Text_Space_Size -= i;
				strcpy(Address->User, Buffer);
				/*
				 *	Now the hostname
				 */
				i = strlen(cp) + 1;
				if (i > (Free_Text_Space_Size - Text_Space_Size)) {
					printf("?Out of text space.\n");
					return;
				}
				Address->Host = Free_Text_Space +
						(sizeof(Free_Text_Space) -
						UserName_Space_Size - i);
				UserName_Space_Size += i;
				Free_Text_Space_Size -= i;
				strcpy(Address->Host, cp);
			}
			/*
			 *	Done
			 */
			Add_Address(Address, &Address_List,
				    Eliminate_Redundant_Addresses);
			tmp = (vstringl *)tmp->next;
		}
		(*dispose_vstringl_list)(&fax_addresses);
		printf ("\n");
	}
}
#endif

static Add_Address1();
static Add_Address(Address,List,Eliminate_Redundant_Addresses)
register struct Address *Address;
struct Address **List;
{

    struct Address *a;
    unsigned int status, ctx, pctx;
    char tmp[1024], *fa, *ra, *pa;
    int i, type;

    if (Address->Type == ADDRESS_LOCAL ||
    	    (Address->Type == ADDRESS_NETWORK && Address->Host == 0)) {
    	ctx = 0;
    	status = personal_alias_lookup(Address->User, &ctx, tmp, sizeof(tmp), 1);
    	if (status & 1) {
    	    do {
    	    	pctx = 0;
    	    	status = parse822(tmp, &pctx, &fa, &ra, &pa, &type);
    	    	if ((status & 1) && (type == ADDRESS_LOCAL || type == ADDRESS_NETWORK || type == ADDRESS_DECNET)
    	    	    	    && Free_Address_Space_Size > 0) {
    	    	    a = &Free_Address_Space[FREE_ADDRESS_SPACE_SIZE-Free_Address_Space_Size];
    	    	    Free_Address_Space_Size--;
    	    	    a->Next_Address = 0;
    	    	    a->Host = 0;
    	    	    a->RFC822_Address = 0;
    	    	    a->Flags = 0;
    	    	    a->Type = type;
    	    	    if (type == ADDRESS_LOCAL || type == ADDRESS_DECNET) {
    	    	    	if (*pa) {
    	    	    	    sprintf(tmp, "%s%s%s@%s %s",
    	    	    	    	(type == ADDRESS_DECNET ? "\"" : ""),
    	    	    	    	ra,
    	    	    	    	(type == ADDRESS_DECNET ? "\"" : ""),
    	    	    	    	Get_Hostname(), pa);
    	    	    	} else {
    	    	    	    sprintf(tmp, "%s%s%s@%s",
    	    	    	    	(type == ADDRESS_DECNET ? "\"" : ""),
    	    	    	    	ra,
    	    	    	    	(type == ADDRESS_DECNET ? "\"" : ""),
    	    	    	    	Get_Hostname());
    	    	    	}
    	    	    	a->Type = type = ADDRESS_LOCAL;
    	    	    	fa = tmp;
    	    	    }

    	    	    i = strlen(fa) + 1;
    	    	    a->RFC822_Address = Free_Text_Space+(sizeof(Free_Text_Space)-
    	    	    	    	    	    UserName_Space_Size - i);
    	    	    UserName_Space_Size += i;
    	    	    Free_Text_Space_Size -= i;
    	    	    strcpy(a->RFC822_Address, fa);

    	    	    if (*ra != '<') {
    	    	    	char *cp;
    	    	    	for (cp = ra+strlen(ra)-1; cp > ra && *cp != '@'; cp--);
    	    	    	if (cp > ra) {
    	    	    	    i = cp - ra + 1;
    	    	    	    if (i > (Free_Text_Space_Size-Text_Space_Size)) goto No_Space;
    	    	    	    a->User = Free_Text_Space+(sizeof(Free_Text_Space)-UserName_Space_Size-i);
    	    	    	    UserName_Space_Size += i;
    	    	    	    Free_Text_Space_Size -= i;
    	    	    	    strncpy(a->User, ra, i-1);
    	    	    	    a->User[i-1] = '\0';
    	    	    	    i = strlen(cp);
    	    	    	    if (i > (Free_Text_Space_Size-Text_Space_Size)) goto No_Space;
    	    	    	    a->Host = Free_Text_Space+(sizeof(Free_Text_Space)-UserName_Space_Size-i);
    	    	    	    UserName_Space_Size += i;
    	    	    	    Free_Text_Space_Size -= i;
    	    	    	    strcpy(a->Host, cp+1);
    	    	    	    for (cp = a->Host; *cp; cp++) if (islower(*cp)) *cp = toupper(*cp);
    	    	    	} else {
    	    	    	    i = strlen(ra) + 1;
    	    	    	    if (i > (Free_Text_Space_Size-Text_Space_Size)) goto No_Space;
    	    	    	    a->User = Free_Text_Space+(sizeof(Free_Text_Space)-UserName_Space_Size-i);
    	    	    	    UserName_Space_Size += i;
    	    	    	    Free_Text_Space_Size -= i;
    	    	    	    strncpy(a->User, ra, i-1);
    	    	    	    a->User[i-1] = '\0';
    	    	    	}
    	    	    } else {
    	    	    	i = strlen(ra)+1;
    	    	    	if (i > (Free_Text_Space_Size-Text_Space_Size)) goto No_Space;
    	    	    	a->User = Free_Text_Space+(sizeof(Free_Text_Space)-UserName_Space_Size-i);
    	    	    	UserName_Space_Size += i;
    	    	    	Free_Text_Space_Size -= i;
    	    	    	strcpy(a->User, ra);
    	    	    }
    	    	    Add_Address1(a, List, Eliminate_Redundant_Addresses);
    	    	}
    	    } while (1 & personal_alias_lookup(Address->User, &ctx, tmp, sizeof(tmp), 1));
    	    
    	    return;
    	}

    }

    Add_Address1(Address, List, Eliminate_Redundant_Addresses);

    return;

No_Space:
    printf("?Out of text space.\n");
    return;
}
/*
 *	Add an address structure to a given list
 */
static Add_Address1(Address,List,Eliminate_Redundant_Addresses)
register struct Address *Address;
struct Address **List;
{
#ifdef MULTINET
	if (RUNNING_MULTINET) {
	    /*
	     *	    Is this a network address, if so, then convert it to the
	     *	    canonical name...
	     */
	    if ((Address->Type == ADDRESS_NETWORK) && (Address->Host)) {
		char HostName[256], temp[2560], *cp;
		int saved_retrans, saved_retry, i;
		struct hostent *hp;

		strcpy(HostName, Address->Host);
		/*
		 *  Try a hostname lookup to get the canonical name
		 */
		if (!(_res.options & RES_INIT)) res_init();
		saved_retrans = _res.retrans; if (_res.retrans > 2) _res.retrans = 2;
		saved_retry   = _res.retry; if (_res.retry > 2) _res.retry = 2;

		hp = gethostbyname(HostName);
		if (hp) {
		    strcpy(HostName, hp->h_name);
		} else if (VMS$TrnLNM("MULTINET_NAMESERVERS", temp)) {
		    /*
		     *	If nameservice, add my domain
		     */
		    if (!strchr(HostName,'.')) { /* No domain, add one */
			if (VMS$TrnLNM("MULTINET_LOCALDOMAIN",temp)) {
			    (void) strcat(HostName, ".");
			    (void) strcat(HostName, temp);
			} else if (cp=strchr(Get_Hostname_Only(),'.')) {
			    (void) strcat(HostName, cp);
			}
		    }
		}

		_res.retrans = saved_retrans;
		_res.retry   = saved_retry;
		/*
		 *	Store the NEW address
		 */
		i = strlen(HostName) + 1;
		if (i < (Free_Text_Space_Size - Text_Space_Size)) {
		    Address->Host = Free_Text_Space +
					    (sizeof(Free_Text_Space) -
						UserName_Space_Size - i);
		    UserName_Space_Size += i;
		    Free_Text_Space_Size -= i;
		    strcpy(Address->Host, HostName);
		}
	    }
	}
#endif

	/*
	 *	Check for duplicate address in ANY list (To,CC,BCC or Address)
	 */
	if (Eliminate_Redundant_Addresses &&
	    (Address_Match(Address,Address_List) ||
	     Address_Match(Address,ToList) ||
	     Address_Match(Address,CcList) ||
	     Address_Match(Address,BccList))) return;	/* Discard address */

	if (*List == 0)
	    *List = Address;	/* List was empty */
	else {			/* add it to the end of the list */
	    register struct Address *p = *List;
	    while(p->Next_Address) p = p->Next_Address;
	    p->Next_Address = Address;
	}
    	Address->Next_Address = 0; /* make sure list is terminated */
	return;
}

/*
 *	Check an Address to see if it is already on a given list
 */
static int Address_Match(Address,List)
register struct Address *Address;
register struct Address *List;
{
	register char *cp,*cp1;
	int Address_Type,List_Type;
	char *Address_Host,*List_Host;

	/*
	 *	Get local copies of the new address type/host
	 */
	Address_Type = Address->Type;
	Address_Host = Address->Host;
	if (!Address_Host) Address_Host = "";
	/*
	 *	If the new address is a LOCAL name we re-do it as a network
	 *	name with the local host name as the host name.
	 */
	if (Address_Type == ADDRESS_LOCAL) {
		/*
		 *	Get the local host name
		 */
		cp = (char *)Get_Hostname();
		if (*cp != 0) {
			Address_Host = cp;
			Address_Type = ADDRESS_NETWORK;
		}
	}
	/*
	 *	Search the list for this address
	 */
	while(List) {
		/*
		 *	Get local copies of this list entry address type/host
		 */
		List_Type = List->Type;
		List_Host = List->Host;
		if (!List_Host) List_Host = "";
		/*
		 *	If the address is a LOCAL name we re-do it as a
		 *	network name with the local host name as the
		 *	host name.
		 */
		if (List_Type == ADDRESS_LOCAL) {
			/*
			 *	Get the local host name
			 */
			cp = (char *)Get_Hostname();
			if (*cp != 0) {
				List_Host = cp;
				List_Type = ADDRESS_NETWORK;
			}
		}
		/*
		 *	Address Type and Host fields must match
		 */
		if ((Address_Type == List_Type) &&
		    (((Address_Host == 0) && (List_Host == 0)) ||
		     (0 == (strcmp(Address_Host, List_Host)))) )  {
			/*
			 *	Do a caseless comparison on User Name
			 */
			cp = Address->User;
			cp1 = List->User;
			while(1) {
				if ((islower(*cp)  ? toupper(*cp)  : *cp) !=
				    (islower(*cp1) ? toupper(*cp1) : *cp1))
						break;		/* No Match */
				if (*cp == 0) return(1);	/* Match    */
				cp++; cp1++;
			}
		}
		List = List->Next_Address;
	}
	/*
	 *	Not on the list, return false
	 */
	return(0);
}

/*
 *	Get subject
 */
Get_Subject(Do_Prompt)
int Do_Prompt;
{
	static struct comnd_function text = {COMND_TEXT};
	char Local_Subject[512];
	char *cp;
	int i;

	if (Do_Prompt) {
		/*
		 *	Save environment in case of rescan
		 */
		setjmp(Send_Top_Level);
		/*
		 *	Setup the comnd jsys & initialize
		 */
		Command_State.prompt = " Subject: ";
		COMMAND_PARSE_INIT(&Command_State);
	}
	/*
	 *	Get the subject line
	 */
	Command_State.atom_buffer = Local_Subject;
	Command_State.atom_buffer_size = sizeof(Local_Subject);
	comnd_jsys(&Command_State,&text,0,0);
	Command_State.atom_buffer = 0;
	/*
	 *	Confirm
	 */
	comnd_jsys(&Command_State,&confirm,0,0);
	/*
	 *	Put the subject line into text space
	 */
	i = strlen(Local_Subject)+1;
	if (i > (Free_Text_Space_Size - Text_Space_Size)) {
		printf("?Insufficient text space for subject.\n");
		longjmp(Goto_Top_Level,0);
	}
	cp = Free_Text_Space +
		(sizeof(Free_Text_Space) - UserName_Space_Size - i);
	UserName_Space_Size += i;
	Free_Text_Space_Size -= i;
	strcpy(cp,Local_Subject);
	Subject = cp;
}


Get_Text(Do_Prompt,Dont_Fixup_Texti_Block)
int Do_Prompt;
int Dont_Fixup_Texti_Block;
{
	int i;
	int Terminator;
	struct texti_block texti_block;
	static unsigned int Break_Mask[4] =
		{0x0c005824,0,0,0};	/* ^B, ^E, ^K, ^L, ^N, ^Z, <ESC> */

	/*
	 *	Initialize the texti block
	 */
	texti_block.block_size	= sizeof(texti_block);
	texti_block.flags	= 0;
	texti_block.input	= 0;
	texti_block.output	= 0;
	texti_block.destination = Free_Text_Space;
	texti_block.destination_size = Free_Text_Space_Size-1;
	texti_block.beginning	= Free_Text_Space;
	texti_block.prompt	= 0;
	texti_block.break_mask	= Break_Mask;
	texti_block.backup_limit= 0;
	/*
	 *	Print prompt
	 */
	if (Do_Prompt) {
		printf(Terse_Text_Prompt ?
			" Msg:\n" :
			" Message (End with ESCAPE or CTRL/Z.\n\
  Use CTRL/B to insert a file, CTRL/E to enter editor, CTRL/K to redisplay\n\
  message, CTRL/L to clear screen and redisplay, CTRL/N to abort.):\n");
	}
	/*
	 *	Fixup Texti block
	 */
	if (!Dont_Fixup_Texti_Block) {
		texti_block.destination += Text_Space_Size;
		texti_block.destination_size -= Text_Space_Size;
	}
	/*
	 *	Get the text
	 */
	while(1) {
	  /*
	   *	Get the text input
	   */
	  texti_jsys(&texti_block);
	  /*
	   *	Get rid of the terminator
	   */
	  texti_block.destination--;
	  texti_block.destination_size++;
	  /*
	   *	Dispatch on terminator
	   */
	  Terminator = *texti_block.destination;
	  switch(Terminator) {
		/*
		 *	^B: Insert file
		 */
		case CTRL_B: {
			static struct comnd_function confirm1 =
				{COMND_CONFIRM};
			static struct comnd_function confirm =
				{COMND_CONFIRM,
				 COMND_HELP_VALID | COMND_SUPPRESS_DEFAULT_HELP,
				 0,
				 0,
				 "return to cancel file insertion"};
			static struct comnd_function filename =
				{COMND_INPUT_FILE,
				 0,
				 &confirm};
			static struct comnd_state Command_State =
				{{0},
				 (COMND_RAISE | COMND_HANDLE_ERRORS),
				 0,
				 0,
				 "(Insert file: "};
			struct comnd_function *f;
			char *cp;
			int Jfn;
			char Filename_Buffer[128];
			char Buffer[132];

			printf("\n");
			/*
			 *	Initialize the filename parse
			 */
			Command_State.buffer = Buffer;
			Command_State.buffer_size = sizeof(Buffer);
			COMMAND_PARSE_INIT(&Command_State);
			/*
			 *	Get the filename
			 */
			if (comnd_jsys(&Command_State,
				       &filename,
				       &Jfn,
				       &f) < 0) break;
			/*
			 *	If just confirmation, break
			 */
			if (f->code == COMND_CONFIRM) {
				printf("...No file inserted)\n");
				break;
			}
			/*
			 *	Free the JFN (TEMP)
			 */
			if (f->code == COMND_INPUT_FILE) {
				local_jfns_jsys(Filename_Buffer,Jfn);
				tops_free_jfn(Jfn);
			}
			/*
			 *	Confirm
			 */
			if (comnd_jsys(&Command_State,&confirm1,0,0) < 0) break;
			/*
			 *	Open the file
			 */
			Jfn = Xopen(Filename_Buffer,0);
			if (Jfn < 0) {
				printf("?File not found\n");
				break;
			}
			/*
			 *	Read in the file
			 */
			i = texti_block.destination - texti_block.beginning;
			i = read(Jfn,
				 texti_block.beginning + i,
				 Free_Text_Space_Size - i);
			texti_block.destination += i;
			texti_block.destination_size -= i;
			/*
			 *	Close the file
			 */
			close(Jfn);
			/*
			 *	Done
			 */
			printf("...EOF)\n");
			break;
			}
		/*
		 *	^K: Retype message text
		 */
		case CTRL_K:
			printf("\n");
			psout_jsys(
			      texti_block.beginning,
			      texti_block.destination - texti_block.beginning);
			break;
		/*
		 *	^E: Enter Editor
		 */
		case CTRL_E:
			printf("\nInvoking editor...\n");  /* Some want to know */
			i = Edit_Buffer((In_Reply_To_String && !Restored_Draft) ?
					     "mm-reply-edit" : "mm-send-edit",
					texti_block.beginning,
					texti_block.destination -
						texti_block.beginning,
					Free_Text_Space_Size);
			i -= (texti_block.destination - texti_block.beginning);
			texti_block.destination += i;
			texti_block.destination_size -= i;
			/*
			 *	Return as though an ESCAPE was typed
			 */
			*texti_block.destination = 0;
			Text_Space_Size =
				texti_block.destination - Free_Text_Space;
			return((Escape_Automatic_Send > 0) ? CTRL_Z : ESCAPE);
		/*
		 *	^L: Clear screen and Retype message text
		 */
		case CTRL_L:
			printf("\n");	/* Go to next line just in case! */
			Blank_Screen();
			printf(" Msg:\n");
			psout_jsys(
			      texti_block.beginning,
			      texti_block.destination - texti_block.beginning);
			break;
		/*
		 *	^N: Abort
		 */
		case CTRL_N:
			write(1,"\010 \010\010 \010",6);  /* TEMP hack!! */
			Do_Abort();
			break;
		/*
		 *	^Z or <ESC>: End of message text
		 */
		case CTRL_Z:
		case ESCAPE:
			/*
			 *	Terminate the line
			 */
			printf("\n");
			*texti_block.destination = 0;
			Text_Space_Size =
				texti_block.destination - Free_Text_Space;
			/*
			 *	Return
			 */
			return(Terminator);
		/*
		 *	Unspecifed terminator (can't happen)
		 */
		default:
			printf("ERROR: TEXTI returned unspecifed terminator!\n");
			return(Terminator);
	  }
	}
}

static Do_Abort()
{
	static struct {
		int current_entries;
		int maximum_entries;
		struct tbluk_keyword keywords[2];
		} yesno = {
			2,
			2,
			{{0,	"no",	0},
			 {0,	"yes",	1}}};
	static struct comnd_function keyword =
		{COMND_KEYWORD,
		 COMND_HELP_VALID | COMND_SUPPRESS_DEFAULT_HELP,
		 0,
		 (int)&yesno,
		 "YES or NO"};
	struct tbluk_keyword *t;
	/*
	 *	Ask the user if we should abort or not
	 */
	while(1) {
		Command_State.prompt = "Abort? ";
		Command_State.atom_buffer = 0;
		Command_State.flags &= ~COMND_HANDLE_ERRORS;
		COMMAND_PARSE_INIT(&Command_State);
		if (comnd_jsys(&Command_State,&keyword,&t,0) >= 0) {
			Command_State.flags |= COMND_HANDLE_ERRORS;
			Confirm();
			if (t->user_data) longjmp(Goto_Top_Level,0);
			break;
		}
		printf("\n?Please answer YES or NO\n");
	}
	/*
	 *	Don't abort
	 */
	return;
}

/*
 *	Send Sub-Command Mode
 *	---------------------
 */

/*
 *	Keyword table for send mode
 */
extern int CMD_Blank(),		CMD_Daytime(),		CMD_Help(),
	   CMD_Push(),		CMD_Status(),		CMD_Version(),
	   MM_Spawn(),		MM_Push(),		MM_Attach(),
	   CMD_Cd();

static int CMD_Bcc(),		CMD_Cc(),		CMD_Delivery_Options(),
	   CMD_Display(),	CMD_Edit(),		CMD_Erase(),
	   CMD_From(),		CMD_Insert(),		CMD_Literal_Type(),
	   CMD_Remove(),	CMD_Reply_To(),		CMD_Save_Draft(),
	   CMD_Sendit(),	CMD_Spell(),		CMD_Subject(),
	   CMD_Text(),		CMD_To(),		CMD_Type(),
    	   CMD_Cc_Original_Recipients();

int CMD_Restore_Draft();


struct {
	int current_entries;
	int maximum_entries;
	struct tbluk_keyword keywords[33];
	} Send_Keywords = {
	33,33,
	{{0,	"Attach",	(int)MM_Attach},
	 {0,	"Bcc",	(int)CMD_Bcc},
	 {0,	"Blank",	(int)CMD_Blank},
	 {0,	"Cc",	(int)CMD_Cc},
	 {0,	"Cd",	(int)CMD_Cd},
	 {0,	"Copy-original-recipients",	(int)CMD_Cc_Original_Recipients},
	 {(COMND_ABBREVIATION | COMND_INVISIBLE),	"D",	(int)&Send_Keywords.keywords[9]},
	 {0,	"Daytime",	(int)CMD_Daytime},
	 {0,	"Delivery-options",	(int)CMD_Delivery_Options},
	 {0,	"Display",	(int)CMD_Display},
	 {0,	"Edit",	(int)CMD_Edit},
	 {0,	"Erase",	(int)CMD_Erase},
	 {0,	"From",	(int)CMD_From},
	 {0,	"Help",	(int)CMD_Help},
	 {0,	"Insert",	(int)CMD_Insert},
	 {0,	"Literal-type",	(int)CMD_Literal_Type},
	 {0,	"Push",	(int)MM_Push},
	 {0,	"Quit",	(int)0},
	 {0,	"Remove",	(int)CMD_Remove},
	 {0,	"Reply-to",	(int)CMD_Reply_To},
	 {0,	"Restore-draft",	(int)CMD_Restore_Draft},
	 {(COMND_ABBREVIATION | COMND_INVISIBLE),	"S",	(int)&Send_Keywords.keywords[23]},
	 {0,	"Save-draft",	(int)CMD_Save_Draft},
	 {0,	"Send",	(int)CMD_Sendit},
	 {0,	"Spawn",	(int)MM_Spawn},
	 {0,	"Spell",	(int)CMD_Spell},
	 {0,	"Status",	(int)CMD_Status},
	 {0,	"Subject",	(int)CMD_Subject},
	 {(COMND_ABBREVIATION | COMND_INVISIBLE),	"T",	(int)&Send_Keywords.keywords[31]},
	 {0,	"Text",	(int)CMD_Text},
	 {0,	"To",	(int)CMD_To},
	 {0,	"Type",	(int)CMD_Type},
	 {0,	"Version",	(int)CMD_Version}}};

/*
 *	Send Mode
 */
static int Send_SubCommand_Mode(Terminator)
int Terminator;		/* Character that terminated the Text input */
{
	jmp_buf Saved_Top_Level;
	struct tbluk_keyword *t;
	int Status;
	static struct comnd_function keyword =
		{COMND_KEYWORD,
		 COMND_DEFAULT_VALID,
		 0,
		 (int)&Send_Keywords,
		 0,
		 "SEND"};

	/*
	 *	Set whether or not the default is valid
	 */
	if (Send_Return_Sends)
		keyword.flags |=  COMND_DEFAULT_VALID;
	else
		keyword.flags &= ~COMND_DEFAULT_VALID;
	/*
	 *	We are now in send mode
	 */
	Send_Mode = 1;
	/*
	 *	If in RSCAN mode and we didn't terminate text input with
	 *	an <ESCAPE>, just send the message
	 */
	if (Doing_Rscan && (Terminator != ESCAPE)) {CMD_Sendit(); return(1);}
	/*
	 *	Check for other conditions than will cause a SEND
	 */
	if (((Escape_Automatic_Send > 0) && (Terminator == ESCAPE)) ||
	    ((Escape_Automatic_Send < 0) && (Terminator == CTRL_Z))) {
		/*
		 *	Send the message!
		 */
		CMD_Sendit();
		return(1);
	}
	/*
	 *	Now we have a send that may be continued
	 */
	Send_Can_Be_Continued = 1;
	/*
	 *	Save the Goto_Top_Level jmp_buf
	 */
	bcopy(&Goto_Top_Level, &Saved_Top_Level, sizeof(Goto_Top_Level));
	/*
	 *	Command Loop; set us as the Top-Level Goto
	 */
	setjmp(Goto_Top_Level);
	while(1) {
		/*
		 *	Make sure we return here on errors
		 */
		setjmp(Send_Top_Level);
		/*
		 *	Initialize
		 */
		Command_State.prompt = Send_Prompt;
		COMMAND_PARSE_INIT(&Command_State);
		/*
		 *	Get the keyword
		 */
		Status = comnd_jsys(&Command_State,&keyword,&t,0);
		if (Status < 0) {
			printf("\n?parse error (later)\n");
			continue;
		}
		/*
		 *	Call action routine
		 */
		if (!t->user_data) {
			/*
			 *	Quit
			 */
			Confirm();
			Send_Mode = 0;
			/*
			 *	Restore the Goto_Top_Level jmp_buf
			 */
			bcopy(&Saved_Top_Level, &Goto_Top_Level, sizeof(Goto_Top_Level));
			return(0);
		}
		(*(int (*)())t->user_data)(&Command_State);
		/*
		 *	If the command was "SEND" we can exit now
		 */
		if (((int (*)())t->user_data) == CMD_Sendit) {
			/*
			 *	Restore the Goto_Top_Level jmp_buf
			 */
			bcopy(&Saved_Top_Level, &Goto_Top_Level, sizeof(Goto_Top_Level));
			return(1);
		}
	}
}


/****************** Send Mode Routines *************************/

/*
 *	Display Message
 */
static CMD_Display()
{
	struct tbluk_keyword *t;
	int Status;

	static struct {
		int current_entries;
		int maximum_entries;
		struct tbluk_keyword keywords[10];
		} Display_Keywords = {
		10,
		10,
	/* 0 */{{0,		"all",		(int)CMD_Display_All},
	/* 1 */ {0,		"bcc",		(int)CMD_Display_Bcc},
	/* 2 */ {0,		"cc",		(int)CMD_Display_Cc},
	/* 3 */ {0,		"from",		(int)CMD_Display_From},
	/* 4 */ {0,		"header",	(int)CMD_Display_Header},
	/* 5 */ {0,		"reply-to",	(int)CMD_Display_Reply_To},
	/* 6 */ {0,		"sender",	(int)CMD_Display_Sender},
	/* 7 */ {0,		"subject",	(int)CMD_Display_Subject},
	/* 8 */ {0,		"text",		(int)CMD_Display_Text},
	/* 9 */ {0,		"to",		(int)CMD_Display_To}
		}};
	static struct comnd_function keyword =
		{COMND_KEYWORD,
		 COMND_DEFAULT_VALID,
		 0,
		 (int)&Display_Keywords,
		 0,
		 "ALL"};

	/*
	 *	Generate noise
	 */
	Noise("message field");
	/*
	 *	Get keyword
	 */
	Status = comnd_jsys(&Command_State,&keyword,&t,0);
	if (Status < 0) {
		printf("\n?parse error (later)\n");
		longjmp(Send_Top_Level,0);
	}
	/*
	 *	Confirm
	 */
	Confirm();
	/*
	 *	Print a blank line
	 */
	printf("\n");
	/*
	 *	Call action routine
	 */
	(*(int (*)())t->user_data)();
}

/*
 *	Print (or create a string in "Buffer" containing) a List of Addresses
 */
static Print_Addresses(String,List,Buffer,Convert_Local_To_Net_Address,
				Print_Invisible_Addresses)
char *String;
struct Address *List;
register char *Buffer;
{
	register struct Address *Address;
	int Column;
	char Out[256];
	int String_Length = strlen(String);
	int i;
	int Doing_Group = 0;

	/*
	 *	Don't print empty lists
	 */
	Address = List;
	if (Address ==	0) return;
	/*
	 *	Print the string
	 */
	if (!Buffer) printf("%s",String);
	else {sprintf(Buffer,"%s",String); Buffer += strlen(Buffer);}
	Column = String_Length;
	/*
	 *	If we don't know our local host name then never
	 *	convert a local address to a network address
	 */
	if (Convert_Local_To_Net_Address)
		if (*(char *)Get_Hostname() == 0)
			Convert_Local_To_Net_Address = 0;
	/*
	 *	Print the address list
	 */
	while(Address) {
		if ((Address->Flags & ADDRESS_INVISIBLE) &&
		    !Print_Invisible_Addresses) {
			if (Address == List) List = Address->Next_Address;
		} else {
			/*
			 *	If we are going from an INVISIBLE address
			 *	to a visible address we add the ";" to
			 *	terminate the group.  Otherwise, count this
			 *	address.
			 */
			if (Doing_Group) {
				if (!(Address->Flags & ADDRESS_INVISIBLE)) {
					Doing_Group = 0;
					if (!Buffer) {
						printf(";");
					} else {
						*Buffer++ = ';';
					}
					Column++;
				} else {
					Doing_Group++;
				}
			}
			/*
			 *	Possibly SPLIT the line here
			 */
			if (Column == String_Length) {
				if (!Buffer) {
					printf(" ");
				} else {
					 *Buffer++ = ' ';
				}
				Column++;
			} else {
				if (Doing_Group != 2) {
					if (!Buffer) {
						printf(", ");
					} else {
						*Buffer++ = ',';
						*Buffer++ = ' ';
					}
					Column += 2;
				}
			}
			switch(Address->Type) {
				case ADDRESS_LOCAL:
					/*
					 *	Convert to local@HOST
					 *	if necessary
					 */
    	    	    	    	    	if (Convert_Local_To_Net_Address){
						/*
						 *	Convert to net address
						 */
    	    	    	    	    	    if (Address->RFC822_Address) {
    	    	    	    	    	    	strcpy(Out, Address->RFC822_Address);
    	    	    	    	    	    } else {
						sprintf(Out,"%s@%s",
							Address->User,
							Get_Hostname());
    	    	    	    	    	    }
					} else {
						/*
						 *	Not necessary
						 */
    	    	    	    	    	    	strcpy(Out, Address->User);
					}
					break;
				case ADDRESS_UUCP:
					sprintf(Out,"%s",Address->User);
					break;
				case ADDRESS_FILE:
					sprintf(Out,"*%s",Address->User);
					break;
				case ADDRESS_NETWORK:
    	    	    	    	    	if (Address->RFC822_Address) {
    	    	    	    	    	    sprintf(Out,"%s",Address->RFC822_Address);
    	    	    	    	    	} else {
					    if (Address->Host)
						sprintf(Out,"%s@%s",
						       Address->User,
						       Address->Host);
					    else
    	    	    	    	    	    	strcpy(Out, Address->User);
    	    	    	    	    	}
					break;
				case ADDRESS_GROUP:
					sprintf(Out,"%s: ",Address->User);
					Doing_Group = 1;
					break;
				default:
					printf("BAD TYPE CODE %d",Address->Type);
					Out[0] = 0;
					break;
			}
			Column += strlen(Out);
			if (Column > 70) {
				if (!Buffer) {
					printf("\n");
				} else {
					*Buffer++ = '\n';
				}
				for(i = 0; i <= String_Length; i++)
					if (!Buffer) printf(" ");
					else *Buffer++ = ' ';
				Column = String_Length+strlen(Out)+1;
			}
			if (!Buffer) {
				printf("%s",Out);
			} else {
				sprintf(Buffer,"%s",Out);
				Buffer += strlen(Buffer);
			}
		}
		 Address = Address->Next_Address;
	}
	if (!Buffer) {
		if (Doing_Group) {
			printf(";\n");
		} else {
			printf("\n");
		}
	} else {
		if (Doing_Group) {
			*Buffer++ = ';';
		}
		*Buffer++ = '\n';
		*Buffer = 0;
	}
}


/*
 *	Print BCC line
 */
static CMD_Display_Bcc()
{Print_Addresses("Bcc:",BccList,0,0,0);}

/*
 *	Print CC line
 */
static CMD_Display_Cc()
{Print_Addresses("Cc:",CcList,0,0,0);}

/*
 *	Print From line
 */
static CMD_Display_From()
{
	char *cp;

	/*
	 *	Possibly do the USER supplied From: field
	 */
	if (From_String && (From_String[0] != 0)) {
		printf("From: %s\n",From_String);
		return;
	}
	/*
	 *	Generate the From: field
	 */
	cp = (char *)Get_From_Hostname();
	if (*cp == 0) cp = 0;
	if (Personal_Name[0])
		printf("From: %s <%s%s%s>\n",
			Personal_Name,
			(char *)Get_Username(),
			cp ? "@" : "",
			cp ? cp : "");
	else
		printf("From: %s%s%s\n",
			(char *)Get_Username(),
			cp ? "@" : "",
			cp ? cp : "");
}

/*
 *	Print Sender line
 */
static CMD_Display_Sender()
{
	char *cp;

	if (From_String && (From_String[0] != 0)) {
		char *cp = (char *)Get_From_Hostname();
		if (*cp == 0) cp = 0;
		printf("Sender: %s%s%s\n",
			(char *)Get_Username(),
			cp ? "@" : "",
			cp ? cp : "");
	}
}

/*
 *	Print Reply-To line
 */
static CMD_Display_Reply_To()
{
	if (Reply_To_String && (Reply_To_String[0] != 0))
		printf("Reply-To: %s\n",Reply_To_String);
}

/*
 *	Print Subject
 */
static CMD_Display_Subject()
{
	if (Subject == 0) return;
	if (*Subject == 0) return;
	printf("Subject: %s\n",Subject);
}

/*
 *	Print Text
 */
static CMD_Display_Text()
{
	register char *cp;

	/*
	 *	Print the text
	 */
	psout_jsys(Free_Text_Space,Text_Space_Size);
	cp = Free_Text_Space+Text_Space_Size - 1;
	if (*cp != '\n') printf("\n");
#ifdef DASHES
	printf("-------\n");
#endif DASHES
}

/*
 *	Print To line
 */
static CMD_Display_To()
{Print_Addresses("To:",ToList,0,0,0);}

/*
 *	Print entire header
 */
static CMD_Display_Header()
{char *cp;
CMD_Display_From(); CMD_Display_Sender(); CMD_Display_Subject();
 CMD_Display_To(); CMD_Display_Cc(); CMD_Display_Bcc();
 CMD_Display_Reply_To();
 /*
  *	Display "In-Reply-To:"
  */
 if (In_Reply_To_String != 0) {
	if (*In_Reply_To_String != 0) {
		printf("In-Reply-To: %s\n",In_Reply_To_String);
	}
 }
	if (Delivery_Options & DELIVERY_OPTION_REGISTERED_MAIL) {
		char *cp;

		cp = (char *)Get_Hostname();
		if (*cp == 0) cp = 0;
		printf("Registered-Mail-Reply-Requested-By: <%s%s%s>\n",
			(char *)Get_Username(),
			cp ? "@" : "",
			cp ? cp : "");
	}
	if (Delivery_Options & DELIVERY_OPTION_READ_RECEIPT) {
		char *cp;

		cp = (char *)Get_Hostname();
		if (*cp == 0) cp = 0;
		printf("Read-Receipt-To: <%s%s%s>\n",
			(char *)Get_Username(),
			cp ? "@" : "",
			cp ? cp : "");
	}
	if (Delivery_Options & DELIVERY_OPTION_DELIVERY_RECEIPT) {
		char *cp;

		cp = (char *)Get_Hostname();
		if (*cp == 0) cp = 0;
		printf("Delivery-Receipt-To: <%s%s%s>\n",
			(char *)Get_Username(),
			cp ? "@" : "",
			cp ? cp : "");
	}
 /*
  *	Display User Headers
  */
 if (User_Header_Str[0] != 0) printf("%s",User_Header_Str);
}

/*
 *	Print Header + Text
 */
static CMD_Display_All()
{CMD_Display_Header(); printf("\n"); CMD_Display_Text();}


/*
 *	Add to an address list
 */
static Add_More_Users_To_List(List)
struct Address **List;
{
	register struct Address *Address;

	/*
	 *	Get the new addresses
	 */
	Address_List = 0;
	Get_User(1);
	/*
	 *	Add the users to given list
	 */
	while((Address = Address_List) != 0) {
		Address_List = Address->Next_Address;
		Add_Address(Address,List,1);
	}
}


/*	Blind CC list	*/
static CMD_Bcc()
{Add_More_Users_To_List(&BccList);}

/*	 CC list	*/
static CMD_Cc() {
    	    Add_More_Users_To_List(&CcList);
}

static CMD_Cc_Original_Recipients() {

    struct Address *Address;

    	Confirm();
	/*
	 *	Add the users to given list
	 */
	while((Address = StandByCcList) != 0) {
		StandByCcList = Address->Next_Address;
		Add_Address(Address,&CcList,1);
	}
}

/*	 To list	*/
static CMD_To()
{Add_More_Users_To_List(&ToList);}


/*
 *	Change the subject field
 */
static CMD_Subject()
{Get_Subject(0);}


/*
 *	Add to the message text
 */
static CMD_Text()
{
	Confirm();
	/*
	 *	Disable TOPS EOF hook during Get_Text()
	 */
	tops_eof_hook = 0;
	Get_Text(0,0);
	tops_eof_hook = Control_Z;
}


/*
 *	Set delivery options
 */
static CMD_Delivery_Options()
{
	
static struct {
	int current_entries;
	int maximum_entries;
	struct tbluk_keyword keywords[3];
	} Delivery_Option_Names = {
	3,3,
	{{0,	"DELIVERY-RECEIPT-REQUESTED",	(int)DELIVERY_OPTION_DELIVERY_RECEIPT},
	 {0,	"READ-RECEIPT-REQUESTED",	(int)DELIVERY_OPTION_READ_RECEIPT},
	 {0,	"REGISTERED-MAIL",	(int)DELIVERY_OPTION_REGISTERED_MAIL}}};
	static struct comnd_function keyword =
		{COMND_KEYWORD,
		 COMND_HELP_VALID,
		 0,
		 (int)&Delivery_Option_Names,
		 "delivery option, "};
	struct tbluk_keyword *tk;
	int Status;

	/*
	 *	Parse the delivery option
	 */
	Status = comnd_jsys(&Command_State,&keyword,&tk,0);
	if (Status < 0) {
		printf("Parse error (later)\n");
		longjmp(Send_Mode ? Send_Top_Level : Goto_Top_Level, 0);
	}
	Confirm();
	/*
	 *	Set it
	 */
	Delivery_Options |= (int)tk->user_data;
}


/*
 *	Edit the message
 */
static CMD_Edit()
{
	Confirm();
	Text_Space_Size =
	   Edit_Buffer((In_Reply_To_String && !Restored_Draft) ?
		       "mm-reply-edit" : "mm-send-edit",
		       Free_Text_Space,
		       Text_Space_Size,
		       Free_Text_Space_Size-100);
}

/*
 *	Insert a file at the end of the message
 */
static CMD_Insert()
{
	static struct comnd_function filename = {COMND_INPUT_FILE};
	register char *cp;
	int Jfn,i;
	char File_Name[128];

	/*
	 *	Get the filename
	 */
	if (comnd_jsys(&Command_State,&filename,&Jfn,0) < 0) return;
	/*
	 *	Free the JFN (TEMP)
	 */
	local_jfns_jsys(File_Name,Jfn);
	tops_free_jfn(Jfn);
	/*
	 *	Confirm
	 */
	Confirm();
	/*
	 *	Open the file
	 */
	Jfn = Xopen(File_Name,0);
	if (Jfn < 0) {
		printf("?File not found\n");
		return;
	}
	/*
	 *	Read it in
	 */
	i = read(Jfn,
		 Free_Text_Space + Text_Space_Size,
		 Free_Text_Space_Size - Text_Space_Size);
	close(Jfn);
	if (i < 0) {
		printf("?I/O error\n");
		return;
	}
	if (i == (Free_Text_Space_Size - Text_Space_Size))
		printf("?Insufficient text space, insert file truncated\n");
	/*
	 *	Update the text space
	 */
	Text_Space_Size += i;
}

/*
 *	Type the current message
 */
static CMD_Type()
{
	/*
	 *	Confirm
	 */
	Confirm();
	/*
	 *	Do it
	 */
	Print_Message(Current_Message,1);
}

/*
 *	Literal Type the current message
 */
static CMD_Literal_Type()
{
	/*
	 *	Confirm
	 */
	Confirm();
	/*
	 *	Do it
	 */
	Print_Message(Current_Message,0);
}

/*
 *	Run spell checker to check messages.
 */
static CMD_Spell()
{
	int fd, i;
    	struct dsc$descriptor dsc;
	char Filename[32];
	char Command_To_Spawn[sizeof(Spell_Invocation_Command)+32];
	int mypid = getpid() & 0xffff;

	/*
	 *	Confirm
	 */
	Confirm();

	/*
	 *	Write the buffer to a temporary file
	 */
	sprintf(Filename,"sys$scratch:mm%d.tmp",mypid);
	fd = Xcreat(Filename,0600,"txt");
	write(fd,Free_Text_Space,Text_Space_Size);
	close(fd);

	/*
	 *	Run spell command
	 */
	dsc.dsc$w_length = sprintf(Command_To_Spawn,
		Spell_Invocation_Command,
		Filename);
    	dsc.dsc$b_dtype = DSC$K_DTYPE_T;
    	dsc.dsc$b_class = DSC$K_CLASS_S;
    	dsc.dsc$a_pointer = Command_To_Spawn;
    	i = lib$spawn(&dsc);
	if (!(i & 1)) {
		/*
		 *	Spawn failed: print status
		 */
		printf("SPAWN failed, status = %x\n", i);
		i = Text_Space_Size;
	} else {
		/*
		 *	Done, read the temp file back in!
		 */
		fd = open(Filename, 0);
		i = read(fd, Free_Text_Space, Free_Text_Space_Size-100);
		if (i == Free_Text_Space_Size-100)
			printf("The editor buffer was too large, it has been truncated\n");
		close(fd);
	}

	/*
	 *	Delete file
	 */
	while(unlink(Filename) >= 0) ;

	/*
	 *	Done
	 */
	return(i);
}

/*
 *	Specify the From: field for this message
 */
static CMD_From()
{
	static struct comnd_function text = {COMND_TEXT};
	char *cp;
	int i;
	char	Local[64];

	/*
	 *	Do the noise
	 */
	Noise("name");
	/*
	 *	Get the Name
	 */
	Command_State.atom_buffer = Local;
	Command_State.atom_buffer_size = sizeof(Local);
	comnd_jsys(&Command_State,&text,0,0);
	Command_State.atom_buffer = 0;
	/*
	 *	Confirm
	 */
	Confirm();
	/*
	 *	Put the From: line into text space
	 */
	i = strlen(Local) + 1;
	if (i > (Free_Text_Space_Size - Text_Space_Size)) {
		printf("?Insufficient text space for From:.\n");
		return;
	}
	cp = Free_Text_Space +
		(sizeof(Free_Text_Space) - UserName_Space_Size - i);
	UserName_Space_Size += i;
	Free_Text_Space_Size -= i;
	strcpy(cp,Local);
	From_String = cp;
	return;
}


/*
 *	Specify the Reply-To: field for this message
 */
static CMD_Reply_To()
{
	static struct comnd_function text = {COMND_TEXT};
	char *cp;
	int i;
	char Local[256];

	/*
	 *	Do the noise
	 */
	Noise("name");
	/*
	 *	Get the Name
	 */
	Command_State.atom_buffer = Local;
	Command_State.atom_buffer_size = sizeof(Local);
	comnd_jsys(&Command_State,&text,0,0);
	Command_State.atom_buffer = 0;
	/*
	 *	Confirm
	 */
	Confirm();
	/*
	 *	Put the From: line into text space
	 */
	i = strlen(Local) + 1;
	if (i > (Free_Text_Space_Size - Text_Space_Size)) {
		printf("?Insufficient text space for Reply-To:.\n");
		return;
	}
	cp = Free_Text_Space +
		(sizeof(Free_Text_Space) - UserName_Space_Size - i);
	UserName_Space_Size += i;
	Free_Text_Space_Size -= i;
	strcpy(cp,Local);
	Reply_To_String = cp;
	return;
}


/*
 *	Remove users from the To:, cc:	and Bcc: lists.
 */
static CMD_Remove()
{
	static struct Address **Address_Lists[3] =
		{&ToList,&CcList,&BccList};
	register struct Address *Address,**q;
	register int i;
	register int local_found, found;
	register char *cp,*cp1;

	/*
	 *	Get the list of users
	 */
	Address_List = 0;
	Get_User(0);
	Confirm();

	/*
	 *	Search all the lists and remove any matches
	 */
	found = 0;
	while(Address_List) {
		local_found = 0;
		for(i = 0; i < (sizeof(Address_Lists)/sizeof(Address_Lists[0])); i++) {
			q = Address_Lists[i];
			Address = *q;
			while(Address) {
				/*
				 *	Check for address type match
				 */
				if (Address->Type == Address_List->Type) {
					/*
					 *	Check for username match
					 *	(case is unimportant!!)
					 */
					cp = Address_List->User;
					cp1 = Address->User;
					while(*cp) {
					  if (*cp != *cp1)
					   if ((isupper(*cp) ?
							tolower(*cp) : *cp) !=
					       (isupper(*cp1) ?
							tolower(*cp1) : *cp1))
							break;
					  cp++;
					  cp1++;
					}
					/*
					 *	Check for partial hostname
					 *	match (case is unimportant!!)
					 */
					if ((*cp == 0) && (*cp1 == 0) &&
					    (!((Address_List->Host == 0) ^
					       (Address->Host == 0)))) {
					    local_found = 0;
					    if ((Address_List->Host == 0) ||
						(Address->Host == 0)) {
						local_found = 1;
					    } else {
						cp = Address_List->Host;
						cp1 = Address->Host;
						while(*cp) {
						  if (*cp != *cp1)
						   if ((isupper(*cp) ?
								tolower(*cp) : *cp) !=
						       (isupper(*cp1) ?
								tolower(*cp1) : *cp1))
								break;
							  cp++;
							  cp1++;
						}
						if (*cp == 0)
						  local_found = 1;
					    }
					    if (local_found) {
						    /*
						     *	Found a match, unlink
						     *	the entry
						     */
						    found++;
						    Address = Address->Next_Address;
						    *q = Address;
						    continue;
					    }
					}
				}
				q = &Address->Next_Address;
				Address = *q;
			}
		}
		/*
		 *	If at least one instance of the user was not
		 *	found, generate an error.
		 */
		if (found == 0) {
			printf("?Address \"");
			switch(Address_List->Type) {
				default:
				case ADDRESS_LOCAL:
				case ADDRESS_UUCP:
					printf("%s",Address_List->User);
					break;
				case ADDRESS_NETWORK:
					if (Address_List->Host)
						printf("%s@%s",
							Address_List->User,
							Address_List->Host);
					else
						printf("%s",
							Address_List->User);
					break;
				case ADDRESS_GROUP:
					printf("%s: ;",Address_List->User);
					break;
			}
			printf("\" not found\n");
			return(0);
		}
		/*
		 *	Remove the next User
		 */
		Address_List = Address_List->Next_Address;
	}
}


/*
 *	Send the message
 */
static CMD_Sendit()
{
	char Header[2048], Address_Buffer[2048];
	char *Header_Pointer;
	int Header_Length, Address_Buffer_Length;
	register struct Address *Address,*Address1;
	register char *cp;
	int i, Delivery_Failed = 0;
	static struct Address **Address_Lists[4] =
		 /* Address_List must be last */
		{&ToList,&CcList,&BccList,&Address_List};

	/*
	 *	Confirm
	 */
	Confirm();
	/*
	 *	This send is GONE!
	 */
	Send_Can_Be_Continued = 0;
	/*
	 *	If there is a SAVED-MESSAGES-FILE, add it to the BCC list
	 */
	if (Saved_Messages_File[0] != 0) {
		/*
		 *	Check if we can access the Saved Messages file
		 */
		if (Xaccess(Saved_Messages_File, 0) < 0) {
			printf("[WARNING: Saved messages file \"%s\" is not accessible]\n",
					Saved_Messages_File);
		} else {
			/*
			 *	Add it to the BCC list
			 */
			Header[0] = '*';
			strcpy(Header+1,Saved_Messages_File);
			Setup_String_Parse(Header);
			Add_More_Users_To_List(&BccList);
		}
	}
	/*
	 *	If there is no To list but there IS a CC list, then make
	 *	the CC list the To list.
	 */
	if ((ToList == 0) && (CcList != 0)) {
		ToList = CcList;
		CcList = 0;
	}
	/*
	 *	If there is still no To List, prompt for it!!!
	 */
	while(ToList == 0) {
		Address_List = 0;
		Get_To(1);
		ToList = Address_List;
	}
	/*
	 *	Add '\n' ------- to the end of the message
	 */
	cp = Free_Text_Space + Text_Space_Size;
	if (cp[-1] != '\n') {*cp++ = '\n'; Text_Space_Size++; *cp = 0;}
#ifdef DASHES
	if (strcmp(cp-8,"-------\n") != 0) {
			strcpy(cp,"-------\n");
			Text_Space_Size += 8;
	}
#endif DASHES
	/*
	 *	Insert signature file if set
	 */
	if (Signature_File[0] != 0) Insert_Signature_File();

	/*
	 *	Generate the header text
	 */
	if (!Substitute_Header)
		Generate_Header(Header);
	Header_Pointer = Substitute_Header ? Substitute_Header : Header;
	Header_Length = strlen(Header_Pointer);
	Substitute_Header = 0;

	/*
	 *	If we are running PMDF, generate an address buffer in case
	 *	we do a file delivery (since PMDF generates its own To:, Cc:,
	 *	and Bcc: lines).
	 */
	if (RUNNING_PMDF) {
		Generate_Address_List(Address_Buffer);
		Address_Buffer_Length = strlen(Address_Buffer);
	}
	else {
		Address_Buffer[0] = '\0';
		Address_Buffer_Length = 0;
	}

	/*
	 *	Create the various Mail Lists (Local/Net-Mail...etc)
	 */
	Address_List = 0;
	LclList = 0;
	FiList = 0;
	NetList = 0;
	for(i = 0; i < (sizeof(Address_Lists)/sizeof(Address_Lists[0])); i++){
	   while(Address = *Address_Lists[i]) {
		*Address_Lists[i] = 0;
		while(Address) {
			Address1 = Address;
			Address = Address->Next_Address;
			Address1->Next_Address = 0;
			/*
			 *	Check for duplicate addresses
			 */
#if defined(MULTINET)||defined(PMDF)||defined(MX)
			/*
			 *	PMDF does not appear in this list --
			 *	it does its own redundant address elimination.
			 */
			if (RUNNING_MULTINET || RUNNING_MX)
				if (Address_Match(Address1,NetList)) continue;
#endif
			if (!RUNNING_MULTINET && !RUNNING_PMDF && !RUNNING_MX)
				if (Address_Match(Address1,LclList) ||
				    Address_Match(Address1,NetList) ||
				    Address_Match(Address1,FiList)) continue;
			/*
			 *	Process this address type
			 */
#if defined(MULTINET)||defined(PMDF)||defined(MX)
			if (RUNNING_MULTINET || RUNNING_PMDF || RUNNING_MX) {
#if defined(MULTINET) || defined(PMDF) || defined(MX)
			  if (RUNNING_MULTINET || RUNNING_PMDF || RUNNING_MX) {
				/*
				 *	If not local address,
				 *	add it to the network list.
				 */
				if (Address1->Host &&
				   (strcmp((char *)Get_Hostname(),
					Address1->Host) == 0)) {
				    /*
				     *	    Local address, drop into the
				     *	    local address code.
				     */
				    Address1->Type = ADDRESS_LOCAL;
				    Address1->Host = 0;
				}
			  Address1->Flags &= ~(ADDRESS_ON_TO_LINE |
					       ADDRESS_ON_CC_LINE |
					       ADDRESS_ON_BCC_LINE);
			  Address1->Flags |= (1 << (i + ADDRESS_ON_START_BIT));
			  }
#endif /* MULTINET || PMDF || MX */
			  Add_Address(Address1,
				      (Address1->Type == ADDRESS_FILE) ?
						&FiList : &NetList,
				      1);
			} else {
#endif /*defined(MULTINET) || defined(PMDF) || defined(MX) */
			  switch(Address1->Type) {
				case ADDRESS_FILE:
					Add_Address(Address1,&FiList,1);
					break;
				case ADDRESS_NETWORK:
					/*
					 *	If not local address,
					 *	add it to the network list.
					 */
					if (strcmp((char *)Get_Hostname(),
						Address1->Host ? Address1->Host : "") != 0) {
						Add_Address(Address1,&NetList,1);
						break;
					}
					/*
					 *	Local address, drop into the
					 *	local address code.
					 */
					Address1->Type = ADDRESS_LOCAL;
					Address1->Host = 0;
				case ADDRESS_LOCAL:
					Add_Address(Address1,&LclList,1);
					break;
				case ADDRESS_GROUP:
					break;
				case ADDRESS_UUCP:
					Add_Address(Address1,&UucpList,1);
					break;
				default:
					printf("Error: Unknown address type %d.\n",
							Address1->Type);
			  }
#if defined(MULTINET)||defined(PMDF)||defined(MX)
			}
#endif
		}
	   }
	}
#if defined(MULTINET) || defined(PMDF) || defined(MX)
	if (RUNNING_MULTINET || RUNNING_PMDF || RUNNING_MX) {
		if (NetList)
			if (!Deliver_Net_Mail(NetList,
					      Header_Pointer,
					      Header_Length,
					      Free_Text_Space,
					      Text_Space_Size))
				Delivery_Failed = 1;
	} else {
#endif	/* MULTINET || PMDF || MX */
		/*
		 * Send Local Mail
		 */
		if (LclList)
			Deliver_Local_Mail(LclList,
					   Header_Pointer,
					   Header_Length,
					   Free_Text_Space,
					   Text_Space_Size);
		/*
		 *	Send Net Mail
		 */
		if (NetList)
			if (!Deliver_Net_Mail(NetList,
					      Header_Pointer,
					      Header_Length,
					      Free_Text_Space,
					      Text_Space_Size))
				Delivery_Failed = 1;
#if defined(MULTINET) || defined(PMDF) || defined(MX)
	}
#endif	/* MULTINET || PMDF || MX */
	/*
	 *	If running PMDF, regenerate the header text for file delivery
	 *	or a dead letter file
	 */
	if (RUNNING_PMDF)
		Merge_Headers(Header_Pointer, &Header_Length,
			      Address_Buffer, Address_Buffer_Length);
	if (FiList) {
		Deliver_File(FiList,
			     Header_Pointer,
			     Header_Length,
			     Free_Text_Space,
			     Text_Space_Size);
		File_Delivery_Done = 1;
	}
	/*
	 *	Done
	 */
	Deliver_Done();
	Send_Mode = 0;
	/*
	 *	If necessary, make the MAIL-COPY-FILE
	 */
	if (Mail_Copy_File[0] != 0) {
		/*
		 *	Delete any OLD MAIL-COPY-FILE
		 */
		if (Mail_Copy_File_Exists)
			unlink(Mail_Copy_File);
		/*
		 *	Create the MAIL-COPY-FILE
		 */
		i = Xcreat(Mail_Copy_File,Mail_File_Mode,"txt");
		if (i < 0)
			printf("?Couldn't create MAIL-COPY-FILE %s\n",
				Mail_Copy_File);
		else {
			/*
			 *	Write the message text
			 */
			if (write(i,Free_Text_Space,Text_Space_Size) != Text_Space_Size)
				printf("?I/O Error writing MAIL-COPY-FILE %s\n",
					Mail_Copy_File);
			/*
			 *	Done
			 */
			close(i);
			Mail_Copy_File_Exists = 1;
		}
	}
	/*
	 *	Any errors sending mail?  If so, write out a dead letter file.
	 */
	if (Delivery_Failed) {
		i = Xcreat(Dead_Letter_File,Mail_File_Mode,"txt");
		if (i < 0)
			printf("?Couldn't create %s\n", Dead_Letter_File);
		else {
			if (write(i,Header_Pointer,Header_Length) != Header_Length)
				printf("?I/O Error writing %s\n", Dead_Letter_File);
			if (write(i,Free_Text_Space,Text_Space_Size) != Text_Space_Size)
				printf("?I/O Error writing %s\n", Dead_Letter_File);
			/*
			 *	Done
			 */
			close(i);
			printf("  Mail message written to %s\n", Dead_Letter_File);
		}
	}
	return;
}


/*
 *	Insert the signature file (if one exists)
 */
Insert_Signature_File()
{
	int Jfn,i;

	/*
	 *	Open the file
	 */
	Jfn = Xopen(Signature_File,0);
	/*
	 *	Return if file not found
	 */
	if (Jfn < 0) return;
	/*
	 *	Read it in
	 */
	i = read(Jfn,
		 Free_Text_Space + Text_Space_Size,
		 Free_Text_Space_Size - Text_Space_Size);
	close(Jfn);
	if (i < 0) {
		printf("?I/O error\n");
		return;
	}
	if (i == (Free_Text_Space_Size - Text_Space_Size))
		printf("?Insufficient text space, insert file truncated\n");
	/*
	 *	Update the text space
	 */
	Text_Space_Size += i;
}


/*
 *	Merge address headers and other headers together.
 */
Merge_Headers(Header, Header_Length, Address_Buffer, Address_Buffer_Length)
char *Header;
int *Header_Length;
char *Address_Buffer;
int Address_Buffer_Length;
{
	register char *cp, *cp1, *cp2;
	register int i;

	/*
	 *	Let's find the From: header first!
	 */
	i = *Header_Length;
	cp = Header;
	while (i > 0) {
		if ((cp[0] == 'F') &&
		    (cp[1] == 'r') &&
		    (cp[2] == 'o') &&
		    (cp[3] == 'm') &&
		    (cp[4] == ':')) {cp += 6; break;}
		/*
		 *	Skip to beyond the next '\n'
		 */
		while(--i > 0)
			if (*cp++ == '\n') break;
	}
	while(--i > 0)
		if (*cp++ == '\n') break;

	/*
	 *	Is the next line the Subject?  If so, skip over it.
	 */
	if ((cp[0] == 'S') &&
	    (cp[1] == 'u') &&
	    (cp[2] == 'b') &&
	    (cp[3] == 'j') &&
	    (cp[4] == 'e') &&
	    (cp[5] == 'c') &&
	    (cp[6] == 't') &&
	    (cp[7] == ':')) {
		cp += 9;
		while(--i > 0)
			if (*cp++ == '\n') break;
	}

	/*
	 *	Is the next line the Sender?  If so, skip over it.
	 */
	if ((cp[0] == 'S') &&
	    (cp[1] == 'e') &&
	    (cp[2] == 'n') &&
	    (cp[3] == 'd') &&
	    (cp[4] == 'e') &&
	    (cp[5] == 'r') &&
	    (cp[6] == ':')) {
		cp += 8;
		while(--i > 0)
			if (*cp++ == '\n') break;
	}

	/*
	 *	This is where we insert our address headers.
	 */
	cp1 = Header + *Header_Length;
	cp2 = cp1 + Address_Buffer_Length;
	while (cp1 >= cp) *cp2-- = *cp1--;
	cp1 = Address_Buffer;
	while (*cp1) *cp++ = *cp1++;

	*Header_Length += Address_Buffer_Length;
	Header[*Header_Length] = '\0';
}


/*
 *	Generate the Message Header text
 */
static Generate_Address_List(Buffer)
register char *Buffer;
{
	/*
	 *	Generate To:
	 */
	if (ToList) {
		Print_Addresses("To:",ToList,Buffer,1,0);
		Buffer += strlen(Buffer);
	}

	/*
	 *	Generate CC:
	 */
	if (CcList) {
		Print_Addresses("Cc:",CcList,Buffer,1,0);
		Buffer += strlen(Buffer);
	}

	/*
	 *	Generate BCC:
	 */
	if (BccList) {
		Print_Addresses("Bcc:",BccList,Buffer,1,0);
		Buffer += strlen(Buffer);
	}

	/*
	 *	Leave a blank line
	 */
	*Buffer = 0;
}


/*
 *	Generate the Message Header text
 */
static Generate_Header(Buffer)
register char *Buffer;
{
	char Date[64];
	register char *cp;
	char *DayName;
	char *Day;
	char *Month;
	char *Year;
	char *Time;

	/*
	 *	Generate the Date
	 */
	Get_DayTime(Date);
	cp = Date;
	DayName = Date;
	cp[3] = 0;	/* Terminate the Day name string */
	cp += 4;
	while(*cp != ' ') cp++;
	while(*cp == ' ') cp++;
	Month = cp;
	/* Watch out for MAY!!!! */
	if (cp[3] == ' ') {
		cp[3] = 0;
		cp += 4;
	} else {
		cp[3] = 0;
		cp += 4;
		while(*cp != ' ') cp++;
		while(*cp == ' ') cp++;
	}
	Day = cp;
	while(*cp != ',') cp++;
	*cp++ = 0;
	while(*cp == ' ') cp++;
	Year = cp /*+2*/;
	cp += 4;
	*cp++ = 0;
	while(*cp == ' ') cp++;
	Time = cp;
	sprintf(Buffer,"Date: %s, %s %s %s %s %s\n",
		DayName,Day,Month,Year,Time,(char *)Timezone_String(1));
	Buffer += strlen(Buffer);
	/*
	 *	Generate From:
	 */
	if ((From_String == 0) || (From_String[0] == 0)) {
		if (Personal_Name[0]) {
			char *cp;

			cp = (char *)Get_From_Hostname();
			if (*cp == 0) cp = 0;
			sprintf(Buffer,"From: %s <%s%s%s>\n",
				Personal_Name,
				(char *)Get_Username(),
				cp ? "@" : "",
				cp ? cp : "");
		} else {
			char *cp;

			cp = (char *)Get_From_Hostname();
			if (*cp == 0) cp = 0;
			sprintf(Buffer,"From: %s%s%s\n",
				(char *)Get_Username(),
				cp ? "@" : "",
				cp ? cp : "");
		}
	} else {
		sprintf(Buffer,"From: %s\n",From_String);
	}
	Buffer += strlen(Buffer);
	/*
	 *	Generate Subject:
	 */
	if (Subject) {
		if (*Subject) {
			sprintf(Buffer,"Subject: %s\n",Subject);
			Buffer += strlen(Buffer);
		}
	}
	/*
	 *	Possibly generate the Sender: field
	 */
	if (From_String && (From_String[0] != 0)) {
		if (Personal_Name[0]) {
			char *cp;

			cp = (char *)Get_From_Hostname();
			if (*cp == 0) cp = 0;
			sprintf(Buffer,"Sender: %s <%s%s%s>\n",
				Personal_Name,
				(char *)Get_Username(),
				cp ? "@" : "",
				cp ? cp : "");
		} else {
			char *cp;

			cp = (char *)Get_From_Hostname();
			if (*cp == 0) cp = 0;
			sprintf(Buffer,"Sender: %s%s%s\n",
				(char *)Get_Username(),
				cp ? "@" : "",
				cp ? cp : "");
		}
		Buffer += strlen(Buffer);
	}

	/*
	 *	PMDF will generate its own To: and Cc: headers!
	 */
	if (!RUNNING_PMDF) {
		/*
		 *	Generate To:
		 */
		if (ToList) {
			Print_Addresses("To:",ToList,Buffer,1,0);
			Buffer += strlen(Buffer);
		}
		/*
		 *	Generate CC:
		 */
		if (CcList) {
			Print_Addresses("Cc:",CcList,Buffer,1,0);
			Buffer += strlen(Buffer);
		}
	}
	/*
	 *	Possibly generate the "Reply-To:" field
	 */
	if (Reply_To_String && (Reply_To_String[0] != 0)) {
		sprintf(Buffer,"Reply-To: %s\n",Reply_To_String);
		Buffer += strlen(Buffer);
	}
	/*
	 *	Do the message ID
	 */
	if (!Dont_Insert_Message_ID) {
		char *Hostname;
		int Time[2];

		idtim_jsys("now",0,Time);
		Hostname = (char *)Get_Hostname();
		sprintf(Buffer,"Message-ID: <%d.%d.%s%s%s>\n",
			Time[0], Time[1],
			Get_Username(),
			Hostname ? "@" : "",
			Hostname ? Hostname : "");
		Buffer += strlen(Buffer);
	}
	/*
	 *	Generate delivery options
	 */
	if (Delivery_Options & DELIVERY_OPTION_REGISTERED_MAIL) {
		char *cp;

		cp = (char *)Get_Hostname();
		if (*cp == 0) cp = 0;
		sprintf(Buffer,"Registered-Mail-Reply-Requested-By: <%s%s%s>\n",
			(char *)Get_Username(),
			cp ? "@" : "",
			cp ? cp : "");
		Buffer += strlen(Buffer);
	}
	if (Delivery_Options & DELIVERY_OPTION_READ_RECEIPT) {
		char *cp;

		cp = (char *)Get_Hostname();
		if (*cp == 0) cp = 0;
		sprintf(Buffer,"Read-Receipt-To: <%s%s%s>\n",
			(char *)Get_Username(),
			cp ? "@" : "",
			cp ? cp : "");
		Buffer += strlen(Buffer);
	}
	if (Delivery_Options & DELIVERY_OPTION_DELIVERY_RECEIPT) {
		char *cp;

		cp = (char *)Get_Hostname();
		if (*cp == 0) cp = 0;
		sprintf(Buffer,"Delivery-Receipt-To: <%s%s%s>\n",
			(char *)Get_Username(),
			cp ? "@" : "",
			cp ? cp : "");
		Buffer += strlen(Buffer);
	}
	/*
	 *	Generate In-Reply-To:
	 */
	if (In_Reply_To_String)
		if (*In_Reply_To_String) {
			sprintf(Buffer,"In-Reply-To: %s\n",In_Reply_To_String);
			Buffer += strlen(Buffer);
		}
	/*
	 *	Generate mail system version
	 */
	if (!Dont_Insert_Message_ID) {
		char *Hostname;

		Hostname = (char *)Get_Hostname();
#ifdef	PMDF
		if (!RUNNING_PMDF) {
#endif	/* PMDF */

#ifdef MX
    	    	    if (RUNNING_MX)
		    	sprintf(Buffer,
		    "Mail-System-Version: <%s(%d)+TOPSLIB%s+MX(%s)%s%s>\n",
				MM_Name,MM_Edit_Number,
				strrchr(Topslib_Version,'('),
				MX_Version(),
				Hostname ? "@" : "",
				Hostname ? Hostname : "");
    	    	    else
#endif MX
		    	sprintf(Buffer,
		    "Mail-System-Version: <%s(%d)+TOPSLIB%s%s%s>\n",
				MM_Name,MM_Edit_Number,
				strrchr(Topslib_Version,'('),
				Hostname ? "@" : "",
				Hostname ? Hostname : "");
#ifdef	PMDF
		} else {
		    sprintf(Buffer,
		    "Mail-System-Version: <%s(%d)+TOPSLIB%s+PMDF(%s)%s%s>\n",
				MM_Name,MM_Edit_Number,
				strrchr(Topslib_Version,'('),
				PMDF_Version(),
				Hostname ? "@" : "",
				Hostname ? Hostname : "");

		}
#endif	/* PMDF */
		Buffer += strlen(Buffer);
	}
	/*
	 *	Generate user headers
	 */
	if (User_Header_Str[0] != 0) {
		strcpy(Buffer,User_Header_Str);
		Buffer += strlen(Buffer);
	}
	/*
	 *	Leave a blank line
	 */
	*Buffer++ = '\n';
	*Buffer = 0;
	/*
	 *	Force a mail check!
	 */
	Init_Mail_Check_Time(0);
	/*
	 *	Done
	 */
	return;
}


/*
 *
 *	Answer the current message
 *
 */
#define REPLY_TO_ALL	0			/* Reply to everyone	*/
#define REPLY_TO_SENDER 1			/* Reply to the sender	*/
int Answer_Message(Number,Answer_To,Insert_Text)
char *Answer_To;
char *Insert_Text;
{
	register struct Msg *Msg = &Messages[Number-1];
	register char *cp, *cp1, *cp2;
	char Prompt[64];
	struct tbluk_keyword *t;
	int i;
	int Terminator;
	int Ignore = 0;
	int Who_To_Reply_To;
	int Include_Original_Message = Reply_Insert_Current_Msg;
	char Buffer[1024];
	char Date[64];
	char From[256];
	static char Subject_String[256];
	static struct {
		int current_entries;
		int maximum_entries;
		struct tbluk_keyword keywords[2];
		} All_or_Sender = {
			2,
			2,
			{{0,	"all",		REPLY_TO_ALL},
			 {0,	"sender",	REPLY_TO_SENDER}}};
	static struct comnd_function reply_keywords =
		{COMND_KEYWORD,
		 COMND_DEFAULT_VALID,
		 0,
		(int)&All_or_Sender};
	static struct {
		int current_entries;
		int maximum_entries;
		struct tbluk_keyword keywords[2];
		} Including_Not_Including = {
			2,
			2,
			{{0,	"including",		1},
			 {0,	"not-including",	0}}};
	static struct comnd_function include_keywords =
		{COMND_KEYWORD,
		 COMND_DEFAULT_VALID,
		 0,
		(int)&Including_Not_Including};

	/*
	 *	Check for deleted messages
	 */
	if (Msg->Flags & MSG_DELETED) {
		printf(" Message %d deleted.\n",Number);
/******		return(0);	******	PKarp	******/
	}
	Send_Mode = 0;
    	Restored_Draft = 0;
	/*
	 *	Reply To "ALL" or "SENDER"
	 */
	if (Answer_To == 0) {
		sprintf(Prompt," Reply message # %d to: ",Number);
		Command_State.prompt = Prompt;
		reply_keywords.default_string =
			Reply_Sender_Only_Default ? "SENDER" : "ALL";
		COMMAND_PARSE_INIT(&Command_State);
		i = comnd_jsys(&Command_State,&reply_keywords,&t,0);
		if (i < 0) return(0);
		Who_To_Reply_To = t->user_data;
		/*
		 *	Include/don't include original message
		 */
		include_keywords.default_string =
			Reply_Insert_Current_Msg ?
				"INCLUDING" : "NOT-INCLUDING";
		i = comnd_jsys(&Command_State,&include_keywords,&t,0);
		if (i < 0) return;
		Include_Original_Message = t->user_data;
		Noise("message text in reply");
		/*
		 *	Confirm
		 */
		Confirm();
	} else {
		t = tbluk_jsys(Answer_To,&All_or_Sender,0,0);
		Who_To_Reply_To = t->user_data;
		t = tbluk_jsys(Insert_Text,&Including_Not_Including,0,0);
		Include_Original_Message = t->user_data;
	}
	/*
	 *	Initialize send
	 */
	Send_Init_No_Default_CC_List();
	/*
	 *	Get the From address (1st try the "Reply-To:" field, then
	 *		the "From:" field then the "Sender:" field)
	 */
	i = 0;
	if ((i == 0) && DOING_BBOARD) {
		/*
		 *	If this is a bboard file, and the article is from
		 *	rnews (has a "Posting-Version:" field), we try for
		 *	the rnews Path: field.
		 */
		if (Get_Header_Field("\nPosting-Version:",
				     Number,
				     Buffer,
				     sizeof(Buffer)) > 0) {
			i = Get_Header_Field("\nPath:",Number,Buffer,sizeof(Buffer));
			if (i > 0) {
				/*
				 *	Got it, delete up to and including the
				 *	1st "!".
				 */
				cp = (char *)strchr(Buffer,'!');
				if (cp != 0) {
					cp++;
					strcpy(Buffer,cp);
				}
			}
		}
	}
	if (i == 0)
		i = Get_Header_Field("\nReply-To:",Number,Buffer,sizeof(Buffer));
	if (i == 0)
		i = Get_Header_Field("\nFrom:",Number,Buffer,sizeof(Buffer));
	if (i == 0)
		i = Get_Header_Field("\nSender:",Number,Buffer,sizeof(Buffer));
	if (i == 0)
		i = Get_Header_Field("\nReturn-Path:",Number,Buffer,sizeof(Buffer));
	if (i != 0) {
		/*
		 *	Get the Username/Address from the field
		 */
    	    if (New_Style_Parsing) {
    	    	Parse_Return_Addresses(Buffer, &ToList);
    	    } else {
		Extract_Mailbox_From_Field(Buffer);
		/*
		 *	Add it to our To: list (fake out the COMND JSYS)
		 */
		Setup_String_Parse(Buffer);
		Get_User(1);
		ToList = Address_List;
		Address_List = 0;
    	    }
	} else {
		printf("?Couldn't find who the message was from\n");
	}
	/*
	 *	If reply to ALL add the message's To [and possibly Cc] lists
	 */
	/*
	 *	Add the source To list to the reply list
	 */
	if (Get_Header_Field("\nTo:",Number,Buffer,sizeof(Buffer))) {
    	    Parse_Return_Addresses(Buffer, (Who_To_Reply_To == REPLY_TO_ALL) ?
    	    	    	    	(Reply_CC_Others <= 0) ? &CcList : &ToList
    	    	    	    	: &StandByCcList);
	}

	/*
	 *	Add the source Cc: list to the reply list (???)
	 */
	if (Get_Header_Field("\nCc:",Number,Buffer,sizeof(Buffer))) {
    	    Parse_Return_Addresses(Buffer,
    	    	    (Who_To_Reply_To == REPLY_TO_ALL) ? &CcList : &StandByCcList);
	}
	/*
	 *	Include Me in the "cc" list???
	 */
	if (Reply_Include_Me) {
		/*
		 *	Yes:
		 */
		Setup_String_Parse((char *)Get_Username());
		Add_More_Users_To_List(&CcList);
	}
	/*
	 *	Add the DEFAULT-CC and DEFAULT-BCC lists
	 */
	if (Default_CC_List[0] != 0) {
		Setup_String_Parse(Default_CC_List);
		Add_More_Users_To_List(&CcList);
	}
	if (Default_BCC_List[0] != 0) {
		Setup_String_Parse(Default_BCC_List);
		Add_More_Users_To_List(&BccList);
	}
	/*
	 *	Set the In-Reply-To Field
	 *	(generate a slightly different one for rnews)
	 */
	if (Get_Header_Field("\nMessage-ID:",Number,From,sizeof(From))) {
		i = strlen(From)+2;
		if (i < (Free_Text_Space_Size - Text_Space_Size)) {
			cp = Free_Text_Space +
				(sizeof(Free_Text_Space) -
					UserName_Space_Size - i);
			UserName_Space_Size += i;
			Free_Text_Space_Size -= i;
			strcpy(cp,From);
			In_Reply_To_String = cp;
		}
	}
	if (In_Reply_To_String == 0) In_Reply_To_String = "";
	/*
	 *	Set the Subject field (leave room for Re: )
	 */
	if (Get_Header_Field("\nSubject:",Number,Subject_String+4,sizeof(Subject_String)-4)) {
		for(i = 4; (Subject_String[i] == ' ') || (Subject_String[i] == '\t'); i++);
		if (((Subject_String[i] == 'r')   || (Subject_String[i] == 'R')) &&
		    ((Subject_String[i+1] == 'e') || (Subject_String[i+1] == 'E')) &&
		     (Subject_String[i+2] == ':')) {
			strcpy(Subject_String,Subject_String+i);
		} else {
			Subject_String[0] = 'R';
			Subject_String[1] = 'e';
			Subject_String[2] = ':';
			Subject_String[3] = ' ';
		}
		Subject = Subject_String;
	}
	/*
	 *	Display the reply header??
	 */
	if (Reply_Initial_Display) CMD_Display_Header();
	/*
	 *	Add the text of the current message?
	 */
	if (Include_Original_Message) {
		cp = MESSAGE_HEADER(Current_Message);
		cp += Messages[Current_Message-1].Header_Size;
		cp1 = Free_Text_Space;
		i = Messages[Current_Message-1].Real_Size;
		i -= Messages[Current_Message-1].Header_Size;
		if (i > Free_Text_Space_Size) {
			printf("[Insufficient text space to include original message]\n");
		} else {
			Text_Space_Size = i;
			for(cp2 = Reply_Leading_String;
			    *cp2;
			    *cp1++ = *cp2++, Text_Space_Size++);
			/*
			 *	Copy in message checking for headers to ignore
			 */
			Ignore = Ignore_Header_Line(cp, Ignore, 1);
			while(--i >= 0) {
				if (*cp == '\n') {
					Ignore = Ignore_Header_Line(cp+1,
								    Ignore, 0);
					if (!Ignore) {
						*cp1++ = *cp++;
						for(cp2 = Reply_Leading_String;
						    *cp2;
						    *cp1++ = *cp2++,
							Text_Space_Size++);
					}
					else {
						cp++;
						Text_Space_Size--;
					}
				}
				else {
					if (Ignore) {
						cp++;
						Text_Space_Size--;
					}
					else
						*cp1++ = *cp++;
				}
			}
			*cp1++ = '\n';
			Text_Space_Size++;
		}
		/*
		 *	Get the text
		 *	One way or another
		 */
		if (Use_Editor_Automatically) {
			int i;

			printf("\nInvoking editor...\n");  /* Some want to know */
			i = Edit_Buffer("mm-reply-edit",
					Free_Text_Space,
					Text_Space_Size,
					Free_Text_Space_Size);
			Text_Space_Size = i;
			/*
			 *	Return as though an ESCAPE was typed
			 */
			Free_Text_Space[Text_Space_Size] = 0;
			Terminator = ((Escape_Automatic_Send > 0) ?
							CTRL_Z : ESCAPE);
		} else {
			/*
			 *	Disable TOPS EOF hook during Get_Text()
			 */
			tops_eof_hook = 0;
			Terminator = Get_Text(1,0);
			tops_eof_hook = Control_Z;
		}
	} else {
		/*
		 *	Get the text
		 *	One way or another
		 */
		if (Use_Editor_Automatically) {
			int i;

			printf("\nInvoking editor...\n");  /* Some want to know */
			i = Edit_Buffer("mm-reply-edit",
					Free_Text_Space,
					Text_Space_Size,
					Free_Text_Space_Size);
			Text_Space_Size = i;
			/*
			 *	Return as though an ESCAPE was typed
			 */
			Free_Text_Space[Text_Space_Size] = 0;
			Terminator = ((Escape_Automatic_Send > 0) ?
							CTRL_Z : ESCAPE);
		} else {
			/*
			 *	Disable TOPS EOF hook during Get_Text()
			 */
			tops_eof_hook = 0;
			Terminator = Get_Text(1,1);
			tops_eof_hook = Control_Z;
		}
	}
	/*
	 *	Do Send SubCommand mode
	 */
	return(Send_SubCommand_Mode(Terminator));
}

Ignore_Header_Line(cp, Ignore, First_Time)
char *cp;
int Ignore;
int First_Time;
{
	static int No_More_Headers;
	int Flags;
	char Header_Field_Name[128];
	char *cp1, *cp2;

	if (First_Time)
		No_More_Headers = 0;
	else
		if (No_More_Headers) return 0;

	/*
	 *	If cp is space or tab, we have a continuation line; did we
	 *	ignore the previous line
	 */
	if ((*cp == ' ') || (*cp == '\t'))
		return Ignore;

	/*
	 *	Get this field name
	 */
	cp1 = cp;
	cp2 = Header_Field_Name;
	while (*cp1 != ':') {
		if (*cp1 == '\n') {
			/*
			 *	Done with headers
			 */
			No_More_Headers = 1;
			return 0;
		}
		*cp2++ = *cp1++;
	}
	*cp2 = 0;

	/*
	 *	Check to see if this header should be ignored
	 */
	if (Suppress_Headers.current_entries > 0) {
		tbluk_jsys(Header_Field_Name,
			   &Suppress_Headers,
			   0,
			   &Flags);
		if (Flags & TBLUK_EXACT_MATCH)
			return 1;
	}
	if (Only_Type_Headers.current_entries > 0) {
		tbluk_jsys(Header_Field_Name,
			   &Only_Type_Headers,
			   0,
			   &Flags);
		if (!(Flags & TBLUK_EXACT_MATCH))
			return 1;
	}
	return 0;
}

/*
 *	Local routine to parse return addresses and put them on the
 *	appropriate list
 */
static Parse_Return_Addresses(Buffer,List)
char *Buffer;
struct Address **List;
{
	register char *cp,*cp1;

	/*
	 *	Add each user to the To: or Cc: List
	 */
	cp = Buffer;

    	if (New_Style_Parsing) {
    	    Setup_String_Parse(cp);
    	    Add_More_Users_To_List(List);
    	    return;
    	}

	while(*cp) {
		/*
		 *	Start at the next user
		 *	and find the end of that specification
		 */
		cp1 = cp;
		while(*cp1) {
			/*
			 *	Deal with quoted strings
			 *	(Squish them out)
			 */
/*
 * Why was this done?  Keep the quotes!!!
 *
			if (*cp1 == '"') {
				char *Saved_cp = cp;

				cp = cp1;
				cp1++;
				while(*cp1)
					if (*cp1++ == '"') break;
				while((*cp++ = *cp1++) != 0) ;
				cp = Saved_cp;
				cp1 = cp;
				continue;
			}
*/
			/*
			 *	If there is an "<>" spec,
			 *	use it.
			 */
			if (*cp1 == '<') {
				cp1++;
				cp = cp1;
				while(*cp1 && (*cp1 != '>')) cp1++;
				if (*cp1 != 0) *cp1++ = 0;
				Setup_String_Parse(cp);
				Add_More_Users_To_List(List);
				/*
				 *	Skip to the end of
				 *	this user
				 */
				while(*cp1)
					if (*cp1++ == ',') break;
				cp = cp1;
				break;
			}
			/*
			 *	If a "," is found, parse the
			 *	username
			 */
			if (*cp1 == ',') {
				*cp1++ = 0;
				Setup_String_Parse(cp);
				Add_More_Users_To_List(List);
				cp = cp1;
				break;
			}
			/*
			 *	Next character
			 */
			cp1++;
		}
		/*
		 *	Parse this last user
		 */
		if (cp != cp1) {
			Setup_String_Parse(cp);
			Add_More_Users_To_List(List);
			break;
		}
	}
}


/*
 *	Send a BUG report
 */
CMD_Bug()
{
	int Terminator;
	char Local_Subject[100];

	/*
	 *	Confirm
	 */
	Confirm();
	/*
	 *	Initialize
	 */
	Erase_All();
	/*
	 *	Get message text
	 */
	printf(" Please enter your %s comments or suggestions, terminated\n",
				MM_Name);
	printf("with ESCAPE or ^Z (^N to abort)\n");
	/*
	 *	Disable TOPS EOF hook during Get_Text()
	 */
	tops_eof_hook = 0;
	Terminator = Get_Text(0,0);
	tops_eof_hook = Control_Z;
	/*
	 *	Set To and Subject
	 */
	Setup_String_Parse(MM_BUG_MAILBOX);
	Get_User(1);
	ToList = Address_List;
	Address_List = 0;
	sprintf(Local_Subject,"Bug in %s %d.%d(%d)",
			MM_Name,MM_Version,MM_Minor_Id_Number,MM_Edit_Number);
	Subject = Local_Subject;
	/*
	 *	Send it
	 */
	Send_SubCommand_Mode(Terminator);
}


/*
 *	Continue
 */
CMD_Continue()
{

	/*
	 *	Confirm
	 */
	Confirm();
	/*
	 *	See if it can be continued
	 */
	if (Send_Can_Be_Continued)
		Send_SubCommand_Mode(0);
	else
		printf("?There is no send to continue\n");
}


/*
 *	Get the To: list for forwarding from Read mode
 */
Get_Forward_To_List()
{
	/*
	 *	Initialize
	 */
	Erase_All();
	/*
	 *	Get To:
	 */
	Get_To(0);
	ToList = Address_List;
	Address_List = 0;
	/*
	 *	Done
	 */
	return;
}



/*
 *	Forward messages
 */
Forward_Messages(Number_Of_Forwarded_Messages,Get_To_List,Use_Current_Message)
{
	register char *cp,*cp1;
	register struct Msg *Msg;
	int i,j;
	int Number;
	int Terminator;
	static char Real_Subject[128];
	char Tmp_From[16];
	char Tmp_Subject[34];



	/*
	 *	Get the To: list if necessary
	 */
	if (Get_To_List) {
		/*
		 *	Initialize
		 */
		Erase_All();
		/*
		 *	Get To:
		 */
		Get_To(1);
		ToList = Address_List;
		Address_List = 0;
	}
	/*
	 *	Add the DEFAULT-CC and DEFAULT-BCC lists
	 */
	if (Default_CC_List[0] != 0) {
		Setup_String_Parse(Default_CC_List);
		Add_More_Users_To_List(&CcList);
	}
	if (Default_BCC_List[0] != 0) {
		Setup_String_Parse(Default_BCC_List);
		Add_More_Users_To_List(&BccList);
	}
	/*
	 *	Get the text
	 *	One way or another
	 */
	if (Use_Editor_Automatically) {
		printf("\nInvoking editor...\n");  /* Some want to know */
		i = Edit_Buffer("mm-forward-edit",
				Free_Text_Space,
				Text_Space_Size,
				Free_Text_Space_Size);
		Text_Space_Size = i;
		/*
		 *	Return as though an ESCAPE was typed
		 */
		Free_Text_Space[Text_Space_Size] = 0;
		Terminator = ((Escape_Automatic_Send > 0) ? CTRL_Z : ESCAPE);
	} else {
		/*
		 *	Disable TOPS EOF hook during Get_Text()
		 */
		tops_eof_hook = 0;
		Terminator = Get_Text(1,1);
		tops_eof_hook = Control_Z;
	}
	/*
	 *	Add a separator line
	 */
	if (Text_Space_Size != 0) {
		cp = Free_Text_Space+Text_Space_Size;
		if (cp[-1] != '\n') {*cp++ = '\n'; Text_Space_Size++;}
		strcpy(cp,"                ---------------\n");
		cp += 32;
		Text_Space_Size += 32;
	}
	/*
	 *	If more than one message, insert a directory
	 *	(also generate the subject line)
	 */
	cp = Free_Text_Space+Text_Space_Size;
	*cp++ = '\n'; Text_Space_Size++;
	if (Use_Current_Message == 0) Re_Init_Next_Message();
	j = 1;
	while(1) {
		/*
		 *	Get the message to forward
		 */
		if (Use_Current_Message != 0) {
			if (Use_Current_Message < 0) break;
			Number = Current_Message;
			Use_Current_Message = -1;
		} else {
			Number = Next_Message(0);
			if (Number <= 0) break;
		}
		Msg = &Messages[Number-1];
		/*
		 *	Extract "From" field
		 */
		i = Msg->From_Size;
		cp1 = Tmp_From;
		cp = MESSAGE_HEADER(Number) + Msg->From_Offset;
		if (i > 15) i = 15;
		while(--i >= 0) {
			if (*cp == '<') break;
			*cp1++ = *cp++;
		}
		*cp1 = 0;
		/*
		 *	Subject
		 */
		i = Msg->Subj_Size;
		cp1 = Tmp_Subject;
		cp = MESSAGE_HEADER(Number) + Msg->Subj_Offset;
		if (i > 33) i = 33;
		while(--i >= 0) *cp1++ = *cp++;
		*cp1 = 0;
		/*
		 *	Generate the subject line
		 */
		if (j == 1) {
			sprintf(Real_Subject,
				"[%*.*s: %s]",
				Msg->From_Size,
				Msg->From_Size,
				MESSAGE_HEADER(Number) + Msg->From_Offset,
				Tmp_Subject);
			/*
			 *	If there is only one message don't do the
			 *	directory.
			 */
			if (Number_Of_Forwarded_Messages == 1) break;
		}
		/*
		 *	Insert the directory line
		 */
		cp = Free_Text_Space+Text_Space_Size;
		sprintf(cp,
			" %3d) %-6.6s %-15s %s\n",
			j++,
			MESSAGE_HEADER(Number),
			Tmp_From,
			Tmp_Subject);
		Text_Space_Size += strlen(cp);
	}
	/*
	 *	Leave a blank line
	 */
	if (Number_Of_Forwarded_Messages > 1) {
		cp = Free_Text_Space+Text_Space_Size;
		*cp++ = '\n'; Text_Space_Size++;
	}
	/*
	 *	Insert the Messages
	 */
	if (Use_Current_Message == 0) {
		Re_Init_Next_Message();
	} else{
		Use_Current_Message = 1;
	}
	j = 1;
	while(1) {
		char Line[128];

		/*
		 *	Get the message to forward
		 */
		if (Use_Current_Message != 0) {
			if (Use_Current_Message < 0) break;
			Number = Current_Message;
			Use_Current_Message = -1;
		} else {
			Number = Next_Message(1);
			if (Number <= 0) break;
		}
		Msg = &Messages[Number-1];
		/*
		 *	Add header if necessary
		 */
		if (Number_Of_Forwarded_Messages > 1) {
			/*
			 *	Generate a header
			 */
			sprintf(Line,"Message %d -- ************************\n",j++);
			if (strlen(Line) > (Free_Text_Space_Size - Text_Space_Size)) {
				printf("\n?Ran out of text space\n");
				return;
			}
			cp = Free_Text_Space+Text_Space_Size;
			strcpy(cp,Line);
			Text_Space_Size += strlen(Line);
		}
		/*
		 *	Add the message
		 */
		i = Msg->Real_Size - Msg->Header_Size;
		if (i > (Free_Text_Space_Size - Text_Space_Size)) {
			printf("\n?Ran out of text space\n");
			return;
		}
		cp = MESSAGE_HEADER(Number) + Msg->Header_Size;
		cp1 = Free_Text_Space+Text_Space_Size;
		Text_Space_Size += i;
		while(--i >= 0) *cp1++ = *cp++;
		/*
		 *	Make sure it ends in "\n-------"
		 */
		cp = Free_Text_Space+Text_Space_Size;
		if (cp[-1] != '\n') {*cp++ = '\n'; Text_Space_Size++; *cp = 0;}
#ifdef DASHES
		if (strcmp(cp-8,"-------\n") != 0) {
				strcpy(cp,"-------\n");
				Text_Space_Size += 8;
				cp += 8;
		}
#endif DASHES
		/*
		 *	Add a blank line
		 */
		*cp++ = '\n';
		Text_Space_Size++;
	}
	printf("\n");
	/*
	 *	Kill the final blank line
	 */
	cp = Free_Text_Space + Text_Space_Size;
	if ((cp[-1] == '\n') && (cp[-2] == '\n')) Text_Space_Size--;
	/*
	 *	Set the subject
	 */
	Subject = Real_Subject;
	/*
	 *	Send it
	 */
	Send_SubCommand_Mode(Terminator);
}


/*
 *	Remail messages
 */
Remail_Messages(Use_Current_Message)
{
	register char *cp,*cp1;
	register struct Msg *Msg;
	int Number,i;
	struct Address *To = 0;
	struct Address *Address,*New_Address;
	int Saved_Free_Address_Space_Size;
	char Header[1024];
	char Remail_Header[4*1024];
    	extern char *strstr(char *, char *);

	/*
	 *	Initialize
	 */
	Erase_All();
	/*
	 *	Try to get the "to" list out of the current command line
	 */
	Get_To(0);
	To = Address_List;
	Address_List = 0;
	/*
	 *	Get to
	 */
	while(To == 0) {
		Get_To(1);
		To = Address_List;
		Address_List = 0;
	}
	Saved_Free_Address_Space_Size = Free_Address_Space_Size;
	/*
	 *	Remail the message
	 */
	while(1) {
		/*
		 *	Get the message to forward
		 */
		if (Use_Current_Message != 0) {
			if (Use_Current_Message < 0) break;
			Number = Current_Message;
			Use_Current_Message = -1;
		} else {
			Number = Next_Message(0);
			if (Number <= 0) break;
		}
		Msg = &Messages[Number-1];
		/*
		 *	Make a copy of the To list
		 */
		Free_Address_Space_Size = Saved_Free_Address_Space_Size;
		ToList = 0;
		for(Address = To; Address; Address = Address->Next_Address) {
			if (Free_Address_Space_Size == 0) {
				printf("?Too many addresses\n");
				return;
			}
			New_Address = &Free_Address_Space
				[FREE_ADDRESS_SPACE_SIZE-Free_Address_Space_Size];
			Free_Address_Space_Size--;
			*New_Address = *Address;
			New_Address->Next_Address = 0;
			Add_Address(New_Address,&ToList,1);
		}
		/*
		 *	Move the text into the text area
		 */
		cp = MESSAGE_HEADER(Number) + Msg->Body_Offset;
		cp1 = Free_Text_Space;
		Text_Space_Size = 0;
		i = Msg->Real_Size - Msg->Body_Offset;
		Text_Space_Size += i;
		while(--i >= 0) *cp1++ = *cp++;
		/*
		 *	Generate the Remail header
		 */
		Generate_Header(Header);
		/*
		 *	Add the Remail header
		 */
		cp1 = Remail_Header;
    	    	cp = strstr(Header, "\nDate:");
    	    	if (cp == 0) cp = strstr(Header, "Date:");
    	    	else cp++;
    	    	if (cp != 0) {
    	    	    cp += 6;
		    strcpy(cp1,"ReSent-Date: ");	cp1 += 13;
		    while((*cp1++ = *cp++) != '\n');
    	    	}

		cp = strstr(Header, "\nFrom:");
    	    	if (cp != 0) {
    	    	    cp += 7;
		    strcpy(cp1,"ReSent-From: ");	cp1 += 13;
		    while((*cp1++ = *cp++) != '\n');
    	    	}

		cp = strstr(Header, "\nSender:");
    	    	if (cp != 0) {
    	    	    cp += 9;
		    strcpy(cp1,"ReSent-Sender: ");	cp1 += 15;
		    while((*cp1++ = *cp++) != '\n');
    	    	}

    	    	cp = strstr(Header, "\nTo:");
    	    	if (cp != 0) {
    	    	    cp += 5;
		    strcpy(cp1,"ReSent-To: ");	cp1 += 11;
		    while((*cp1++ = *cp++) != '\n');
    	    	}

		/*
		 *	Copy the Real Header
		 */
		cp = MESSAGE_HEADER(Number) + Msg->Header_Size;
		i = Msg->Body_Offset - Msg->Header_Size;
		while(--i >= 0) *cp1++ = *cp++;
		/*
		 *	Kill the trailing blank lines
		 */
		while(cp1[-1] == '\n') cp1--;
		*cp1++ = '\n';	/* Terminate the last line */
		*cp1++ = '\n';
		*cp1 = 0;
		/*
		 *	Mail it
		 */
		Substitute_Header = Remail_Header;
		CMD_Sendit();
	}
}


/*
 *	Send an internal message to the indicated address
 */
int Send_Internal_Message(To,Mail_Subject,Text)
char *To;
char *Mail_Subject;
char *Text;
{
	char Buffer[128];

	/*
	 *	We are no longer in send mode
	 */
	Send_Mode = 0;
	/*
	 *	Initialize send
	 */
	Send_Init_No_Default_CC_List();
	/*
	 *	Parse the "To:" address
	 */
	strcpy(Buffer,To);
	Extract_Mailbox_From_Field(Buffer);
	/*
	 *	Add it to our To: list (fake out the COMND JSYS)
	 */
	Setup_String_Parse(Buffer);
	Get_User(1);
	ToList = Address_List;
	Address_List = 0;
	/*
	 *	Set the subject
	 */
	Subject = Mail_Subject;
	/*
	 *	Insert the text
	 */
	Text_Space_Size = strlen(Text);
	strcpy(Free_Text_Space,Text);
	/*
	 *	Send the message
	 */
	printf("[Sending registered-mail reply to %s]\n",Buffer);
	return(CMD_Sendit());
}


/*
 *	Save the draft of a letter
 */
static CMD_Save_Draft()
{
	static struct comnd_function filename = {COMND_OUTPUT_FILE};
	static struct gtjfn_block gtjfn;
	int i;
	FILE *f;
	char Buffer[1024];

	/*
	 *	Noise
	 */
	Noise("into file");
	/*
	 *	Get the filename
	 */
	gtjfn.default_filename = "LETTER";
	gtjfn.default_extension = "DRAFT";
	Command_State.gtjfn = &gtjfn;
	if (comnd_jsys(&Command_State,&filename,&i,0) < 0) return;
	local_jfns_jsys(Buffer,i);
	tops_free_jfn(i);	/* TEMP */
	/*
	 *	Confirm
	 */
	Confirm();
	/*
	 *	Create the saved draft file
	 */
	i = Xcreat(Buffer,Mail_File_Mode,"txt");
	if (i < 0) {
		printf("?Couldn't create saved-draft file %s\n",Buffer);
		return;
	}
	f = fdopen(i,"w");
	/*
	 *	Output the subject line
	 */
	if (Subject)
		if (*Subject)
			fprintf(f,"Subject: %s\n",Subject);
	/*
	 *	Output the "To:" list
	 */
	if (ToList) {
		Print_Addresses("To:",ToList,Buffer,0,1);
		fprintf(f,"%s",Buffer);
	}
	/*
	 *	Output the "Cc:" list
	 */
	if (CcList) {
		Print_Addresses("Cc:",CcList,Buffer,0,1);
		fprintf(f,"%s",Buffer);
	}
	/*
	 *	Output the "Bcc:" list
	 */
	if (BccList) {
		Print_Addresses("Bcc:",BccList,Buffer,0,1);
		fprintf(f,"%s",Buffer);
	}
	/*
	 *	Output the In-Reply-To: string
	 */
	if (In_Reply_To_String)
		if (*In_Reply_To_String)
			fprintf(f,"In-Reply-To: %s\n",In_Reply_To_String);
	/*
	 *	Output the Reply-To: string
	 */
	if (Reply_To_String)
		if (*Reply_To_String)
			fprintf(f,"Reply-To: %s\n",Reply_To_String);
	/*
	 *	Output the From: string
	 */
	if (From_String)
		if (*From_String)
			fprintf(f,"From: %s\n",From_String);
	/*
	 *	End of header
	 */
	fprintf(f,"\n");
	fflush(f);
	/*
	 *	Do the text
	 */
	if (Text_Space_Size > 0) {
		/* This is due to yet another bug in the VAX-11 "C" runtime */
		fwrite(Free_Text_Space,Text_Space_Size,sizeof(char),f);
	}
	/*
	 *	Done
	 */
	fclose(f);
	return;
}


/*
 *	Restore the draft of a letter
 */
CMD_Restore_Draft()
{
	static struct comnd_function filename = {COMND_INPUT_FILE};
	static struct gtjfn_block gtjfn;
	int i;
	FILE *f;
	char Buffer[1024];
	char *Save_String();

	/*
	 *	Noise
	 */
	Noise("from file");
	/*
	 *	Get the filename
	 */
	gtjfn.default_filename = "LETTER";
	gtjfn.default_extension = "DRAFT";
	Command_State.gtjfn = &gtjfn;
	if (comnd_jsys(&Command_State,&filename,&i,0) < 0) return;
	local_jfns_jsys(Buffer,i);
	tops_free_jfn(i);	/* TEMP */
	/*
	 *	Confirm
	 */
	Confirm();
	/*
	 *	Open the saved draft file
	 */
	i = Xopen(Buffer,0);
	if (i < 0) {
		printf("?Couldn't open saved-draft file %s\n",Buffer);
		return;
	}
	f = fdopen(i,"r");
	/*
	 *	Initialize the send
	 */
	Send_Init_No_Default_CC_List();
	/*
	 *	Read in the file (starting with the header)
	 */
	while(1) {
		/*
		 *	Get the next header field
		 */
		if (fgets(Buffer,sizeof(Buffer),f) == NULL) break;
		i = strlen(Buffer);
		if (Buffer[i-1] == '\n') Buffer[i-1] = 0;
		/*
		 *	An empty line signifies the end of the header
		 */
		if (Buffer[0] == 0) break;
		while(1) {
			i = fgetc(f);
			if ((i != ' ') && (i != '\t')) {
				ungetc(i,f);
				break;
			}
			i = strlen(Buffer);
			if (fgets(Buffer+i,sizeof(Buffer)-i,f) == NULL) break;
			i = strlen(Buffer);
			if (Buffer[i-1] == '\n') Buffer[i-1] = 0;
		}
		/*
		 *	Subject:
		 */
		if (strcmpn(Buffer,"Subject: ",9) == 0) {
			Subject = Save_String(Buffer+9);
			continue;
		}
		/*
		 *	To:
		 */
		if (strcmpn(Buffer,"To: ",4) == 0) {
			Setup_String_Parse(Buffer+4);
			Add_More_Users_To_List(&ToList);
			continue;
		}
		/*
		 *	Cc:
		 */
		if (strcmpn(Buffer,"Cc: ",4) == 0) {
			Setup_String_Parse(Buffer+4);
			Add_More_Users_To_List(&CcList);
			continue;
		}
		/*
		 *	Bcc:
		 */
		if (strcmpn(Buffer,"Bcc: ",5) == 0) {
			Setup_String_Parse(Buffer+5);
			Add_More_Users_To_List(&BccList);
			continue;
		}
		/*
		 *	In-Reply-To:
		 */
		if (strcmpn(Buffer,"In-Reply-To: ",13) == 0) {
			In_Reply_To_String = Save_String(Buffer+13);
			continue;
		}
		/*
		 *	Reply-To:
		 */
		if (strcmpn(Buffer,"Reply-To: ",10) == 0) {
			Reply_To_String = Save_String(Buffer+10);
			continue;
		}
		/*
		 *	From:
		 */
		if (strcmpn(Buffer,"From: ",6) == 0) {
			From_String = Save_String(Buffer+6);
			continue;
		}
	}
	/*
	 *	Get the text
	 */
	i = fread(Free_Text_Space,
		  sizeof(char),
		  Free_Text_Space_Size - Text_Space_Size,
		  f);
	if (i == (Free_Text_Space_Size - Text_Space_Size))
		printf("?Insufficient text space, draft file truncated\n");
	fclose(f);
	Text_Space_Size = i;
	Restored_Draft = 1;
	/*
	 *	There is send information now
	 */
	Send_Can_Be_Continued = 1;
	if (Send_Mode) return;
	/*
	 *	Display it
	 */
	CMD_Display_Header();
	printf("\n");
	psout_jsys(Free_Text_Space,Text_Space_Size);
	/*
	 *	Get more text
	 *	Disable TOPS EOF hook during Get_Text()
	 */
	tops_eof_hook = 0;
	i = Get_Text(0,0);
	tops_eof_hook = Control_Z;
	/*
	 *	Continue the send
	 */
	Send_Mode = 1;
	Send_SubCommand_Mode(i);
}

static int strcmpn(cp1,cp2,n)
register char *cp1,*cp2;
register int n;
{
	while(--n >= 0)
		if (*cp1++ != *cp2++) return(-1);
	return(0);
}

static char *Save_String(cp)
char *cp;
{
	int i;
	char *cp1;

	i = strlen(cp) + 1;
	if (i > (Free_Text_Space_Size - Text_Space_Size)) {
		printf("?Insufficent text space to save string.\n");
		return(0);
	}
	cp1 = Free_Text_Space +
		(sizeof(Free_Text_Space) - UserName_Space_Size - i);
	UserName_Space_Size += i;
	Free_Text_Space_Size -= i;
	strcpy(cp1,cp);
	return(cp1);
}

static Erase_Bcc() {BccList = 0;}
static Erase_Cc() {CcList = 0;}
static Erase_Recipients()
{
	BccList = 0;
	CcList = 0;
	ToList = 0;
}
static Erase_Reply_To()
{
	if (Reply_To_String) {
		if (Reply_To_String == User_Reply_To_String)
			Reply_To_String = 0;
		else
			Reply_To_String[0] = 0;
	}
}
static Erase_Subject() {Subject = 0;}
static Erase_Text() {Text_Space_Size = 0;}
static Erase_To() {ToList = 0;}
static Erase_Delivery_Receipt() {Delivery_Options &= ~DELIVERY_OPTION_DELIVERY_RECEIPT;}
static Erase_Read_Receipt() {Delivery_Options &= ~DELIVERY_OPTION_READ_RECEIPT;}
static Erase_Registered_Mail() {Delivery_Options &= ~DELIVERY_OPTION_REGISTERED_MAIL;}
static Erase_In_Reply_To() {In_Reply_To_String = 0;}

/*
 *	Erase various message fields
 */
static CMD_Erase()
{
	struct tbluk_keyword *t;
	int Status;

	static struct {
		int current_entries;
		int maximum_entries;
		struct tbluk_keyword keywords[12];
		} Erase_Keywords = {
		12,
		12,
	/* 0 */{{0,		"all",		(int)Erase_All},
	/* 1 */ {0,		"bcc",		(int)Erase_Bcc},
	/* 2 */ {0,		"cc",		(int)Erase_Cc},
    	    	{0, 	    	"delivery-receipt-requested", (int)Erase_Delivery_Receipt},
    	    	{0, 	    	"in-reply-to", (int)Erase_In_Reply_To},
    	    	{0, 	    	"read-receipt-requested", (int)Erase_Read_Receipt},
	/* 3 */ {0,		"recipients",	(int)Erase_Recipients},
    	    	{0, 	    	"registered-mail", (int)Erase_Registered_Mail},
	/* 4 */ {0,		"reply-to",	(int)Erase_Reply_To},
	/* 5 */ {0,		"subject",	(int)Erase_Subject},
	/* 6 */ {0,		"text",		(int)Erase_Text},
	/* 7 */ {0,		"to",		(int)Erase_To}}};
	static struct comnd_function keyword =
		{COMND_KEYWORD,
		 0,
		 0,
		 (int)&Erase_Keywords,
		 0,
		 0};

	/*
	 *	Noise
	 */
	Noise("message field");
	/*
	 *	Get keyword
	 */
	Status = comnd_jsys(&Command_State,&keyword,&t,0);
	if (Status < 0) longjmp(Send_Top_Level,0);
	/*
	 *	Confirm
	 */
	Confirm();
	/*
	 *	Call action routine
	 */
	(*(int (*)())t->user_data)();
}



/*
 *	Given the contents of a message field, extract
 *	the Mailbox (username/address) part of the field
 */
static Extract_Mailbox_From_Field(Buffer)
char *Buffer;
{
	register char *cp, *cp1;
	register int i;
	int Dont_Check_For_Personal_Name = 0;

	/*
	 *	Deal with <> form of address
	 */
	cp = (char *)strchr(Buffer,'<');
	if (cp) {
		/*
		 *	Scan for non-blank after the "<"
		 */
		cp1 = cp + 1;
		while((*cp1 == ' ') || (*cp1 == '\t')) cp1++;
		/*
		 *	Is it an "@"?
		 */
		if (*cp1 == '@') {
			/*
			 *	Yes: This is a Source route
			 */
			cp1 = (char *)strchr(cp,'>');
			if (cp1) {
				cp1[1] = 0;
				strcpy(Buffer,cp);
			}
			Dont_Check_For_Personal_Name = 0;
		} else {
			/*
			 *	Not a source route: kill the "<>"
			 */
			cp1 = (char *)strchr(cp, '>');
			if (cp1) {
				*cp1 = 0;
				strcpy(Buffer,cp+1);
			}
		}
	}
	/*
	 *	See if we need to check for personal name
	 *	and eliminate it
	 */
	if (!Dont_Check_For_Personal_Name) {
		/*
		 *	Deal with () form of personal name
		 *	(don't forget to allow nesting of parens)
		 */
		cp = Buffer;
		cp1 = Buffer;
		while (*cp) {
			if (*cp == '(') {
				cp++;
				i = 0;
				while (*cp) {
					if (*cp == '(')
						i++;
					if (*cp == ')')
						i--;
					cp++;
					if (i < 0) break;
				}
				if (!*cp) break;
			}
			else
				*cp1++ = *cp++;
		}
		*cp1 = '\0';
	}
}

#if	defined(PMDF) || defined(MX)
#include <ssdef.h>

static int Find_Image_Symbol(Image, Symbol, Value)
char *Image, *Symbol;
int *Value;
{
	struct {int len; char *buf;} ImageDsc, SymbolDsc;
	int Status;

	/*
	 *	Return all errors as statuses, never allow
	 *	LIB$FIND_IMAGE_SYMBOL to signal.
	 */

	(void) LIB$ESTABLISH(SIG_TO_RET);

	ImageDsc.len = strlen(ImageDsc.buf=Image);
	SymbolDsc.len = strlen(SymbolDsc.buf=Symbol);
	Status = LIB$FIND_IMAGE_SYMBOL(&ImageDsc, &SymbolDsc, Value);
	return(Status);
}

/*
 *  This is a special version of LIB$SIG_TO_RET which is a little
 *  smarter about decoding the double-condition signals from
 *  LIB$FIND_IMAGE_SYMBOL
 *
 *  One of the signals signal array looks like:
 *
 *	00000006	# of args
 *	001512BA	LIB$_ACTIMAGE
 *	00000001	    1 arg
 *	????????	    Descriptor to image name
 *	********	Real reason
 *	????????	PC
 *	????????	PSL
 */

#define CHF$L_SIG_NAME 4
#define CHF$L_MCH_SAVR0 12

static int SIG_TO_RET(Sig_Args, Mch_Args)
int Sig_Args[];
int Mch_Args[];
{
	int Status;

	if (Sig_Args[CHF$L_SIG_NAME/4] == SS$_UNWIND) return(SS$_NORMAL);

	/*
	 * Copy condition value to saved image of R0
	 */

	Status = Sig_Args[CHF$L_SIG_NAME/4];
	if (((Status&0x1fff0000) == 0x150000) && Sig_Args[0] >= 6) {
	    Status = Sig_Args[Sig_Args[2]+3];
	}
	Mch_Args[CHF$L_MCH_SAVR0/4] = Status;

	/*
	 * Set to unwind stack using default depth and default new PC,
	 * namely return to caller of the procedure which established the handler
	 */

	return(SYS$UNWIND(0,0));
}

#endif	/*PMDF|MX*/
