static char rcsid[] = "@(#)$Id: alias.c,v 1.60 2007/03/08 11:22:48 hurtta Exp $";

/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.60 $   $State: Exp $
 *
 *  Modified by: Kari Hurtta <hurtta+elm@posti.FMI.FI> 
 *                           (was hurtta+elm@ozone.FMI.FI)
 ******************************************************************************
 *  The Elm Mail System 
 *
 * 			Copyright (c) 1988-1992 USENET Community Trust
 * 			Copyright (c) 1986,1987 Dave Taylor
 *****************************************************************************/

/** This file contains alias stuff

**/

#include "def_elm.h"
#include "s_elm.h"
#include "s_aliases.h"
#include "ndbz.h"

DEBUG_VAR(Debug,__FILE__,"alias");

static char *us2s P_((unsigned char *str));
static char *us2s(str) 
     unsigned char *str;
{
    return (char *)str;
}

#define	ECHOIT	1 	/* echo on for prompting */

static int add_to_alias_text P_((char *aliasname, char *firstname, 
				 char *lastname, char *comment, 
				 char *address));

static int get_aliasname P_((char *aliasname, char *buffer,int *duplicate,
			     int size,int  buffer_size,
			     struct AliasView *aview,
			     struct menu_context *page,
			     struct menu_context *prompt_area));
static int superceed_system P_((int this_alias, char *buffer, 
				int buffer_size,
				struct AliasView *aview,
				struct menu_context *page,
				struct menu_context *prompt_area));

/*
 * A simple macro to make it easier to remember how to do a simple
 * resync and not screw up whether or not to prompt on deletions.
 */

#define resync_aliases(newaliases,aview, page, prompt_area) \
  delete_aliases(newaliases,TRUE, aview, page, prompt_area)

static int get_realnames P_((char *aliasname, 
			     char *firstname, 
			     char *lastname, 
			     char *comment, 
			     char *buffer,
			     int size_first, 
			     int size_last, 
			     int size_comment, 
			     int size_buffer,
			     int is_group,
			     struct menu_context *page,
			     struct menu_context  *prompt_area));
static int add_alias P_((int replace, int to_replace, 
			 struct AliasView *aview, 
			 struct menu_context  *page,
			 struct screen_parts *LOC));	
static int ask_accept P_((char *aliasname, 
			  char *firstname, 
			  char *lastname, 
			  char *comment, 
			  char *address, 
			  char *buffer,
			  int replace, 
			  int replacement, 
			  int size_buffer,
			  struct AliasView *avies, 
			  struct menu_context  *page,
			  struct screen_parts *LOC));
static void alias_help P_((struct menu_context  *page,
			   struct menu_context  *prompt_area));


extern int  is_system;		/* system file updating?     */

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


#if 0
DBZ *system_hash = NULL, *user_hash = NULL;
#endif

char *a_rev_alias_pad, *a_rev_alias_abr, *a_rev_alias_name,
	*a_rev_full_pad, *a_full_abr, *a_rev_full_name,
	*a_rev_text_pad, *a_text_abr, *a_rev_text_file,
	*a_alias_pad, *a_alias_abr, *a_alias_name,
	*a_full_pad, *a_full_name,
	*a_text_pad, *a_text_file,
	*a_group_name, *a_person_name, *a_system_flag;
	

void open_alias_files(aview, LOC)
     struct AliasView *aview;
     struct screen_parts *LOC;
{
    /*
     *	Close and re-open the system and user alias files, if present,
     *	and if they have changed since last we opened them.
     *
     *	Also, parse the data files into memory if needed
     */

    int A,B;

    if (update_aview(aview)) {
	if (!mail_only && !check_only) {
	    int tac = get_total_alias_count(aview);
	    
	    set_alias_current(aview,0);
	    
	    if (tac) {
		sort_aliases(tac, FALSE, LOC ? 1 : 0,aview);
		set_alias_current(aview,1);
	    }

           if (LOC) {
                struct menu_common MENU;

                set_mcommon_from_aliasview(&MENU, aview);
		copy_current(&MENU,LOC->header_page);

                get_page(&MENU, LOC->header_page);
            }

	}
    }
    
}

static int add_alias(replace, to_replace, aview, page, LOC)
     int replace, to_replace;
     struct AliasView *aview;
     struct menu_context  *page;
     struct screen_parts *LOC;
{
    /*
     *	Add an alias to the user alias text file.  If there
     *	are aliases tagged, the user is asked if he wants to
     *	create a group alias from the tagged files.
     *
     *	Return zero if alias not added in actuality.
     *
     *	If replace == FALSE, then we will ask for the new
     *	aliasname.
     *
     *	If replace == TRUE, then we are replacing the alias
     *	denoted by to_replace.
     *
     *	Note that even if replace == FALSE, if the user types
     *	in the name of a current alias then we can still do
     *	a replacement.
     */
    
    int i, leftoff = 0, tagged = 0;
    int is_group = 0;
    
    char aliasname[SLEN], firstname[SLEN], lastname[SLEN];
    char address1[LONG_STRING];
    char comment[LONG_STRING], ch = *def_ans_no;
    char *ch_ptr;

    char bufferA[100]; /* TODO: Can remove? */
    int ac;

    int delay_redraw  = 0;

    /*
     *	See if there are any tagged aliases.
     */
    ac = get_alias_count(aview);
    for (i=0; i < ac; i++) {
	struct alias_rec * a = give_alias(aview,i);
	
	if (a &&
	    ison(a->status, TAGGED)) {
	    if (tagged == 0) leftoff = i;
	    tagged++;
	}
    }
    
    if (tagged == 1) {
	char * buffer = NULL;

	/*
	 * There is only on alias tagged.  Ask the question
	 * but the default response is NO.
	 */
	menu_PutLineX(LOC->prompt_page,1,0, CATGETS(elm_msg_cat,
						    AliasesSet, 
						    AliasesOneTagged,
						    "There is 1 alias tagged..."));
	menu_CleartoEOLN(LOC->prompt_page);
	buffer = elm_message(CATGETS(elm_msg_cat,
				     AliasesSet, AliasesCreateGroup,
				     "Create group alias? (%c/%c) "),
			     *def_ans_yes, *def_ans_no);
	ch = want_to(buffer, *def_ans_no, 0, 0, LOC->prompt_page);
	free(buffer);
    }
    else if (tagged > 1) {
	char * buffer = NULL;

	/*
	 * If multiple tagged aliases then we assume the user
	 * wants to create a group alias.  The default response
	 * is YES.
	 */
	menu_PutLineX(LOC->prompt_page,
		      1,0, CATGETS(elm_msg_cat,
					 AliasesSet, AliasesManyTagged,
				   "There are %d aliases tagged..."),
		 tagged);
	menu_CleartoEOLN(LOC->prompt_page);
	buffer = elm_message(CATGETS(elm_msg_cat,
				     AliasesSet, AliasesCreateGroup,
				     "Create group alias? (%c/%c) "),
			     *def_ans_yes, *def_ans_no);
	ch = want_to(buffer, *def_ans_yes, 0, 0, LOC->prompt_page);
	free(buffer);
    }

    /*
     *	Create the group alias address.  This is only done
     *	if one of the above want_to() questions were
     *	answered YES (and thus there *were* tagged messages
     *	and the user responded correctly).
     */
    if (ch == *def_ans_yes) {
	struct alias_rec * a = give_alias(aview,leftoff);

	/* TODO: Fix this mess */
	strfcpy(address1, a->alias, sizeof address1);
	
	ac = get_alias_count(aview);
	for (i=leftoff+1; i < ac; i++) {
	    struct alias_rec * a = give_alias(aview,i);

	    if (a &&
		ison(a->status, TAGGED)) {
		strfcat(address1, ",", sizeof address1);
		strfcat(address1, a->alias, 
			sizeof address1);
	    }
	}
	is_group = 1;
    }
    else {
	tagged = 0;
    }

    /*
     *	Only ask for an aliasname if we are NOT replacing the
     *	current alias.
     */
    if (replace) {
	char buffer[100];    /* TODO: Fix this mess! */
	
	struct alias_rec * a = give_alias(aview,to_replace);

	aliasname[0] = '\0';
	if (a) {
	    strfcpy(aliasname, a->alias, sizeof aliasname);

	    /*
	     *  First, see if what we are replacing is a SYSTEM
	     *  alias.  If so, we need to ask a question.
	     */
	    if(a->type & SYSTEM) {
		DPRINT(Debug,3,
		       (&Debug, 
			"Aliasname [%s] is SYSTEM in add_alias\n", 
			aliasname));
		
		/*
		 *  If they don't want to superceed the SYSTEM alias 
		 * then just return.
		 */
		if( ! superceed_system(to_replace, buffer, sizeof buffer,
				       aview, page, LOC->prompt_page)) {
		    menu_ClearLine(LOC->prompt_page,1);
		    return(0);
		}
	    }
	}
    }
    else {
	char buffer[100];    /* TODO: Fix this mess! */

	strfcpy(buffer, catgets(elm_msg_cat,
				AliasesSet, AliasesEnterAliasName, 
				"Enter alias name: "),
		sizeof buffer);
	menu_PutLine0(LOC->prompt_page,1,0, buffer);
	menu_CleartoEOLN(LOC->prompt_page);
	*aliasname = '\0';

	replace = get_aliasname(aliasname, buffer, &to_replace,
				sizeof aliasname, sizeof buffer,
				aview, page,LOC->prompt_page);
	while (REDRAW_MARK == replace) {
	    menu_ClearScreen(page);   /* Reset possible redraw flag */
	    
	    /* Call refresh routines of children */
	    menu_redraw_children(page);
    
	    if (menu_need_redraw(LOC->prompt_page))
		menu_ClearScreen(LOC->prompt_page);
	    delay_redraw++;

	    menu_PutLine0(LOC->prompt_page,1,0, buffer);
	    replace = get_aliasname(aliasname, buffer, &to_replace,
				    sizeof aliasname, sizeof buffer,
				    aview, page,LOC->prompt_page);
	}
	
	if (replace < 0) {

	    if (delay_redraw)
		menu_trigger_redraw(page);

	    DPRINT(Debug,3,
		   (&Debug,
		    "Aliasname [%s] was rejected in add_alias\n", aliasname));
	    menu_ClearLine(LOC->prompt_page,1);
	    return(0);
	}
    }

