
static char rcsid[] = "@(#)$Id: alias.c,v 1.6 1996/08/08 19:49:22 wfp5p Exp $";

/*******************************************************************************
 *  The Elm Mail System  -  $Revision: 1.6 $   $State: Exp $
 *
 *                      Copyright (c) 1988-1995 USENET Community Trust
 * 			Copyright (c) 1986,1987 Dave Taylor
 *******************************************************************************
 * Bug reports, patches, comments, suggestions should be sent to:
 *
 *      Bill Pemberton, Elm Coordinator
 *      flash@virginia.edu
 *
 *******************************************************************************
 * $Log: alias.c,v $
 * Revision 1.6  1996/08/08  19:49:22  wfp5p
 * Alpha 11
 *
 * Revision 1.5  1996/05/09  15:51:14  wfp5p
 * Alpha 10
 *
 * Revision 1.4  1996/03/14  17:27:50  wfp5p
 * Alpha 9
 *
 * Revision 1.3  1995/09/29  17:41:57  wfp5p
 * Alpha 8 (Chip's big changes)
 *
 * Revision 1.2  1995/05/24  15:34:37  wfp5p
 * Change to deal with parenthesized comments in when eliminating members from
 * an alias. (from Keith Neufeld <neufeld@pvi.org>)
 *
 * Allow a shell escape from the alias screen (just like from
 * the index screen).  It does not put the shell escape onto the alias
 * screen menu. (from Keith Neufeld <neufeld@pvi.org>)
 *
 * Allow the use of "T" from the builtin pager. (from Keith Neufeld
 * <neufeld@pvi.org>)
 *
 * Revision 1.1.1.1  1995/04/19  20:38:34  wfp5p
 * Initial import of elm 2.4 PL0 as base for elm 2.5.
 *
 ******************************************************************************/

/** This file contains alias stuff

**/

#include "elm_defs.h"
#include "elm_globals.h"
#include "port_stat.h"
#include "s_elm.h"
#include "s_aliases.h"
#include "ndbz.h"

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

/*
 * 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)	delete_aliases(newaliases,TRUE)

extern char *alias_type();
void get_realnames();
void install_aliases();

int  is_system=0;		/* system file updating?     */

int num_duplicates;
DBZ *system_hash = NULL, *user_hash = NULL;


open_alias_files(are_in_aliases)
int are_in_aliases;
{
	if(open_system_aliases() | open_user_aliases()) {
	    dprint(5, (debugfile,
		      "Reading alias data files...\n"));
	    get_aliases(are_in_aliases);
	}
}

int
open_system_aliases()
{
/*
 *	Open the system alias file, if present,
 *	and if it has changed since last we read it.
 *
 *	Return 0 if hash file wasn't opened, otherwise 1
 */

	struct stat hst;
	static time_t system_ctime = 0, system_mtime = 0;

	/* If file hasn't changed, don't bother re-opening. */

	if (stat(system_data_file, &hst) == 0) {	/* File exists */
	    if (hst.st_ctime == system_ctime &&
	        hst.st_mtime == system_mtime) {		/* No changes */
	        return(0);
	    }

	   /*
	    * Re-open system hash table.  If we can't, just return.
	    */

	    if (system_hash != NULL)
	        dbz_close(system_hash);

	    if ((system_hash = dbz_open(system_data_file, O_RDONLY, 0)) == NULL)
	        return(0);

	    /* Remember hash file times. */

	    system_ctime = hst.st_ctime;
	    system_mtime = hst.st_mtime;

            return(1);
	}
	else {					/* File does not exist */
	    if (system_ctime == 0 && system_mtime == 0) {
	        return(0);			/* File never existed */
	    }
	    else {			/* Once existed, better re-read */

	       /*
	        * Since we no longer exist, we pretend we never existed.
	        */

	        system_ctime = 0;
	        system_mtime = 0;

	        return(1);
	    }
	}

}

int
open_user_aliases()
{
/*
 *	Open the user alias file, if present,
 *	and if it has changed since last we read it.
 *
 *	Return 0 if hash file wasn't opened, otherwise 1
 */

	struct stat hst;
	char fname[SLEN];
	static time_t user_ctime = 0, user_mtime = 0;

	/* If hash file hasn't changed, don't bother re-reading. */

	sprintf(fname, "%s/%s", user_home, ALIAS_DATA);

	if (stat(fname, &hst) == 0) {			/* File exists */
	    if (hst.st_ctime == user_ctime &&
	        hst.st_mtime == user_mtime) {		/* No changes */
	        return(0);
	    }

	   /*
	    * Open user hash table.  If we can't, just return.
	    */

	    if (user_hash != NULL)
	        dbz_close(user_hash);

	    if ((user_hash = dbz_open(fname, O_RDONLY, 0)) == NULL)
	        return(0);

	    /* Remember hash file times. */

	    user_ctime = hst.st_ctime;
	    user_mtime = hst.st_mtime;

            return(1);
	}
	else {					/* File does not exist */
	    if (user_ctime == 0 && user_mtime == 0) {
	        return(0);			/* File never existed */
	    }
	    else {			/* Once existed, better re-read */

	       /*
	        * Since we no longer exist, we pretend we never existed.
	        */

	        user_ctime = 0;
	        user_mtime = 0;

	        return(1);
	    }
	}

}

