This is alias.c in view mode; [Download] [Up]
static char rcsid[] = "@(#)$Id: alias.c,v 5.17 1992/12/13 17:59:18 syd Exp $";
/*******************************************************************************
* The Elm Mail System - $Revision: 5.17 $ $State: Exp $
*
* Copyright (c) 1988-1992 USENET Community Trust
* Copyright (c) 1986,1987 Dave Taylor
*******************************************************************************
* Bug reports, patches, comments, suggestions should be sent to:
*
* Syd Weinstein, Elm Coordinator
* elm@DSI.COM dsinc!elm
*
*******************************************************************************
* $Log: alias.c,v $
* Revision 5.17 1992/12/13 17:59:18 syd
* Please write on the blackboard 500 times `NULL != 0.'
* From: chip@chinacat.unicom.com (Chip Rosenthal)
*
* Revision 5.16 1992/12/11 02:09:06 syd
* Fix where the user creates a first new alias, then deletes it, the
* alias stays on screen, but the file really will be empty if it was the
* last alias, so the retry to delete gives 'cannot open ...file' messages
* From: "Robert L. Howard" <robert.howard@matd.gatech.edu>
*
* Revision 5.15 1992/12/11 01:58:22 syd
* Anytime elm wants to re-run newalias, selected is set to 0.
* (removing any limit in effect)
* From: "Robert L. Howard" <robert.howard@matd.gatech.edu>
*
* Revision 5.14 1992/12/11 01:45:04 syd
* remove sys/types.h include, it is now included by defs.h
* and this routine includes defs.h or indirectly includes defs.h
* From: Syd
*
* Revision 5.13 1992/12/07 03:02:03 syd
* On machines with 64 bit pointers (and 64 bit longs) using int
* for newmax causes pointer truncation.
* From: Jim Brown
*
* Revision 5.12 1992/11/26 00:46:50 syd
* Fix how errno is used so err is inited and used instead
* as errno gets overwritten by print system call
* From: Syd
*
* Revision 5.11 1992/11/15 01:24:34 syd
* The situation is that the .elm/aliases file is missing, but
* .elm/aliases.dir and .elm/aliases.pag exist (isn't serendipity
* wonderful?). The ndbz functions tolerate this and just put a NULL
* pointer in the db structure for the data file FILE pointer. However,
* get_one_alias() in listalias and elm doesn't account for the db_open()
* succeeding but the dbz_basef field being NULL, so it passes the NULL
* pointer to fread(). Detect null and return 0
* From: dwolfe@pffft.sps.mot.com (Dave Wolfe)
*
* Revision 5.10 1992/11/15 01:15:28 syd
* The alias message_count isn't set to zero if the last alias has
* been deleted from the alias table. As no aliases are reread from
* the aliases database the message_count is left as it was before.
*
* Fixed that the function do_newalias() sometimes returns without freeing
* the buffer allocated before. The patch adds these free calls.
*
* When you erroneously type a number in your folder elm asks you for
* a new current message number. But now if you erase this one number
* and leave the string empty elm will set the new current message to
* the second message on our sun4! The patch adds a check for an empty
* string and returns the current number if no number was entered.
* From: vogt@isa.de (Gerald Vogt)
*
* Revision 5.9 1992/10/24 13:35:39 syd
* changes found by using codecenter on Elm 2.4.3
* From: Graham Hudspith <gwh@inmos.co.uk>
*
* Revision 5.8 1992/10/19 16:58:18 syd
* more on the update of compiler warnings
* From: Syd
*
* Revision 5.7 1992/10/19 16:50:41 syd
* Fix a couple more compiler gripes from SYSVR4
* From: Tom Moore <tmoore@wnas.DaytonOH.NCR.COM>
*
* Revision 5.6 1992/10/17 22:47:09 syd
* adds the function bytemap() and the macros MAPIN and MAPOUT from the file
* lib/ndbz.c in the file src/alias.c.
*
* prevent elm from exiting when resyncing the empty incoming mailbox.
* From: vogt@isa.de (Gerald Vogt)
*
* Revision 5.5 1992/10/11 01:46:35 syd
* change dbm name to dbz to avoid conflicts with partial call
* ins from shared librarys, and from mixing code with yp code.
* From: Syd via prompt from Jess Anderson
*
* Revision 5.4 1992/10/11 01:21:17 syd
* 1. If firstname && lastname is null then copy aliasname into the
* personal name field (inside the ()'s) when creating an alias
* from the menu using the 'n' command.
*
* 2. Now if for some reason and alias has a null personal name field
* (the person hand edited aliases.text) the blank () is not printed
* as part of the address. This actually cured another problem, where
* the To: field on the screen (when you hit 'm' on the alias menu)
* used to be blank, now the address shows up....
* From: "Robert L. Howard" <robert.howard@matd.gatech.edu>
*
* Revision 5.3 1992/10/11 01:07:52 syd
* get_return() assumes that message_count reflects the number of
* messages in the current folder, but the message_count it's seeing
* from the alias subsystem is actually the *alias* count.
* toggle the main state before and after calling get_return().
* From: cliff@sfn.ORG (R. Cliff Young)
*
* Revision 5.2 1992/10/11 00:59:39 syd
* Fix some compiler warnings that I receive compiling Elm on my SVR4
* machine.
* From: Tom Moore <tmoore@fievel.DaytonOH.NCR.COM>
*
* Revision 5.1 1992/10/03 22:58:40 syd
* Initial checkin as of 2.4 Release at PL0
*
*
******************************************************************************/
/** This file contains alias stuff
**/
#include "headers.h"
#include "s_elm.h"
#include <errno.h>
#include <ctype.h>
#include <sys/stat.h>
#include "s_aliases.h"
#include "ndbz.h"
#ifdef BSD
#undef tolower
#endif
#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(), *get_alias_address();
char *error_description(), *get_parens();
void get_realnames();
int is_system=0; /* system file updating? */
extern int errno;
int current_mail_message;
int num_duplicates;
DBZ *system_hash = NULL, *user_hash = NULL;
char *a_rev_alias_pad, *a_rev_alias_abr, *a_rev_alias_name,
*a_rev_full_pad, *a_full_abr, *a_rev_full_name,
*a_rev_text_pad, *a_text_abr, *a_rev_text_file,
*a_alias_pad, *a_alias_abr, *a_alias_name,
*a_full_pad, *a_full_name,
*a_text_pad, *a_text_file,
*a_group_name, *a_person_name, *a_system_flag;
int
ok_alias_name(name)
char *name;
{
while ( *name != '\0' && ok_alias_char(*name) )
++name;
return ( *name == '\0' );
}
open_alias_files()
{
static int first_time = TRUE;
/*
* Close and re-open the system and user alias files, if present,
* and if they have changed since last we opened them.
*
* Also, parse the data files into memory if needed
*/
if (first_time) {
a_group_name = catgets(elm_msg_cat, AliasesSet, AliasesGroup,
" Group");
a_person_name = catgets(elm_msg_cat, AliasesSet, AliasesPerson,
"Person");
a_system_flag = catgets(elm_msg_cat, AliasesSet, AliasesSystemFlag,
"(S)");
a_rev_alias_pad = catgets(elm_msg_cat, AliasesSet, AliasesRevAliasPad,
"Reverse Alias Name ");
a_rev_alias_abr = catgets(elm_msg_cat, AliasesSet, AliasesRevAliasAbr,
"Reverse-Alias");
a_rev_alias_name = catgets(elm_msg_cat, AliasesSet, AliasesRevAliasName,
"Reverse Alias Name");
a_rev_full_pad = catgets(elm_msg_cat, AliasesSet, AliasesRevFullPad,
"Reverse Full (Real) Name");
a_full_abr = catgets(elm_msg_cat, AliasesSet, AliasesRevFullAbr,
"Reverse-Name");
a_rev_full_name = catgets(elm_msg_cat, AliasesSet, AliasesRevFullName,
"Reverse Full (Real) Name");
a_rev_text_pad = catgets(elm_msg_cat, AliasesSet, AliasesRevTextPad,
"Reverse Text File ");
a_text_abr = catgets(elm_msg_cat, AliasesSet, AliasesRevTextAbr,
"Reverse-Text");
a_rev_text_file = catgets(elm_msg_cat, AliasesSet, AliasesRevTextFile,
"Reverse Text File");
a_alias_pad = catgets(elm_msg_cat, AliasesSet, AliasesAliasPad,
"Alias Name ");
a_alias_abr = catgets(elm_msg_cat, AliasesSet, AliasesAliasAbr,
"Alias");
a_alias_name = catgets(elm_msg_cat, AliasesSet, AliasesAliasName,
"Alias Name");
a_full_pad = catgets(elm_msg_cat, AliasesSet, AliasesFullPad,
"Full (Real) Name ");
a_full_abr = catgets(elm_msg_cat, AliasesSet, AliasesFullAbr,
"Name");
a_full_name = catgets(elm_msg_cat, AliasesSet, AliasesFullName,
"Full (Real) Name");
a_text_pad = catgets(elm_msg_cat, AliasesSet, AliasesTextPad,
"Text File ");
a_text_abr = catgets(elm_msg_cat, AliasesSet, AliasesTextAbr,
"Text");
a_text_file = catgets(elm_msg_cat, AliasesSet, AliasesTextFile,
"Text File");
first_time = FALSE;
}
if(open_system_aliases() | open_user_aliases()) {
dprint(5, (debugfile,
"Reading alias data files...\n"));
get_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", 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()
{
/*
* 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.
*/
int i, leftoff, tagged = 0;
char aliasname[SLEN], firstname[SLEN], lastname[SLEN];
char address1[LONG_STRING], buffer[SLEN];
char comment[LONG_STRING], ch;
/*
* See if there are any tagged aliases.
*/
for (i=0; i < message_count; 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();
MCsprintf(buffer, catgets(elm_msg_cat,
AliasesSet, AliasesCreateGroup,
"Create group alias? (%c/%c) "),
*def_ans_yes, *def_ans_no);
ch = want_to(buffer, *def_ans_no);
}
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();
MCsprintf(buffer, catgets(elm_msg_cat,
AliasesSet, AliasesCreateGroup,
"Create group alias? (%c/%c) "),
*def_ans_yes, *def_ans_no);
ch = want_to(buffer, *def_ans_yes);
}
/*
* Create the group alias. This is (hopefully) only
* done if one of the above want_to() questions were
* answered YES (and thus there *were* tagged messages
* and the user responded correctly).
*/
if (ch == *def_ans_yes) {
strcpy(address1, aliases[leftoff]->alias);
clearit(aliases[leftoff]->status, TAGGED);
show_msg_tag(leftoff);
for (i=leftoff+1; i < message_count; i++) {
if (ison(aliases[i]->status, TAGGED)) {
strcat(address1, ",");
strcat(address1, aliases[i]->alias);
clearit(aliases[i]->status, TAGGED);
show_msg_tag(i);
}
}
}
strcpy(buffer, catgets(elm_msg_cat,
AliasesSet, AliasesEnterAliasName, "Enter alias name: "));
PutLine0(LINES-2,0, buffer);
CleartoEOLN();
*aliasname = '\0';
if (get_aliasname(aliasname, buffer) != 0) {
dprint(3, (debugfile,
"Aliasname [%s] was rejected in add_alias\n", aliasname));
ClearLine(LINES-2);
return(0);
}
*lastname = '\0';
*firstname = '\0';
*comment = '\0';
get_realnames(aliasname, firstname, lastname, comment, buffer);
if ((tagged == 0) || (ch == *def_ans_no)) {
sprintf(buffer, catgets(elm_msg_cat,
AliasesSet, AliasesEnterAddress,
"Enter address for %s: "), aliasname);
PutLine0(LINES-2,0, buffer);
CleartoEOLN();
*address1 = '\0';
optionally_enter(address1, LINES-2, strlen(buffer), FALSE, FALSE);
Raw(ON);
if (strlen(address1) == 0) {
error(catgets(elm_msg_cat, AliasesSet, AliasesNoAddressSpec,
"No address specified!"));
return(0);
}
}
return(ask_accept(aliasname, firstname, lastname, comment, address1,
buffer));
}
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;
if (current_mail_message == 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 = headers[current_mail_message - 1];
strcpy(buffer, catgets(elm_msg_cat, AliasesSet, AliasesCurrentMessage,
"Current message address aliased to: "));
PutLine0(LINES-2,0, buffer);
CleartoEOLN();
*aliasname = '\0';
if (get_aliasname(aliasname, buffer) != 0) {
dprint(3, (debugfile,
"Aliasname [%s] was rejected in add_current_alias\n",
aliasname));
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 == SPACE) bufptr++; /* Always strip leading WS */
if ((chspace = index(bufptr, (int) SPACE)) != NULL) {
/*
* A space means that there is at least (firstname lastname)
* Get firstname and move bufptr.
*/
*chspace = '\0';
strcpy(firstname, bufptr);
bufptr = chspace + 1; /* Move the pointer */
while (*bufptr == SPACE) bufptr++;
}
above: if ((chspace = index(bufptr, (int) SPACE)) != NULL) {
/*
* Another space means a third+ word. We either have:
* 1. Word 3+ is a comment, or
* 2. Word 2 is a middle initial (word 3 is lastname).
* Check and see.
*/
*chspace = '\0';
if ((strlen(bufptr) == 1) ||
(strlen(bufptr) == 2 && *(bufptr+1) == '.')) {
/*
* If the second word is either a single
* character or a character followed by '.' it was
* probably a middle initial. Add it to firstname
* and shift.
*/
strcat(firstname, " ");
strcat(firstname, bufptr);
bufptr = chspace + 1; /* Move the pointer */
while (*bufptr == SPACE) bufptr++;
goto above;
}
strcpy(lastname, bufptr);
bufptr = chspace + 1; /* Move the pointer */
while (*bufptr == SPACE) 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 */
main_state(); /* toggle main state so that message_count is right */
get_return(address1, current_mail_message-1);
main_state(); /* toggle main state back to alias mode */
strcpy(address1, strip_parens(address1)); /* remove parens! */
return(ask_accept(aliasname, firstname, lastname, comment, address1,
buffer));
}
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", 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", error_description(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", error_description(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", home, ALIAS_TEXT);
sprintf(tmpfname,"%s/%s.t", 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", error_description(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", error_description(err)));
error1(catgets(elm_msg_cat, AliasesSet, AliasesCouldntOpenTemp,
"Couldn't open tempfile %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])) != NULL) {
/*
* 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", error_description(err)));
error1(catgets(elm_msg_cat, AliasesSet, AliasesCouldntWriteTemp,
"Couldn't write to tempfile %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 tempfile %s after deleting alias!"), tmpfname);
return(1);
}
restore_file_stats(fname);
return(0);
}
alias()
{
/*
* Work with alias commands...
*/
char name[NLEN], *address, ch, buffer[SLEN];
char *commap;
int key_offset; /** Position offset within keyboard string **/
static int newaliases = 0;
int i, j;
/*
* 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(); /* First, read the alias files. RLH */
alias_screen();
define_softkeys(ALIAS);
while (1) {
#ifdef SIGWINCH
if (resize_screen) {
int newLINES, newCOLUMNS;
ScreenSize(&newLINES, &newCOLUMNS);
resize_screen = 0;
if (newLINES != LINES || newCOLUMNS != COLUMNS) {
LINES = newLINES, COLUMNS = newCOLUMNS;
#define max(a,b) ((a) < (b) ? (b) : (a))
if (mini_menu)
headers_per_page = max (LINES - 13, 1);
else
headers_per_page = max (LINES - 8, 1); /* 5 more headers! */
#undef max
redraw++;
}
}
else redraw = 0;
#else
redraw = 0;
#endif
nucurr = 0;
nufoot = 0;
prompt(Prompt);
CleartoEOLN();
ch = ReadCh();
MoveCursor(LINES-3,strlen(Prompt)); CleartoEOS();
dprint(3, (debugfile, "\n-- Alias command: %c\n\n", ch));
switch (ch) {
case '?': redraw += alias_help(); break;
case '$': PutLine0(LINES-3, strlen(Prompt),
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(LINES-3, strlen(Prompt),
catgets(elm_msg_cat, AliasesSet, AliasesAddCurrent,
"Add address from current message..."));
clear_error();
newaliases += add_current_alias(); break;
case 'e': PutLine1(LINES-3, strlen(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 (current > 0) {
edit_aliases_text();
if (cursor_control) {
transmit_functions(ON); /* insurance */
}
newaliases = 0;
redraw++;
}
else {
/*
* Here we don't allow editing when there are no
* aliases (and thus no aliases.text file). I
* suppose we could create one from scratch but
* you just can't do everything...
*/
error(catgets(elm_msg_cat, AliasesSet,
AliasesNoneToEdit, "No aliases to edit!"));
fflush(stdin);
}
break;
case 'm':
if (current > 0) {
PutLine0(LINES-3, strlen(Prompt),
catgets(elm_msg_cat, AliasesSet, AliasesMail,
"Mail..."));
redraw += a_sendmsg(TRUE,allow_forms);
}
else {
error(catgets(elm_msg_cat,
AliasesSet, AliasesNoneToMail,
"Warning: no aliases to send mail to!"));
}
break;
case 'n': PutLine0(LINES-3, strlen(Prompt),
catgets(elm_msg_cat, AliasesSet, AliasesAddNew,
"Add a new alias to database..."));
clear_error();
newaliases += add_alias(); break;
case 'q':
case 'Q':
case 'i':
case 'r':
case 'R': PutLine0(LINES-3, strlen(Prompt),
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 SPACE:
case 'v':
if (newaliases) { /* Need this ?? */
error(catgets(elm_msg_cat,
AliasesSet, AliasesNotInstalled,
"Warning: new aliases not installed yet!"));
}
if (current > 0) {
if (aliases[current-1]->type & GROUP) {
PutLine1(LINES-1, 0, catgets(elm_msg_cat,
AliasesSet, AliasesGroupAlias,
"Group alias: %-60.60s"),
aliases[current-1]->address);
}
else {
PutLine1(LINES-1, 0, catgets(elm_msg_cat,
AliasesSet, AliasesAliasedAddress,
"Aliased address: %-60.60s"),
aliases[current-1]->address);
}
}
else {
error(catgets(elm_msg_cat,
AliasesSet, AliasesNoneToView,
"Warning: no aliases to view!"));
}
break;
case 'x':
case 'X': PutLine0(LINES-3, strlen(Prompt),
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 (current > 0) {
strcpy(name, aliases[current-1]->alias);
if (ch == 'F') {
strcpy(buffer, catgets(elm_msg_cat,
AliasesSet, AliasesFullyExpanded,
"Fully expand alias: "));
PutLine0(LINES-2,0, buffer);
CleartoEOS();
optionally_enter(name, LINES-2, strlen(buffer),
FALSE, FALSE);
}
address = get_alias_address(name, TRUE);
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) getchar();
if (commap == NULL) {
redraw++;
break;
}
}
}
else {
error(catgets(elm_msg_cat,
AliasesSet, AliasesNotFound,
"Not found."));
}
}
else {
error(catgets(elm_msg_cat,
AliasesSet, AliasesNoneToView,
"Warning: no aliases to view!"));
}
break;
/*
* None of the menu specific commands were chosen, therefore
* it must be a "motion" command (or an error).
*/
default : motion(ch);
}
if (redraw) /* Redraw screen if necessary */
alias_screen();
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... */
}
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..."));
sleep(2);
sprintf(itextfile, "%s/%s", home, ALIAS_TEXT);
sprintf(odatafile, "%s/%s", 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);
sleep(2);
open_alias_files();
set_error(catgets(elm_msg_cat, AliasesSet, AliasesUpdatedOK,
"Aliases updated successfully."));
}
else {
/*
* All we need to do is sleep so the user can read the
* message that was put to the screen by the do_newalias()
* call.
*/
message_count = 0;
sleep(2);
}
}
alias_help()
{
/*
* Help section for the alias menu...
*
* Return non-0 if main part of screen overwritten, else 0
*/
char 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()) != '.') {
ch = tolower(ch);
switch(ch) {
case '?' : display_helpfile(ALIAS_HELP);
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 SPACE:
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 '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,
"i = Return from alias menu (with prompting)."));
break;
case 'R':
case 'Q': error(catgets(elm_msg_cat, AliasesSet, AliasesHelpQ,
"R = 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 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()
{
/*
* 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;
current = 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));
lseek(user_hash->dbz_basef, 0L, 0);
while (get_one_alias(user_hash, current)) {
dprint(8, (debugfile, "%d\t%s\t%s\n", current+1,
aliases[current]->alias,
aliases[current]->address));
current++;
}
}
message_count = current; /* 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, current)) {
/* If an identical user alias is found, we may
* not want to display it, so we had better mark it.
*/
if (find_alias(aliases[current]->alias, USER) >= 0) {
setit(aliases[current]->type, DUPLICATE);
dups++;
setit(aliases[current]->status, URGENT);
/* Not really, I want the U for User */
dprint(6, (debugfile,
"System alias %s is same as user alias.\n",
aliases[current]->alias));
}
dprint(8, (debugfile, "%d\t%s\t%s\n", current+1,
aliases[current]->alias,
aliases[current]->address));
current++;
}
num_duplicates = dups;
}
message_count = current - num_duplicates;
if (!mail_only && !check_only && message_count) {
current = 0;
sort_aliases((message_count+num_duplicates), FALSE);
current = 1;
(void) get_page(current);
}
}
/* byte-ordering stuff */
#define MAPIN(o) ((db->dbz_bytesame) ? (of_t) (o) : bytemap((of_t)(o), db->dbz_conf.bytemap, db->dbz_mybmap))
#define MAPOUT(o) ((db->dbz_bytesame) ? (of_t) (o) : bytemap((of_t)(o), db->dbz_mybmap, db->dbz_conf.bytemap))
static of_t /* transformed result */
bytemap(ino, map1, map2)
of_t ino;
int *map1;
int *map2;
{
union oc {
of_t o;
char c[SOF];
};
union oc in;
union oc out;
register int i;
in.o = ino;
for (i = 0; i < SOF; i++)
out.c[map2[i]] = in.c[map1[i]];
return(out.o);
}
get_one_alias(db, current)
DBZ *db;
int current;
{
/*
* Get an alias (name, address, etc.) from the data file
*/
long new_max;
register struct alias_rec **new_aliases, *a;
struct alias_rec ar;
FILE *data_file = db->dbz_basef;
if (data_file == NULL)
return(0); /* no alias file, but hash exists, error condition */
if (fread((char *) &ar, sizeof(ar), 1, data_file) <= 0)
return(0);
if (current >= max_aliases) {
new_max = max_aliases + KLICK;
if (max_aliases == 0)
new_aliases = (struct alias_rec **)
malloc(new_max * sizeof(struct alias_rec *));
else
new_aliases = (struct alias_rec **)
realloc((char *) aliases,
new_max * sizeof(struct alias_rec *));
if (new_aliases == NULL) {
error1(catgets(elm_msg_cat, AliasesSet, AliasesErrorMemory,
"\n\r\n\rCouldn't allocate enough memory! Alias #%d.\n\r\n\r"),
current);
return(0);
}
aliases = new_aliases;
while (max_aliases < new_max)
aliases[max_aliases++] = NULL;
}
if (aliases[current] != NULL) {
free((char *) aliases[current]);
aliases[current] = NULL;
}
ar.status = (int) MAPIN(ar.status);
ar.alias = (char *) MAPIN(ar.alias);
ar.last_name = (char *) MAPIN(ar.last_name);
ar.name = (char *) MAPIN(ar.name);
ar.comment = (char *) MAPIN(ar.comment);
ar.address = (char *) MAPIN(ar.address);
ar.type = (int) MAPIN(ar.type);
ar.length = (long) MAPIN(ar.length);
if ((a = (struct alias_rec *)
malloc(sizeof(ar) + ar.length)) == NULL) {
error1(catgets(elm_msg_cat, AliasesSet, AliasesErrorMemory,
"\n\r\n\rCouldn't allocate enough memory! Alias #%d.\n\r\n\r"),
current);
return(0);
}
aliases[current] = a;
fread((char *) (a + 1), ar.length, 1, data_file);
*a = ar;
new_max = (long) (a + 1);
a->alias += new_max;
a->last_name += new_max;
a->name += new_max;
a->comment += new_max;
a->address += new_max;
a->length = current;
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_count = 0, alias_current = 0, alias_last = -1,
alias_selected = 0, alias_page = 0;
static int main_count = 0, main_current = 0, main_last = -1,
main_selected = 0, main_page = 0;
if (inalias) { /* Restore the settings */
alias_count = message_count;
alias_current = current;
alias_last = last_current;
alias_selected = selected;
alias_page = header_page;
message_count = main_count;
current = main_current;
last_current = main_last;
selected = main_selected;
header_page = main_page;
strcpy(item, catgets(elm_msg_cat, ElmSet, Elmitem, "message"));
strcpy(items, catgets(elm_msg_cat, ElmSet, Elmitems, "messages"));
strcpy(Item, catgets(elm_msg_cat, ElmSet, ElmItem, "Message"));
strcpy(Items, catgets(elm_msg_cat, ElmSet, ElmItems, "Messages"));
strcpy(Prompt, catgets(elm_msg_cat, ElmSet, ElmPrompt, "Command: "));
dprint(3, (debugfile, "Leaving alias mode\n"));
inalias = FALSE;
}
else {
main_count = message_count;
main_current = current;
current_mail_message = current;
main_last = last_current;
main_selected = selected;
main_page = header_page;
message_count = alias_count;
current = alias_current;
last_current = alias_last;
selected = alias_selected;
header_page = alias_page;
strcpy(item, catgets(elm_msg_cat, AliasesSet, Aliasesitem, "alias"));
strcpy(items, catgets(elm_msg_cat, AliasesSet, Aliasesitems, "aliases"));
strcpy(Item, catgets(elm_msg_cat, AliasesSet, AliasesItem, "Alias"));
strcpy(Items, catgets(elm_msg_cat, AliasesSet, AliasesItems, "Aliases"));
strcpy(Prompt, catgets(elm_msg_cat, AliasesSet, AliasesPrompt, "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';
/* Now, count the aliases */
number = 0;
for (s = buffer; *s; s++)
if (*s == ',')
number++;
return (number);
}
int
get_aliasname(aliasname, buffer)
char *aliasname, *buffer;
{
int loc;
char ch;
optionally_enter(aliasname, LINES-2, strlen(buffer), FALSE, FALSE);
if (strlen(aliasname) == 0)
return(-1);
if ( !ok_alias_name(aliasname) ) {
error1(catgets(elm_msg_cat, AliasesSet, AliasesBadChars,
"Bad character(s) in alias name %s."), aliasname);
return(-1);
}
if ((loc = find_alias(aliasname, USER)) >= 0) {
dprint(3, (debugfile,
"Attempt to add a duplicate alias [%s] in get_aliasname\n",
aliases[loc]->address));
if (aliases[loc]->type & GROUP )
error1(catgets(elm_msg_cat, AliasesSet, AliasesAlreadyGroup,
"Already a group with name %s."), aliases[loc]->alias);
else
error1(catgets(elm_msg_cat, AliasesSet, AliasesAlreadyAlias,
"Already an alias for %s."), aliases[loc]->alias);
return(-1);
}
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));
PutLine2(LINES-2, 0, catgets(elm_msg_cat,
AliasesSet, AliasesSystemAlias,
"System (%6s) alias for %s."),
alias_type(aliases[loc]->type), aliases[loc]->alias);
MCsprintf(buffer, catgets(elm_msg_cat, AliasesSet, AliasesSuperceed,
"Superceed? (%c/%c)"), *def_ans_yes, *def_ans_no);
if ((ch = want_to(buffer, *def_ans_yes)) != *def_ans_yes)
return(-1);
}
return(0);
}
void
get_realnames(aliasname, firstname, lastname, comment, buffer)
char *aliasname, *firstname, *lastname, *comment, *buffer;
{
sprintf(buffer, catgets(elm_msg_cat, AliasesSet, AliasesEnterLastName,
"Enter last name for %s: "), aliasname);
PutLine0(LINES-2,0, buffer);
CleartoEOLN();
optionally_enter(lastname, LINES-2, strlen(buffer), FALSE, FALSE);
sprintf(buffer, catgets(elm_msg_cat, AliasesSet, AliasesEnterFirstName,
"Enter first name for %s: "), aliasname);
PutLine0(LINES-2,0, buffer);
CleartoEOLN();
optionally_enter(firstname, LINES-2, strlen(buffer), FALSE, FALSE);
if ((strlen(lastname) == 0) && (strlen(firstname) == 0)) {
strcpy(lastname, aliasname);
}
sprintf(buffer, catgets(elm_msg_cat, AliasesSet, AliasesEnterComment,
"Enter optional comment for %s: "), aliasname);
PutLine0(LINES-2,0, buffer);
optionally_enter(comment, LINES-2, strlen(buffer), FALSE, FALSE);
}
int
ask_accept(aliasname, firstname, lastname, comment, address, buffer)
char *aliasname, *firstname, *lastname, *comment, *address, *buffer;
{
char ch;
if (strlen(firstname) == 0) {
strcpy(buffer, lastname);
}
else {
sprintf(buffer, "%s %s", firstname, lastname);
}
PutLine3(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);
}
PutLine3(LINES-2,0, catgets(elm_msg_cat, AliasesSet, AliasesAddressTo,
"New alias: %s is '%s'."), aliasname, buffer);
CleartoEOLN();
MCsprintf(buffer, catgets(elm_msg_cat, AliasesSet, AliasesAcceptNew,
" Accept new alias? (%c/%c) "), *def_ans_yes, *def_ans_no);
if((ch = want_to(buffer, *def_ans_yes)) == *def_ans_yes)
add_to_alias_text(aliasname, firstname, lastname, comment, address);
ClearLine(LINES-2);
ClearLine(LINES-1);
return(ch == *def_ans_yes ? 1 : 0);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.