    /*
     *	If we are replacing an existing alias, we will assume that
     *	they might want to be just editing most of what is already
     *	there.  So we copy some defaults from the existing alias.
     */

    if (replace) {

	struct alias_rec * a = give_alias(aview,to_replace);

	lastname[0] = '\0';
	firstname[0] = '\0';
	comment[0] = '\0';

	if (a) {
	    strfcpy(lastname, a->last_name, sizeof lastname);
	    strfcpy(firstname, a->name,	sizeof firstname);

	    ch_ptr = strstr(firstname, lastname);

	    if (ch_ptr)
		*(ch_ptr-1) = '\0';
	    strfcpy(comment, a->comment, sizeof comment);
	}
    }
    else {
	*lastname = '\0';
	*firstname = '\0';
	*comment = '\0';
    }
    
    /*
     *	Since there are no tagged aliases, we must ask for an
     *	address.  If we are replacing, a default address is
     *	presented.
     */
    if (tagged == 0) {
	char buffer[1000]; /* Fix this mess !!! */        

	elm_sfprintf(buffer, sizeof buffer,
		     CATGETS(elm_msg_cat,
			     AliasesSet, AliasesEnterAddress,
			     "Enter address for %s: "), 
		     aliasname);


	menu_PutLine0(LOC->prompt_page,1,0, buffer);

	menu_CleartoEOLN(LOC->prompt_page);
	if (replace) {

	    struct alias_rec * a = give_alias(aview,to_replace);

	    if (a)
		strfcpy(address1, a->address, sizeof address1);
	    else
		address1[0] = '\0';

	}
	else {
	    *address1 = '\0';
	}
	
	do {
	    /* FIXME --optionally_enter*  should use prompt_page */	  
	    int line = menu_GetAbsLine(LOC->prompt_page,1);
	    int status =
	        optionally_enter(address1, line, strlen(buffer),
	                         OE_REDRAW_MARK|
				 OE_SIG_CHAR /* Ctrl-C */, sizeof address1,
				 page);
	    
	    while (REDRAW_MARK == status) {
		menu_ClearScreen(page);   /* Reset possible redraw flag */
		delay_redraw++;   /* Can't trigger redraw yet... */

		/* Call refresh routines of children */
		menu_redraw_children(page);
		
		if (menu_need_redraw(LOC->prompt_page))
		    menu_ClearScreen(LOC->prompt_page);

		elm_sfprintf(buffer, sizeof buffer,
			     CATGETS(elm_msg_cat,
				     AliasesSet, AliasesEnterAddress,
				     "Enter address for %s: "), 
			     aliasname);
		menu_PutLine0(LOC->prompt_page,1,0, buffer);
		status =
		    optionally_enter(address1, line, strlen(buffer),
				     OE_REDRAW_MARK|OE_APPEND_CURRENT|
				     OE_SIG_CHAR /* Ctrl-C */,
				     sizeof address1,
				     page);
	    }
	    
	    if (0 != status ||
		strlen(address1) == 0) {

		if (delay_redraw)
		    menu_trigger_redraw(page);


		lib_error(CATGETS(elm_msg_cat, AliasesSet, 
				  AliasesNoAddressSpec,
				  "No address specified!"));
		return(0);
	    }
	} while (check_address(address1) == -1);
	
	clear_error();			/* Just in case */
    }
	
    if (!is_group && strchr(address1,',') != NULL)
	is_group = 1;
    
    if (!get_realnames(aliasname, firstname, lastname, comment, bufferA,
		       sizeof firstname, sizeof lastname, sizeof comment,
		       sizeof bufferA, is_group, page,LOC->prompt_page)) {

	if (delay_redraw)
	    menu_trigger_redraw(page);

	return 0;
    }

    if(ask_accept(aliasname, firstname, lastname, comment, address1,
		  bufferA, replace, to_replace,
		  sizeof bufferA, aview,  page, LOC)) {

	if (delay_redraw)
	    menu_trigger_redraw(page);


	/*
	 * We can only clear the tags after we know that the
	 * alias was added.  This allows the user to back out
	 * and rethink without losing the tags.
	 */
	if (tagged > 0) {
	    ac = get_alias_count(aview);
	    
	    for (i=leftoff; i < ac; i++) {
		struct alias_rec * a = give_alias(aview,i);

		if (a &&
		    ison(a->status, TAGGED)) {
		    struct menu_common MENU;
		    int vis;

		    clearit(a->status, TAGGED);

		    set_mcommon_from_aliasview(&MENU,aview);
    
		    vis = compute_visible(i+1, &MENU);
		    menu_header_status_update(LOC->header_page,vis-1);

		}
	    }
	}

	return(1);
    }
   

    if (delay_redraw)
	menu_trigger_redraw(page);
    
    return(0);       
}

static int add_current_alias P_((struct MailboxView *mailbox,
				 struct AliasView *aview,
				 struct menu_context  *page,
				 struct screen_parts *LOC));
static int add_current_alias(mailbox,aview,  page, LOC)
     struct MailboxView *mailbox;
     struct AliasView *aview;
     struct menu_context  *page;
     struct screen_parts *LOC;
{
    /*
     *	Alias the current message to the specified name and
     *	add it to the alias text file, for processing as
     *	the user leaves the program.
     *
     *	Returns non-zero iff alias actually added to file.
     */
    
    char aliasname[SLEN], firstname[SLEN], lastname[SLEN];
    char comment[SLEN], address1[LONG_STRING], buffer[SLEN];
    char comment_buff[LONG_STRING];
    char *chspace, *bufptr;
    struct header_rec *current_header;
    
    static char bad_punc[] = ",.:;";
    char *punc_ptr;
    int i, match;
    int replace, to_replace;

    int delay_redraw = 0;
    int current_mail_message = get_current(mailbox);


    if (current_mail_message == 0) {
	DPRINT(Debug,3,
	       (&Debug,
		"Add current alias called without any current message!\n"));
	lib_error(CATGETS(elm_msg_cat, AliasesSet, AliasesNoMessage,
			  "No message to alias to!"));
	return(0);
    }

    current_header = give_header(mailbox,current_mail_message - 1);
    if (!current_header ||
	!current_header->from || 
	!current_header->from[0].fullname ||
	!current_header->from[0].addr ||
	!current_header->from[0].comment)
	return 0;
    

    /* TODO: Fix this mess ... */
    strfcpy(buffer, catgets(elm_msg_cat, AliasesSet, AliasesCurrentMessage,
			    "Current message address aliased to: "),
	    sizeof buffer);
    menu_PutLine0(LOC->prompt_page,1,0, buffer);
    menu_CleartoEOLN(LOC->prompt_page);

    *aliasname = '\0';
    replace = get_aliasname(aliasname, buffer, &to_replace,
			    sizeof aliasname, sizeof buffer,
			    aview, page,LOC->prompt_page);
    while (REDRAW_MARK == replace) {
	menu_ClearScreen(page);   /* Reset possible redraw flag */
	
	/* Call refresh routines of children */
	menu_redraw_children(page);
	
	if (menu_need_redraw(LOC->prompt_page))
	    menu_ClearScreen(LOC->prompt_page);   /* Clear redraw mark from prompt_area*/
	
	/* NOTICE: using menu_trigger_redraw(page) on here
	   may cause redraw loop!
	*/
	delay_redraw++;

	menu_PutLine0(LOC->prompt_page,1,0, buffer);
	replace = get_aliasname(aliasname, buffer, &to_replace,
				sizeof aliasname, sizeof buffer,
				aview, page,LOC->prompt_page);
    }

    if (delay_redraw)
	menu_trigger_redraw(page);

    if (replace < 0) {
	DPRINT(Debug,3,
	       (&Debug,
		"Aliasname [%s] was rejected in add_current_alias\n",
		aliasname));
	menu_ClearLine(LOC->prompt_page,1);
	return(0);
    }
    
    {
	struct string * T = 
	    convert_string(display_charset,
			   current_header->from[0].fullname,
			   1);
	char * A = us2s(stream_from_string(T,1,NULL));
	strfcpy(comment_buff,A,sizeof comment_buff);
	free(A);
	free_string(&T);
    }
    