int
add_alias(replace, to_replace)
int replace, to_replace;
{
/*
 *	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, ans, tagged = 0;

	char aliasname[SLEN], firstname[SLEN], lastname[SLEN];
	char address1[LONG_STRING], buffer[SLEN];
	char comment[LONG_STRING];
	char *ch_ptr;

/*
 *	See if there are any tagged aliases.
 */
	for (i=0; i < num_aliases; i++) {
	    if (ison(aliases[i]->status, TAGGED)) {
		if (tagged == 0) leftoff = i;
	        tagged++;
	    }
	}

	if (tagged == 1) {
	 /*
	  * There is only on alias tagged.  Ask the question
	  * but the default response is NO.
	  */
	    PutLine0(LINES-2,0, catgets(elm_msg_cat,
	            AliasesSet, AliasesOneTagged,
	            "There is 1 alias tagged..."));
	    CleartoEOLN();
	    ans = enter_yn(catgets(elm_msg_cat, AliasesSet, AliasesCreateGroup,
			"Create group alias?"), FALSE, LINES-3, FALSE);
	}
	else if (tagged > 1) {
	 /*
	  * If multiple tagged aliases then we assume the user
	  * wants to create a group alias.  The default response
	  * is YES.
	  */
	    PutLine1(LINES-2,0, catgets(elm_msg_cat,
	            AliasesSet, AliasesManyTagged,
	            "There are %d aliases tagged..."), tagged);
	    CleartoEOLN();
	    ans = enter_yn(catgets(elm_msg_cat, AliasesSet, AliasesCreateGroup,
			"Create group alias?"), TRUE, LINES-3, FALSE);
	} else {
	    /*
	     * Nothing tagged ... thus nothing to make a group of.
	     */
	    ans = FALSE;
	}

/*
 *	If requested above, create the group alias address.
 */
	if (ans) {
	    strcpy(address1, aliases[leftoff]->alias);
	    for (i=leftoff+1; i < num_aliases; i++) {
	        if (ison(aliases[i]->status, TAGGED)) {
	            strcat(address1, ",");
	            strcat(address1, aliases[i]->alias);
	        }
	    }
	}
	else {
	    tagged = 0;
	}

/*
 *	Only ask for an aliasname if we are NOT replacing the
 *	current alias.
 */
	if (replace) {
	    strcpy(aliasname, aliases[to_replace]->alias);
	/*
	 *  First, see if what we are replacing is a SYSTEM
	 *  alias.  If so, we need to ask a question.
	 */
	    if(aliases[to_replace]->type & SYSTEM) {
	        dprint(3, (debugfile, 
	            "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)) {
	            ClearLine(LINES-2);
	            return(0);
	        }
	    }
	}
	else {
	    strcpy(buffer, catgets(elm_msg_cat,
	            AliasesSet, AliasesEnterAliasName, "Enter alias name: "));
	    PutLine0(LINES-2,0, buffer);
	    CleartoEOLN();
	    *aliasname = '\0';
	    if ((replace = get_aliasname(aliasname, buffer, &to_replace)) < 0) {
	        dprint(3, (debugfile, 
	            "Aliasname [%s] was rejected in add_alias\n", aliasname));
	        ClearLine(LINES-2);
	        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) {
	    strcpy(lastname, aliases[to_replace]->last_name);
	    strcpy(firstname, aliases[to_replace]->name);
	    ch_ptr = strstr(firstname, lastname);
	    *(ch_ptr-1) = '\0';
	    strcpy(comment, aliases[to_replace]->comment);
	}
	else {
	    *lastname = '\0';
	    *firstname = '\0';
	    *comment = '\0';
	}
	get_realnames(aliasname, firstname, lastname, comment, buffer);

/*
 *	Since there are no tagged aliases, we must ask for an
 *	address.  If we are replacing, a default address is
 *	presented.
 */
	if (tagged == 0) {
	    sprintf(buffer, catgets(elm_msg_cat,
	            AliasesSet, AliasesEnterAddress,
	            "Enter address for %s: "), aliasname);
	    PutLine0(LINES-2, 0, buffer);
	    if (replace)
	        strcpy(address1, aliases[to_replace]->address);
	    else
	        *address1 = '\0';

	    if (enter_string(address1, sizeof(address1), -1, -1,
			ESTR_REPLACE) < 0 || address1[0] == '\0') {
		Raw(ON);
	        error(catgets(elm_msg_cat, AliasesSet, AliasesNoAddressSpec,
	                "No address specified!"));
	        return(0);
	    }
	    Raw(ON);

	    despace_address(address1);

	    clear_error();			/* Just in case */
	}

	if(ask_accept(aliasname, firstname, lastname, comment, address1,
	        buffer, replace, to_replace)) {
	 /*
	  * 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) {
	        for (i=leftoff; i < num_aliases; i++) {
	            if (ison(aliases[i]->status, TAGGED)) {
	                clearit(aliases[i]->status, TAGGED);
	                show_msg_tag(i);
	            }
	        }
	    }
	    return(1);
	}
	else {
	    return(0);
	}

}

int
add_current_alias()
{
/*
 *	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;

	if (curr_folder.curr_mssg == 0) {
	 dprint(4, (debugfile, 
		"Add current alias called without any current message!\n"));
	 error(catgets(elm_msg_cat, AliasesSet, AliasesNoMessage,
		"No message to alias to!"));
	 return(0);
	}
	current_header = curr_folder.headers[curr_folder.curr_mssg-1];
	
	strcpy(buffer, catgets(elm_msg_cat, AliasesSet, AliasesCurrentMessage,
		"Current message address aliased to: "));
	PutLine0(LINES-2,0, buffer);
	CleartoEOLN();
	*aliasname = '\0';
	if ((replace = get_aliasname(aliasname, buffer, &to_replace)) < 0) {
	    dprint(3, (debugfile, 
	        "Aliasname [%s] was rejected in add_current_alias\n",
	        aliasname));
	    ClearLine(LINES-2);
	    return(0);
	}

	/* use full name in current message for default comment */
	tail_of(current_header->from, comment_buff, current_header->to);
	if(index(comment_buff, (int)'!') || index(comment_buff, (int)'@'))
	  /* never mind - it's an address not a full name */
	  *comment_buff = '\0';

/*
 *	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 == ' ') bufptr++;	/* Always strip leading WS */
	    if ((chspace = index(bufptr, ' ')) != NULL) {
	   /*
	    *   A space means that there is at least (firstname lastname)
	    *   Get firstname and move bufptr.
	    */
	        *chspace = '\0';
	        strcpy(firstname, bufptr);
	        bufptr = chspace + 1;			/* Move the pointer */
	        while (*bufptr == ' ') bufptr++;
	    }

above:	    if ((chspace = index(bufptr, ' ')) != 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.
	        */
	            strcat(firstname, " ");
	            strcat(firstname, bufptr);
	            bufptr = chspace + 1;		/* Move the pointer */
	            while (*bufptr == ' ') bufptr++;
	            goto above;
	        }
	        strcpy(lastname, bufptr);
	        bufptr = chspace + 1;			/* Move the pointer */
	        while (*bufptr == ' ') bufptr++;
	        strcpy(comment, bufptr);
	    }
	    else {
	   /*
	    *   Only a lastname left.
	    */
	        strcpy(lastname, bufptr);
	    }

	/*
	 *  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;
	            }
	        }
	    }
	}

	get_realnames(aliasname, firstname, lastname, comment, buffer);

	/* grab the return address of this message */
	get_return(address1, curr_folder.curr_mssg-1);
	strcpy(address1, strip_parens(address1));	/* remove parens! */

	return(ask_accept(aliasname, firstname, lastname, comment, address1,
	        buffer, replace, to_replace));

}

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;
	
	sprintf(fname,"%s/%s", user_home, ALIAS_TEXT);
	
	save_file_stats(fname);
	if ((file = fopen(fname, "a")) == NULL) {
	  err = errno;
	  dprint(2, (debugfile, 
		 "Failure attempting to add alias to file %s within %s",
		   fname, "add_to_alias_text"));
	  dprint(2, (debugfile, "** %s **\n", strerror(err)));
	  error1(catgets(elm_msg_cat, AliasesSet, AliasesCouldntOpenAdd,
		 "Couldn't open %s to add new alias!"), fname);
	  return(1);
	}

	if (strlen(firstname) == 0) {
	    strcpy(buffer, lastname);  
	}
	else {
	    sprintf(buffer, "%s; %s", lastname, firstname);
	}
	if (strlen(comment) != 0) {
	    strcat(buffer, ", ");
	    strcat(buffer, comment);
	}
	if (fprintf(file,"%s = %s = %s\n", aliasname, buffer, address) == EOF) {
	    err = errno;
	    dprint(2, (debugfile,
		       "Failure attempting to write alias to file within %s",
		       fname, "add_to_alias_text"));
	    dprint(2, (debugfile, "** %s **\n", strerror(err)));
	    error1(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);
}

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;

	for (i=0; i < num_to_delete; i++)
	  strcat(name[i], ","); 

	sprintf(fname,"%s/%s", user_home, ALIAS_TEXT);
	sprintf(tmpfname,"%s/%s.t", user_home, ALIAS_TEXT);
	
	save_file_stats(fname);

	if ((file = fopen(fname, "r")) == NULL) {
	  err = errno;
	  dprint(2, (debugfile, 
		 "Failure attempting to delete alias from file %s within %s",
		   fname, "delete_from_alias_text"));
	  dprint(2, (debugfile, "** %s **\n", strerror(err)));
	  error1(catgets(elm_msg_cat, AliasesSet, AliasesCouldntOpenDelete,
		 "Couldn't open %s to delete alias!"), fname);
	  return(1);
	}

	if ((tmp_file = fopen(tmpfname, "w")) == NULL) {
	  err = errno;
	  dprint(2, (debugfile, 
		 "Failure attempting to open temp file %s within %s",
		   tmpfname, "delete_from_alias_text"));
	  dprint(2, (debugfile, "** %s **\n", strerror(err)));
	  error1(catgets(elm_msg_cat, AliasesSet, AliasesCouldntOpenTemp,
	  	 "Couldn't open temp file %s to delete alias!"), tmpfname);
	  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 (num_aliases = parse_aliases(line_in_file, rest_of_line)) {
	        for (i=0; i < num_to_delete && num_aliases; i++) {
	          if ( ((s = strstr(line_in_file, name[i])) == line_in_file) ||
		       ((s != NULL) && (*(s-1) == ',')) ) {
/*
 *	Collapse the to be deleted alias out of line_in_file
 */
	            rest = index(s, (int)',');
	            for (++rest; *rest; rest++)
	              *s++ = *rest;
	            *s = '\0';
	            num_aliases--;
	          }
	        }
	        if (num_aliases) {
	          *(line_in_file + strlen(line_in_file) - 1) = ' ';
	          strcat(line_in_file, rest_of_line);
	        }
	        else {
	          delete_continues = TRUE;
	        }
	      }
	    }
	  }
	  if (! delete_continues) {
	    if (fprintf(tmp_file,"%s", line_in_file) == EOF) {
	      err = errno;
	      dprint(2, (debugfile,
		"Failure attempting to write to temp file %s within %s",
		tmpfname, "delete_from_alias_text"));
	      dprint(2, (debugfile, "** %s **\n", strerror(err)));
	      error1(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)
	{
		error1(catgets(elm_msg_cat, AliasesSet, AliasesCouldntRenameTemp,
			"Couldn't rename temp file %s after deleting alias!"), tmpfname);
		return(1);
	}

	restore_file_stats(fname);

	return(0);
}

alias()
{
/*
 *	Work with alias commands...
 */

	char name[NLEN], *address, buffer[SLEN];
	char *commap;
	int  key_offset;        /** Position offset within keyboard string   **/
	static int  newaliases = 0;
	int  ch, i, j;
	int nutitle = 0;
	int too_long;

/*
 *	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
 */

	main_state();		/* Save globals for return to main menu */

	open_alias_files(FALSE);	/* First, read the alias files. RLH */

	alias_screen(newaliases);

	while (1) {

	  redraw = 0;
	  nucurr = 0;
	  nufoot = 0;

	  prompt(nls_Prompt);
	  CleartoEOLN();
	  ch = GetKey(0);

	  MoveCursor(LINES-3,strlen(nls_Prompt)); CleartoEOS();
	  
	  dprint(3, (debugfile, "\n-- Alias command: %c\n\n", ch));

	  switch (ch) {
	    case '?': redraw += alias_help();			break;

#ifdef ALLOW_SUBSHELL
	    case '!' : WriteChar('!');
	      main_state(); /** reload index screen vars **/
	      redraw += subshell();
	      main_state(); /** reload alias screen vars **/
	      break;
#endif /* ALLOW_SUBSHELL */

	    case '$': PutLine0(-1, -1, catgets(elm_msg_cat,
					AliasesSet, AliasesResync,
					"Resynchronize aliases..."));
	           /*
	            * Process deletions and then see if we need to
	            * re-run the "newalias" routine.
	            */
		      if (resync_aliases(newaliases)) {
		        install_aliases();
	                newaliases = 0;
		        redraw++;
		      }
		      break;

	    case 'a': PutLine0(-1, -1, catgets(elm_msg_cat,
					AliasesSet, AliasesAddCurrent,
					"Add address from current message..."));
		      clear_error();
		      if (add_current_alias()) {
		          newaliases++;
		          nutitle++;
		      }
		      break;

	    case 'c':
	              if (curr_alias > 0) {
			  PutLine0(-1, -1, catgets(elm_msg_cat,
	                              AliasesSet, AliasesReplaceCurrent,
	                              "Replace current alias in database..."));
		          clear_error();
		          if (add_alias(TRUE, curr_alias-1)) {
		              newaliases++;
		              nutitle++;
		          }
	              }
	              else {
		          error(catgets(elm_msg_cat,
	                          AliasesSet, AliasesNoneToReplace,
				  "Warning: no aliases to replace!"));
	              }
		      break;

	    case 'e': PutLine1(LINES-3, strlen(nls_Prompt),
	                  catgets(elm_msg_cat, AliasesSet, AliasesEdit,
	                      "Edit %s..."), ALIAS_TEXT);
	           /*
	            * Process aliases.text for deletions, etc.  You
	            * have to do this *before* checking current because
	            * all aliases could be marked for deletion.
	            */
	              (void) resync_aliases(newaliases);
	              if (edit_aliases_text()) {
	                  newaliases = 0;
	              }
		      redraw++;
		      break;

	    case 'm':
	              if (curr_alias > 0) {
			  PutLine0(-1, -1, catgets(elm_msg_cat,
					  AliasesSet, AliasesMail, "Mail..."));
	                  redraw += a_sendmsg();
	              }
	              else {
		          error(catgets(elm_msg_cat,
	                          AliasesSet, AliasesNoneToMail,
				  "Warning: no aliases to send mail to!"));
	              }
		      break;

	    case 'n': PutLine0(-1, -1, catgets(elm_msg_cat,
					AliasesSet, AliasesAddNew,
					"Add a new alias to database..."));
		      clear_error();
		      if (add_alias(FALSE, -1)) {
		          newaliases++;
		          nutitle++;
		      }
		      break;

	    case 'q':
	    case 'Q':
	    case 'i':
	    case 'I':
	    case 'r':
	    case 'R': PutLine0(-1, -1, catgets(elm_msg_cat,
	    				AliasesSet, AliasesAddReturn,
					"Return to main menu..."));
	           /*
	            * leaving the alias system.  Must check for
	            * pending deletes, etc.  prompt is set to FALSE
	            * on uppercase letters so that deletions are
	            * NOT queried.
	            */
	              if (delete_aliases(newaliases, islower(ch))) {
	                install_aliases();
	                newaliases = 0;
	              }
		      clear_error();
		      main_state();		/* Done with aliases. */
		      return;

	    case RETURN:
	    case LINE_FEED:
	    case ' ':
	    case 'v':
		      if (newaliases) {		/* Need this ?? */
		          error(catgets(elm_msg_cat,
	                          AliasesSet, AliasesNotInstalled,
				  "Warning: new aliases not installed yet!"));
	              }

	              if (curr_alias > 0) {
	                  if (aliases[curr_alias-1]->type & GROUP) {
	                      PutLine1(LINES-1, 0, catgets(elm_msg_cat,
	                              AliasesSet, AliasesGroupAlias,
				      "Group alias: %-60.60s"),
	                          aliases[curr_alias-1]->address);
		          }
		          else {
	                      PutLine1(LINES-1, 0, catgets(elm_msg_cat,
	                              AliasesSet, AliasesAliasedAddress,
				      "Aliased address: %-60.60s"), 
	                          aliases[curr_alias-1]->address);
		          }
		      }
	              else {
		          error(catgets(elm_msg_cat,
	                          AliasesSet, AliasesNoneToView,
				  "Warning: no aliases to view!"));
		      }
		      break;

	    case 'x':
	    case 'X': PutLine0(-1, -1, catgets(elm_msg_cat,
	    				AliasesSet, AliasesAddReturn,
					"Return to main menu..."));
	              exit_alias();
		      clear_error();
		      main_state();		/* Done with aliases. */
		      return;

	    case 'f':
	    case 'F':
	              if (curr_alias > 0) {
		          clear_error();
		          strcpy(name, aliases[curr_alias-1]->alias);
		          if (ch == 'F') {
		              strcpy(buffer, catgets(elm_msg_cat,
	                              AliasesSet, AliasesFullyExpanded,
				      "Fully expand alias: "));
		              PutLine0(LINES-2, 0, buffer);
			      if (enter_string(name, sizeof(name), -1, -1,
					  ESTR_REPLACE) < 0 || name[0] == '\0')
				break;
		          }
	                  too_long = FALSE;
		          address = get_alias_address(name, TRUE, &too_long);
		          if (address != NULL) {
		              while (TRUE) {
	                          ClearScreen();
			          PutLine1(2,0, catgets(elm_msg_cat,
	                                  AliasesSet, AliasesAliasedFull,
					  "Aliased address for:\t%s\n\r"),
	                              name);
		                  i = 4;
		                  while (i < LINES-2) {
		                      if ((commap = index(address, (int)','))
	                                          == NULL) {
		                          PutLine0(i, 4, address);
		                          break;
		                      }
		                      *commap = '\0';
		                      PutLine0(i++, 4, address);
		                      address = commap+2;
		                  }
	                          PutLine0(LINES-1, 0, catgets(elm_msg_cat,
	                                  AliasesSet, AliasesPressReturn,
					  "Press <return> to continue."));
			          (void) ReadCh();
		                  if (commap == NULL) {
			              redraw++;
		                      break;
		                  }
		              }
		          }
	                  else if (! too_long) {
			      error(catgets(elm_msg_cat,
	                              AliasesSet, AliasesNotFound,
				      "Not found."));
		          }
		      }
	              else {
		          error(catgets(elm_msg_cat,
	                          AliasesSet, AliasesNoneToView,
				  "Warning: no aliases to view!"));
		      }
		      break;

	  case KEY_REDRAW:
		      redraw = 1;
		      break;

	 /*
	  * None of the menu specific commands were chosen, therefore
	  * it must be a "motion" command (or an error).
	  */
	    default	: motion(ch);

	  }

	  if (redraw) {			/* Redraw screen if necessary */
	      alias_screen(newaliases);
	      nutitle = 0;
	  }

	  if (nutitle) {		/* Redraw title if necessary */
	      alias_title(newaliases);
	      nutitle = 0;
	  }

	  check_range();

	  if (nucurr == NEW_PAGE)
	    show_headers();
	  else if (nucurr == SAME_PAGE)
	    show_current();
	  else if (nufoot) {
	    if (mini_menu) {
	      MoveCursor(LINES-7, 0);  
              CleartoEOS();
	      show_alias_menu();
	    }
	    else {
	      MoveCursor(LINES-4, 0);
	      CleartoEOS();
	    }
	    show_last_error();	/* for those operations that have to
				 * clear the footer except for a message.
				 */
	  }
	}			/* BIG while loop... */
}

void
install_aliases()
{
/*
 *	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];
	char buffer[SLEN];


	error(catgets(elm_msg_cat, AliasesSet, AliasesUpdating,
		"Updating aliases..."));
	if (sleepmsg > 0)
		sleep(sleepmsg);

	sprintf(itextfile, "%s/%s", user_home, ALIAS_TEXT);
	sprintf(odatafile, "%s/%s", user_home, ALIAS_DATA);

/*
 *	We need to unlimit everything since aliases are 
 * 	eing read in from scratch.
 */
	selected = 0;

	na = do_newalias(itextfile, odatafile, TRUE, FALSE);
	if (na >= 0) {
	    error1(catgets(elm_msg_cat, AliasesSet, AliasesReReading,
		  "Processed %d aliases.  Re-reading the database..."), na);
	    if (sleepmsg > 0)
		sleep(sleepmsg);
	    open_alias_files(TRUE);
	    set_error(catgets(elm_msg_cat, AliasesSet, AliasesUpdatedOK,
		  "Aliases updated successfully."));
	}
}

alias_help()
{
/*
 *	Help section for the alias menu...
 *
 *	Return non-0 if main part of screen overwritten, else 0
 */
	
	int  ch;
	int  redraw=0;
	char *alias_prompt;
	
	
	if (mini_menu)
		alias_prompt = catgets(elm_msg_cat, AliasesSet, AliasesShortKey,
			"Key: ");
	else
		alias_prompt = catgets(elm_msg_cat, AliasesSet, AliasesLongKey,
			"Key you want help for: ");

	MoveCursor(LINES-3, 0);
	CleartoEOS();
	if (mini_menu) {
	  CenterLine(LINES-3, catgets(elm_msg_cat, AliasesSet, AliasesKeyMenu,
 "Press the key you want help for, '?' for a key list, or '.' to exit help"));
	}

	lower_prompt(alias_prompt);

	while ((ch = ReadCh()) != '.') {
	  switch(ch) {
	    case '?' : display_helpfile("alias");	
		       redraw++;
		       return(redraw);

	    case '$': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpDollar,
"$ = Force resynchronization of aliases, processing additions and deletions."));
		      break;

	    case '/': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpSlash,
			"/ = Search for specified name or alias in list."));
		      break;

	    case RETURN:
	    case LINE_FEED:
	    case ' ':
	    case 'v': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpv,
	    "v = View the address for the currently selected alias."));
		      break;
	
	    case 'a': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpa,
	    "a = Add (return) address of current message to alias database."));
		      break;

	    case 'c': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpc,
