1 
2 static char rcsid[] = "@(#)$Id: alias.c,v 1.6 1996/08/08 19:49:22 wfp5p Exp $";
3 
4 /*******************************************************************************
5  *  The Elm Mail System  -  $Revision: 1.6 $   $State: Exp $
6  *
7  *                      Copyright (c) 1988-1995 USENET Community Trust
8  * 			Copyright (c) 1986,1987 Dave Taylor
9  *******************************************************************************
10  * Bug reports, patches, comments, suggestions should be sent to:
11  *
12  *      Bill Pemberton, Elm Coordinator
13  *      flash@virginia.edu
14  *
15  *******************************************************************************
16  * $Log: alias.c,v $
17  * Revision 1.6  1996/08/08  19:49:22  wfp5p
18  * Alpha 11
19  *
20  * Revision 1.5  1996/05/09  15:51:14  wfp5p
21  * Alpha 10
22  *
23  * Revision 1.4  1996/03/14  17:27:50  wfp5p
24  * Alpha 9
25  *
26  * Revision 1.3  1995/09/29  17:41:57  wfp5p
27  * Alpha 8 (Chip's big changes)
28  *
29  * Revision 1.2  1995/05/24  15:34:37  wfp5p
30  * Change to deal with parenthesized comments in when eliminating members from
31  * an alias. (from Keith Neufeld <neufeld@pvi.org>)
32  *
33  * Allow a shell escape from the alias screen (just like from
34  * the index screen).  It does not put the shell escape onto the alias
35  * screen menu. (from Keith Neufeld <neufeld@pvi.org>)
36  *
37  * Allow the use of "T" from the builtin pager. (from Keith Neufeld
38  * <neufeld@pvi.org>)
39  *
40  * Revision 1.1.1.1  1995/04/19  20:38:34  wfp5p
41  * Initial import of elm 2.4 PL0 as base for elm 2.5.
42  *
43  ******************************************************************************/
44 
45 /** This file contains alias stuff
46 
47 **/
48 
49 #include "elm_defs.h"
50 #include "elm_globals.h"
51 #include "port_stat.h"
52 #include "s_elm.h"
53 #include "s_aliases.h"
54 #include "ndbz.h"
55 
56 #define	ECHOIT	1 	/* echo on for prompting */
57 
58 /*
59  * A simple macro to make it easier to remember how to do a simple
60  * resync and not screw up whether or not to prompt on deletions.
61  */
62 
63 #define resync_aliases(newaliases)	delete_aliases(newaliases,TRUE)
64 
65 extern char *alias_type();
66 void get_realnames();
67 void install_aliases();
68 
69 int  is_system=0;		/* system file updating?     */
70 
71 int num_duplicates;
72 DBZ *system_hash = NULL, *user_hash = NULL;
73 
74 
open_alias_files(are_in_aliases)75 open_alias_files(are_in_aliases)
76 int are_in_aliases;
77 {
78 	if(open_system_aliases() | open_user_aliases()) {
79 	    dprint(5, (debugfile,
80 		      "Reading alias data files...\n"));
81 	    get_aliases(are_in_aliases);
82 	}
83 }
84 
85 int
open_system_aliases()86 open_system_aliases()
87 {
88 /*
89  *	Open the system alias file, if present,
90  *	and if it has changed since last we read it.
91  *
92  *	Return 0 if hash file wasn't opened, otherwise 1
93  */
94 
95 	struct stat hst;
96 	static time_t system_ctime = 0, system_mtime = 0;
97 
98 	/* If file hasn't changed, don't bother re-opening. */
99 
100 	if (stat(system_data_file, &hst) == 0) {	/* File exists */
101 	    if (hst.st_ctime == system_ctime &&
102 	        hst.st_mtime == system_mtime) {		/* No changes */
103 	        return(0);
104 	    }
105 
106 	   /*
107 	    * Re-open system hash table.  If we can't, just return.
108 	    */
109 
110 	    if (system_hash != NULL)
111 	        dbz_close(system_hash);
112 
113 	    if ((system_hash = dbz_open(system_data_file, O_RDONLY, 0)) == NULL)
114 	        return(0);
115 
116 	    /* Remember hash file times. */
117 
118 	    system_ctime = hst.st_ctime;
119 	    system_mtime = hst.st_mtime;
120 
121             return(1);
122 	}
123 	else {					/* File does not exist */
124 	    if (system_ctime == 0 && system_mtime == 0) {
125 	        return(0);			/* File never existed */
126 	    }
127 	    else {			/* Once existed, better re-read */
128 
129 	       /*
130 	        * Since we no longer exist, we pretend we never existed.
131 	        */
132 
133 	        system_ctime = 0;
134 	        system_mtime = 0;
135 
136 	        return(1);
137 	    }
138 	}
139 
140 }
141 
142 int
open_user_aliases()143 open_user_aliases()
144 {
145 /*
146  *	Open the user alias file, if present,
147  *	and if it has changed since last we read it.
148  *
149  *	Return 0 if hash file wasn't opened, otherwise 1
150  */
151 
152 	struct stat hst;
153 	char fname[SLEN];
154 	static time_t user_ctime = 0, user_mtime = 0;
155 
156 	/* If hash file hasn't changed, don't bother re-reading. */
157 
158 	sprintf(fname, "%s/%s", user_home, ALIAS_DATA);
159 
160 	if (stat(fname, &hst) == 0) {			/* File exists */
161 	    if (hst.st_ctime == user_ctime &&
162 	        hst.st_mtime == user_mtime) {		/* No changes */
163 	        return(0);
164 	    }
165 
166 	   /*
167 	    * Open user hash table.  If we can't, just return.
168 	    */
169 
170 	    if (user_hash != NULL)
171 	        dbz_close(user_hash);
172 
173 	    if ((user_hash = dbz_open(fname, O_RDONLY, 0)) == NULL)
174 	        return(0);
175 
176 	    /* Remember hash file times. */
177 
178 	    user_ctime = hst.st_ctime;
179 	    user_mtime = hst.st_mtime;
180 
181             return(1);
182 	}
183 	else {					/* File does not exist */
184 	    if (user_ctime == 0 && user_mtime == 0) {
185 	        return(0);			/* File never existed */
186 	    }
187 	    else {			/* Once existed, better re-read */
188 
189 	       /*
190 	        * Since we no longer exist, we pretend we never existed.
191 	        */
192 
193 	        user_ctime = 0;
194 	        user_mtime = 0;
195 
196 	        return(1);
197 	    }
198 	}
199 
200 }
201 
202 int
add_alias(replace,to_replace)203 add_alias(replace, to_replace)
204 int replace, to_replace;
205 {
206 /*
207  *	Add an alias to the user alias text file.  If there
208  *	are aliases tagged, the user is asked if he wants to
209  *	create a group alias from the tagged files.
210  *
211  *	Return zero if alias not added in actuality.
212  *
213  *	If replace == FALSE, then we will ask for the new
214  *	aliasname.
215  *
216  *	If replace == TRUE, then we are replacing the alias
217  *	denoted by to_replace.
218  *
219  *	Note that even if replace == FALSE, if the user types
220  *	in the name of a current alias then we can still do
221  *	a replacement.
222  */
223 
224 	int i, leftoff, ans, tagged = 0;
225 
226 	char aliasname[SLEN], firstname[SLEN], lastname[SLEN];
227 	char address1[LONG_STRING], buffer[SLEN];
228 	char comment[LONG_STRING];
229 	char *ch_ptr;
230 
231 /*
232  *	See if there are any tagged aliases.
233  */
234 	for (i=0; i < num_aliases; i++) {
235 	    if (ison(aliases[i]->status, TAGGED)) {
236 		if (tagged == 0) leftoff = i;
237 	        tagged++;
238 	    }
239 	}
240 
241 	if (tagged == 1) {
242 	 /*
243 	  * There is only on alias tagged.  Ask the question
244 	  * but the default response is NO.
245 	  */
246 	    PutLine0(LINES-2,0, catgets(elm_msg_cat,
247 	            AliasesSet, AliasesOneTagged,
248 	            "There is 1 alias tagged..."));
249 	    CleartoEOLN();
250 	    ans = enter_yn(catgets(elm_msg_cat, AliasesSet, AliasesCreateGroup,
251 			"Create group alias?"), FALSE, LINES-3, FALSE);
252 	}
253 	else if (tagged > 1) {
254 	 /*
255 	  * If multiple tagged aliases then we assume the user
256 	  * wants to create a group alias.  The default response
257 	  * is YES.
258 	  */
259 	    PutLine1(LINES-2,0, catgets(elm_msg_cat,
260 	            AliasesSet, AliasesManyTagged,
261 	            "There are %d aliases tagged..."), tagged);
262 	    CleartoEOLN();
263 	    ans = enter_yn(catgets(elm_msg_cat, AliasesSet, AliasesCreateGroup,
264 			"Create group alias?"), TRUE, LINES-3, FALSE);
265 	} else {
266 	    /*
267 	     * Nothing tagged ... thus nothing to make a group of.
268 	     */
269 	    ans = FALSE;
270 	}
271 
272 /*
273  *	If requested above, create the group alias address.
274  */
275 	if (ans) {
276 	    strcpy(address1, aliases[leftoff]->alias);
277 	    for (i=leftoff+1; i < num_aliases; i++) {
278 	        if (ison(aliases[i]->status, TAGGED)) {
279 	            strcat(address1, ",");
280 	            strcat(address1, aliases[i]->alias);
281 	        }
282 	    }
283 	}
284 	else {
285 	    tagged = 0;
286 	}
287 
288 /*
289  *	Only ask for an aliasname if we are NOT replacing the
290  *	current alias.
291  */
292 	if (replace) {
293 	    strcpy(aliasname, aliases[to_replace]->alias);
294 	/*
295 	 *  First, see if what we are replacing is a SYSTEM
296 	 *  alias.  If so, we need to ask a question.
297 	 */
298 	    if(aliases[to_replace]->type & SYSTEM) {
299 	        dprint(3, (debugfile,
300 	            "Aliasname [%s] is SYSTEM in add_alias\n", aliasname));
301 	    /*
302 	     *  If they don't want to superceed the SYSTEM alias then
303 	     *  just return.
304 	     */
305 	        if( ! superceed_system(to_replace, buffer)) {
306 	            ClearLine(LINES-2);
307 	            return(0);
308 	        }
309 	    }
310 	}
311 	else {
312 	    strcpy(buffer, catgets(elm_msg_cat,
313 	            AliasesSet, AliasesEnterAliasName, "Enter alias name: "));
314 	    PutLine0(LINES-2,0, buffer);
315 	    CleartoEOLN();
316 	    *aliasname = '\0';
317 	    if ((replace = get_aliasname(aliasname, buffer, &to_replace)) < 0) {
318 	        dprint(3, (debugfile,
319 	            "Aliasname [%s] was rejected in add_alias\n", aliasname));
320 	        ClearLine(LINES-2);
321 	        return(0);
322 	    }
323 	}
324 
325 /*
326  *	If we are replacing an existing alias, we will assume that
327  *	they might want to be just editing most of what is already
328  *	there.  So we copy some defaults from the existing alias.
329  */
330 	if (replace) {
331 	    strcpy(lastname, aliases[to_replace]->last_name);
332 	    strcpy(firstname, aliases[to_replace]->name);
333 	    ch_ptr = strstr(firstname, lastname);
334 	    *(ch_ptr-1) = '\0';
335 	    strcpy(comment, aliases[to_replace]->comment);
336 	}
337 	else {
338 	    *lastname = '\0';
339 	    *firstname = '\0';
340 	    *comment = '\0';
341 	}
342 	get_realnames(aliasname, firstname, lastname, comment, buffer);
343 
344 /*
345  *	Since there are no tagged aliases, we must ask for an
346  *	address.  If we are replacing, a default address is
347  *	presented.
348  */
349 	if (tagged == 0) {
350 	    sprintf(buffer, catgets(elm_msg_cat,
351 	            AliasesSet, AliasesEnterAddress,
352 	            "Enter address for %s: "), aliasname);
353 	    PutLine0(LINES-2, 0, buffer);
354 	    if (replace)
355 	        strcpy(address1, aliases[to_replace]->address);
356 	    else
357 	        *address1 = '\0';
358 
359 	    if (enter_string(address1, sizeof(address1), -1, -1,
360 			ESTR_REPLACE) < 0 || address1[0] == '\0') {
361 		Raw(ON);
362 	        error(catgets(elm_msg_cat, AliasesSet, AliasesNoAddressSpec,
363 	                "No address specified!"));
364 	        return(0);
365 	    }
366 	    Raw(ON);
367 
368 	    despace_address(address1);
369 
370 	    clear_error();			/* Just in case */
371 	}
372 
373 	if(ask_accept(aliasname, firstname, lastname, comment, address1,
374 	        buffer, replace, to_replace)) {
375 	 /*
376 	  * We can only clear the tags after we know that the
377 	  * alias was added.  This allows the user to back out
378 	  * and rethink without losing the tags.
379 	  */
380 	    if (tagged > 0) {
381 	        for (i=leftoff; i < num_aliases; i++) {
382 	            if (ison(aliases[i]->status, TAGGED)) {
383 	                clearit(aliases[i]->status, TAGGED);
384 	                show_msg_tag(i);
385 	            }
386 	        }
387 	    }
388 	    return(1);
389 	}
390 	else {
391 	    return(0);
392 	}
393 
394 }
395 
396 int
add_current_alias()397 add_current_alias()
398 {
399 /*
400  *	Alias the current message to the specified name and
401  *	add it to the alias text file, for processing as
402  *	the user leaves the program.
403  *
404  *	Returns non-zero iff alias actually added to file.
405  */
406 
407 	char aliasname[SLEN], firstname[SLEN], lastname[SLEN];
408 	char comment[SLEN], address1[LONG_STRING], buffer[SLEN];
409 	char comment_buff[LONG_STRING];
410 	char *chspace, *bufptr;
411 	struct header_rec *current_header;
412 
413 	static char bad_punc[] = ",.:;";
414 	char *punc_ptr;
415 	int i, match;
416 	int replace, to_replace;
417 
418 	if (curr_folder.curr_mssg == 0) {
419 	 dprint(4, (debugfile,
420 		"Add current alias called without any current message!\n"));
421 	 error(catgets(elm_msg_cat, AliasesSet, AliasesNoMessage,
422 		"No message to alias to!"));
423 	 return(0);
424 	}
425 	current_header = curr_folder.headers[curr_folder.curr_mssg-1];
426 
427 	strcpy(buffer, catgets(elm_msg_cat, AliasesSet, AliasesCurrentMessage,
428 		"Current message address aliased to: "));
429 	PutLine0(LINES-2,0, buffer);
430 	CleartoEOLN();
431 	*aliasname = '\0';
432 	if ((replace = get_aliasname(aliasname, buffer, &to_replace)) < 0) {
433 	    dprint(3, (debugfile,
434 	        "Aliasname [%s] was rejected in add_current_alias\n",
435 	        aliasname));
436 	    ClearLine(LINES-2);
437 	    return(0);
438 	}
439 
440 	/* use full name in current message for default comment */
441 	tail_of(current_header->from, comment_buff, current_header->to);
442 	if(index(comment_buff, (int)'!') || index(comment_buff, (int)'@'))
443 	  /* never mind - it's an address not a full name */
444 	  *comment_buff = '\0';
445 
446 /*
447  *	Try to break up the From: comment into firstname, lastname, and
448  *	any other text.  This is based on the fact that many address
449  *	comments are pretty straightforward.  This will break on many
450  *	situations.  Should handle:
451  *		(Robert Howard)
452  *		(Robert L. Howard)
453  *		(Robert Howard, Georgia Tech)
454  *	pretty well.  Will break on:
455  *		(The Voice of Reason)
456  *		and others....
457  */
458 
459 	*firstname = '\0';
460 	*lastname = '\0';
461 	*comment = '\0';
462 	if (strlen(comment_buff) != 0) {	/* There is something. */
463 	    bufptr = comment_buff;
464 	    while (*bufptr == ' ') bufptr++;	/* Always strip leading WS */
465 	    if ((chspace = index(bufptr, ' ')) != NULL) {
466 	   /*
467 	    *   A space means that there is at least (firstname lastname)
468 	    *   Get firstname and move bufptr.
469 	    */
470 	        *chspace = '\0';
471 	        strcpy(firstname, bufptr);
472 	        bufptr = chspace + 1;			/* Move the pointer */
473 	        while (*bufptr == ' ') bufptr++;
474 	    }
475 
476 above:	    if ((chspace = index(bufptr, ' ')) != NULL) {
477 	   /*
478 	    *   Another space means a third+ word.  We either have:
479 	    *       1. Word 3+ is a comment, or
480 	    *       2. Word 2 is a middle initial (word 3 is lastname).
481 	    *   Check and see.
482 	    */
483 	        *chspace = '\0';
484 	        if ((strlen(bufptr) == 1) ||
485 	            (strlen(bufptr) == 2  && *(bufptr+1) == '.')) {
486 	       /*
487 	        *   If the second word is either a single
488 	        *   character or a character followed by '.' it was
489 	        *   probably a middle initial.  Add it to firstname
490 	        *   and shift.
491 	        */
492 	            strcat(firstname, " ");
493 	            strcat(firstname, bufptr);
494 	            bufptr = chspace + 1;		/* Move the pointer */
495 	            while (*bufptr == ' ') bufptr++;
496 	            goto above;
497 	        }
498 	        strcpy(lastname, bufptr);
499 	        bufptr = chspace + 1;			/* Move the pointer */
500 	        while (*bufptr == ' ') bufptr++;
501 	        strcpy(comment, bufptr);
502 	    }
503 	    else {
504 	   /*
505 	    *   Only a lastname left.
506 	    */
507 	        strcpy(lastname, bufptr);
508 	    }
509 
510 	/*
511 	 *  Finally, get any puctuation characters off the end of
512 	 *  lastname.
513 	 */
514 	    match = TRUE;
515 	    for (i = strlen(lastname) - 1; match && i>0; i--) {
516 	        match = FALSE;
517 	        for (punc_ptr = bad_punc; *punc_ptr != '\0'; punc_ptr++) {
518 	            if (lastname[i] == *punc_ptr) {
519 	                lastname[i] = '\0';
520 	                match = TRUE;
521 	                break;
522 	            }
523 	        }
524 	    }
525 	}
526 
527 	get_realnames(aliasname, firstname, lastname, comment, buffer);
528 
529 	/* grab the return address of this message */
530 	get_return(address1, curr_folder.curr_mssg-1);
531 	strcpy(address1, strip_parens(address1));	/* remove parens! */
532 
533 	return(ask_accept(aliasname, firstname, lastname, comment, address1,
534 	        buffer, replace, to_replace));
535 
536 }
537 
add_to_alias_text(aliasname,firstname,lastname,comment,address)538 add_to_alias_text(aliasname, firstname, lastname, comment, address)
539 char *aliasname, *firstname, *lastname, *comment, *address;
540 {
541 /*
542  *	Add the data to the user alias text file.
543  *
544  *	Return zero if we succeeded, 1 if not.
545  */
546 
547 	FILE *file;
548 	char fname[SLEN];
549 	char buffer[SLEN];
550 	int  err;
551 
552 	sprintf(fname,"%s/%s", user_home, ALIAS_TEXT);
553 
554 	save_file_stats(fname);
555 	if ((file = fopen(fname, "a")) == NULL) {
556 	  err = errno;
557 	  dprint(2, (debugfile,
558 		 "Failure attempting to add alias to file %s within %s",
559 		   fname, "add_to_alias_text"));
560 	  dprint(2, (debugfile, "** %s **\n", strerror(err)));
561 	  error1(catgets(elm_msg_cat, AliasesSet, AliasesCouldntOpenAdd,
562 		 "Couldn't open %s to add new alias!"), fname);
563 	  return(1);
564 	}
565 
566 	if (strlen(firstname) == 0) {
567 	    strcpy(buffer, lastname);
568 	}
569 	else {
570 	    sprintf(buffer, "%s; %s", lastname, firstname);
571 	}
572 	if (strlen(comment) != 0) {
573 	    strcat(buffer, ", ");
574 	    strcat(buffer, comment);
575 	}
576 	if (fprintf(file,"%s = %s = %s\n", aliasname, buffer, address) == EOF) {
577 	    err = errno;
578 	    dprint(2, (debugfile,
579 		       "Failure attempting to write alias to file within %s",
580 		       fname, "add_to_alias_text"));
581 	    dprint(2, (debugfile, "** %s **\n", strerror(err)));
582 	    error1(catgets(elm_msg_cat, AliasesSet, AliasesCouldntWrite,
583 		   "Couldn't write alias to file %s!"), fname);
584 	    fclose(file);
585 	    return(1);
586 	}
587 
588 	fclose(file);
589 
590 	restore_file_stats(fname);
591 
592 	return(0);
593 }
594 
delete_from_alias_text(name,num_to_delete)595 delete_from_alias_text(name, num_to_delete)
596 char **name;
597 int num_to_delete;
598 {
599 /*
600  *	Delete the data from the user alias text file.
601  *
602  *	Return zero if we succeeded, 1 if not.
603  */
604 
605 	FILE *file, *tmp_file;
606 
607 	char fname[SLEN], tmpfname[SLEN];
608 	char line_in_file[LONG_STRING];
609 	char rest_of_line[LONG_STRING];
610 	char *s, *rest;
611 
612 	register int i;
613 	int num_aliases;
614 	int delete_continues;
615 	int err;
616 
617 	delete_continues = FALSE;
618 
619 	for (i=0; i < num_to_delete; i++)
620 	  strcat(name[i], ",");
621 
622 	sprintf(fname,"%s/%s", user_home, ALIAS_TEXT);
623 	sprintf(tmpfname,"%s/%s.t", user_home, ALIAS_TEXT);
624 
625 	save_file_stats(fname);
626 
627 	if ((file = fopen(fname, "r")) == NULL) {
628 	  err = errno;
629 	  dprint(2, (debugfile,
630 		 "Failure attempting to delete alias from file %s within %s",
631 		   fname, "delete_from_alias_text"));
632 	  dprint(2, (debugfile, "** %s **\n", strerror(err)));
633 	  error1(catgets(elm_msg_cat, AliasesSet, AliasesCouldntOpenDelete,
634 		 "Couldn't open %s to delete alias!"), fname);
635 	  return(1);
636 	}
637 
638 	if ((tmp_file = file_open(tmpfname, "w")) == NULL) {
639 	  err = errno;
640 	  dprint(2, (debugfile,
641 		 "Failure attempting to open temp file %s within %s",
642 		   tmpfname, "delete_from_alias_text"));
643 	  dprint(2, (debugfile, "** %s **\n", strerror(err)));
644 	  error1(catgets(elm_msg_cat, AliasesSet, AliasesCouldntOpenTemp,
645 	  	 "Couldn't open temp file %s to delete alias!"), tmpfname);
646 	  return(1);
647 	}
648 
649 	while (mail_gets(line_in_file, sizeof(line_in_file), file) != 0)
650 	{
651 	  if (! whitespace(line_in_file[0])) {
652 	    delete_continues = FALSE;
653 	    if (line_in_file[0] != '#') {
654 	      if (num_aliases = parse_aliases(line_in_file, rest_of_line)) {
655 	        for (i=0; i < num_to_delete && num_aliases; i++) {
656 	          if ( ((s = strstr(line_in_file, name[i])) == line_in_file) ||
657 		       ((s != NULL) && (*(s-1) == ',')) ) {
658 /*
659  *	Collapse the to be deleted alias out of line_in_file
660  */
661 	            rest = index(s, (int)',');
662 	            for (++rest; *rest; rest++)
663 	              *s++ = *rest;
664 	            *s = '\0';
665 	            num_aliases--;
666 	          }
667 	        }
668 	        if (num_aliases) {
669 	          *(line_in_file + strlen(line_in_file) - 1) = ' ';
670 	          strcat(line_in_file, rest_of_line);
671 	        }
672 	        else {
673 	          delete_continues = TRUE;
674 	        }
675 	      }
676 	    }
677 	  }
678 	  if (! delete_continues) {
679 	    if (fprintf(tmp_file,"%s", line_in_file) == EOF) {
680 	      err = errno;
681 	      dprint(2, (debugfile,
682 		"Failure attempting to write to temp file %s within %s",
683 		tmpfname, "delete_from_alias_text"));
684 	      dprint(2, (debugfile, "** %s **\n", strerror(err)));
685 	      error1(catgets(elm_msg_cat, AliasesSet, AliasesCouldntWriteTemp,
686 		"Couldn't write to temp file %s!"), tmpfname);
687 	      fclose(file);
688 	      fclose(tmp_file);
689 	      unlink(tmpfname);
690 	      return(1);
691 	    }
692 	  }
693 	}
694 	fclose(file);
695 	fclose(tmp_file);
696 	if (rename(tmpfname, fname) != 0)
697 	{
698 		error1(catgets(elm_msg_cat, AliasesSet, AliasesCouldntRenameTemp,
699 			"Couldn't rename temp file %s after deleting alias!"), tmpfname);
700 		return(1);
701 	}
702 
703 	restore_file_stats(fname);
704 
705 	return(0);
706 }
707 
708 void
alias()709 alias()
710 {
711 /*
712  *	Work with alias commands...
713  */
714 
715 	char name[NLEN], *address, buffer[SLEN];
716 	char *commap;
717 	int  key_offset;        /** Position offset within keyboard string   **/
718 	static int  newaliases = 0;
719 	int  ch, i, j;
720 	int nutitle = 0;
721 	int too_long;
722 
723 /*
724  *	We're going to try to match the way elm does it at
725  * 	he main menu.  I probably won't be able to use any
726  *	main menu routines, but I will "borrow" from them. RLH
727  */
728 
729 	main_state();		/* Save globals for return to main menu */
730 
731 	open_alias_files(FALSE);	/* First, read the alias files. RLH */
732 
733 	alias_screen(newaliases);
734 
735 	while (1) {
736 
737 	  redraw = 0;
738 	  nucurr = 0;
739 	  nufoot = 0;
740 
741 	  prompt(nls_Prompt);
742 	  CleartoEOLN();
743 	  ch = GetKey(0);
744 
745 	  MoveCursor(LINES-3,strlen(nls_Prompt)); CleartoEOS();
746 
747 	  dprint(3, (debugfile, "\n-- Alias command: %c\n\n", ch));
748 
749 	  switch (ch) {
750 	    case '?': redraw += alias_help();			break;
751 
752 #ifdef ALLOW_SUBSHELL
753 	    case '!' : WriteChar('!');
754 	      main_state(); /** reload index screen vars **/
755 	      redraw += subshell();
756 	      main_state(); /** reload alias screen vars **/
757 	      break;
758 #endif /* ALLOW_SUBSHELL */
759 
760 	    case '$': PutLine0(-1, -1, catgets(elm_msg_cat,
761 					AliasesSet, AliasesResync,
762 					"Resynchronize aliases..."));
763 	           /*
764 	            * Process deletions and then see if we need to
765 	            * re-run the "newalias" routine.
766 	            */
767 		      if (resync_aliases(newaliases)) {
768 		        install_aliases();
769 	                newaliases = 0;
770 		        redraw++;
771 		      }
772 		      break;
773 
774 	    case 'a': PutLine0(-1, -1, catgets(elm_msg_cat,
775 					AliasesSet, AliasesAddCurrent,
776 					"Add address from current message..."));
777 		      clear_error();
778 		      if (add_current_alias()) {
779 		          newaliases++;
780 		          nutitle++;
781 		      }
782 		      break;
783 
784 	    case 'c':
785 	              if (curr_alias > 0) {
786 			  PutLine0(-1, -1, catgets(elm_msg_cat,
787 	                              AliasesSet, AliasesReplaceCurrent,
788 	                              "Replace current alias in database..."));
789 		          clear_error();
790 		          if (add_alias(TRUE, curr_alias-1)) {
791 		              newaliases++;
792 		              nutitle++;
793 		          }
794 	              }
795 	              else {
796 		          error(catgets(elm_msg_cat,
797 	                          AliasesSet, AliasesNoneToReplace,
798 				  "Warning: no aliases to replace!"));
799 	              }
800 		      break;
801 
802 	    case 'e': PutLine1(LINES-3, strlen(nls_Prompt),
803 	                  catgets(elm_msg_cat, AliasesSet, AliasesEdit,
804 	                      "Edit %s..."), ALIAS_TEXT);
805 	           /*
806 	            * Process aliases.text for deletions, etc.  You
807 	            * have to do this *before* checking current because
808 	            * all aliases could be marked for deletion.
809 	            */
810 	              (void) resync_aliases(newaliases);
811 	              if (edit_aliases_text()) {
812 	                  newaliases = 0;
813 	              }
814 		      redraw++;
815 		      break;
816 
817 	    case 'm':
818 	              if (curr_alias > 0) {
819 			  PutLine0(-1, -1, catgets(elm_msg_cat,
820 					  AliasesSet, AliasesMail, "Mail..."));
821 	                  redraw += a_sendmsg();
822 	              }
823 	              else {
824 		          error(catgets(elm_msg_cat,
825 	                          AliasesSet, AliasesNoneToMail,
826 				  "Warning: no aliases to send mail to!"));
827 	              }
828 		      break;
829 
830 	    case 'n': PutLine0(-1, -1, catgets(elm_msg_cat,
831 					AliasesSet, AliasesAddNew,
832 					"Add a new alias to database..."));
833 		      clear_error();
834 		      if (add_alias(FALSE, -1)) {
835 		          newaliases++;
836 		          nutitle++;
837 		      }
838 		      break;
839 
840 	    case 'q':
841 	    case 'Q':
842 	    case 'i':
843 	    case 'I':
844 	    case 'r':
845 	    case 'R': PutLine0(-1, -1, catgets(elm_msg_cat,
846 	    				AliasesSet, AliasesAddReturn,
847 					"Return to main menu..."));
848 	           /*
849 	            * leaving the alias system.  Must check for
850 	            * pending deletes, etc.  prompt is set to FALSE
851 	            * on uppercase letters so that deletions are
852 	            * NOT queried.
853 	            */
854 	              if (delete_aliases(newaliases, islower(ch))) {
855 	                install_aliases();
856 	                newaliases = 0;
857 	              }
858 		      clear_error();
859 		      main_state();		/* Done with aliases. */
860 		      return;
861 
862 	    case RETURN:
863 	    case LINE_FEED:
864 	    case ' ':
865 	    case 'v':
866 		      if (newaliases) {		/* Need this ?? */
867 		          error(catgets(elm_msg_cat,
868 	                          AliasesSet, AliasesNotInstalled,
869 				  "Warning: new aliases not installed yet!"));
870 	              }
871 
872 	              if (curr_alias > 0) {
873 	                  if (aliases[curr_alias-1]->type & GROUP) {
874 	                      PutLine1(LINES-1, 0, catgets(elm_msg_cat,
875 	                              AliasesSet, AliasesGroupAlias,
876 				      "Group alias: %-60.60s"),
877 	                          aliases[curr_alias-1]->address);
878 		          }
879 		          else {
880 	                      PutLine1(LINES-1, 0, catgets(elm_msg_cat,
881 	                              AliasesSet, AliasesAliasedAddress,
882 				      "Aliased address: %-60.60s"),
883 	                          aliases[curr_alias-1]->address);
884 		          }
885 		      }
886 	              else {
887 		          error(catgets(elm_msg_cat,
888 	                          AliasesSet, AliasesNoneToView,
889 				  "Warning: no aliases to view!"));
890 		      }
891 		      break;
892 
893 	    case 'x':
894 	    case 'X': PutLine0(-1, -1, catgets(elm_msg_cat,
895 	    				AliasesSet, AliasesAddReturn,
896 					"Return to main menu..."));
897 	              exit_alias();
898 		      clear_error();
899 		      main_state();		/* Done with aliases. */
900 		      return;
901 
902 	    case 'f':
903 	    case 'F':
904 	              if (curr_alias > 0) {
905 		          clear_error();
906 		          strcpy(name, aliases[curr_alias-1]->alias);
907 		          if (ch == 'F') {
908 		              strcpy(buffer, catgets(elm_msg_cat,
909 	                              AliasesSet, AliasesFullyExpanded,
910 				      "Fully expand alias: "));
911 		              PutLine0(LINES-2, 0, buffer);
912 			      if (enter_string(name, sizeof(name), -1, -1,
913 					  ESTR_REPLACE) < 0 || name[0] == '\0')
914 				break;
915 		          }
916 	                  too_long = FALSE;
917 		          address = get_alias_address(name, TRUE, &too_long);
918 		          if (address != NULL) {
919 		              while (TRUE) {
920 	                          ClearScreen();
921 			          PutLine1(2,0, catgets(elm_msg_cat,
922 	                                  AliasesSet, AliasesAliasedFull,
923 					  "Aliased address for:\t%s\n\r"),
924 	                              name);
925 		                  i = 4;
926 		                  while (i < LINES-2) {
927 		                      if ((commap = index(address, (int)','))
928 	                                          == NULL) {
929 		                          PutLine0(i, 4, address);
930 		                          break;
931 		                      }
932 		                      *commap = '\0';
933 		                      PutLine0(i++, 4, address);
934 		                      address = commap+2;
935 		                  }
936 	                          PutLine0(LINES-1, 0, catgets(elm_msg_cat,
937 	                                  AliasesSet, AliasesPressReturn,
938 					  "Press <return> to continue."));
939 			          (void) ReadCh();
940 		                  if (commap == NULL) {
941 			              redraw++;
942 		                      break;
943 		                  }
944 		              }
945 		          }
946 	                  else if (! too_long) {
947 			      error(catgets(elm_msg_cat,
948 	                              AliasesSet, AliasesNotFound,
949 				      "Not found."));
950 		          }
951 		      }
952 	              else {
953 		          error(catgets(elm_msg_cat,
954 	                          AliasesSet, AliasesNoneToView,
955 				  "Warning: no aliases to view!"));
956 		      }
957 		      break;
958 
959 	  case KEY_REDRAW:
960 		      redraw = 1;
961 		      break;
962 
963 	 /*
964 	  * None of the menu specific commands were chosen, therefore
965 	  * it must be a "motion" command (or an error).
966 	  */
967 	    default	: motion(ch);
968 
969 	  }
970 
971 	  if (redraw) {			/* Redraw screen if necessary */
972 	      alias_screen(newaliases);
973 	      nutitle = 0;
974 	  }
975 
976 	  if (nutitle) {		/* Redraw title if necessary */
977 	      alias_title(newaliases);
978 	      nutitle = 0;
979 	  }
980 
981 	  check_range();
982 
983 	  if (nucurr == NEW_PAGE)
984 	    show_headers();
985 	  else if (nucurr == SAME_PAGE)
986 	    show_current();
987 	  else if (nufoot) {
988 	    if (mini_menu) {
989 	      MoveCursor(LINES-7, 0);
990               CleartoEOS();
991 	      show_alias_menu();
992 	    }
993 	    else {
994 	      MoveCursor(LINES-4, 0);
995 	      CleartoEOS();
996 	    }
997 	    show_last_error();	/* for those operations that have to
998 				 * clear the footer except for a message.
999 				 */
1000 	  }
1001 	}			/* BIG while loop... */
1002 }
1003 
1004 void
install_aliases()1005 install_aliases()
1006 {
1007 /*
1008  *	Run the 'newalias' program and update the
1009  *	aliases before going back to the main program!
1010  *
1011  *	No return value.....
1012  */
1013 
1014 	int na;
1015 	char itextfile[SLEN], odatafile[SLEN];
1016 	char buffer[SLEN];
1017 
1018 
1019 	error(catgets(elm_msg_cat, AliasesSet, AliasesUpdating,
1020 		"Updating aliases..."));
1021 	if (sleepmsg > 0)
1022 		sleep(sleepmsg);
1023 
1024 	sprintf(itextfile, "%s/%s", user_home, ALIAS_TEXT);
1025 	sprintf(odatafile, "%s/%s", user_home, ALIAS_DATA);
1026 
1027 /*
1028  *	We need to unlimit everything since aliases are
1029  * 	eing read in from scratch.
1030  */
1031 	selected = 0;
1032 
1033 	na = do_newalias(itextfile, odatafile, TRUE, FALSE);
1034 	if (na >= 0) {
1035 	    error1(catgets(elm_msg_cat, AliasesSet, AliasesReReading,
1036 		  "Processed %d aliases.  Re-reading the database..."), na);
1037 	    if (sleepmsg > 0)
1038 		sleep(sleepmsg);
1039 	    open_alias_files(TRUE);
1040 	    set_error(catgets(elm_msg_cat, AliasesSet, AliasesUpdatedOK,
1041 		  "Aliases updated successfully."));
1042 	}
1043 }
1044 
alias_help()1045 alias_help()
1046 {
1047 /*
1048  *	Help section for the alias menu...
1049  *
1050  *	Return non-0 if main part of screen overwritten, else 0
1051  */
1052 
1053 	int  ch;
1054 	int  redraw=0;
1055 	char *alias_prompt;
1056 
1057 
1058 	if (mini_menu)
1059 		alias_prompt = catgets(elm_msg_cat, AliasesSet, AliasesShortKey,
1060 			"Key: ");
1061 	else
1062 		alias_prompt = catgets(elm_msg_cat, AliasesSet, AliasesLongKey,
1063 			"Key you want help for: ");
1064 
1065 	MoveCursor(LINES-3, 0);
1066 	CleartoEOS();
1067 	if (mini_menu) {
1068 	  CenterLine(LINES-3, catgets(elm_msg_cat, AliasesSet, AliasesKeyMenu,
1069  "Press the key you want help for, '?' for a key list, or '.' to exit help"));
1070 	}
1071 
1072 	lower_prompt(alias_prompt);
1073 
1074 	while ((ch = ReadCh()) != '.') {
1075 	  switch(ch) {
1076 	    case '?' : display_helpfile("alias");
1077 		       redraw++;
1078 		       return(redraw);
1079 
1080 	    case '$': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpDollar,
1081 "$ = Force resynchronization of aliases, processing additions and deletions."));
1082 		      break;
1083 
1084 	    case '/': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpSlash,
1085 			"/ = Search for specified name or alias in list."));
1086 		      break;
1087 
1088 	    case RETURN:
1089 	    case LINE_FEED:
1090 	    case ' ':
1091 	    case 'v': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpv,
1092 	    "v = View the address for the currently selected alias."));
1093 		      break;
1094 
1095 	    case 'a': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpa,
1096 	    "a = Add (return) address of current message to alias database."));
1097 		      break;
1098 
1099 	    case 'c': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpc,
1100 "c = Change current user alias, modifying alias database at next resync."));
1101 		      break;
1102 
1103 	    case 'd': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpd,
1104 	    "d = Mark the current alias for deletion from alias database."));
1105 		      break;
1106 
1107 	    case ctrl('D'): error(catgets(elm_msg_cat, AliasesSet, AliasesHelpCtrlD,
1108 	    "^D = Mark for deletion user aliases matching specified pattern."));
1109 		      break;
1110 
1111 	    case 'e': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpe,
1112 	    "e = Edit the alias text file directly (will run newalias)."));
1113 		      break;
1114 
1115 	    case 'f': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpf,
1116 		"f = Display fully expanded address of current alias."));
1117 		      break;
1118 
1119 	    case 'l': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpl,
1120 	    "l = Limit displayed aliases on the specified criteria."));
1121 		      break;
1122 
1123 	    case ctrl('L'): error(catgets(elm_msg_cat, AliasesSet, AliasesHelpCtrlL,
1124 		      "^L = Rewrite the screen."));
1125 	    	      break;
1126 
1127 	    case 'm': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpm,
1128 	    "m = Send mail to the current or tagged aliases."));
1129 		      break;
1130 
1131 	    case 'n': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpn,
1132 "n = Add a new user alias, adding to alias database at next resync."));
1133 		      break;
1134 
1135 	    case 'r':
1136 	    case 'q':
1137 	    case 'i': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpi,
1138 		      "r,q,i = Return from alias menu (with prompting)."));
1139 	   	      break;
1140 
1141 	    case 'R':
1142 	    case 'Q':
1143 	    case 'I': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpQ,
1144 		      "R,Q,I = Return from alias menu (no prompting)."));
1145 	   	      break;
1146 
1147 	    case 't': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpt,
1148 		      "t = Tag current alias for further operations."));
1149 		      break;
1150 
1151 	    case 'T': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpT,
1152 		      "T = Tag current alias and go to next alias."));
1153 		      break;
1154 
1155 	    case ctrl('T'): error(catgets(elm_msg_cat, AliasesSet, AliasesHelpCtrlT,
1156 	    "^T = Tag aliases matching specified pattern."));
1157 		      break;
1158 
1159 	    case 'u': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpu,
1160 	    "u = Unmark the current alias for deletion from alias database."));
1161 		      break;
1162 
1163 	    case ctrl('U'): error(catgets(elm_msg_cat, AliasesSet, AliasesHelpCtrlU,
1164 "^U = Mark for undeletion user aliases matching specified pattern."));
1165 		      break;
1166 
1167 	    case 'x':
1168 	    case 'X': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpX,
1169 	    "x = Exit from alias menu, abandoning any pending deletions."));
1170 	   	      break;
1171 
1172 	    default : error(catgets(elm_msg_cat, AliasesSet, AliasesHelpNoHelp,
1173 			"That key isn't used in this section."));
1174 	   	      break;
1175 	  }
1176 	  lower_prompt(alias_prompt);
1177 	}
1178 
1179 	/* Remove help lines */
1180 	MoveCursor(LINES-3, 0);	CleartoEOS();
1181 	return(redraw);
1182 }
1183 
get_aliases(are_in_aliases)1184 get_aliases(are_in_aliases)
1185 int are_in_aliases;
1186 {
1187 /*
1188  *	Get all the system and user alias info
1189  *
1190  *	If we get this far, we must be needing to re-read from
1191  *	at least one data file.  Unfortunately that means we
1192  *	really need to read both since the aliases may be sorted
1193  *	and all mixed up...  :-(
1194  */
1195 
1196 	char fname[SLEN];
1197 	register int i = -1;
1198 	int dups = 0;
1199 
1200 	curr_alias = 0;
1201 	num_duplicates = 0;
1202 /*
1203  *	Read from user data file if it is open.
1204  */
1205 	if (user_hash != NULL) {
1206 	    dprint(6, (debugfile,
1207 		      "About to read user data file = %d.\n",
1208 	              user_hash->dbz_basef));
1209 	    fseek(user_hash->dbz_basef, 0L, 0);
1210 	    while (get_one_alias(user_hash, curr_alias)) {
1211 		dprint(8, (debugfile, "%d\t%s\t%s\n", curr_alias+1,
1212 				       aliases[curr_alias]->alias,
1213 				       aliases[curr_alias]->address));
1214 
1215 		curr_alias++;
1216 	    }
1217 	}
1218 	num_aliases = curr_alias;		/* Needed for find_alias() */
1219 
1220 /*
1221  *	Read from system data file if it is open.
1222  */
1223 	if (system_hash != NULL) {
1224 	    dprint(6, (debugfile,
1225 		      "About to read system data file = %d.\n",
1226 	              system_hash->dbz_basef));
1227 	    fseek(system_hash->dbz_basef, 0L, 0);
1228 	    while (get_one_alias(system_hash, curr_alias)) {
1229 	    /*
1230 	     *  If an identical user alias is found, we may
1231 	     *  not want to display it, so we had better mark it.
1232 	     */
1233 		if (find_alias(aliases[curr_alias]->alias, USER) >= 0) {
1234 		    setit(aliases[curr_alias]->type, DUPLICATE);
1235 		    dups++;
1236 		    setit(aliases[curr_alias]->status, URGENT);
1237 				    /* Not really, I want the U for User */
1238 		    dprint(6, (debugfile,
1239 			       "System alias %s is same as user alias.\n",
1240 			       aliases[curr_alias]->alias));
1241 		}
1242 		dprint(8, (debugfile, "%d\t%s\t%s\n", curr_alias+1,
1243 				       aliases[curr_alias]->alias,
1244 				       aliases[curr_alias]->address));
1245 
1246 		curr_alias++;
1247 	    }
1248 	    num_duplicates = dups;
1249 	}
1250 	num_aliases = curr_alias - num_duplicates;
1251 
1252 	if (OPMODE_IS_READMODE(opmode) && num_aliases > 0) {
1253 	    curr_alias = 0;
1254 	    sort_aliases((num_aliases+num_duplicates), FALSE, are_in_aliases);
1255 	    curr_alias = 1;
1256 	    if (are_in_aliases) {
1257 	        (void) get_page(curr_alias);
1258 	    }
1259 	}
1260 
1261 }
1262 
get_one_alias(db,current)1263 get_one_alias(db, current)
1264 DBZ *db;
1265 int current;
1266 {
1267 /*
1268  *	Get an alias (name, address, etc.) from the data file
1269  */
1270 
1271 	int new_max;
1272 	register struct alias_rec *a;
1273 
1274 	if ((a = fetch_alias(db, (char *)NULL)) == NULL)
1275 	    return 0;
1276 
1277 	if (current >= max_aliases) {
1278 	    new_max = max_aliases + KLICK;
1279 	    if (max_aliases == 0) {
1280 		aliases = (struct alias_rec **)
1281 		    safe_malloc(new_max * sizeof(struct alias_rec *));
1282 	    } else {
1283 		aliases = (struct alias_rec **) safe_realloc((malloc_t)aliases,
1284 		    new_max * sizeof(struct alias_rec *));
1285 	    }
1286 	    while (max_aliases < new_max)
1287 		aliases[max_aliases++] = NULL;
1288 	}
1289 
1290 	if (aliases[current] != NULL)
1291 	    free((malloc_t)aliases[current]);
1292 	aliases[current] = a;
1293 	return 1;
1294 }
1295 
1296 
main_state()1297 main_state()
1298 {
1299 /*	Save the globals that are shared for both menus
1300  *	so that we can return to the main menu without
1301  *	"tragedy".
1302  */
1303 
1304 	static int alias_last = -1, alias_selected = 0, alias_page = 0;
1305 	static int main_last = -1, main_selected = 0,  main_page = 0;
1306 
1307 	if (inalias) {			/* Restore the settings */
1308 	    alias_last = last_current;
1309 	    alias_selected = selected;
1310 	    alias_page = header_page;
1311 
1312 	    last_current = main_last;
1313 	    selected = main_selected;
1314 	    header_page = main_page;
1315 
1316 	    nls_item = catgets(elm_msg_cat, ElmSet, Elmitem, "message");
1317 	    nls_items = catgets(elm_msg_cat, ElmSet, Elmitems, "messages");
1318 	    nls_Item = catgets(elm_msg_cat, ElmSet, ElmItem, "Message");
1319 	    nls_Items = catgets(elm_msg_cat, ElmSet, ElmItems, "Messages");
1320 	    nls_Prompt = catgets(elm_msg_cat, ElmSet, ElmPrompt, "Command: ");
1321 
1322 	    (void) define_softkeys(SOFTKEYS_MAIN);
1323 
1324 	    dprint(3, (debugfile, "Leaving alias mode\n"));
1325 	    inalias = FALSE;
1326 	}
1327 	else {
1328 	    main_last = last_current;
1329 	    main_selected = selected;
1330 	    main_page = header_page;
1331 
1332 	    last_current = alias_last;
1333 	    selected = alias_selected;
1334 	    header_page = alias_page;
1335 
1336 	    nls_item = catgets(elm_msg_cat, AliasesSet, Aliasesitem, "alias");
1337 	    nls_items = catgets(elm_msg_cat, AliasesSet, Aliasesitems, "aliases");
1338 	    nls_Item = catgets(elm_msg_cat, AliasesSet, AliasesItem, "Alias");
1339 	    nls_Items = catgets(elm_msg_cat, AliasesSet, AliasesItems, "Aliases");
1340 	    nls_Prompt = catgets(elm_msg_cat, AliasesSet, AliasesPrompt, "Alias: ");
1341 
1342 	    (void) define_softkeys(SOFTKEYS_ALIAS);
1343 
1344 	    dprint(3, (debugfile, "Entered alias mode\n"));
1345 	    inalias = TRUE;
1346 	}
1347 }
1348 
1349 int
parse_aliases(buffer,remainder)1350 parse_aliases(buffer, remainder)
1351 char *buffer, *remainder;
1352 {
1353 /*
1354  *	This routine will parse out the individual aliases present
1355  *	on the line passed in buffer.  This involves:
1356  *
1357  *	1. Testing for an '=' to make sure this is an alias entry.
1358  *
1359  *	2. Setting remainder to point to the rest of the line starting
1360  *	   at the '=' (for later rewriting if needed).
1361  *
1362  *	3. Parsing the aliases into an string padded with ',' at
1363  *	   the end.
1364  *
1365  *	4. Returning the number of aliases found (0 if test #1 fails).
1366  */
1367 
1368 	char *s;
1369 	int number;
1370 
1371 /*	Check to see if an alias */
1372 
1373 	if ((s = index(buffer, (int)'=')) == NULL)
1374 	  return (0);
1375 
1376 	strcpy(remainder, s);		/* Save the remainder of the line */
1377 
1378 /*	Terminate the list of aliases with a ',' */
1379 
1380 	while (--s >= buffer && whitespace(*s)) ;
1381 	*++s = ',';
1382 	*++s = '\0';
1383 
1384 /*	Lowercase everything */
1385 
1386 	s = shift_lower(buffer);
1387 	strcpy(buffer, s);
1388 
1389 /*	Now, count the aliases */
1390 
1391 	number = 0;
1392 	for (s = buffer; *s; s++)
1393 	  if (*s == ',')
1394 	    number++;
1395 
1396 	return (number);
1397 }
1398 
1399 int
get_aliasname(aliasname,buffer,duplicate)1400 get_aliasname(aliasname, buffer, duplicate)
1401 char *aliasname, *buffer;
1402 int *duplicate;
1403 {
1404 
1405 /*
1406  *	Have the user enter an aliasname, check to see if it
1407  *	is legal, then check for duplicates.  If a duplicate
1408  *	is found offer to replace existing alias.
1409  *
1410  *	Return values:
1411  *
1412  *	-1	Either the aliasname was zero length, had bad
1413  *		characters and was a duplicate which the user
1414  *		chose not to replace.
1415  *
1416  *	0	A new alias was entered successfully.
1417  *
1418  *	1	The entered alias was an existing USER alias
1419  *		that the user has chosen to replace.  In this
1420  *		case the alias to replace is passed back in
1421  *		in the variable 'duplicate'.
1422  */
1423 
1424 	int loc;
1425 
1426 	do {
1427 	    if (enter_string(aliasname, SLEN,
1428 				LINES-2, strlen(buffer), ESTR_REPLACE) < 0
1429 			|| aliasname[0] == '\0')
1430 	        return(-1);
1431 	} while (check_alias(aliasname) == -1);
1432 
1433 	clear_error();			/* Just in case */
1434 /*
1435  *	Check to see if there is already a USER alias by this name.
1436  */
1437 	if ((loc = find_alias(aliasname, USER)) >= 0) {
1438 	    dprint(3, (debugfile,
1439 	         "Attempt to add a duplicate alias [%s] in get_aliasname\n",
1440 	         aliases[loc]->alias));
1441 	    if (aliases[loc]->type & GROUP )
1442 	        PutLine1(LINES-2,0, catgets(elm_msg_cat,
1443 	                AliasesSet, AliasesAlreadyGroup,
1444 	                "Already a group with name %s."), aliases[loc]->alias);
1445 	    else
1446 	        PutLine1(LINES-2,0, catgets(elm_msg_cat,
1447 	                AliasesSet, AliasesAlreadyAlias,
1448 	                "Already an alias for %s."), aliases[loc]->alias);
1449 	    CleartoEOLN();
1450 	 /*
1451 	  * If they don't want to replace the alias by that name
1452 	  * then just return.
1453 	  */
1454 	    if (!enter_yn(catgets(elm_msg_cat, AliasesSet,
1455 			AliasesReplaceExisting,
1456 			"Replace existing alias?"), FALSE, LINES-3, FALSE))
1457 	        return(-1);
1458 	    *duplicate = loc;
1459 	    return(1);
1460 	}
1461 /*
1462  *	If they have elected to replace an existing alias then
1463  *	we assume that they would also elect to superceed a
1464  *	system alias by that name (since they have already
1465  *	done so).  So we don't even bother to check or ask.
1466  *
1467  *	Of course we do check if there was no USER alias match.
1468  */
1469 	if ((loc = find_alias(aliasname, SYSTEM)) >= 0) {
1470 	    dprint(3, (debugfile,
1471 	      "Attempt to add a duplicate system alias [%s] in get_aliasname\n",
1472 	      aliases[loc]->address));
1473 
1474 	    if( ! superceed_system(loc, buffer))
1475 	        return(-1);
1476 	}
1477 	return(0);
1478 
1479 }
1480 
1481 int
superceed_system(this_alias,buffer)1482 superceed_system(this_alias, buffer)
1483 int this_alias;
1484 char *buffer;
1485 {
1486 
1487 	PutLine2(LINES-2, 0, catgets(elm_msg_cat,
1488 	        AliasesSet, AliasesSystemAlias, "System (%6s) alias for %s."),
1489 	    alias_type(aliases[this_alias]->type), aliases[this_alias]->alias);
1490 /*
1491  *	If they don't want to superceed the SYSTEM alias then
1492  *	return a FALSE.
1493  */
1494 	return enter_yn(catgets(elm_msg_cat, AliasesSet, AliasesSuperceed,
1495 	        "Superceed?"), FALSE, LINES-3, FALSE);
1496 }
1497 
1498 void
get_realnames(aliasname,firstname,lastname,comment,buffer)1499 get_realnames(aliasname, firstname, lastname, comment, buffer)
1500 char *aliasname, *firstname, *lastname, *comment, *buffer;
1501 {
1502 	/* FOO - this is not handling enter_string() aborts properly */
1503 
1504 	sprintf(buffer, catgets(elm_msg_cat, AliasesSet, AliasesEnterLastName,
1505 		"Enter last name for %s: "), aliasname);
1506 	PutLine0(LINES-2, 0, buffer);
1507 	enter_string(lastname, SLEN, -1, -1, ESTR_REPLACE);
1508 
1509 	sprintf(buffer, catgets(elm_msg_cat, AliasesSet, AliasesEnterFirstName,
1510 		"Enter first name for %s: "), aliasname);
1511 	PutLine0(LINES-2, 0, buffer);
1512 	enter_string(firstname, SLEN, -1, -1, ESTR_REPLACE);
1513 
1514 	if (strlen(lastname) == 0) {
1515 	    if (strlen(firstname) == 0) {
1516 	        strcpy(lastname, aliasname);
1517 	    }
1518 	    else {
1519 	        strcpy(lastname, firstname);
1520 	        *firstname = '\0';
1521 	    }
1522 	}
1523 
1524 	sprintf(buffer, catgets(elm_msg_cat, AliasesSet, AliasesEnterComment,
1525 		"Enter optional comment for %s: "), aliasname);
1526 	PutLine0(LINES-2, 0, buffer);
1527 	enter_string(comment, SLEN, -1, -1, ESTR_REPLACE);
1528 
1529 }
1530 
1531 int
ask_accept(aliasname,firstname,lastname,comment,address,buffer,replace,replacement)1532 ask_accept(aliasname, firstname, lastname, comment, address, buffer,
1533 	replace, replacement)
1534 char *aliasname, *firstname, *lastname, *comment, *address, *buffer;
1535 int replace, replacement;
1536 {
1537 
1538 	int ans;
1539 	char *(old_alias[1]);
1540 /*
1541  *	If firstname == lastname, they probably just took all
1542  *	the deafaults.  We *assume* they don't want lastname
1543  *	entered twice, so we will truncate it.
1544  */
1545 	if (strcmp(firstname, lastname) == 0) {
1546 	    *firstname = '\0';
1547 	}
1548 
1549 	if (strlen(firstname) == 0) {
1550 	    strcpy(buffer, lastname);
1551 	}
1552 	else {
1553 	    sprintf(buffer, "%s %s", firstname, lastname);
1554 	}
1555 	PutLine2(LINES-1,0, catgets(elm_msg_cat, AliasesSet, AliasesAddressAs,
1556 	        "Messages addressed as: %s (%s)"), address, buffer);
1557 	if (strlen(comment) != 0) {
1558 	    strcat(buffer, ", ");
1559 	    strcat(buffer, comment);
1560 	}
1561 
1562 	PutLine2(LINES-2,0, catgets(elm_msg_cat, AliasesSet, AliasesAddressTo,
1563 	        "New alias: %s is '%s'."), aliasname, buffer);
1564 	CleartoEOLN();
1565 /*
1566  *	Kludge Alert:  Spaces are padded to the front of the prompt
1567  *	to write over the previous question.  Should probably record
1568  *	the end of the line, move to it, and CleartoEOLN() it.
1569  */
1570 	ans = enter_yn(catgets(elm_msg_cat, AliasesSet, AliasesAcceptNew,
1571 		"      Accept new alias?"), TRUE, LINES-3, FALSE);
1572 	if(ans) {
1573 	    if (replace) {
1574 	        old_alias[0] = aliases[replacement]->alias;
1575 	    /*
1576 	     *  First, clear flag if this is marked to be deleted.
1577 	     *  This prevents the problem where they marked it for
1578 	     *  deletion and then figured out that it could be
1579 	     *  c)hanged but didn't explicitly U)ndelete it.  Without
1580 	     *  this test, the resync action would then delete
1581 	     *  the new alias we just so carefully added to the
1582 	     *  text file.
1583 	     */
1584 	        if (ison(aliases[replacement]->status, DELETED)) {
1585 	            clearit(aliases[replacement]->status, DELETED);
1586 	        }
1587 	    /*
1588 	     *  Changed aliases are given the NEW flag.
1589 	     */
1590 	        setit(aliases[replacement]->status, NEW);
1591 	        show_msg_status(replacement);
1592 	    /*
1593 	     *  Now we can delete it...
1594 	     */
1595 	        delete_from_alias_text(old_alias, 1);
1596 	    /*
1597 	     *  Kludge Alert:  We need to get the trailing comma
1598 	     *  (added in delete_from_alias_text()) off of the
1599 	     *  alias since the display won't be re-sync'd right
1600 	     *  away.
1601 	     */
1602 	        *((old_alias[0])+strlen(old_alias[0])-1) = '\0';
1603 	    }
1604 	    add_to_alias_text(aliasname, firstname, lastname, comment, address);
1605 	}
1606 	ClearLine(LINES-2);
1607 	ClearLine(LINES-1);
1608 	return ans;
1609 }
1610 
1611 /* Check whether an address is aliased; if so return the alias, otherwise
1612  * return NULL. */
address_to_alias(address)1613 char *address_to_alias(address)
1614 char *address;
1615 {
1616 	int i;
1617 	char return_address[SLEN];
1618 
1619 	(void) open_alias_files(FALSE);
1620 
1621 	get_return_address(address, return_address);
1622 
1623 	for (i = 0; i < num_aliases; i++) {
1624 	    if (istrcmp(return_address, aliases[i]->address) == 0)
1625 		return aliases[i]->alias;
1626 	}
1627 	return NULL;
1628 }
1629