    /*
     *	Try to break up the From: comment into firstname, lastname, and
     *	any other text.  This is based on the fact that many address
     *	comments are pretty straightforward.  This will break on many
     *	situations.  Should handle:
     *		(Robert Howard)
     *		(Robert L. Howard)
     *		(Robert Howard, Georgia Tech)
     *	pretty well.  Will break on:
     *		(The Voice of Reason)
     *		and others....
     */

    *firstname = '\0';
    *lastname = '\0';
    *comment = '\0';
    if (strlen(comment_buff) != 0) {	/* There is something. */
	bufptr = comment_buff;
	while (*bufptr == SPACE) bufptr++;	/* Always strip leading WS */
	if ((chspace = index(bufptr, (int) SPACE)) != NULL) {
	    /*
	     *   A space means that there is at least (firstname lastname)
	     *   Get firstname and move bufptr.
	     */
	    *chspace = '\0';
	    strfcpy(firstname, bufptr, sizeof firstname);
	    bufptr = chspace + 1;			/* Move the pointer */
	    while (*bufptr == SPACE) bufptr++;
	}
	
    above:	    if ((chspace = index(bufptr, (int) SPACE)) != NULL) {
	/*
	 *   Another space means a third+ word.  We either have:
	 *       1. Word 3+ is a comment, or
	 *       2. Word 2 is a middle initial (word 3 is lastname).
	 *   Check and see.
	 */
	*chspace = '\0';
	if ((strlen(bufptr) == 1) ||
	    (strlen(bufptr) == 2  && *(bufptr+1) == '.')) {
	    /*
	     *   If the second word is either a single
	     *   character or a character followed by '.' it was
	     *   probably a middle initial.  Add it to firstname
	     *   and shift.
	     */
	    strfcat(firstname, " ", sizeof firstname);
	    strfcat(firstname, bufptr, sizeof firstname);
	    bufptr = chspace + 1;		/* Move the pointer */
	    while (*bufptr == SPACE) bufptr++;
	    goto above;
	}
	strfcpy(lastname, bufptr, sizeof lastname);
	bufptr = chspace + 1;			/* Move the pointer */
	while (*bufptr == SPACE) bufptr++;
	strfcpy(comment, bufptr, sizeof comment);
    }
    else {
	/*
	 *   Only a lastname left.
	 */
	strfcpy(lastname, bufptr, sizeof lastname);
    }
	
	if (!comment[0]) {
	    struct string * T = 
		convert_string(display_charset,
			       current_header->from[0].comment,
			       1);
	    char * A = us2s(stream_from_string(T,1,NULL));
	    strfcpy(comment, A, sizeof comment);
	    free(A);
	    free_string(&T);
	}
	
	/*
	 *  Finally, get any puctuation characters off the end of
	 *  lastname.
	 */
	match = TRUE;
	for (i = strlen(lastname) - 1; match && i>0; i--) {
	    match = FALSE;
	    for (punc_ptr = bad_punc; *punc_ptr != '\0'; punc_ptr++) {
		if (lastname[i] == *punc_ptr) {
		    lastname[i] = '\0';
		    match = TRUE;
		    break;
		}
	    }
	}
    }
    
    if (!get_realnames(aliasname, firstname, lastname, comment, buffer,
		       sizeof firstname, sizeof lastname, sizeof comment,
		       sizeof buffer, 0, page,LOC->prompt_page))
	return 0;
    
    /* grab the return address of this message */
    strfcpy(address1,current_header->from[0].addr,sizeof address1);
    
    return(ask_accept(aliasname, firstname, lastname, comment, address1,
		      buffer, replace, to_replace, sizeof buffer, aview,
		      page, LOC));

}

static int add_to_alias_text(aliasname, firstname, lastname, comment, address)
     char *aliasname, *firstname, *lastname, *comment, *address;
{
/*
 *	Add the data to the user alias text file.
 *
 *	Return zero if we succeeded, 1 if not.
 */
	
	FILE *file;
	char fname[SLEN];
	char buffer[SLEN];
	int  err;
	
	strfcpy(fname,user_text_file,sizeof fname);
	
	save_file_stats(fname);

	err = can_open(fname, "a");
	if (err) {
	    DPRINT(Debug,2,
		   (&Debug, 
		    "Failure attempting to add alias to file %s within %s (can_open)",
		    fname, "add_to_alias_text"));
	    DPRINT(Debug,2,
		   (&Debug, "** %s **\n", error_description(err)));
	    lib_error(CATGETS(elm_msg_cat, AliasesSet, AliasesCouldntOpenAdd,
			      "Couldn't open %s to add new alias!"), 
		      fname);
	    return(1);
	}


	if ((file = fopen(fname, "a")) == NULL) {
	  err = errno;
	  DPRINT(Debug,2,
		 (&Debug, 
		  "Failure attempting to add alias to file %s within %s",
		  fname, "add_to_alias_text"));
	  DPRINT(Debug,2,
		 (&Debug, "** %s **\n", error_description(err)));
	  lib_error(CATGETS(elm_msg_cat, AliasesSet, AliasesCouldntOpenAdd,
			    "Couldn't open %s to add new alias!"), 
		    fname);
	  return(1);
	}

	if (strlen(firstname) == 0) {
	    strfcpy(buffer, lastname, sizeof buffer);  
	}
	else {
	  elm_sfprintf(buffer, sizeof buffer,
		       FRM("%s; %s"), lastname, firstname);
	}
	if (strlen(comment) != 0) {
	    strfcat(buffer, ", ", sizeof buffer);
	    strfcat(buffer, comment, sizeof buffer);
	}
	if (fprintf(file,"%s = %s = %s\n", aliasname, buffer, address) == EOF) {
	    err = errno;
	    DPRINT(Debug,2,
		   (&Debug,
		    "Failure attempting to write alias to file %s within %s",
		    fname, "add_to_alias_text"));
	    DPRINT(Debug,2,
		   (&Debug, "** %s **\n", error_description(err)));
	    lib_error(CATGETS(elm_msg_cat, AliasesSet, AliasesCouldntWrite,
			      "Couldn't write alias to file %s!"), 
		      fname);
	    fclose(file);
	    return(1);
	}

	fclose(file);

	restore_file_stats(fname);

	return(0);
}

static int parse_aliases P_((char *, char *, int, int)); /* Prototype */


int delete_from_alias_text(name, num_to_delete)
     char **name;
     int num_to_delete;
{
/*
 *	Delete the data from the user alias text file.
 *
 *	Return zero if we succeeded, 1 if not.
 */
	
	FILE *file, *tmp_file;

	char fname[SLEN], tmpfname[SLEN];
	char line_in_file[LONG_STRING];
	char rest_of_line[LONG_STRING];
	char *s, *rest;

	register int i;
	int num_aliases;
	int delete_continues;
	int err;

	delete_continues = FALSE;

	strfcpy(fname,user_text_file,sizeof fname);
	elm_sfprintf(tmpfname,sizeof tmpfname,
		     FRM("%s.t"), user_text_file);
	
	save_file_stats(fname);

	err = can_open(fname, "r");
	if (err) {
	    DPRINT(Debug,2,
		   (&Debug, 
		    "Failure attempting to delete alias from file %s within %s (can_open)",
		    fname, "delete_from_alias_text"));
	    DPRINT(Debug,2,
		   (&Debug, "** %s **\n", error_description(err)));
	    lib_error(CATGETS(elm_msg_cat, AliasesSet, AliasesCouldntOpenDelete,
			      "Couldn't open %s to delete alias!"), 
		      fname);
	    return(1);

	}

	if ((file = fopen(fname, "r")) == NULL) {
	    err = errno;
	    DPRINT(Debug,2,
		   (&Debug, 
		    "Failure attempting to delete alias from file %s within %s",
		    fname, "delete_from_alias_text"));
	    DPRINT(Debug,2,
		   (&Debug, "** %s **\n", error_description(err)));
	    lib_error(CATGETS(elm_msg_cat, AliasesSet, AliasesCouldntOpenDelete,
			      "Couldn't open %s to delete alias!"), 
		      fname);
	    return(1);
	}


	err = can_open(tmpfname, "w");
	if (err) {
	    err = errno;
	    DPRINT(Debug,2,
		   (&Debug, 
		    "Failure attempting to open temp file %s within %s (can_open)",
		    tmpfname, "delete_from_alias_text"));
	    DPRINT(Debug,2,
		   (&Debug, "** %s **\n", error_description(err)));
	    lib_error(CATGETS(elm_msg_cat, AliasesSet, AliasesCouldntOpenTemp,
			      "Couldn't open temp file %s to delete alias!"), 
		      tmpfname);

	    fclose(file);
	    return(1);
	}

	if ((tmp_file = fopen(tmpfname, "w")) == NULL) {
	    err = errno;
	    DPRINT(Debug,2,
		   (&Debug, 
		    "Failure attempting to open temp file %s within %s",
		    tmpfname, "delete_from_alias_text"));
	    DPRINT(Debug,2,
		   (&Debug, "** %s **\n", error_description(err)));
	    lib_error(CATGETS(elm_msg_cat, AliasesSet, AliasesCouldntOpenTemp,
			      "Couldn't open temp file %s to delete alias!"), 
		      tmpfname);

	    fclose(file);
	    return(1);
	}

	while (mail_gets(line_in_file, sizeof(line_in_file), file) != 0)
	{
	  if (! whitespace(line_in_file[0])) {
	    delete_continues = FALSE;
	    if (line_in_file[0] != '#') {
	      if (0 != (num_aliases = 
			parse_aliases(line_in_file, rest_of_line,
				      sizeof line_in_file,
				      sizeof rest_of_line))) {
	        for (i=0; i < num_to_delete && num_aliases; i++) {
		  char buf[LONG_STRING];
		  strfcpy(buf,name[i], sizeof buf);
		  strfcat(buf,",", sizeof buf);

	          if ((s = strstr(line_in_file, buf)) != NULL) {
/*
 *	Collapse the to be deleted alias out of line_in_file
 */
	            rest = index(s, ',');
	            for (++rest; *rest; rest++)
	              *s++ = *rest;
	            *s = '\0';
	            num_aliases--;
	          }
	        }
	        if (num_aliases) {
	          *(line_in_file + strlen(line_in_file) - 1) = ' ';
	          strfcat(line_in_file, rest_of_line,
			  sizeof line_in_file);
	        }
	        else {
	          delete_continues = TRUE;
	        }
	      }
	    }
	  }
	  if (! delete_continues) {
	    if (fprintf(tmp_file,"%s", line_in_file) == EOF) {
	      err = errno;
	      DPRINT(Debug,2,
		     (&Debug,
		      "Failure attempting to write to temp file %s within %s",
		      tmpfname, "delete_from_alias_text"));
	      DPRINT(Debug,2,
		     (&Debug, "** %s **\n", error_description(err)));
	      lib_error(CATGETS(elm_msg_cat, AliasesSet, 
				AliasesCouldntWriteTemp,
				"Couldn't write to temp file %s!"), 
			tmpfname);
	      fclose(file);
	      fclose(tmp_file);
	      unlink(tmpfname);
	      return(1);
	    }
	  }
	}
	fclose(file);
	fclose(tmp_file);
	if (rename(tmpfname, fname) != 0)
	{
		lib_error(CATGETS(elm_msg_cat, AliasesSet, 
				  AliasesCouldntRenameTemp,
				  "Couldn't rename temp file %s after deleting alias!"), 
			  tmpfname);
		return(1);
	}

	restore_file_stats(fname);

	return(0);
}