"c = Change current user alias, modifying alias database at next resync."));
		      break;

	    case 'd': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpd,
	    "d = Mark the current alias for deletion from alias database."));
		      break;

	    case ctrl('D'): error(catgets(elm_msg_cat, AliasesSet, AliasesHelpCtrlD,
	    "^D = Mark for deletion user aliases matching specified pattern."));
		      break;

	    case 'e': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpe,
	    "e = Edit the alias text file directly (will run newalias)."));
		      break;

	    case 'f': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpf,
		"f = Display fully expanded address of current alias."));
		      break;

	    case 'l': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpl,
	    "l = Limit displayed aliases on the specified criteria."));
		      break;

	    case ctrl('L'): error(catgets(elm_msg_cat, AliasesSet, AliasesHelpCtrlL,
		      "^L = Rewrite the screen."));
	    	      break;

	    case 'm': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpm,
	    "m = Send mail to the current or tagged aliases."));
		      break;

	    case 'n': error(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': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpi,
		      "r,q,i = Return from alias menu (with prompting)."));
	   	      break;
		      
	    case 'R':
	    case 'Q':
	    case 'I': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpQ,
		      "R,Q,I = Return from alias menu (no prompting)."));
	   	      break;
		      
	    case 't': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpt,
		      "t = Tag current alias for further operations."));
		      break;
	
	    case 'T': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpT,
		      "T = Tag current alias and go to next alias."));
		      break;
	
	    case ctrl('T'): error(catgets(elm_msg_cat, AliasesSet, AliasesHelpCtrlT,
	    "^T = Tag aliases matching specified pattern."));
		      break;

	    case 'u': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpu,
	    "u = Unmark the current alias for deletion from alias database."));
		      break;

	    case ctrl('U'): error(catgets(elm_msg_cat, AliasesSet, AliasesHelpCtrlU,
"^U = Mark for undeletion user aliases matching specified pattern."));
		      break;

	    case 'x':
	    case 'X': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpX,
	    "x = Exit from alias menu, abandoning any pending deletions."));
	   	      break;

	    default : error(catgets(elm_msg_cat, AliasesSet, AliasesHelpNoHelp,
			"That key isn't used in this section."));
	   	      break;
	  }
	  lower_prompt(alias_prompt);
	}

	/* Remove help lines */
	MoveCursor(LINES-3, 0);	CleartoEOS();
	return(redraw);
}

