home *** CD-ROM | disk | FTP | other *** search
- Subject: v09i008: ELM Mail System, Part08/19
- Newsgroups: mod.sources
- Approved: rs@mirror.TMC.COM
-
- Submitted by: Dave Taylor <hplabs!taylor>
- Mod.sources: Volume 9, Issue 8
- Archive-name: elm2/Part08
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line,
- # then unpack it by saving it in a file and typing "sh file".
- # If this archive is complete, you will see the message:
- # "End of archive 8 (of 19)."
- # Contents: filter/parse.c src/input_utils.c src/mailmsg1.c
- # src/options.c utils/answer.c
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- echo shar: Extracting \"filter/parse.c\" \(8929 characters\)
- if test -f filter/parse.c ; then
- echo shar: Will not over-write existing file \"filter/parse.c\"
- else
- sed "s/^X//" >filter/parse.c <<'END_OF_filter/parse.c'
- X/** filter_parse.c **/
- X
- X/** This is the parser for the filter program. It accepts a wide variety of
- X constructs, building the ruleset table as it goes along. Check the
- X data structure in filter.h for more information on how the rules are
- X stored. The parser is a cunning state-table based program.
- X
- X (C) Copyright 1986, Dave Taylor
- X**/
- X
- X#include <stdio.h>
- X#include <ctype.h>
- X
- X#include "defs.h"
- X#include "filter.h"
- X
- X#define NONE 0
- X#define AND 10
- X
- X#define NEXT_CONDITION 0
- X#define GETTING_OP 1
- X#define READING_ARGUMENT 2
- X#define READING_ACTION 3
- X#define ACTION_ARGUMENT 4
- X
- Xchar *strtok(), *whatname(), *actionname();
- X
- Xint
- Xget_filter_rules()
- X{
- X /** Given the users home directory, open and parse their rules table,
- X building the data structure as we go along.
- X returns -1 if we hit an error of any sort...
- X **/
- X
- X FILE *fd; /* the file descriptor */
- X char buffer[SLEN], /* fd reading buffer */
- X *str, /* ptr to read string */
- X *word, /* ptr to 'token' */
- X filename[SLEN], /* the name of the ruleset */
- X action_argument[SLEN], /* action arg, per rule */
- X cond_argument[SLEN]; /* cond arg, per condition */
- X int not_condition = FALSE, /* are we in a "not" ?? */
- X type=NONE, /* what TYPE of condition? */
- X lasttype, /* and the previous TYPE? */
- X state = NEXT_CONDITION, /* the current state */
- X in_single, in_double, /* for handling spaces. */
- X i, /* misc integer for loops */
- X relop = NONE, /* relational operator */
- X action, /* the current action type */
- X line = 0; /* line number we're on */
- X
- X struct condition_rec *cond, *newcond;
- X
- X sprintf(filename,"%s/%s", home, filterfile);
- X
- X if ((fd = fopen(filename,"r")) == NULL) {
- X fprintf(stderr,"filter (%s): Couldn't read user filter rules file!\n",
- X username);
- X return(-1);
- X }
- X
- X cond_argument[0] = action_argument[0] = '\0';
- X
- X /* Now, for each line... **/
- X
- X if ((cond = (struct condition_rec *)
- X malloc(sizeof(struct condition_rec))) == NULL) {
- X fprintf(stderr,"couldn't malloc first condition rec!\n");
- X return(-1);
- X }
- X
- X rules[total_rules].condition = cond; /* hooked in! */
- X
- X while (fgets(buffer, SLEN, fd) != NULL) {
- X line++;
- X
- X if (buffer[0] == '#' || strlen(buffer) < 2)
- X continue; /* nothing to look at! */
- X
- X in_single = in_double = 0;
- X
- X for (i=0; i < strlen(buffer); i++) {
- X if (buffer[i] == '"')
- X in_double = ! in_double;
- X else if (buffer[i] == '\'')
- X in_single = ! in_single;
- X if ((in_double || in_single) && buffer[i] == ' ')
- X buffer[i] = '_';
- X }
- X
- X lasttype = type;
- X type = NONE;
- X str = (char *) buffer;
- X
- X /** Three pieces to this loop - get the `field', the 'relop' (if
- X there) then, if needed, get the argument to check against (not
- X needed for errors or the AND, of course)
- X **/
- X
- X while ((word = strtok(str, " ()[]:\t\n")) != NULL) {
- X
- X str = (char *) NULL; /* we can start stomping! */
- X
- X lowercase(word);
- X
- X if (strcmp(word, "if") == 0) { /* only ONE 'if' allowed */
- X if ((word = strtok(str, " ()[]:\t\n")) == NULL) /* NEXT! */
- X continue;
- X lowercase(word);
- X }
- X
- X if (state == NEXT_CONDITION) {
- X lasttype = type;
- X type = NONE;
- X
- X if (the_same(word, "not") || the_same(word, "!")) {
- X not_condition = TRUE;
- X if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
- X continue;
- X }
- X
- X if (the_same(word, "from")) type = FROM;
- X else if (the_same(word, "to")) type = TO;
- X else if (the_same(word, "subject")) type = SUBJECT;
- X else if (the_same(word, "lines")) type = LINES;
- X else if (the_same(word, "contains")) type = CONTAINS;
- X else if (the_same(word, "and") ||
- X the_same(word, "&&")) type = AND;
- X
- X else if (the_same(word,"?") || the_same(word, "then")) {
- X
- X /** shove THIS puppy into the structure and let's continue! **/
- X
- X if (lasttype == AND) {
- X fprintf(stderr,
- X "%sfilter (%s): Error reading line %d of rules - badly placed \"and\"\n",
- X BEEP, username, line);
- X return(-1);
- X }
- X
- X cond->matchwhat = lasttype;
- X if (relop == NONE) relop = EQ; /* otherwise can't do -relop */
- X cond->relation = (not_condition? - (relop) : relop);
- X
- X for (i=0;i<strlen(cond_argument);i++)
- X if (cond_argument[i] == '_') cond_argument[i] = ' ';
- X
- X strcpy(cond->argument1, cond_argument);
- X if ((newcond = (struct condition_rec *)
- X malloc(sizeof(struct condition_rec))) == NULL) {
- X fprintf(stderr,"Couldn't malloc new cond rec!!\n");
- X return(-1);
- X }
- X cond->next = NULL;
- X
- X relop = EQ; /* default relational condition */
- X
- X state = READING_ACTION;
- X if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
- X continue;
- X goto get_outta_loop;
- X }
- X
- X if (type == NONE) {
- X fprintf(stderr,
- X "%sfilter (%s): Error reading line %d of rules - field \"%s\" unknown!\n",
- X BEEP, username, line, word);
- X return(-1);
- X }
- X
- X if (type == AND) {
- X
- X /** shove THIS puppy into the structure and let's continue! **/
- X
- X cond->matchwhat = lasttype;
- X cond->relation = (not_condition? - (relop) : relop);
- X strcpy(cond->argument1, cond_argument);
- X if ((newcond = (struct condition_rec *)
- X malloc(sizeof(struct condition_rec))) == NULL) {
- X fprintf(stderr,"Couldn't malloc new cond rec!!\n");
- X return(-1);
- X }
- X cond->next = newcond;
- X cond = newcond;
- X cond->next = NULL;
- X
- X not_condition = FALSE;
- X state = NEXT_CONDITION;
- X }
- X else {
- X state = GETTING_OP;
- X }
- X }
- X
- Xget_outta_loop: /* jump out when we change state, if needed */
- X
- X if (state == GETTING_OP) {
- X
- X if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
- X continue;
- X
- X lowercase(word);
- X
- X relop = NONE;
- X
- X if (the_same(word, "=") || the_same(word, "in") ||
- X the_same(word, "contains")) {
- X state = READING_ARGUMENT;
- X relop = EQ;
- X }
- X else {
- X if (the_same(word, "<=")) relop = LE;
- X else if (the_same(word, ">=")) relop = GE;
- X else if (the_same(word, ">")) relop = GT;
- X else if (the_same(word, "<>")||
- X the_same(word, "!=")) relop = NE;
- X else if (the_same(word, "<")) relop = LT;
- X
- X /* maybe there isn't a relop at all!! */
- X
- X state=READING_ARGUMENT;
- X
- X }
- X }
- X
- X if (state == READING_ARGUMENT) {
- X if (relop != NONE) {
- X if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
- X continue;
- X }
- X for (i=0;i<strlen(word);i++)
- X if (word[i] == '_') word[i] = ' ';
- X
- X strcpy(cond_argument, word);
- X state = NEXT_CONDITION;
- X }
- X
- X if (state == READING_ACTION) {
- X action = NONE;
- X
- X not_condition = FALSE;
- X
- X if (the_same(word, "delete")) action = DELETE;
- X else if (the_same(word, "savec")) action = SAVECC;
- X else if (the_same(word, "save")) action = SAVE;
- X else if (the_same(word, "forward")) action = FORWARD;
- X else if (the_same(word, "exec")) action = EXEC;
- X else if (the_same(word, "leave")) action = LEAVE;
- X else {
- X fprintf(stderr,
- X "%sfilter (%s): Error on line %d of rules - action \"%s\" unknown\n",
- X BEEP, username, line, word);
- X }
- X
- X if (action == DELETE || action == LEAVE) {
- X /** add this to the rules section and alloc next... **/
- X
- X rules[total_rules].action = action;
- X rules[total_rules].argument2[0] = '\0'; /* nothing! */
- X total_rules++;
- X
- X if ((cond = (struct condition_rec *)
- X malloc(sizeof(struct condition_rec))) == NULL) {
- X fprintf(stderr,"couldn't malloc first condition rec!\n");
- X return(-1);
- X }
- X
- X rules[total_rules].condition = cond; /* hooked in! */
- X state = NEXT_CONDITION;
- X }
- X else {
- X state = ACTION_ARGUMENT;
- X }
- X
- X if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
- X continue;
- X
- X }
- X
- X if (state == ACTION_ARGUMENT) {
- X strcpy(action_argument, word);
- X
- X /** add this to the rules section and alloc next... **/
- X
- X rules[total_rules].action = action;
- X expand_macros(action_argument, rules[total_rules].argument2,line);
- X total_rules++;
- X
- X if ((cond = (struct condition_rec *)
- X malloc(sizeof(struct condition_rec))) == NULL) {
- X fprintf(stderr,"couldn't malloc first condition rec!\n");
- X return(-1);
- X }
- X
- X rules[total_rules].condition = cond; /* hooked in! */
- X
- X state = NEXT_CONDITION;
- X if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
- X continue;
- X }
- X }
- X }
- X
- X return(0);
- X}
- END_OF_filter/parse.c
- if test 8929 -ne `wc -c <filter/parse.c`; then
- echo shar: \"filter/parse.c\" unpacked with wrong size!?
- fi
- # end of overwriting check
- fi
- echo shar: Extracting \"src/input_utils.c\" \(8598 characters\)
- if test -f src/input_utils.c ; then
- echo shar: Will not over-write existing file \"src/input_utils.c\"
- else
- sed "s/^X//" >src/input_utils.c <<'END_OF_src/input_utils.c'
- X/** input_utils.c **/
- X
- X/** Mindless I/O routines for ELM
- X
- X (C) Copyright 1985 Dave Taylor
- X**/
- X
- X#include "headers.h"
- X#include <errno.h>
- X
- Xextern int errno; /* system error number */
- X
- Xunsigned alarm();
- X
- X#define special_char(c) (c == ' ' || c == '\t' || c == '/' || c == ',' \
- X || c == '\0')
- X
- X#define erase_a_char() { Writechar(BACKSPACE); Writechar(' '); \
- X Writechar(BACKSPACE); fflush(stdout); }
- X
- Xint
- Xwant_to(question, dflt, echo_answer)
- Xchar *question, dflt;
- Xint echo_answer;
- X{
- X /** Ask 'question' at LINES-2, COLUMNS-40, returning the answer in
- X lower case. If 'echo_answer', then echo answer. 'dflt' is the
- X default answer if <return> is pressed. (Note: 'dflt' is also what
- X will be returned if <return> is pressed!)
- X **/
- X register char ch, cols;
- X
- X cols = (strlen(question) < 30)? COLUMNS-40 : COLUMNS-50;
- X
- X PutLine3(LINES-3, cols,"%s%c%c", question, dflt, BACKSPACE);
- X fflush(stdout);
- X fflush(stdin);
- X ch = tolower(ReadCh());
- X
- X if (echo_answer && ch > (char) ' ') {
- X Writechar(ch);
- X fflush(stdout);
- X }
- X
- X return(ch == '\n' || ch == '\r' ? dflt : ch);
- X}
- X
- Xint
- Xread_number(ch)
- Xchar ch;
- X{
- X /** Read a number, where 'ch' is the leading digit! **/
- X
- X char buff[SHORT_SLEN];
- X int num;
- X
- X buff[0] = ch;
- X buff[1] = '\0';
- X
- X PutLine0(LINES-3, COLUMNS-40,"Set current message to :");
- X if (optionally_enter(buff, LINES-3, COLUMNS-15, TRUE) == -1)
- X return(current);
- X
- X sscanf(buff,"%d", &num);
- X return(num);
- X}
- X
- Xint
- Xoptionally_enter(string, x, y, append_current)
- Xchar *string;
- Xint x,y, append_current;
- X{
- X /** Display the string on the screen and if RETURN is pressed, return
- X it. Otherwise, allow standard text input, including backspaces
- X and such until RETURN is hit.
- X If "append_current" is set, then leave the default string in
- X place and edit AFTER it...assume 'x,y' is placing us at the
- X beginning of the string...
- X This routine returns zero unless INTERRUPT hit, then it returns
- X -1 and must be treated accordingly.
- X Added ^W and ^R support...
- X Also added that if x and y are < 0 don't try any cursor stuff
- X **/
- X
- X char ch;
- X register int index = 0, use_cursor_control;
- X
- X use_cursor_control = ((! mail_only) && x >= 0 && y >= 0);
- X
- X if (use_cursor_control)
- X PutLine1(x,y, "%s", string);
- X else
- X printf("%s", string);
- X
- X CleartoEOLN();
- X
- X if (! append_current)
- X if (use_cursor_control)
- X MoveCursor(x,y);
- X else
- X non_destructive_back_up(strlen(string));
- X
- X if (cursor_control)
- X transmit_functions(OFF);
- X
- X ch = getchar();
- X
- X if (ch == '\n' || ch == '\r') {
- X if (cursor_control)
- X transmit_functions(ON);
- X return(0); /* we're done. No change needed */
- X }
- X
- X CleartoEOLN();
- X
- X index = (append_current? strlen(string) : 0);
- X
- X if (ch == kill_line) {
- X if (use_cursor_control)
- X MoveCursor(x,y);
- X else
- X back_up(index);
- X CleartoEOLN();
- X index = 0;
- X }
- X else if (ch != backspace) {
- X Writechar(ch);
- X string[index++] = ch;
- X }
- X else if (index > 0) {
- X index--;
- X erase_a_char();
- X }
- X else {
- X Writechar(' ');
- X Writechar(BACKSPACE);
- X fflush(stdout);
- X }
- X
- X do {
- X ch = getchar();
- X
- X /* the following is converted from a case statement to
- X allow the variable characters (backspace, kill_line
- X and break) to be processed. Case statements in
- X C require constants as labels, so it failed ...
- X */
- X
- X if (ch == backspace) {
- X if (index > 0) {
- X erase_a_char();
- X index--;
- X }
- X else {
- X Writechar(' ');
- X Writechar(BACKSPACE);
- X fflush(stdout);
- X }
- X }
- X else if (ch == '\n' || ch == '\r') {
- X string[index] = '\0';
- X if (cursor_control)
- X transmit_functions(ON);
- X return(0);
- X }
- X else if (ch == ctrl('W')) { /* back up a word! */
- X if (special_char(string[index]) && index > 0) {
- X index--;
- X erase_a_char();
- X }
- X while (index > 0 && ! special_char(string[index])) {
- X index--;
- X erase_a_char();
- X }
- X }
- X else if (ch == ctrl('R')) {
- X string[index] = '\0';
- X if (use_cursor_control) {
- X PutLine1(x,y, "%s", string);
- X CleartoEOLN();
- X }
- X else
- X printf("\n%s", string);
- X }
- X else if (ch == kill_line) {
- X if (use_cursor_control)
- X MoveCursor(x,y);
- X else
- X back_up(index+1);
- X CleartoEOLN();
- X index = 0;
- X }
- X else if (ch == NULL) {
- X if (cursor_control)
- X transmit_functions(ON);
- X fflush(stdin); /* remove extraneous chars, if any */
- X string[0] = '\0'; /* clean up string, and... */
- X return(-1);
- X }
- X else { /* default case */
- X
- X string[index++] = ch;
- X Writechar(ch);
- X }
- X } while (index < SLEN);
- X
- X string[index] = '\0';
- X
- X if (cursor_control)
- X transmit_functions(ON);
- X return(0);
- X}
- X
- Xint
- Xpattern_enter(string, alt_string, x, y, alternate_prompt)
- Xchar *string, *alt_string, *alternate_prompt;
- Xint x,y;
- X{
- X /** This function is functionally similar to the routine
- X optionally-enter, but if the first character pressed
- X is a '/' character, then the alternate prompt and string
- X are used rather than the normal one. This routine
- X returns 1 if alternate was used, 0 if not
- X **/
- X
- X char ch;
- X register index = 0;
- X
- X PutLine1(x, y, "%s", string);
- X CleartoEOLN();
- X MoveCursor(x,y);
- X
- X if (cursor_control)
- X transmit_functions(OFF);
- X
- X ch = getchar();
- X
- X if (ch == '\n' || ch == '\r') {
- X if (cursor_control)
- X transmit_functions(ON);
- X return(0); /* we're done. No change needed */
- X }
- X
- X if (ch == '/') {
- X PutLine1(x, 0, "%s", alternate_prompt);
- X CleartoEOLN();
- X (void) optionally_enter(alt_string, x, strlen(alternate_prompt)+1,
- X FALSE);
- X return(1);
- X }
- X
- X CleartoEOLN();
- X
- X index = 0;
- X
- X if (ch == kill_line) {
- X MoveCursor(x,y);
- X CleartoEOLN();
- X index = 0;
- X }
- X else if (ch != backspace) {
- X Writechar(ch);
- X string[index++] = ch;
- X }
- X else if (index > 0) {
- X index--;
- X erase_a_char();
- X }
- X else {
- X Writechar(' ');
- X Writechar(BACKSPACE);
- X }
- X
- X do {
- X fflush(stdout);
- X ch = getchar();
- X
- X /* the following is converted from a case statement to
- X allow the variable characters (backspace, kill_line
- X and break) to be processed. Case statements in
- X C require constants as labels, so it failed ...
- X */
- X
- X if (ch == backspace) {
- X if (index > 0) {
- X index--;
- X erase_a_char();
- X }
- X else {
- X Writechar(' ');
- X Writechar(BACKSPACE);
- X }
- X }
- X else if (ch == '\n' || ch == '\r') {
- X string[index] = '\0';
- X if (cursor_control)
- X transmit_functions(ON);
- X return(0);
- X }
- X else if (ch == ctrl('W')) {
- X /* get to rightmost non-alpha */
- X if (special_char (string[index]) && index > 0)
- X index--;
- X while (index > 0 && ! special_char(string[index])) {
- X erase_a_char();
- X index--;
- X }
- X }
- X else if (ch == ctrl('R')) {
- X string[index] = '\0';
- X if (!mail_only) {
- X PutLine1(x,y, "%s", string);
- X CleartoEOLN();
- X }
- X else
- X printf("\n%s", string);
- X }
- X else if (ch == kill_line) {
- X MoveCursor(x,y);
- X CleartoEOLN();
- X index = 0;
- X }
- X else if (ch == NULL) {
- X if (cursor_control)
- X transmit_functions(ON);
- X fflush(stdin); /* remove extraneous chars, if any */
- X string[0] = '\0'; /* clean up string, and... */
- X return(-1);
- X }
- X else { /* default case */
- X
- X string[index++] = ch;
- X Writechar(ch);
- X }
- X } while (index < SLEN);
- X
- X string[index] = '\0';
- X
- X if (cursor_control)
- X transmit_functions(ON);
- X return(0);
- X}
- X
- Xback_up(spaces)
- Xint spaces;
- X{
- X /** this routine is to replace the goto x,y call for when sending
- X mail without starting the entire "elm" system up... **/
- X
- X while (spaces--) {
- X erase_a_char();
- X }
- X}
- X
- Xnon_destructive_back_up(spaces)
- Xint spaces;
- X{
- X /** same as back_up() but doesn't ERASE the characters on the screen **/
- X
- X while (spaces--)
- X Writechar(BACKSPACE);
- X fflush(stdout);
- X}
- X
- Xint
- XGetPrompt()
- X{
- X /** This routine does a read/timeout for a single character.
- X The way that this is determined is that the routine to
- X read a character is called, then the "errno" is checked
- X against EINTR (interrupted call). If they match, this
- X returns NO_OP_COMMAND otherwise it returns the normal
- X command.
- X **/
- X
- X int ch;
- X
- X if (timeout > 0) {
- X alarm((unsigned) timeout);
- X errno = 0; /* we actually have to do this. *sigh* */
- X ch = ReadCh();
- X if (errno == EINTR) ch = NO_OP_COMMAND;
- X alarm((unsigned) 0);
- X }
- X else
- X ch = ReadCh();
- X
- X return(ch);
- X}
- END_OF_src/input_utils.c
- if test 8598 -ne `wc -c <src/input_utils.c`; then
- echo shar: \"src/input_utils.c\" unpacked with wrong size!?
- fi
- # end of overwriting check
- fi
- echo shar: Extracting \"src/mailmsg1.c\" \(8412 characters\)
- if test -f src/mailmsg1.c ; then
- echo shar: Will not over-write existing file \"src/mailmsg1.c\"
- else
- sed "s/^X//" >src/mailmsg1.c <<'END_OF_src/mailmsg1.c'
- X/** mailmsg1.c **/
- X
- X/** Interface to allow mail to be sent to users. Part of ELM **/
- X
- X/** (C) Copyright 1986, Dave Taylor **/
- X
- X#include "headers.h"
- X
- X/** strings defined for the hdrconfg routines **/
- X
- Xchar subject[SLEN], action[SLEN], reply_to[SLEN], expires[SLEN], priority[SLEN];
- Xchar to[VERY_LONG_STRING], cc[VERY_LONG_STRING], in_reply_to[SLEN];
- Xchar user_defined_header[SLEN];
- X
- Xchar expanded_to[VERY_LONG_STRING], expanded_cc[VERY_LONG_STRING];
- X
- X#ifdef ALLOW_BCC
- Xchar bcc[VERY_LONG_STRING], expanded_bcc[VERY_LONG_STRING];
- X#endif
- X
- Xchar *format_long(), *strip_commas(), *tail_of_string(), *strcpy();
- Xunsigned long sleep();
- X
- Xint
- Xsend(given_to, given_subject, edit_message, form_letter)
- Xchar *given_to, *given_subject;
- Xint edit_message, form_letter;
- X{
- X /** Prompt for fields and then call mail() to send the specified
- X message. If 'edit_message' is true then don't allow the
- X message to be edited. 'form_letter' can be "YES" "NO" or "MAYBE".
- X if YES, then add the header. If MAYBE, then add the M)ake form
- X option to the last question (see mailsg2.c) etc. etc. **/
- X
- X int copy_msg = FALSE, is_a_response = FALSE;
- X
- X /* First: zero all current global message strings */
- X
- X cc[0] = action[0] = reply_to[0] = expires[0] = priority[0] = '\0';
- X#ifdef ALLOW_BCC
- X bcc[0] = expanded_bcc[0] = '\0';
- X#endif
- X in_reply_to[0] = expanded_to[0] = expanded_cc[0] = '\0';
- X
- X strcpy(subject, given_subject); /* copy given subject */
- X strcpy(to, given_to); /* copy given to: */
- X
- X /******* And now the real stuff! *******/
- X
- X copy_msg=copy_the_msg(&is_a_response); /* copy msg into edit buffer? */
- X
- X if (get_to(to, expanded_to) == 0) /* get the To: address and expand */
- X return(0);
- X
- X /** are we by any chance just checking the addresses? **/
- X
- X if (check_only) {
- X printf("Expands to: %s\n", format_long(expanded_to, 12));
- X putchar('\r'); /* don't ask... */
- X leave();
- X }
- X
- X /** if we're batchmailing, let's send it and GET OUTTA HERE! **/
- X
- X if (mail_only && strlen(batch_subject) > 0) {
- X strcpy(subject, batch_subject); /* get the batch subject */
- X return(mail(FALSE, FALSE, TRUE, form_letter));
- X }
- X
- X display_to(expanded_to); /* display the To: field on screen... */
- X
- X dprint1(3,"\nMailing to %s\n", expanded_to);
- X
- X if (get_subject(subject) == 0) /* get the Subject: field */
- X return(0);
- X
- X dprint1(4,"Subject is %s\n", subject);
- X
- X if (get_copies(cc, expanded_to, expanded_cc) == 0)
- X return(0);
- X
- X if (strlen(cc) > 0)
- X dprint1(4,"Copies to %s\n", expanded_cc);
- X
- X if (mail_only) /* indicate next step... */
- X printf("\n\r");
- X else
- X MoveCursor(LINES,0); /* you know you're hit <return> ! */
- X
- X /** generate the In-Reply-To: header... **/
- X
- X if (is_a_response)
- X generate_reply_to(current-1);
- X
- X /* and mail that puppy outta here! */
- X
- X mail(copy_msg, edit_message, FALSE, form_letter);
- X
- X return(edit_message);
- X}
- X
- Xget_to(to_field, address)
- Xchar *to_field, *address;
- X{
- X /** prompt for the "To:" field, expanding into address if possible.
- X This routine returns ZERO if errored, or non-zero if okay **/
- X
- X if (strlen(to_field) == 0) {
- X if (user_level < 2) {
- X PutLine0(LINES-2, 0, "Send the message to: ");
- X (void) optionally_enter(to_field, LINES-2, 21, FALSE);
- X }
- X else {
- X PutLine0(LINES-2, 0, "To: ");
- X (void) optionally_enter(to_field, LINES-2, 4, FALSE);
- X }
- X if (strlen(to_field) == 0) {
- X ClearLine(LINES-2);
- X return(0);
- X }
- X build_address(strip_commas(to_field), address);
- X }
- X else if (mail_only)
- X build_address(strip_commas(to_field), address);
- X else
- X strcpy(address, to_field);
- X
- X if (strlen(address) == 0) { /* bad address! Removed!! */
- X if (! mail_only)
- X ClearLine(LINES-2);
- X return(0);
- X }
- X
- X return(1); /* everything is okay... */
- X}
- X
- Xget_subject(subject_field)
- Xchar *subject_field;
- X{
- X /** get the subject and return non-zero if all okay... **/
- X int len = 9;
- X
- X if (mail_only)
- X printf("Subject: ");
- X else
- X if (user_level == 0) {
- X PutLine0(LINES-2,0,"Subject of message: ");
- X len = 21;
- X }
- X else
- X PutLine0(LINES-2,0,"Subject: ");
- X
- X CleartoEOLN();
- X
- X if (optionally_enter(subject_field, LINES-2, len, TRUE) == -1) {
- X /** User hit the BREAK key! **/
- X MoveCursor(LINES-2,0);
- X CleartoEOLN();
- X error("mail not sent");
- X return(0);
- X }
- X
- X if (strlen(subject_field) == 0) { /* zero length subject?? */
- X if (mail_only)
- X printf("\n\rNo subject - Continue with message? (y/n) n%c",
- X BACKSPACE);
- X else
- X PutLine1(LINES-2,0,"No subject - Continue with message? (y/n) n%c",
- X BACKSPACE);
- X
- X if (tolower(ReadCh()) != 'y') { /* user says no! */
- X if (mail_only) {
- X printf("\n\r\n\rMail Cancelled!\n\r");
- X return(0);
- X }
- X ClearLine(LINES-2);
- X error("mail not sent");
- X return(0);
- X }
- X else if (! mail_only) {
- X PutLine0(LINES-2,0,"Subject: <none>");
- X CleartoEOLN();
- X }
- X }
- X
- X return(1); /** everything is cruising along okay **/
- X}
- X
- Xget_copies(cc_field, address, addressII)
- Xchar *cc_field, *address, *addressII;
- X{
- X /** Get the list of people that should be cc'd, returning ZERO if
- X any problems arise. Address and AddressII are for expanding
- X the aliases out after entry!
- X If 'bounceback' is nonzero, add a cc to ourselves via the remote
- X site, but only if hops to machine are > bounceback threshold.
- X **/
- X
- X if (mail_only)
- X printf("\n\rCopies To: ");
- X else
- X PutLine0(LINES-1,0,"Copies To: ");
- X
- X fflush(stdout);
- X
- X if (optionally_enter(cc_field, LINES-1, 11, FALSE) == -1) {
- X if (mail_only) {
- X printf("\n\r\n\rMail not sent!\n\r");
- X return(0);
- X }
- X ClearLine(LINES-2);
- X ClearLine(LINES-1);
- X
- X error("mail not sent");
- X return(0);
- X }
- X
- X build_address(strip_commas(cc_field), addressII);
- X
- X if (strlen(address) + strlen(addressII) > VERY_LONG_STRING) {
- X dprint0(2,
- X "String length of \"To:\" + \"Cc\" too long! (get_copies)\n");
- X error("Too many people. Copies ignored");
- X sleep(2);
- X cc_field[0] = '\0';
- X }
- X
- X return(1); /* everything looks okay! */
- X}
- X
- Xint
- Xcopy_the_msg(is_a_response)
- Xint *is_a_response;
- X{
- X /** Returns True iff the user wants to copy the message being
- X replied to into the edit buffer before invoking the editor!
- X Sets "is_a_response" to true if message is a response...
- X **/
- X
- X int answer = FALSE;
- X
- X if (strlen(to) > 0 && !mail_only) { /* predefined 'to' line! */
- X if (auto_copy)
- X answer = TRUE;
- X else
- X answer = (want_to("Copy message? (y/n) ", 'n', TRUE) == 'y');
- X *is_a_response = TRUE;
- X }
- X else
- X if (strlen(subject) > 0) /* predefined 'subject' (Forward) */
- X answer = TRUE;
- X
- X return(answer);
- X}
- X
- Xdisplay_to(address)
- Xchar *address;
- X{
- X /** Simple routine to display the "To:" line according to the
- X current configuration (etc)
- X **/
- X register int open_paren;
- X
- X if (mail_only)
- X printf("To: %s\n\r", format_long(address, 3));
- X else {
- X if (names_only)
- X if ((open_paren = chloc(address, '(')) > 0) {
- X if (open_paren < chloc(address, ')')) {
- X output_abbreviated_to(address);
- X return;
- X }
- X }
- X if (strlen(address) > 45)
- X PutLine1(LINES-3, COLUMNS-50, "To: (%s)",
- X tail_of_string(address, 40));
- X else {
- X if (strlen(address) > 30)
- X PutLine1(LINES-3, COLUMNS-50, "To: %s", address);
- X else
- X PutLine1(LINES-3, COLUMNS-50, " To: %s", address);
- X CleartoEOLN();
- X }
- X }
- X}
- X
- Xoutput_abbreviated_to(address)
- Xchar *address;
- X{
- X /** Output just the fields in parens, separated by commas if need
- X be, and up to COLUMNS-50 characters...This is only used if the
- X user is at level BEGINNER.
- X **/
- X
- X char newaddress[LONG_STRING];
- X register int index, newindex = 0, in_paren = 0;
- X
- X index = 0;
- X
- X while (newindex < 55 && index < strlen(address)) {
- X if (address[index] == '(') in_paren++;
- X else if (address[index] == ')') {
- X in_paren--;
- X if (index < strlen(address)-4) {
- X newaddress[newindex++] = ',';
- X newaddress[newindex++] = ' ';
- X }
- X }
- X
- X if (in_paren && address[index] != '(')
- X newaddress[newindex++] = address[index];
- X
- X index++;
- X }
- X
- X newaddress[newindex] = '\0';
- X
- X if (strlen(newaddress) > 50)
- X PutLine1(LINES-3, COLUMNS-50, "To: (%s)",
- X tail_of_string(newaddress, 40));
- X else {
- X if (strlen(newaddress) > 30)
- X PutLine1(LINES-3, COLUMNS-50, "To: %s", newaddress);
- X else
- X PutLine1(LINES-3, COLUMNS-50, " To: %s", newaddress);
- X CleartoEOLN();
- X }
- X
- X return;
- X}
- END_OF_src/mailmsg1.c
- if test 8412 -ne `wc -c <src/mailmsg1.c`; then
- echo shar: \"src/mailmsg1.c\" unpacked with wrong size!?
- fi
- # end of overwriting check
- fi
- echo shar: Extracting \"src/options.c\" \(9046 characters\)
- if test -f src/options.c ; then
- echo shar: Will not over-write existing file \"src/options.c\"
- else
- sed "s/^X//" >src/options.c <<'END_OF_src/options.c'
- X/** options.c **/
- X
- X/** This set of routines allows the alteration of a number of paramaters
- X in the Elm mailer, including the following;
- X
- X calendar-file <where to put calendar entries>
- X display pager <how to page messages>
- X editor <name of composition editor>
- X folder-dir <folder directory>
- X sort-by <how to sort mailboxes>
- X savefile <file to save outbound message copies to>
- X printmail <how to print messages>
- X full_username <your full user name for outgoing mail>
- X
- X arrow-cursor <on or off>
- X menu-display <on or off>
- X
- X user-level <BEGINNER|INTERMEDIATE|EXPERT>
- X names-only <on or off>
- X
- X And others as they seem useful.
- X
- X (C) Copyright 1986, Dave Taylor
- X**/
- X
- X#include "headers.h"
- X
- X#undef onoff
- X#define onoff(n) (n == 1? "ON ":"OFF")
- X
- Xchar *one_liner_for(), *level_name();
- Xunsigned long sleep();
- X
- Xoptions()
- X{
- X /** change options... **/
- X
- X char ch;
- X
- X display_options();
- X
- X do {
- X ClearLine(LINES-4);
- X
- X Centerline(LINES-4,
- X "Select first letter of Option line, '>' to Save, or R)eturn");
- X
- X PutLine0(LINES-2, 0, "Command: ");
- X
- X ch = tolower(ReadCh());
- X
- X clear_error(); /* remove possible "sorting" message etc... */
- X
- X one_liner(one_liner_for(ch));
- X
- X switch (ch) {
- X case 'c' : optionally_enter(calendar_file, 2, 23, FALSE); break;
- X case 'd' : optionally_enter(pager, 3, 23, FALSE); break;
- X case 'e' : optionally_enter(editor, 4, 23, FALSE); break;
- X case 'f' : optionally_enter(folders, 5, 23, FALSE); break;
- X case 's' : change_sort(6,23); break;
- X case 'o' : optionally_enter(savefile, 7, 23, FALSE); break;
- X case 'p' : optionally_enter(printout, 8, 23, FALSE); break;
- X case 'y' : optionally_enter(full_username, 9, 23, FALSE); break;
- X case 'a' : on_or_off(&arrow_cursor, 12, 23); break;
- X case 'm' : on_or_off(&mini_menu, 13, 23);
- X headers_per_page = LINES - (mini_menu ? 13 : 8); break;
- X
- X case 'u' : switch_user_level(&user_level,15, 23); break;
- X case 'n' : on_or_off(&names_only, 16, 23); break;
- X
- X case '?' : options_help();
- X PutLine0(LINES-2,0,"Command: "); break;
- X
- X case '>' : printf("Save options in .elmrc...");
- X fflush(stdout); save_options(); break;
- X
- X case 'x' :
- X case 'r' :
- X case ctrl('M'):
- X case ctrl('J'): return;
- X case ctrl('L'): display_options(); break;
- X default: error("Command unknown!");
- X }
- X
- X } while (ch != 'r');
- X}
- X
- Xdisplay_options()
- X{
- X /** Display all the available options.. **/
- X
- X char *sort_name();
- X
- X ClearScreen();
- X Centerline(0,"-- Elm Options Editor --");
- X
- X#ifdef ENABLE_CALENDAR
- X PutLine1(2, 0, "C)alendar file : %s", calendar_file);
- X#endif
- X PutLine1(3, 0, "D)isplay mail using : %s", pager);
- X PutLine1(4, 0, "E)ditor : %s", editor);
- X PutLine1(5, 0, "F)older directory : %s", folders);
- X PutLine1(6, 0, "S)orting criteria : %s", sort_name(FULL));
- X PutLine1(7, 0, "O)utbound mail saved : %s", savefile);
- X PutLine1(8, 0, "P)rint mail using : %s", printout);
- X PutLine1(9, 0, "Y)our full name : %s", full_username);
- X
- X PutLine1(12,0, "A)rrow cursor : %s", onoff(arrow_cursor));
- X PutLine1(13,0, "M)enu display : %s", onoff(mini_menu));
- X
- X PutLine1(15,0, "U)ser level : %s", level_name(user_level));
- X PutLine1(16,0, "N)ames only : %s", onoff(names_only));
- X}
- X
- Xon_or_off(var, x, y)
- Xint *var, x,y;
- X{
- X /** 'var' field at x.y toggles between on and off... **/
- X
- X char ch;
- X
- X PutLine0(x, y+6,
- X "(use <space> to toggle, any other key to leave)");
- X
- X MoveCursor(x,y+3); /* at end of value... */
- X
- X do {
- X ch = ReadCh();
- X
- X if (ch == SPACE) {
- X *var = ! *var;
- X PutLine0(x,y, onoff(*var));
- X }
- X } while (ch == SPACE);
- X
- X MoveCursor(x,y+4); CleartoEOLN(); /* remove help prompt */
- X}
- X
- X
- Xswitch_user_level(ulevel, x, y)
- Xint *ulevel, x, y;
- X{
- X /** step through possible user levels... **/
- X
- X PutLine0(x, y+20, "<space> to change");
- X
- X MoveCursor(x,y); /* at end of value... */
- X
- X while (ReadCh() == ' ') {
- X *ulevel = (*ulevel == 2? 0 : *ulevel + 1);
- X PutLine1(x,y, "%s", level_name(*ulevel));
- X }
- X
- X MoveCursor(x,y+20); CleartoEOLN(); /* remove help prompt */
- X}
- X
- Xchange_sort(x, y)
- Xint x,y;
- X{
- X /** change the sorting scheme... **/
- X
- X int last_sortby, /* so we know if it changes... */
- X sign = 1; /* are we reverse sorting?? */
- X char ch; /* character typed in ... */
- X
- X last_sortby = sortby; /* remember current ordering */
- X
- X PutLine0(x, COLUMNS-29, "(SPACE for next, or R)everse)");
- X sort_one_liner(sortby);
- X MoveCursor(x, y);
- X
- X do {
- X ch = tolower(ReadCh());
- X switch (ch) {
- X case SPACE : if (sortby < 0) {
- X sign = -1;
- X sortby = - sortby;
- X }
- X else sign = 1; /* insurance! */
- X sortby = sign * ((sortby + 1) % (STATUS+1));
- X if (sortby == 0) sortby = sign; /* snicker */
- X PutLine0(x, y, sort_name(PAD));
- X sort_one_liner(sortby);
- X MoveCursor(x, y);
- X break;
- X
- X case 'r' : sortby = - sortby;
- X PutLine0(x, y, sort_name(PAD));
- X sort_one_liner(sortby);
- X MoveCursor(x, y);
- X }
- X } while (ch == SPACE || ch == 'r');
- X
- X MoveCursor(x, COLUMNS-30); CleartoEOLN();
- X
- X if (sortby != last_sortby) {
- X error("resorting mailbox...");
- X sleep(1);
- X sort_mailbox(message_count, 0);
- X }
- X ClearLine(LINES-2); /* clear sort_one_liner()! */
- X}
- X
- Xone_liner(string)
- Xchar *string;
- X{
- X /** A single-line description of the selected item... **/
- X
- X ClearLine(LINES-4);
- X Centerline(LINES-4, string);
- X}
- X
- Xsort_one_liner(sorting_by)
- Xint sorting_by;
- X{
- X /** A one line summary of the particular sorting scheme... **/
- X
- X ClearLine(LINES-2);
- X
- X switch (sorting_by) {
- X
- X case -SENT_DATE : Centerline(LINES-2,
- X"This sort will order most-recently-sent to least-recently-sent"); break;
- X case -RECEIVED_DATE : Centerline(LINES-2,
- X"This sort will order most-recently-received to least-recently-received");
- X break;
- X case -SENDER : Centerline(LINES-2,
- X"This sort will order by sender name, in reverse alphabetical order"); break;
- X case -SIZE : Centerline(LINES-2,
- X"This sort will order messages by longest to shortest"); break;
- X case -SUBJECT : Centerline(LINES-2,
- X"This sort will order by subject, in reverse alphabetical order"); break;
- X case -STATUS : Centerline(LINES-2,
- X"This sort will order by reverse status - Deleted through Tagged..."); break;
- X
- X case SENT_DATE : Centerline(LINES-2,
- X"This sort will order least-recently-sent to most-recently-sent"); break;
- X case RECEIVED_DATE : Centerline(LINES-2,
- X"This sort will order least-recently-received to most-recently-received");
- X break;
- X case SENDER : Centerline(LINES-2,
- X "This sort will order by sender name"); break;
- X case SIZE : Centerline(LINES-2,
- X "This sort will order messages by shortest to longest");
- X break;
- X case SUBJECT : Centerline(LINES-2,
- X "This sort will order messages by subject"); break;
- X case STATUS : Centerline(LINES-2,
- X"This sort will order by status - Tagged through Deleted..."); break;
- X }
- X}
- X
- Xchar *one_liner_for(c)
- Xchar c;
- X{
- X /** returns the one-line description of the command char... **/
- X
- X switch (c) {
- X case 'c' : return(
- X"This is the file where calendar entries from messages are saved.");
- X
- X case 'd' : return(
- X"This is the program invoked to display individual messages (try 'builtin')");
- X
- X case 'e' : return(
- X"This is the editor that will be used for sending messages, etc.");
- X
- X case 'f' : return(
- X"This is the folders directory used when '=' (etc) is used in filenames");
- X
- X case 'm' : return(
- X"This determines if you have the mini-menu displayed or not");
- X
- X case 'n' : return(
- X"Whether to display the names and addresses on mail, or names only");
- X case 'o' : return(
- X"This is where copies of outbound messages are saved automatically.");
- X
- X case 'p' : return(
- X"This is how printouts are generated. \"%s\" will be replaced by the filename.");
- X
- X case 's' : return(
- X"This is used to specify the sorting criteria for the mailboxes");
- X
- X case 'y' : return(
- X"When mail is sent out, this is what your full name will be recorded as.");
- X
- X case 'a' : return(
- X"This defines whether the ELM cursor is an arrow or a highlight bar.");
- X
- X case 'u' : return(
- X"The level of knowledge you have about the Elm mail system.");
- X
- X default : return(""); /* nothing if we don't know! */
- X }
- X}
- X
- Xoptions_help()
- X{
- X /** help menu for the options screen... **/
- X
- X char c, *ptr;
- X
- X Centerline(LINES-3,
- X "Enter the key you want help on, '?' for a list, or '.' to exit help");
- X
- X lower_prompt("Key : ");
- X
- X while ((c = tolower(ReadCh())) != '.') {
- X if (c == '?') {
- X display_helpfile(OPTIONS_HELP);
- X display_options();
- X return;
- X }
- X if ((ptr = one_liner_for(c)) != NULL)
- X error2("%c = %s", c, ptr);
- X else
- X error1("%c isn't used in this section", c);
- X lower_prompt("Key : ");
- X }
- X}
- X
- Xchar *level_name(n)
- Xint n;
- X{
- X /** return the 'name' of the level... **/
- X
- X switch (n) {
- X case 0 : return("Beginning User ");
- X case 1 : return("Intermediate User");
- X default: return("Expert User ");
- X }
- X}
- END_OF_src/options.c
- if test 9046 -ne `wc -c <src/options.c`; then
- echo shar: \"src/options.c\" unpacked with wrong size!?
- fi
- # end of overwriting check
- fi
- echo shar: Extracting \"utils/answer.c\" \(8992 characters\)
- if test -f utils/answer.c ; then
- echo shar: Will not over-write existing file \"utils/answer.c\"
- else
- sed "s/^X//" >utils/answer.c <<'END_OF_utils/answer.c'
- X/** answer.c **/
- X
- X/** This program is a phone message transcription system, and
- X is designed for secretaries and the like, to allow them to
- X painlessly generate electronic mail instead of paper forms.
- X
- X Note: this program ONLY uses the local alias file, and does not
- X even read in the system alias file at all.
- X
- X (C) Copyright 1986, Dave Taylor
- X
- X**/
- X
- X#include <stdio.h>
- X#include <fcntl.h>
- X#include <ctype.h>
- X
- X#include "defs.h" /* ELM system definitions */
- X
- X#define ELM "elm" /* where the elm program lives */
- X
- X#define answer_temp_file "/tmp/answer."
- X
- Xstatic char ident[] = { WHAT_STRING };
- X
- Xstruct alias_rec user_hash_table [MAX_UALIASES];
- X
- Xint user_data; /* fileno of user data file */
- X
- Xchar *expand_group(), *get_alias_address(), *get_token(), *strip_parens();
- X
- Xmain()
- X{
- X FILE *fd;
- X char *address, buffer[LONG_STRING], tempfile[SLEN];
- X char name[SLEN], user_name[SLEN];
- X int msgnum = 0, eof;
- X
- X read_alias_files();
- X
- X while (1) {
- X if (msgnum > 9999) msgnum = 0;
- X
- X printf("\n-------------------------------------------------------------------------------\n");
- X
- Xprompt: printf("\nMessage to: ");
- X gets(user_name, SLEN);
- X if (user_name == NULL)
- X goto prompt;
- X
- X if ((strcmp(user_name,"quit") == 0) ||
- X (strcmp(user_name,"exit") == 0) ||
- X (strcmp(user_name,"done") == 0) ||
- X (strcmp(user_name,"bye") == 0))
- X exit(0);
- X
- X if (translate(user_name, name) == 0)
- X goto prompt;
- X
- X address = get_alias_address(name, 1, 0);
- X
- X printf("address '%s'\n", address);
- X
- X if (address == NULL || strlen(address) == 0) {
- X printf("Sorry, could not find '%s' [%s] in list!\n", user_name,
- X name);
- X goto prompt;
- X }
- X
- X sprintf(tempfile, "%s%d", answer_temp_file, msgnum++);
- X
- X if ((fd = fopen(tempfile,"w")) == NULL)
- X exit(printf("** Fatal Error: could not open %s to write\n",
- X tempfile));
- X
- X
- X printf("\nEnter message for %s ending with a blank line.\n\n",
- X user_name);
- X
- X fprintf(fd,"\n\n");
- X
- X do {
- X printf("> ");
- X if (! (eof = (gets(buffer, SLEN) == NULL)))
- X fprintf(fd, "%s\n", buffer);
- X } while (! eof && strlen(buffer) > 0);
- X
- X fclose(fd);
- X
- X sprintf(buffer,
- X "((%s -s \"While You Were Out\" %s ; %s %s) & ) < %s > /dev/null",
- X ELM, strip_parens(address), remove, tempfile, tempfile);
- X
- X system(buffer);
- X }
- X}
- X
- Xint
- Xtranslate(fullname, name)
- Xchar *fullname, *name;
- X{
- X /** translate fullname into name..
- X 'first last' translated to first_initial - underline - last
- X 'initial last' translated to initial - underline - last
- X Return 0 if error.
- X **/
- X register int i, lastname = 0;
- X
- X for (i=0; i < strlen(fullname); i++) {
- X
- X if (isupper(fullname[i]))
- X fullname[i] = tolower(fullname[i]);
- X
- X if (fullname[i] == ' ')
- X if (lastname) {
- X printf(
- X "** Can't have more than 'FirstName LastName' as address!\n");
- X return(0);
- X }
- X else
- X lastname = i+1;
- X
- X }
- X
- X if (lastname)
- X sprintf(name, "%c_%s", fullname[0], (char *) fullname + lastname);
- X else
- X strcpy(name, fullname);
- X
- X return(1);
- X}
- X
- X
- Xread_alias_files()
- X{
- X /** read the user alias file **/
- X
- X char fname[SLEN];
- X int hash;
- X
- X sprintf(fname, "%s/.alias_hash", getenv("HOME"));
- X
- X if ((hash = open(fname, O_RDONLY)) == -1)
- X exit(printf("** Fatal Error: Could not open %s!\n", fname));
- X
- X read(hash, user_hash_table, sizeof user_hash_table);
- X close(hash);
- X
- X sprintf(fname, "%s/.alias_data", getenv("HOME"));
- X
- X if ((user_data = open(fname, O_RDONLY)) == -1)
- X return;
- X}
- X
- Xchar *get_alias_address(name, mailing, depth)
- Xchar *name;
- Xint mailing, depth;
- X{
- X /** return the line from either datafile that corresponds
- X to the specified name. If 'mailing' specified, then
- X fully expand group names. Returns NULL if not found.
- X Depth is the nesting depth, and varies according to the
- X nesting level of the routine. **/
- X
- X static char buffer[VERY_LONG_STRING];
- X int loc;
- X
- X if ((loc = find(name, user_hash_table, MAX_UALIASES)) >= 0) {
- X lseek(user_data, user_hash_table[loc].byte, 0L);
- X get_line(user_data, buffer, LONG_STRING);
- X if (buffer[0] == '!' && mailing)
- X return( (char *) expand_group(buffer, depth));
- X else
- X return( (char *) buffer);
- X }
- X
- X return( (char *) NULL);
- X}
- X
- Xchar *expand_group(members, depth)
- Xchar *members;
- Xint depth;
- X{
- X /** given a group of names separated by commas, this routine
- X will return a string that is the full addresses of each
- X member separated by spaces. Depth is the current recursion
- X depth of the expansion (for the 'get_token' routine) **/
- X
- X char buffer[VERY_LONG_STRING];
- X char buf[LONG_STRING], *word, *address, *bufptr;
- X
- X strcpy(buf, members); /* parameter safety! */
- X buffer[0] = '\0'; /* nothing in yet! */
- X bufptr = (char *) buf; /* grab the address */
- X depth++; /* one more deeply into stack */
- X
- X while ((word = (char *) get_token(bufptr, "!, ", depth)) != NULL) {
- X if ((address = (char *) get_alias_address(word, 1, depth)) == NULL) {
- X fprintf(stderr, "Alias %s not found for group expansion!", word);
- X return( (char *) NULL);
- X }
- X else if (strcmp(buffer,address) != 0) {
- X sprintf(buffer,"%s %s", buffer, address);
- X }
- X
- X bufptr = NULL;
- X }
- X
- X return( (char *) buffer);
- X}
- X
- Xint
- Xfind(word, table, size)
- Xchar *word;
- Xstruct alias_rec table[];
- Xint size;
- X{
- X /** find word and return loc, or -1 **/
- X register int loc;
- X
- X if (strlen(word) > 20)
- X exit(printf("Bad alias name: %s. Too long.\n", word));
- X
- X loc = hash_it(word, size);
- X
- X while (strcmp(word, table[loc].name) != 0) {
- X if (table[loc].name[0] == '\0')
- X return(-1);
- X loc = (loc + 1) % size;
- X }
- X
- X return(loc);
- X}
- X
- Xint
- Xhash_it(string, table_size)
- Xchar *string;
- Xint table_size;
- X{
- X /** compute the hash function of the string, returning
- X it (mod table_size) **/
- X
- X register int i, sum = 0;
- X
- X for (i=0; string[i] != '\0'; i++)
- X sum += (int) string[i];
- X
- X return(sum % table_size);
- X}
- X
- Xget_line(fd, buffer)
- Xint fd;
- Xchar *buffer;
- X{
- X /* read from file fd. End read upon reading either
- X EOF or '\n' character (this is where it differs
- X from a straight 'read' command!) */
- X
- X register int i= 0;
- X char ch;
- X
- X while (read(fd, &ch, 1) > 0)
- X if (ch == '\n' || ch == '\r') {
- X buffer[i] = 0;
- X return;
- X }
- X else
- X buffer[i++] = ch;
- X}
- X
- Xprint_long(buffer, init_len)
- Xchar *buffer;
- Xint init_len;
- X{
- X /** print buffer out, 80 characters (or less) per line, for
- X as many lines as needed. If 'init_len' is specified,
- X it is the length that the first line can be.
- X **/
- X
- X register int i, loc=0, space, length;
- X
- X /* In general, go to 80 characters beyond current character
- X being processed, and then work backwards until space found! */
- X
- X length = init_len;
- X
- X do {
- X if (strlen(buffer) > loc + length) {
- X space = loc + length;
- X while (buffer[space] != ' ' && space > loc + 50) space--;
- X for (i=loc;i <= space;i++)
- X putchar(buffer[i]);
- X putchar('\n');
- X loc = space;
- X }
- X else {
- X for (i=loc;i < strlen(buffer);i++)
- X putchar(buffer[i]);
- X putchar('\n');
- X loc = strlen(buffer);
- X }
- X length = 80;
- X } while (loc < strlen(buffer));
- X}
- X
- X/****
- X The following is a newly chopped version of the 'strtok' routine
- X that can work in a recursive way (up to 20 levels of recursion) by
- X changing the character buffer to an array of character buffers....
- X****/
- X
- X#define MAX_RECURSION 20 /* up to 20 deep recursion */
- X
- X#undef NULL
- X#define NULL (char *) 0 /* for this routine only */
- X
- Xextern int strspn();
- Xextern char *strpbrk();
- X
- Xchar *get_token(string, sepset, depth)
- Xchar *string, *sepset;
- Xint depth;
- X{
- X
- X /** string is the string pointer to break up, sepstr are the
- X list of characters that can break the line up and depth
- X is the current nesting/recursion depth of the call **/
- X
- X register char *p, *q, *r;
- X static char *savept[MAX_RECURSION];
- X
- X /** is there space on the recursion stack? **/
- X
- X if (depth >= MAX_RECURSION) {
- X fprintf(stderr,"Error: Get_token calls nested greated than %d deep!\n",
- X MAX_RECURSION);
- X exit(1);
- X }
- X
- X /* set up the pointer for the first or subsequent call */
- X p = (string == NULL)? savept[depth]: string;
- X
- X if(p == 0) /* return if no tokens remaining */
- X return(NULL);
- X
- X q = p + strspn(p, sepset); /* skip leading separators */
- X
- X if (*q == '\0') /* return if no tokens remaining */
- X return(NULL);
- X
- X if ((r = strpbrk(q, sepset)) == NULL) /* move past token */
- X savept[depth] = 0; /* indicate this is last token */
- X else {
- X *r = '\0';
- X savept[depth] = ++r;
- X }
- X return(q);
- X}
- X
- Xchar *strip_parens(string)
- Xchar *string;
- X{
- X /** Return string with all parenthesized information removed.
- X This is a non-destructive algorithm... **/
- X
- X static char buffer[LONG_STRING];
- X register int i, depth = 0, buffer_index = 0;
- X
- X for (i=0; i < strlen(string); i++) {
- X if (string[i] == '(')
- X depth++;
- X else if (string[i] == ')')
- X depth--;
- X else if (depth == 0)
- X buffer[buffer_index++] = string[i];
- X }
- X
- X buffer[buffer_index] = '\0';
- X
- X return( (char *) buffer);
- X}
- END_OF_utils/answer.c
- if test 8992 -ne `wc -c <utils/answer.c`; then
- echo shar: \"utils/answer.c\" unpacked with wrong size!?
- fi
- # end of overwriting check
- fi
- echo shar: End of archive 8 \(of 19\).
- cp /dev/null ark8isdone
- DONE=true
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
- if test ! -f ark${I}isdone ; then
- echo shar: You still need to run archive ${I}.
- DONE=false
- fi
- done
- if test "$DONE" = "true" ; then
- echo You have unpacked all 19 archives.
- echo "See the Instructions file"
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- fi
- ## End of shell archive.
- exit 0
-