static void set_alias_screen P_((struct menu_context  *page, 
				   struct screen_parts *LOC,
				   struct menu_param  *LIST));
static void set_alias_screen(page,LOC, LIST)
     struct menu_context  *page;
     struct screen_parts *LOC;
     struct menu_param  *LIST;
{    
    int   LINES, COLUMNS;	

    menu_get_sizes(page,&LINES, &COLUMNS);

    /* 1)  Title part of screen */

    if (! LOC->title_page)
	LOC->title_page = new_menu_subpage(page,0,4,sb_update_title,LIST);
    else
	menu_subpage_relocate(LOC->title_page,page,0,4);

    /* 2) menu part */

    if (LOC->menu_page)
	menu_subpage_relocate(LOC->menu_page,page,LINES-8,4);
    else if (mini_menu)
	LOC->menu_page = new_menu_subpage(page,LINES-8,4,
					  sb_alias_menu,LIST);
   
    mailbox_screen_common(page,LOC, LIST);		
}

static void check_alias_screen P_((struct screen_parts *LOC,
				     struct menu_param *list));
static void check_alias_screen(LOC,list)
     struct screen_parts *LOC;
     struct menu_param *list;
{
    /* 1) title page */
    if (menu_resized(LOC->title_page)) {
	DPRINT(Debug,1, (&Debug, "title page resized\n"));

    }
    if (menu_need_redraw(LOC->title_page)) {
	DPRINT(Debug,1, (&Debug, "title page redraw???\n"));
	sb_update_title(LOC->title_page,list);
    }

    if (LOC->menu_page) {
	/* 2) menu page */
	if (menu_resized(LOC->menu_page)) {
	    DPRINT(Debug,1, (&Debug, "menu page resized\n"));
	    
	}
	if (menu_need_redraw(LOC->menu_page)) {
	    DPRINT(Debug,1, (&Debug, "menu page redraw???\n"));
	    sb_show_menu(LOC->menu_page,list);
	}
    }

    /* 3) prompt part */
    if (menu_resized(LOC->prompt_page)) {
	DPRINT(Debug,1, (&Debug, "prompt page resized\n"));
    }
    if (menu_need_redraw(LOC->prompt_page)) {
	menu_ClearScreen(LOC->prompt_page);

	show_last_error();	/* for those operations that have to
				 * clear the footer except for a message.
				 */
    }

    /* 4) headers part */
    if (menu_resized(LOC->header_page)) {
	DPRINT(Debug,1, (&Debug, "header page resized\n"));
    }
    if (menu_need_redraw(LOC->header_page)) {
	DPRINT(Debug,1, (&Debug, "header page redraw\n"));
	menu_ClearScreen(LOC->header_page);
    }
}


void alias(mailbox, aview)
     struct MailboxView *mailbox;
     struct AliasView *aview;
{
    
    /*
     *	Work with alias commands...
     */
    
    char name[NLEN], buffer[SLEN];
    int ch;
    static int  newaliases = 0;
    int  i;
    int too_long;
    
    struct menu_context  *page = new_menu_context();
    
    
    struct screen_parts  LOC  = { NULL, NULL };
    struct menu_common MENU;
    struct menu_param  PARAM[elm_mp_COUNT+1] = { 
	{ mp_menu_common, 0 },
	{ mp_integer, 0 },
	{ mp_END,0 }
    };

    static int first_time = TRUE;

/*
 *	We're going to try to match the way elm does it at
 * 	he main menu.  I probably won't be able to use any
 *	main menu routines, but I will "borrow" from them. RLH
 */


    if (first_time) {
	a_group_name = catgets(elm_msg_cat, AliasesSet, AliasesGroup,
			       " Group");
	a_person_name = catgets(elm_msg_cat, AliasesSet, AliasesPerson,
				"Person");
	a_system_flag = catgets(elm_msg_cat, AliasesSet, AliasesSystemFlag,
				"(S)");
	a_rev_alias_pad = catgets(elm_msg_cat, AliasesSet, AliasesRevAliasPad,
				  "Reverse Alias Name      ");
	a_rev_alias_abr = catgets(elm_msg_cat, AliasesSet, AliasesRevAliasAbr,
				  "Reverse-Alias");
	a_rev_alias_name = catgets(elm_msg_cat, AliasesSet, AliasesRevAliasName,
				   "Reverse Alias Name");
	a_rev_full_pad = catgets(elm_msg_cat, AliasesSet, AliasesRevFullPad,
				 "Reverse Full (Real) Name");
	a_full_abr = catgets(elm_msg_cat, AliasesSet, AliasesRevFullAbr,
			     "Reverse-Name");
	a_rev_full_name = catgets(elm_msg_cat, AliasesSet, AliasesRevFullName,
				  "Reverse Full (Real) Name");
	a_rev_text_pad = catgets(elm_msg_cat, AliasesSet, AliasesRevTextPad,
				 "Reverse Text File       ");
	a_text_abr = catgets(elm_msg_cat, AliasesSet, AliasesRevTextAbr,
			     "Reverse-Text");
	a_rev_text_file = catgets(elm_msg_cat, AliasesSet, AliasesRevTextFile,
				  "Reverse Text File");
	a_alias_pad = catgets(elm_msg_cat, AliasesSet, AliasesAliasPad,
			      "Alias Name              ");
	a_alias_abr = catgets(elm_msg_cat, AliasesSet, AliasesAliasAbr,
			      "Alias");
	a_alias_name = catgets(elm_msg_cat, AliasesSet, AliasesAliasName,
			       "Alias Name");
	a_full_pad = catgets(elm_msg_cat, AliasesSet, AliasesFullPad,
			     "Full (Real) Name        ");
	a_full_abr = catgets(elm_msg_cat, AliasesSet, AliasesFullAbr,
			     "Name");
	a_full_name = catgets(elm_msg_cat, AliasesSet, AliasesFullName,
			      "Full (Real) Name");
	a_text_pad = catgets(elm_msg_cat, AliasesSet, AliasesTextPad,
			     "Text File               ");
	a_text_abr = catgets(elm_msg_cat, AliasesSet, AliasesTextAbr,
			     "Text");
	a_text_file = catgets(elm_msg_cat, AliasesSet, AliasesTextFile,
			      "Text File");
	first_time = FALSE;
    }

    set_mcommon_from_aliasview(&MENU, aview);
    mp_list_set_mcommon(PARAM,elm_mp_menu,&MENU);

    mp_list_set_integer(PARAM,elm_mp_modified,newaliases);
    set_alias_screen(page,&LOC,PARAM);

    open_alias_files(aview, &LOC);	/* First, read the alias files. RLH */

    copy_current(&MENU,LOC.header_page);
    alias_screen(aview, page);
    /* define_softkeys(ALIAS); */