get_aliases(are_in_aliases)
int are_in_aliases;
{
/*
 *	Get all the system and user alias info
 *
 *	If we get this far, we must be needing to re-read from
 *	at least one data file.  Unfortunately that means we 
 *	really need to read both since the aliases may be sorted
 *	and all mixed up...  :-(
 */

	char fname[SLEN];
	register int i = -1;
	int dups = 0;

	curr_alias = 0;
	num_duplicates = 0;
/*
 *	Read from user data file if it is open.
 */
	if (user_hash != NULL) {
	    dprint(6, (debugfile,
		      "About to read user data file = %d.\n",
	              user_hash->dbz_basef));
	    fseek(user_hash->dbz_basef, 0L, 0);
	    while (get_one_alias(user_hash, curr_alias)) {
		dprint(8, (debugfile, "%d\t%s\t%s\n", curr_alias+1,
				       aliases[curr_alias]->alias,
				       aliases[curr_alias]->address));

		curr_alias++;
	    }
	}
	num_aliases = curr_alias;		/* Needed for find_alias() */

/*
 *	Read from system data file if it is open.
 */
	if (system_hash != NULL) {
	    dprint(6, (debugfile,
		      "About to read system data file = %d.\n",
	              system_hash->dbz_basef));
	    fseek(system_hash->dbz_basef, 0L, 0);
	    while (get_one_alias(system_hash, curr_alias)) {
	    /*
	     *  If an identical user alias is found, we may
	     *  not want to display it, so we had better mark it.
	     */
		if (find_alias(aliases[curr_alias]->alias, USER) >= 0) {
		    setit(aliases[curr_alias]->type, DUPLICATE);
		    dups++;
		    setit(aliases[curr_alias]->status, URGENT);
				    /* Not really, I want the U for User */
		    dprint(6, (debugfile,
			       "System alias %s is same as user alias.\n",
			       aliases[curr_alias]->alias));
		}
		dprint(8, (debugfile, "%d\t%s\t%s\n", curr_alias+1,
				       aliases[curr_alias]->alias,
				       aliases[curr_alias]->address));

		curr_alias++;
	    }
	    num_duplicates = dups;
	}
	num_aliases = curr_alias - num_duplicates;

	if (OPMODE_IS_READMODE(opmode) && num_aliases > 0) {
	    curr_alias = 0;
	    sort_aliases((num_aliases+num_duplicates), FALSE, are_in_aliases);
	    curr_alias = 1;
	    if (are_in_aliases) {
	        (void) get_page(curr_alias);
	    }
	}

}

