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.