    while (1) {
	
    resize_mark:
	menu_set_default(page);

	set_mcommon_from_aliasview(&MENU, aview);

	if (menu_resized(page)) {
	    int	LINES, COLUMNS;
		
	    set_alias_screen(page,&LOC,PARAM);
	
	    menu_get_sizes(page,&LINES, &COLUMNS);
		
	    menu_trigger_redraw(page);

	}

	if (menu_need_redraw(page)) {	  /* Redraw screen if necessary */
	    DPRINT(Debug,7, (&Debug, 
			     "alias: pending redraw\n"));
	    
	    mp_list_set_integer(PARAM,elm_mp_modified,newaliases);
	    alias_screen(aview, page);
	     
	}
	check_alias_screen(&LOC, PARAM);
	
	{
	    int lin,col;
	    
	    menu_PutLineX(LOC.prompt_page,0,0,
			  FRM("%S"),mcommon_give_item(&MENU, m_Prompt));
	    
	    menu_GetXYLocation(LOC.prompt_page,&lin,&col);
	    
	    menu_CleartoEOLN(LOC.prompt_page);

	    show_last_error();
	    menu_MoveCursor(LOC.prompt_page,lin,col);

	    ch = menu_ReadCh(LOC.prompt_page,
			     REDRAW_MARK|READCH_CURSOR|
			     READCH_resize);
	    menu_MoveCursor(LOC.prompt_page,lin,col); 
	    menu_CleartoEOS(LOC.prompt_page);
	
	
	    if (isascii(ch) && isprint(ch)) {
		DPRINT(Debug,4,
		       (&Debug, "-- Alias command: %c [%d]\n",ch,ch));
	    } else {
		DPRINT(Debug,4,
		       (&Debug, "-- Alias command: [%d]\n",ch));
	    }

	    set_error("");	/* clear error buffer */
	    
	    menu_MoveCursor(LOC.prompt_page,lin,col);
	}

	  switch (ch) {
	  case RESIZE_MARK:
	      DPRINT(Debug,4,  (&Debug," ... resizing\n"));
	      goto resize_mark;

	  case HELP_MARK:
	  case '?': 
	      alias_help(page,LOC.prompt_page);			
	      break;
	      
	  case REDRAW_MARK:
	    case 'L'&31: 
		menu_trigger_redraw(page);
		break;


	  case '$': 
	      menu_Write_to_screen(LOC.prompt_page,
				   CATGETS(elm_msg_cat, AliasesSet, 
					   AliasesResync,
					   "Resynchronize aliases..."));
	      FlushBuffer();

	           /*
	            * Process deletions and then see if we need to
	            * re-run the "newalias" routine.
	            */
	      if (resync_aliases(newaliases,aview, page, LOC.prompt_page) 
		  >=0) {
		  install_aliases(aview,&LOC);
		  newaliases = 0;
		  menu_trigger_redraw(page);
		  
	      }
	      break;

	  case 'a': 
	      menu_Write_to_screen(LOC.prompt_page,
				   CATGETS(elm_msg_cat, AliasesSet, 
				      AliasesAddCurrent,
				      "Add address from current message..."));
	      FlushBuffer();

	      clear_error();
	      if (add_current_alias(mailbox,aview, page, &LOC)) {
		  newaliases++;

		  mp_list_set_integer(PARAM,elm_mp_modified,newaliases);
		  menu_trigger_redraw(LOC.title_page);
		 
	      }
	      break;

	  case 'c': {
	      int alias_current = get_alias_current(aview);

	      if (alias_current > 0) {
		  menu_Write_to_screen(LOC.prompt_page,
				       CATGETS(elm_msg_cat,
					       AliasesSet, AliasesReplaceCurrent,
					       "Replace current alias in database..."));
		  FlushBuffer();

		  clear_error();
		  if (add_alias(TRUE, alias_current-1, aview, 
				page, &LOC)) {
		      newaliases++;

		      mp_list_set_integer(PARAM,elm_mp_modified,newaliases);
		      menu_trigger_redraw(LOC.title_page);

		  }
	      }
	      else {
		  lib_error(CATGETS(elm_msg_cat,
				    AliasesSet, AliasesNoneToReplace,
				    "Warning: no aliases to replace!"));
	      }
	  }
	      break;

	  case 'e': 
	      menu_Write_to_screen(LOC.prompt_page,
				   CATGETS(elm_msg_cat, AliasesSet, AliasesEdit,
					   "Edit %s..."), 
				   USER_ALIAS_TEXT);
	      FlushBuffer();

	      /*
	       * Process aliases.text for deletions, etc.  You
	       * have to do this *before* checking current because
	       * all aliases could be marked for deletion.
	       */
	      if (resync_aliases(newaliases,aview, page, 
				 LOC.prompt_page) < 0)
		  break;
	      if (edit_aliases_text(aview, page, &LOC)) {
		  newaliases = 0;
	      }
	      menu_trigger_redraw(page);
	      
	      break;

	    case 'm':{
		int alias_current = get_alias_current(aview);
		
		if (alias_current > 0) {
		    menu_Write_to_screen(LOC.prompt_page,
					 CATGETS(elm_msg_cat, AliasesSet, AliasesMail,
						 "Mail..."));
		    FlushBuffer();

		    a_sendmsg(TRUE,allow_forms,
			      mailbox, aview, 
			      page, &LOC);

		}
		else {
		    lib_error(CATGETS(elm_msg_cat,
				      AliasesSet, AliasesNoneToMail,
				      "Warning: no aliases to send mail to!"));
		}
	    } 
		break;

	  case 'n': 
	      menu_Write_to_screen(LOC.prompt_page,
				   CATGETS(elm_msg_cat, AliasesSet, AliasesAddNew,
					   "Add a new alias to database..."));
	      FlushBuffer();
		
		      clear_error();
		      if (add_alias(FALSE, -1, aview, page, &LOC)) {
		          newaliases++;
		          
			  mp_list_set_integer(PARAM,elm_mp_modified,
					      newaliases);
			  menu_trigger_redraw(LOC.title_page);
		      }
		      break;

	    case 'q':
	    case 'Q':
	    case 'i':
	    case 'I':
	    case 'r':
	  case 'R': {
	      int r;
	      menu_Write_to_screen(LOC.prompt_page,
				   CATGETS(elm_msg_cat, AliasesSet, 
					   AliasesAddReturn,
					   "Return to main menu..."));
	      FlushBuffer();

	           /*
	            * leaving the alias system.  Must check for
	            * pending deletes, etc.  prompt is set to FALSE
	            * on uppercase letters so that deletions are
	            * NOT queried.
	            */
	      r = delete_aliases(newaliases, islower(ch), aview, page,
				 LOC.prompt_page);
	      if (-1 == r) { /* Ctrl-C */
		  break;
	      }

	      if (r > 0) {
		  install_aliases(aview,&LOC);
		  newaliases = 0;
	      }
	      clear_error();

	      goto OUT;
	  }
	  case RETURN:
	    case LINE_FEED:
	    case SPACE:
	    case 'v':	{
		int alias_current = get_alias_current(aview);
		
		if (newaliases) {		/* Need this ?? */
		    int lin,col;
		    GetXYLocation(&lin,&col);

		    lib_error(CATGETS(elm_msg_cat,
				      AliasesSet, AliasesNotInstalled,
				      "Warning: new aliases not installed yet!"));
		    MoveCursor(lin,col);
		}
		
		if (alias_current > 0) {
		    struct alias_rec *a = give_alias(aview,
						     alias_current-1);
		    
		    if (a) {		     
			if (a->type & GROUP) {			    
			    menu_PutLineX(LOC.prompt_page,2, 0,
					  CATGETS(elm_msg_cat,
						  AliasesSet, 
						  AliasesGroupAlias,
						  "Group alias: %-60.60s"),
					  a->address);
			}
			else {
			    menu_PutLineX(LOC.prompt_page,2, 0,
					  CATGETS(elm_msg_cat,
						  AliasesSet, 
						  AliasesAliasedAddress,
						  "Aliased address: %-60.60s"),
				     a->address);
			}
		    }
		} else {
		    lib_error(CATGETS(elm_msg_cat,
				      AliasesSet, AliasesNoneToView,
				      "Warning: no aliases to view!"));
		}
	    }
		break;

	    case 'x':
	  case 'X': 
	      menu_Write_to_screen(LOC.prompt_page,
				   CATGETS(elm_msg_cat, AliasesSet, 
					   AliasesAddReturn,
					   "Return to main menu..."));
	      FlushBuffer();
	      
	      exit_alias(aview);
	      clear_error();
	      
	      goto OUT;

	  case 'f':
	  case 'F': {
	      int alias_current = get_alias_current(aview);

	      if (alias_current > 0) {
		  struct alias_rec *a = give_alias(aview,alias_current-1);
		  
		  if (a) {
		      clear_error();
		      strfcpy(name, a->alias, sizeof name);

		      if (ch == 'F') {
			  int status, line;
			  int delay_redraw = 0;

			  /* TODO: Fix this mess... */
			  strfcpy(buffer, catgets(elm_msg_cat,
						  AliasesSet, 
						  AliasesFullyExpanded,
						  "Fully expand alias: "),
				  sizeof buffer);
			  menu_PutLine0(LOC.prompt_page,1,0, buffer);
			  menu_CleartoEOS(LOC.prompt_page);

			  /* FIXME --optionally_enter*  should use prompt_page */
			  line = menu_GetAbsLine(LOC.prompt_page,1);
			  status = optionally_enter(name, line, 
						    strlen(buffer),
						    OE_REDRAW_MARK|
						    OE_SIG_CHAR /* Ctrl-C */, 
						    sizeof name,
						    page);

			  while (REDRAW_MARK == status) {
			      menu_ClearScreen(page);   /* Reset possible redraw flag */
			      delay_redraw++;   /* Can't trigger redraw yet... */

			      menu_PutLine0(LOC.prompt_page,1,0, buffer);
			      status = optionally_enter(name, line, 
							strlen(buffer),
							OE_REDRAW_MARK|
							OE_APPEND_CURRENT|
							OE_SIG_CHAR /* Ctrl-C */,
							sizeof name,
							page);
			      
			  }
			  if (delay_redraw)
			      menu_trigger_redraw(page);

			  if (0 != status)
			      break;
		      }

		      {
			  struct addr_item * address;
			  
			  too_long = FALSE;
			  address = get_alias_address_l(name, TRUE, 
							&too_long, NULL,
							aview);
			  if (address != NULL) {
			      struct menu_context  *page2 = 
				  new_menu_context();

			      struct addr_item *walk ;

			  redraw2:			

			      walk  =address;
			      while (TRUE) {
				  int LINES, COLUMNS;
				  
				  menu_get_sizes(page2,&LINES,&COLUMNS);

				  menu_ClearScreen(page2);
				  
				  menu_PutLineX(page2,2,0, 
						CATGETS(elm_msg_cat,
							AliasesSet, AliasesAliasedFull,
							"Aliased address for:\t%s\n\r"),
						name);
				  i = 4;
				  
				  while (i < LINES-3) {
				      if (walk->addr && walk->fullname) {
					  if (string_len(walk->fullname) ||
					      NULL != strchr(walk->addr,'@')) {
					      menu_PutLineX(page2,
							    i++, 4, FRM("%S <%s>"),
							    walk->fullname,walk->addr);
					  } else
					      menu_PutLine0(page2,
							    i++, 4, walk->addr);
					  walk++;
				      } else
					  break;
				  }
				  menu_PutLineX(page2, 
						LINES-2, 0, 
						CATGETS(elm_msg_cat,
							AliasesSet, AliasesPressReturn,
							"Press <return> to continue."));
				  if (REDRAW_MARK == menu_ReadCh(page2,
								 REDRAW_MARK)) {
				      menu_ClearScreen(page2);   /* Reset possible redraw flag */
				      goto redraw2;
				  }
				  if (walk->addr == NULL) {
				      break;
				  }
			      }
			      free_addr_items(address);

			      erase_menu_context(&page2);
			      menu_trigger_redraw(page);

			  } else if (! too_long) {
			      lib_error(CATGETS(elm_msg_cat,
						AliasesSet, AliasesNotFound,
						"Not found."));
			  }
		      }
		  }
	      }
	      else {
		  lib_error(CATGETS(elm_msg_cat,
				    AliasesSet, AliasesNoneToView,
				    "Warning: no aliases to view!"));
	      }
	  }
	      break;
	      
	 /*
	  * None of the menu specific commands were chosen, therefore
	  * it must be a "motion" command (or an error).
	  */
	    default	: 
		ch = motion(ch,&MENU,&LOC, page);
	      		
		switch (ch) {
		case 0: /* OK */
		    break;
    
		case EOF: leave(0);  /* Read failed, control tty died? */
		    break;

		default:
		    lib_error(CATGETS(elm_msg_cat, ElmSet, 
				      ElmUnknownCommand,
				      "Unknown command. Use '?' for help."));		    
		}
	  }

	  if (menu_need_redraw(page)) {	  /* Redraw screen if necessary */
	      DPRINT(Debug,7, (&Debug, 
			       "alias: pending redraw\n"));

	      mp_list_set_integer(PARAM,elm_mp_modified,newaliases);
	      alias_screen(aview, page);
	  }

	  check_range(&MENU, &LOC);   
	  check_alias_screen(&LOC, PARAM);
	  
	  
    }			/* BIG while loop... */