get_one_alias(db, current)
DBZ *db;
int current;
{
/*
 *	Get an alias (name, address, etc.) from the data file
 */

	int new_max;
	register struct alias_rec *a;

	if ((a = fetch_alias(db, (char *)NULL)) == NULL)
	    return 0;

	if (current >= max_aliases) {
	    new_max = max_aliases + KLICK;
	    if (max_aliases == 0) {
		aliases = (struct alias_rec **)
		    safe_malloc(new_max * sizeof(struct alias_rec *));
	    } else {
		aliases = (struct alias_rec **) safe_realloc((malloc_t)aliases,
		    new_max * sizeof(struct alias_rec *));
	    }
	    while (max_aliases < new_max)
		aliases[max_aliases++] = NULL;
	}

	if (aliases[current] != NULL)
	    free((malloc_t)aliases[current]);
	aliases[current] = a;
	return 1;
}


main_state()
{
/*	Save the globals that are shared for both menus
 *	so that we can return to the main menu without
 *	"tragedy".
 */

	static int alias_last = -1, alias_selected = 0, alias_page = 0;
	static int main_last = -1, main_selected = 0,  main_page = 0;

	if (inalias) {			/* Restore the settings */
	    alias_last = last_current;
	    alias_selected = selected;
	    alias_page = header_page;

	    last_current = main_last;
	    selected = main_selected;
	    header_page = main_page;

	    nls_item = catgets(elm_msg_cat, ElmSet, Elmitem, "message");
	    nls_items = catgets(elm_msg_cat, ElmSet, Elmitems, "messages");
	    nls_Item = catgets(elm_msg_cat, ElmSet, ElmItem, "Message");
	    nls_Items = catgets(elm_msg_cat, ElmSet, ElmItems, "Messages");
	    nls_Prompt = catgets(elm_msg_cat, ElmSet, ElmPrompt, "Command: ");

	    (void) define_softkeys(SOFTKEYS_MAIN);

	    dprint(3, (debugfile, "Leaving alias mode\n"));
	    inalias = FALSE;
	}
	else {
	    main_last = last_current;
	    main_selected = selected;
	    main_page = header_page;

	    last_current = alias_last;
	    selected = alias_selected;
	    header_page = alias_page;

	    nls_item = catgets(elm_msg_cat, AliasesSet, Aliasesitem, "alias");
	    nls_items = catgets(elm_msg_cat, AliasesSet, Aliasesitems, "aliases");
	    nls_Item = catgets(elm_msg_cat, AliasesSet, AliasesItem, "Alias");
	    nls_Items = catgets(elm_msg_cat, AliasesSet, AliasesItems, "Aliases");
	    nls_Prompt = catgets(elm_msg_cat, AliasesSet, AliasesPrompt, "Alias: ");

	    (void) define_softkeys(SOFTKEYS_ALIAS);

	    dprint(3, (debugfile, "Entered alias mode\n"));
	    inalias = TRUE;
	}
}