 OUT:

    free_mailbox_screen(&LOC);
    
    erase_menu_context(&page);
    return;
}

void install_aliases(aview,LOC)
     struct AliasView *aview;
     struct screen_parts *LOC;
{
/*
 *	Run the 'newalias' program and update the
 *	aliases before going back to the main program! 
 *
 *	No return value.....
 */

	int na;
	char itextfile[SLEN], odatafile[SLEN];

	lib_error(CATGETS(elm_msg_cat, AliasesSet, AliasesUpdating,
			  "Updating aliases..."));

	strfcpy(itextfile,user_text_file, sizeof itextfile);
	strfcpy(odatafile,user_data_file,sizeof odatafile);

/*
 *	We need to unlimit everything since aliases are 
 * 	eing read in from scratch.
 */
	set_alias_selected(aview,0);

	na = do_newalias(itextfile, odatafile, TRUE, FALSE);
	if (na >= 0) {
	    lib_error(CATGETS(elm_msg_cat, AliasesSet, AliasesReReading,
			      "Processed %d aliases.  Re-reading the database..."), 
		      na);
	    open_alias_files(aview, LOC);
	    lib_error(CATGETS(elm_msg_cat, AliasesSet, AliasesUpdatedOK,
			      "Aliases updated successfully."));
	}
}

static void alias_help(page,prompt_area)
     struct menu_context  *page;
     struct menu_context  *prompt_area;
{
    /*
     *	Help section for the alias menu...
     *
     *	If redraw is needed use menu_trigger_redraw(page)
     */
	
    int  ch;
    int  delay_redraw=0;

 redraw:    
    menu_ClearScreen(prompt_area);
    
    if (mini_menu) {
	menu_print_format_center(prompt_area,0, 
				 CATGETS(elm_msg_cat, AliasesSet, 
					 AliasesKeyMenu,
					 "Press the key you want help for, '?' for a key list, or '.' to exit help"));
    }


    do {
	menu_PutLineX(prompt_area,
		      2, 0, 
		      CATGETS(elm_msg_cat, AliasesSet, AliasesLongKey,
			      "Key you want help for: "));

	ch = menu_ReadCh(prompt_area,
			 REDRAW_MARK|READCH_CURSOR|READCH_sig_char);

	if (ch == REDRAW_MARK) {
	    menu_ClearScreen(page);   /* Clear possible redraw mark */

	    /* Call refresh routines of children */
	    menu_redraw_children(page);

	    delay_redraw++;
	    
	    /* This clear redraw mark from prompt_area */
	    goto redraw;
	}

	if (ch == '.')
	    break;
	
	if (ch == TERMCH_interrupt_char)
	    break;
	switch(ch) {
	case EOF : 
	    leave(0);   
	    break;
	case HELP_MARK:
	case '?' : 
	    display_helpfile(ALIAS_HELP);	
	    menu_trigger_redraw(page);
	    return;
	    
	case '$': lib_transient(CATGETS(elm_msg_cat, AliasesSet, 
				    AliasesHelpDollar,
				    "$ = Force resynchronization of aliases, processing additions and deletions."));
	break;
	
	case FIND_MARK:
	case '/': lib_transient(CATGETS(elm_msg_cat, AliasesSet, 
				    AliasesHelpSlash,
				    "/ = Search for specified name or alias in list."));
	break;
	
	case RETURN:
	case LINE_FEED:
	case SPACE:
	case 'v': lib_transient(CATGETS(elm_msg_cat, AliasesSet, AliasesHelpv,
				    "v = View the address for the currently selected alias."));
	break;
	
	case 'a':lib_transient(CATGETS(elm_msg_cat, AliasesSet, AliasesHelpa,
				       "a = Add (return) address of current message to alias database."));
	break;
	
	case 'c': lib_transient(CATGETS(elm_msg_cat, AliasesSet, AliasesHelpc,
				    "c = Change current user alias, modifying alias database at next resync."));
	break;
	
	case 'd': lib_transient(CATGETS(elm_msg_cat, AliasesSet, AliasesHelpd,
					"d = Mark the current alias for deletion from alias database."));
	break;
	
	case ctrl('D'): lib_transient(CATGETS(elm_msg_cat, AliasesSet, 
					  AliasesHelpCtrlD,
					  "^D = Mark for deletion user aliases matching specified pattern."));
	break;
	
	case 'e': lib_transient(CATGETS(elm_msg_cat, AliasesSet, AliasesHelpe,
				    "e = Edit the alias text file directly (will run newalias)."));
	break;
	
	case 'f': lib_transient(CATGETS(elm_msg_cat, AliasesSet, AliasesHelpf,
				    "f = Display fully expanded address of current alias."));
	break;
	
	case 'l': lib_transient(CATGETS(elm_msg_cat, AliasesSet, AliasesHelpl,
				    "l = Limit displayed aliases on the specified criteria."));
	break;
	
	case ctrl('L'): lib_transient(CATGETS(elm_msg_cat, AliasesSet, 
					      AliasesHelpCtrlL,
					      "^L = Rewrite the screen."));
	break;
	
	case 'm': lib_transient(CATGETS(elm_msg_cat, AliasesSet, AliasesHelpm,
					"m = Send mail to the current or tagged aliases."));
	break;
	
	case 'n': lib_transient(CATGETS(elm_msg_cat, AliasesSet, AliasesHelpn,
					"n = Add a new user alias, adding to alias database at next resync."));
	break;
	
	case 'r':
	case 'q':
	case 'i': lib_transient(CATGETS(elm_msg_cat, AliasesSet, AliasesHelpi,
					"r,q,i = Return from alias menu (with prompting)."));
	break;
	
	case 'R':
	case 'Q':
	case 'I': lib_transient(CATGETS(elm_msg_cat, AliasesSet, AliasesHelpQ,
					"R,Q,I = Return from alias menu (no prompting)."));
	break;
	
	case 't': lib_transient(CATGETS(elm_msg_cat, AliasesSet, AliasesHelpt,
					"t = Tag current alias for further operations."));
	break;
	
	case 'T': lib_transient(CATGETS(elm_msg_cat, AliasesSet, AliasesHelpT,
					"T = Tag current alias and go to next alias."));
	break;
	
	case ctrl('T'): lib_transient(CATGETS(elm_msg_cat, AliasesSet, 
					      AliasesHelpCtrlT,
					      "^T = Tag aliases matching specified pattern."));
	break;
	
	case 'u': lib_transient(CATGETS(elm_msg_cat, AliasesSet, AliasesHelpu,
					"u = Unmark the current alias for deletion from alias database."));
	break;
	
	case ctrl('U'): lib_transient(CATGETS(elm_msg_cat, AliasesSet, 
					      AliasesHelpCtrlU,
					      "^U = Mark for undeletion user aliases matching specified pattern."));
	break;
	
	case 'x':
	case 'X': lib_transient(CATGETS(elm_msg_cat, AliasesSet, AliasesHelpX,
				    "x = Exit from alias menu, abandoning any pending deletions."));
	break;
	
	default : lib_error(CATGETS(elm_msg_cat, AliasesSet, 
				    AliasesHelpNoHelp,
				    "That key isn't used in this section."));
	break;
	}

    } while (ch != '.');

    if (delay_redraw) 
	menu_trigger_redraw(page);
    
    menu_trigger_redraw(prompt_area);
    return;
}


static int parse_aliases(buffer, remainder, size_buffer, size_remainder)
     char *buffer, *remainder;
     int size_buffer, size_remainder;
{
/*
 *	This routine will parse out the individual aliases present
 *	on the line passed in buffer.  This involves:
 *
 *	1. Testing for an '=' to make sure this is an alias entry.
 *
 *	2. Setting remainder to point to the rest of the line starting
 *	   at the '=' (for later rewriting if needed).
 *
 *	3. Parsing the aliases into an string padded with ',' at 
 *	   the end.
 *
 *	4. Returning the number of aliases found (0 if test #1 fails).
 */

	char *s;
	int number;

/*	Check to see if an alias */

	if ((s = index(buffer, '=')) == NULL)
	  return (0);

	/* Save the remainder of the line */
	strfcpy(remainder, s, size_remainder);		

/*	Terminate the list of aliases with a ',' */

	while (--s >= buffer && whitespace(*s)) ;
	if (s < buffer + size_buffer -2) {
	  *++s = ',';
	  *++s = '\0';
	}

/*	Lowercase everything */

	s = shift_lower(buffer);
	strfcpy(buffer, s, size_buffer);

/*	Now, count the aliases */

	number = 0;
	for (s = buffer; *s; s++)
	  if (*s == ',')
	    number++;

	return (number);
}

static int get_aliasname(aliasname, buffer, duplicate, size, buffer_size,
			 aview, page, prompt_area)
     char *aliasname, *buffer;
     int *duplicate;
     int size, buffer_size;
     struct AliasView *aview;
     struct menu_context *page;
     struct menu_context *prompt_area;
{

/*
 *	Have the user enter an aliasname, check to see if it
 *	is legal, then check for duplicates.  If a duplicate
 *	is found offer to replace existing alias.
 *
 *	Return values:
 *
 *	-1	Either the aliasname was zero length, had bad
 *		characters and was a duplicate which the user
 *		chose not to replace.
 *
 *	0	A new alias was entered successfully.
 *
 *	1	The entered alias was an existing USER alias
 *		that the user has chosen to replace.  In this
 *		case the alias to replace is passed back in
 *		in the variable 'duplicate'.
 *
 *   REDRAW_MARK
 */

    int loc;


    do {
	/* FIXME --optionally_enter*  should use prompt_page */
	int line = menu_GetAbsLine(prompt_area,1);
	int status =
	    optionally_enter(aliasname, line, strlen(buffer), 
			     OE_REDRAW_MARK|OE_SIG_CHAR, size, page);

	  if (REDRAW_MARK == status)
	      return REDRAW_MARK;

	/*
	 *  Return if nothing was entered.
	 */
	  if (0 != status || strlen(aliasname) == 0) 
	      return(-1);

	} while (check_alias(aliasname) == -1);

	clear_error();			/* Just in case */
/*
 *	Check to see if there is already a USER alias by this name.
 */
	if ((loc = find_alias(aliasname, USER, aview)) >= 0) {

	    struct alias_rec *a  = give_alias(aview,loc);
	    
	    if (a) {
		int answer;
		int redraw = 0;

		DPRINT(Debug,2,
		       (&Debug, 
			"Attempt to add a duplicate alias [%s] in get_aliasname\n",
			a->alias)); 

	    againD:

		if (a->type & GROUP )
		    menu_PutLineX(prompt_area,1,0, 
				  CATGETS(elm_msg_cat,
					  AliasesSet, AliasesAlreadyGroup,
					  "Already a group with name %s."), 
				  a->alias);
		else
		    menu_PutLineX(prompt_area,1,0, 
				  CATGETS(elm_msg_cat,
					  AliasesSet, AliasesAlreadyAlias,
					  "Already an alias for %s."), 
				  a->alias);
		menu_CleartoEOLN(prompt_area);

			     
		/*
		 * If they don't want to replace the alias by that name
		 * then just return.
		 */

		answer = prompt_letter(1,"",*def_ans_no,
				       PROMPT_yesno|PROMPT_redraw_mark|
				       PROMPT_ctrlL|PROMPT_cancel,
				       prompt_area,
				       CATGETS(elm_msg_cat,
					       AliasesSet, AliasesReplaceExisting,
					       "Replace existing alias? (%c/%c) "),
				       *def_ans_yes, *def_ans_no);
		
		if (('L'&31)    == answer ||
		    REDRAW_MARK == answer) {
		    menu_ClearScreen(page);   /* Reset possible redraw flag */
		   
		    /* Call refresh routines of children */
		    menu_redraw_children(page);

		    if (menu_need_redraw(prompt_area))
			menu_ClearScreen(prompt_area);

		    redraw++;   /* Can't trigger redraw yet... */
		    goto againD;
		}
		if (redraw)
		    menu_trigger_redraw(page);

		if (TERMCH_interrupt_char == answer)
		    return -1;
		
		if (answer != *def_ans_yes)
		    return(-1);
		
		*duplicate = loc;
		return(1);
	    }
	}

/*
 *	If they have elected to replace an existing alias then
 *	we assume that they would also elect to superceed a
 *	system alias by that name (since they have already
 *	done so).  So we don't even bother to check or ask.
 *
 *	Of course we do check if there was no USER alias match.
 */
	if ((loc = find_alias(aliasname, SYSTEM, aview)) >= 0) {


	    struct alias_rec *a  = give_alias(aview,loc);
	    
	    if (a) {

		DPRINT(Debug,2,
		       (&Debug,
			"Attempt to add a duplicate system alias [%s] in get_aliasname\n",
			a->address)); 
	    
		if( ! superceed_system(loc, buffer, buffer_size,
				       aview, page,prompt_area))
		    return(-1);
	    }
	}
	return(0);

}

static int superceed_system(this_alias, buffer, buffer_size, aview,page,prompt_area)
     int this_alias;
     char *buffer;
     int buffer_size;
     struct AliasView *aview;
     struct menu_context *page;
     struct menu_context *prompt_area;
{
    struct alias_rec *a =  give_alias(aview,this_alias);

    if (!a)
	return 0;
    
    menu_PutLineX(prompt_area,1, 0, 
		  CATGETS(elm_msg_cat,
			  AliasesSet, AliasesSystemAlias, 
			  "System (%6s) alias for %s."),
		  alias_type(a->type), a->alias);

    elm_sfprintf(buffer, buffer_size,
		 CATGETS(elm_msg_cat, AliasesSet, AliasesSuperceed,
			 "Superceed? (%c/%c) "), *def_ans_yes, *def_ans_no);
/*
 *	If they don't want to superceed the SYSTEM alias then
 *	return a FALSE.
 */
    return(want_to(buffer, *def_ans_no, 0, 0,
		   prompt_area) == *def_ans_yes);

}

static int get_realnames(aliasname, firstname, lastname, comment, buffer,
			  size_first, size_last, size_comment, size_buffer,
			  is_group, page, prompt_area)
     char *aliasname, *firstname, *lastname, *comment, *buffer;
     int size_first, size_last, size_comment, size_buffer;
     int is_group;
     struct menu_context *page;
     struct menu_context  *prompt_area;
{
    int status;
    int delay_redraw = 0;
	