int
parse_aliases(buffer, remainder)
char *buffer, *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, (int)'=')) == NULL)
	  return (0);

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

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

	while (--s >= buffer && whitespace(*s)) ;
	*++s = ',';
	*++s = '\0';

/*	Lowercase everything */

	s = shift_lower(buffer);
	strcpy(buffer, s);

/*	Now, count the aliases */

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

	return (number);
}

int
get_aliasname(aliasname, buffer, duplicate)
char *aliasname, *buffer;
int *duplicate;
{

/*
 *	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'.
 */

	int loc;

	do {
	    if (enter_string(aliasname, SLEN,
				LINES-2, strlen(buffer), ESTR_REPLACE) < 0
			|| aliasname[0] == '\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)) >= 0) {
	    dprint(3, (debugfile, 
	         "Attempt to add a duplicate alias [%s] in get_aliasname\n",
	         aliases[loc]->alias)); 
	    if (aliases[loc]->type & GROUP )
	        PutLine1(LINES-2,0, catgets(elm_msg_cat,
	                AliasesSet, AliasesAlreadyGroup,
	                "Already a group with name %s."), aliases[loc]->alias);
	    else
	        PutLine1(LINES-2,0, catgets(elm_msg_cat,
	                AliasesSet, AliasesAlreadyAlias,
	                "Already an alias for %s."), aliases[loc]->alias);
	    CleartoEOLN();
	 /*
	  * If they don't want to replace the alias by that name
	  * then just return.
	  */
	    if (!enter_yn(catgets(elm_msg_cat, AliasesSet,
			AliasesReplaceExisting,
			"Replace existing alias?"), FALSE, LINES-3, FALSE))
	        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)) >= 0) {
	    dprint(3, (debugfile, 
	      "Attempt to add a duplicate system alias [%s] in get_aliasname\n",
	      aliases[loc]->address)); 
	  
	    if( ! superceed_system(loc, buffer))
	        return(-1);
	}
	return(0);

}