    if (is_group) {
	lastname[0] = '\0';
	firstname[0] = '\0';
    } else {
	int line;

	elm_sfprintf(buffer, size_buffer,
		   CATGETS(elm_msg_cat, AliasesSet, AliasesEnterLastName,
			   "Enter last name for %s: "), aliasname);
	menu_PutLine0(prompt_area,1,0, buffer);
	menu_CleartoEOLN(prompt_area);

	/* FIXME --optionally_enter*  should use prompt_page */
	line = menu_GetAbsLine(prompt_area,1);

	status = optionally_enter(lastname, line, strlen(buffer),
				  OE_REDRAW_MARK|
				  OE_SIG_CHAR /* Ctrl-C */, size_last, page);
	while (REDRAW_MARK == status) {
	    menu_ClearScreen(page);   /* Reset possible redraw flag */
	    delay_redraw++;   /* Can't trigger redraw yet... */

	    /* Call refresh routines of children */
	    menu_redraw_children(page);
	    
	    if (menu_need_redraw(prompt_area))
		menu_ClearScreen(prompt_area);

	    /* FIXME --optionally_enter*  should use prompt_page */
	    line = menu_GetAbsLine(prompt_area,1);
	    menu_PutLine0(prompt_area,1,0, buffer);
	    status = optionally_enter(lastname, line, strlen(buffer),
				      OE_REDRAW_MARK|OE_APPEND_CURRENT|
				      OE_SIG_CHAR /* Ctrl-C */,
				      size_last, page);
	}

      
      if (status != 0) { /* Error or Ctrl-C */
	  if (delay_redraw) 
	      menu_trigger_redraw(page);
	  return 0;
      }

      {
	  int line;
	  
	  elm_sfprintf(buffer, size_buffer,
		       CATGETS(elm_msg_cat, AliasesSet, AliasesEnterFirstName,
			       "Enter first name for %s: "), aliasname);
	  menu_PutLine0(prompt_area,1,0, buffer);
	  menu_CleartoEOLN(prompt_area);

	  /* FIXME --optionally_enter*  should use prompt_page */
	  line = menu_GetAbsLine(prompt_area,1);

	  status = optionally_enter(firstname, line, strlen(buffer), 
				    OE_REDRAW_MARK|
				    OE_SIG_CHAR /* Ctrl-C */, size_first, page);
	  while (REDRAW_MARK == status) {
	      menu_ClearScreen(page);   /* Reset possible redraw flag */
	      delay_redraw++;   /* Can't trigger redraw yet... */

	      /* Call refresh routines of children */
	      menu_redraw_children(page);
	    
	      if (menu_need_redraw(prompt_area))
		  menu_ClearScreen(prompt_area);

	      /* FIXME --optionally_enter*  should use prompt_page */
	      line = menu_GetAbsLine(prompt_area,1);
	      menu_PutLine0(prompt_area,1,0, buffer);
	      status = optionally_enter(firstname, line, strlen(buffer), 
					OE_REDRAW_MARK|OE_APPEND_CURRENT|
					OE_SIG_CHAR /* Ctrl-C */,
					size_first, page);
	  }
      }
      
      if (0 != status) { /* Ctrl-C or error */
	  if (delay_redraw)
	      menu_trigger_redraw(page);
	  return 0;
      }

      if (strlen(lastname) == 0) {
	  strfcpy(lastname, firstname, size_last);  
	  *firstname = '\0';
      }
    }       

    {
	int line;
	
	elm_sfprintf(buffer, size_buffer,
		 CATGETS(elm_msg_cat, AliasesSet, AliasesEnterComment,
			 "Enter optional comment for %s: "), aliasname);
	menu_PutLine0(prompt_area,1,0, buffer);

	/* FIXME --optionally_enter*  should use prompt_page */
	line = menu_GetAbsLine(prompt_area,1);

	status = optionally_enter(comment, line, strlen(buffer), 
				  OE_REDRAW_MARK|
				  OE_SIG_CHAR /* Ctrl-C */, size_comment, page);
	while (status == REDRAW_MARK) {
	    menu_ClearScreen(page);   /* Reset possible redraw flag */
	    delay_redraw++;   /* Can't trigger redraw yet... */

	    
	    /* Call refresh routines of children */
	    menu_redraw_children(page);
	    
	    if (menu_need_redraw(prompt_area))
		menu_ClearScreen(prompt_area);

	    menu_PutLine0(prompt_area,1,0, buffer);
	    status = optionally_enter(comment, line, strlen(buffer), 
				      OE_REDRAW_MARK|OE_APPEND_CURRENT|
				      OE_SIG_CHAR /* Ctrl-C */,
				      size_comment, page);
	}  
    }

    if (delay_redraw)
	menu_trigger_redraw(page);
    
    if (0 != status)  /* Ctrl-C or error */
	return 0;
    
    return 1;
}

static int ask_accept(aliasname, firstname, lastname, comment, address, buffer,
		      replace, replacement, size_buffer, aview, 
		      page,LOC)
     char *aliasname, *firstname, *lastname, *comment, *address, *buffer;
     int replace, replacement;
     int size_buffer;
     struct AliasView *aview;
     struct menu_context  *page;
     struct screen_parts *LOC;
{
    int delay_redraw = 0;
    int answer = 0;

    char *(old_alias[1]);


 again:
/*
 *	If firstname == lastname, they probably just took all
 *	the deafaults.  We *assume* they don't want lastname
 *	entered twice, so we will truncate it.
 */

    if (strcmp(firstname, lastname) == 0) {
	*firstname = '\0';
    }

    if (strlen(lastname) == 0) {
	menu_PutLineX(LOC->prompt_page,
		      2,0, CATGETS(elm_msg_cat, AliasesSet, 
				   AliasesAddressAs1,
				   "Messages addressed as: %s"), 
		      address);
	strfcpy(buffer, aliasname, size_buffer);  
    } else {
	if (strlen(firstname) == 0) {
	    strfcpy(buffer, lastname, size_buffer);  
	}
	else {
	    elm_sfprintf(buffer, size_buffer,
			 FRM("%s %s"), firstname, lastname);
	}
	menu_PutLineX(LOC->prompt_page,
		      2,0, 
		      CATGETS(elm_msg_cat, AliasesSet, 
			      AliasesAddressAs,
			      "Messages addressed as: %s <%s>"), 
		      buffer,address);
    }
    if (strlen(comment) != 0) {
	strfcat(buffer, ", ", size_buffer);
	strfcat(buffer, comment, size_buffer);
    }
    
    menu_PutLineX(LOC->prompt_page,1,0, 
		  CATGETS(elm_msg_cat, AliasesSet, 
			  AliasesAddressTo,
			  "New alias: %s is '%s'."), 
		  aliasname, buffer);
    menu_CleartoEOLN(LOC->prompt_page);
/*
 *	Kludge Alert:  Spaces are padded to the front of the prompt
 *	to write over the previous question.  Should probably record
 *	the end of the line, move to it, and CleartoEOLN() it.
 */

    answer = prompt_letter(1,"",*def_ans_no,
			   PROMPT_yesno|PROMPT_redraw_mark|
			   PROMPT_ctrlL|PROMPT_cancel,
			   LOC->prompt_page,
			   CATGETS(elm_msg_cat, AliasesSet, AliasesAcceptNew,
				   "      Accept new alias? (%c/%c) "), 
			   *def_ans_yes, *def_ans_no);
    if (('L'&31)    == answer ||
	REDRAW_MARK == answer) {
	menu_ClearScreen(page);   /* Reset possible redraw flag */
	
	/* Call refresh routines of children */
	menu_redraw_children(page);

	if (menu_need_redraw(LOC->prompt_page))
	    menu_ClearScreen(LOC->prompt_page);
	
	delay_redraw++;   /* Can't trigger redraw yet... */
	goto again;
    }
    if (delay_redraw)
	menu_trigger_redraw(page);
    
    if (TERMCH_interrupt_char == answer)
	goto clean;
    

    if(answer == *def_ans_yes) {
	if (replace) {
	    struct alias_rec *a = give_alias(aview,replacement);
	    
	    if (a) {
		old_alias[0] = a->alias;
		
		    /*
		     *  First, clear flag if this is marked to be deleted.
		     *  This prevents the problem where they marked it for
		     *  deletion and then figured out that it could be
		     *  c)hanged but didn't explicitly U)ndelete it.  Without
		     *  this test, the resync action would then delete
		     *  the new alias we just so carefully added to the
		     *  text file.
		     */
		if (ison(a->status, DELETED)) {
		    clearit(a->status, DELETED);
		}
		    /*
		     *  Changed aliases are given the NEW flag.
		     */
		setit(a->status, NEW);

		{
			struct menu_common MENU;
			int vis;

			set_mcommon_from_aliasview(&MENU,aview);
			
			vis = compute_visible(replacement+1, &MENU);
			menu_header_status_update(LOC->header_page,vis-1);

		}
		    /*
		     *  Now we can delete it...
		     */
		delete_from_alias_text(old_alias, 1);
	    }
	}
	add_to_alias_text(aliasname, firstname, lastname, comment, address);
    }

 clean:
    menu_ClearLine(LOC->prompt_page,1);
    menu_ClearLine(LOC->prompt_page,2);

    return(answer == *def_ans_yes ? 1 : 0);

}

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


syntax highlighted by Code2HTML, v. 0.9.1