int
superceed_system(this_alias, buffer)
int this_alias;
char *buffer;
{

	PutLine2(LINES-2, 0, catgets(elm_msg_cat,
	        AliasesSet, AliasesSystemAlias, "System (%6s) alias for %s."),
	    alias_type(aliases[this_alias]->type), aliases[this_alias]->alias);
/*
 *	If they don't want to superceed the SYSTEM alias then
 *	return a FALSE.
 */
	return enter_yn(catgets(elm_msg_cat, AliasesSet, AliasesSuperceed,
	        "Superceed?"), FALSE, LINES-3, FALSE);
}

void
get_realnames(aliasname, firstname, lastname, comment, buffer)
char *aliasname, *firstname, *lastname, *comment, *buffer;
{
	/* FOO - this is not handling enter_string() aborts properly */

	sprintf(buffer, catgets(elm_msg_cat, AliasesSet, AliasesEnterLastName,
		"Enter last name for %s: "), aliasname);
	PutLine0(LINES-2, 0, buffer);
	enter_string(lastname, SLEN, -1, -1, ESTR_REPLACE);

	sprintf(buffer, catgets(elm_msg_cat, AliasesSet, AliasesEnterFirstName,
		"Enter first name for %s: "), aliasname);
	PutLine0(LINES-2, 0, buffer);
	enter_string(firstname, SLEN, -1, -1, ESTR_REPLACE);

	if (strlen(lastname) == 0) {
	    if (strlen(firstname) == 0) {
	        strcpy(lastname, aliasname);  
	    }
	    else {
	        strcpy(lastname, firstname);  
	        *firstname = '\0';
	    }
	}

	sprintf(buffer, catgets(elm_msg_cat, AliasesSet, AliasesEnterComment,
		"Enter optional comment for %s: "), aliasname);
	PutLine0(LINES-2, 0, buffer);
	enter_string(comment, SLEN, -1, -1, ESTR_REPLACE);

}

int
ask_accept(aliasname, firstname, lastname, comment, address, buffer,
	replace, replacement)
char *aliasname, *firstname, *lastname, *comment, *address, *buffer;
int replace, replacement;
{

	int ans;
	char *(old_alias[1]);
/*
 *	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(firstname) == 0) {
	    strcpy(buffer, lastname);  
	}
	else {
	    sprintf(buffer, "%s %s", firstname, lastname);
	}
	PutLine2(LINES-1,0, catgets(elm_msg_cat, AliasesSet, AliasesAddressAs,
	        "Messages addressed as: %s (%s)"), address, buffer);
	if (strlen(comment) != 0) {
	    strcat(buffer, ", ");
	    strcat(buffer, comment);
	}

	PutLine2(LINES-2,0, catgets(elm_msg_cat, AliasesSet, AliasesAddressTo,
	        "New alias: %s is '%s'."), aliasname, buffer);
	CleartoEOLN();
/*
 *	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.
 */
	ans = enter_yn(catgets(elm_msg_cat, AliasesSet, AliasesAcceptNew,
		"      Accept new alias?"), TRUE, LINES-3, FALSE);
	if(ans) {
	    if (replace) {
	        old_alias[0] = aliases[replacement]->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(aliases[replacement]->status, DELETED)) {
	            clearit(aliases[replacement]->status, DELETED);
	        }
	    /*
	     *  Changed aliases are given the NEW flag.
	     */
	        setit(aliases[replacement]->status, NEW);
	        show_msg_status(replacement);
	    /*
	     *  Now we can delete it...
	     */
	        delete_from_alias_text(old_alias, 1);
	    /*
	     *  Kludge Alert:  We need to get the trailing comma
	     *  (added in delete_from_alias_text()) off of the
	     *  alias since the display won't be re-sync'd right
	     *  away.
	     */
	        *((old_alias[0])+strlen(old_alias[0])-1) = '\0';
	    }
	    add_to_alias_text(aliasname, firstname, lastname, comment, address);
	}
	ClearLine(LINES-2);
	ClearLine(LINES-1);
	return ans;
}

/* Check whether an address is aliased; if so return the alias, otherwise
 * return NULL. */
char *address_to_alias(address)
char *address;
{
	int i;
	char return_address[SLEN];

	(void) open_alias_files(FALSE);

	get_return_address(address, return_address);
	
	for (i = 0; i < num_aliases; i++) {
	    if (istrcmp(return_address, aliases[i]->address) == 0)
		return aliases[i]->alias;
	}
	return NULL;
}
