[comp.sources.unix] v09i064: Fixed reply.c for ELM, Patch2

sources-request@mirror.TMC.COM (05/01/87)

Submitted by: rs (Rich Salz)
Mod.sources: Volume 9, Issue 64
Archive-name: elm2/Patch2

[  Sorry about the delay on this one -- I had to dig it out of a
   tape library...  --r$  ]

#! /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 shell archive."
# Contents:  reply.c
# Wrapped by rs@mirror on Thu Apr 30 16:55:12 1987
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo shar: Extracting \"reply.c\" \(13964 characters\)
if test -f reply.c ; then 
  echo shar: Will not over-write existing file \"reply.c\"
else
sed "s/^X//" >reply.c <<'END_OF_reply.c'
X/**		reply.c		**/
X
X/*** routine allows replying to the sender of the current message 
X
X     (C) Copyright 1985, Dave Taylor
X***/
X
X#include "headers.h"
X#include <errno.h>
X
X#ifndef BSD
X#  include <sys/types.h>
X#  include <sys/utsname.h>
X#endif
X
X/** Note that this routine generates automatic header information
X    for the subject and (obviously) to lines, but that these can
X    be altered while in the editor composing the reply message! 
X**/
X
Xchar *strip_parens(), *get_token();
X
Xextern int errno;
X
Xchar *error_name(), *strcat(), *strcpy();
X
Xint
Xreply()
X{
X	/** Reply to the current message.  Returns non-zero iff
X	    the screen has to be rewritten. **/
X
X	char return_address[LONG_SLEN], subject[SLEN];
X	int  return_value, form_letter;
X
X	form_letter = (header_table[current-1].status & FORM_LETTER);
X
X	get_return(return_address);
X
X	if (first_word(header_table[current-1].from, "To:")) {
X	  strcpy(subject, header_table[current-1].subject);
X	  if (form_letter)
X	    return_value = mail_filled_in_form(return_address, subject);
X	  else
X	    return_value = send(return_address, subject, TRUE, NO);
X	}
X	else if (header_table[current-1].subject[0] != '\0') {
X	  if ((strncmp("Re:", header_table[current-1].subject, 3) == 0) ||
X	      (strncmp("RE:", header_table[current-1].subject, 3) == 0) ||
X	      (strncmp("re:", header_table[current-1].subject, 3) == 0)) 
X	    strcpy(subject, header_table[current-1].subject);
X	  else {
X	    strcpy(subject,"Re: ");
X	    strcat(subject,header_table[current-1].subject); 
X	  }
X	  if (form_letter)
X	    return_value = mail_filled_in_form(return_address, subject);
X	  else
X	    return_value = send(return_address, subject, TRUE, NO);
X	}
X	else
X	  if (form_letter)
X	    return_value = mail_filled_in_form(return_address, 
X						"Filled in Form");
X	  else
X	    return_value = send(return_address, "Re: your mail", TRUE, NO);
X
X	return(return_value);
X}
X
Xint
Xreply_to_everyone()
X{
X	/** Reply to everyone who received the current message.  
X	    This includes other people in the 'To:' line and people
X	    in the 'Cc:' line too.  Returns non-zero iff the screen 
X            has to be rewritten. **/
X
X	char return_address[LONG_SLEN], subject[SLEN];
X	char full_address[VERY_LONG_STRING];
X	int  return_value;
X
X	get_return(return_address);
X
X	strcpy(full_address, return_address);	/* sender gets copy */
X	
X	get_and_expand_everyone(return_address, full_address);
X
X	if (header_table[current-1].subject[0] != '\0') {
X	  if ((strncmp("Re:", header_table[current-1].subject, 3) == 0) ||
X	      (strncmp("RE:", header_table[current-1].subject, 3) == 0) ||
X	      (strncmp("re:", header_table[current-1].subject, 3) == 0)) 
X	    strcpy(subject, header_table[current-1].subject);
X	  else {
X	    strcpy(subject,"Re: ");
X	    strcat(subject,header_table[current-1].subject); 
X	  }
X	  return_value = send(full_address, subject, TRUE, NO);
X	}
X	else
X	  return_value = send(full_address, "Re: your mail", TRUE, NO);
X
X	return(return_value);
X
X}
X
Xint
Xforward()
X{
X	/** Forward the current message.  What this actually does is
X	    to set auto_copy to true, then call 'send' to get the 
X	    address and route the mail. 
X	**/
X
X	char subject[SLEN], address[VERY_LONG_STRING];
X	int  original_cc, results, edit_msg = FALSE;
X
X	original_cc = auto_copy;
X	address[0] = '\0';
X
X	if (header_table[current-1].status & FORM_LETTER)
X	  PutLine0(LINES-3,COLUMNS-40,"<no editing allowed>");
X	else {
X	  edit_msg = (want_to("Edit outgoing message (y/n) ? ",'y',FALSE)!='n');
X	  Write_to_screen("%s", 1, edit_msg? "Yes" : "No");
X	}
X
X	auto_cc = TRUE;			/* we want a copy */
X
X	if (strlen(header_table[current-1].subject) > 0) {
X	  strcpy(subject,header_table[current-1].subject); 
X	  results = send(address, subject, edit_msg,
X	    header_table[current-1].status & FORM_LETTER? 
X	    PREFORMATTED : allow_forms);
X	}
X	else
X	  results = send(address, "Forwarded Mail...", edit_msg, 
X	    header_table[current-1].status & FORM_LETTER? 
X	    PREFORMATTED : allow_forms);
X	
X	auto_copy = original_cc;
X
X	return(results);
X}
X
Xget_and_expand_everyone(return_address, full_address)
Xchar *return_address, *full_address;
X{
X	/** Read the current message, extracting addresses from the 'To:'
X	    and 'Cc:' lines.   As each address is taken, ensure that it
X	    isn't to the author of the message NOR to us.  If neither,
X	    prepend with current return address and append to the 
X	    'full_address' string.
X	**/
X
X    char ret_address[LONG_SLEN], buf[LONG_SLEN], new_address[LONG_SLEN],
X	 address[LONG_SLEN], comment[LONG_SLEN];
X    int  in_message = 1, first_pass = 0, index;
X
X    /** First off, get to the first line of the message desired **/
X
X    if (fseek(mailfile, header_table[current-1].offset, 0) == -1) {
X	dprint3(1,"Error: seek %ld resulted in errno %s (%s)\n", 
X		 header_table[current-1].offset, error_name(errno), 
X		 "get_and_expand_everyone");
X	error2("ELM [seek] couldn't read %d bytes into file (%s)",
X	       header_table[current-1].offset, error_name(errno));
X	return;
X    }
X 
X    /** okay!  Now we're there!  **/
X
X    /** let's fix the ret_address to reflect the return address of this
X	message with '%s' instead of the persons login name... **/
X
X    translate_return(return_address, ret_address);
X
X    /** now let's parse the actual message! **/
X
X    while (in_message) {
X      in_message = (int) (fgets(buf, LONG_SLEN, mailfile) != NULL);
X      if (first_word(buf, "From ") && first_pass++ != 0) 
X	in_message = FALSE;
X      else if (first_word(buf, "To:") || first_word(buf, "Cc:") ||
X	       first_word(buf, "CC:") || first_word(buf, "cc:")) {
X	do {
X	  no_ret(buf);
X
X	  /** we have a buffer with a list of addresses, each of either the
X	      form "address (name)" or "name <address>".  Our mission, should
X	      we decide not to be too lazy, is to break it into the two parts.
X	  **/
X	      
X	  if (!whitespace(buf[0]))
X	    index = chloc(buf, ':')+1;		/* skip header field */
X	  else
X	    index = 0;				/* skip whitespace   */
X
X	  while (break_down_tolist(buf, &index, address, comment)) {
X
X	    if (okay_address(address, return_address)) {
X	      sprintf(new_address, ret_address, address);
X	      optimize_and_add(new_address, full_address);
X	    }
X	  }
X
X          in_message = (int) (fgets(buf, LONG_SLEN, mailfile) != NULL);
X
X	  if (in_message) dprint1(1,"> %s", buf);
X	
X	} while (in_message && whitespace(buf[0]));
X
X      }
X      else if (strlen(buf) < 2)	/* done with header */
X	 in_message = FALSE;
X    }
X}
X
Xint
Xokay_address(address, return_address)
Xchar *address, *return_address;
X{
X	/** This routine checks to ensure that the address we just got
X	    from the "To:" or "Cc:" line isn't us AND isn't the person	
X	    who sent the message.  Returns true iff neither is the case **/
X
X	char our_address[SLEN];
X	struct addr_rec  *alternatives;
X
X	if (in_string(address, return_address))
X	  return(FALSE);
X
X	sprintf(our_address, "%s!%s", hostname, username);
X
X	if (in_string(address, our_address))
X	  return(FALSE);
X
X	sprintf(our_address, "%s@%s", username, hostname);
X	  
X	if (in_string(address, our_address))
X	  return(FALSE);
X
X	alternatives = alternative_addresses;
X
X	while (alternatives != NULL) {
X	  if (in_string(address, alternatives->address))
X	    return(FALSE);
X	  alternatives = alternatives->next;
X	}
X
X	return(TRUE);
X}
X	    
Xoptimize_and_add(new_address, full_address)
Xchar *new_address, *full_address;
X{
X	/** This routine will add the new address to the list of addresses
X	    in the full address buffer IFF it doesn't already occur.  It
X	    will also try to fix dumb hops if possible, specifically hops
X	    of the form ...a!b...!a... and hops of the form a@b@b etc 
X	**/
X
X	register int len, host_count = 0, i;
X	char     hosts[MAX_HOPS][SLEN];	/* array of machine names */
X	char     *host, *addrptr;
X
X	if (in_string(full_address, new_address))
X	  return(1);	/* duplicate address */
X
X	/** optimize **/
X	/*  break down into a list of machine names, checking as we go along */
X	
X	addrptr = (char *) new_address;
X
X	while ((host = get_token(addrptr, "!", 1)) != NULL) {
X	  for (i = 0; i < host_count && ! equal(hosts[i], host); i++)
X	      ;
X
X	  if (i == host_count) {
X	    strcpy(hosts[host_count++], host);
X	    if (host_count == MAX_HOPS) {
X	       dprint1(2,
X              "Error: hit max_hops limit trying to build return address (%s)\n",
X		      "optimize_and_add");
X	       error("Can't build return address - hit MAX_HOPS limit!");
X	       return(1);
X	    }
X	  }
X	  else 
X	    host_count = i + 1;
X	  addrptr = NULL;
X	}
X
X	/** fix the ARPA addresses, if needed **/
X	
X	if (chloc(hosts[host_count-1], '@') > -1)
X	  fix_arpa_address(hosts[host_count-1]);
X	  
X	/** rebuild the address.. **/
X
X	new_address[0] = '\0';
X
X	for (i = 0; i < host_count; i++)
X	  sprintf(new_address, "%s%s%s", new_address, 
X	          new_address[0] == '\0'? "" : "!",
X	          hosts[i]);
X
X	if (full_address[0] == '\0')
X	  strcpy(full_address, new_address);
X	else {
X	  len = strlen(full_address);
X	  full_address[len  ] = ',';
X	  full_address[len+1] = ' ';
X	  full_address[len+2] = '\0';
X	  strcat(full_address, new_address);
X	}
X
X	return(0);
X}
X
Xget_return_name(address, name, shift_lower)
Xchar *address, *name;
Xint   shift_lower;
X{
X	/** Given the address (either a single address or a combined list 
X	    of addresses) extract the login name of the first person on
X	    the list and return it as 'name'.  Modified to stop at
X	    any non-alphanumeric character. **/
X
X	/** An important note to remember is that it isn't vital that this
X	    always returns just the login name, but rather that it always
X	    returns the SAME name.  If the persons' login happens to be,
X	    for example, joe.richards, then it's arguable if the name 
X	    should be joe, or the full login.  It's really immaterial, as
X	    indicated before, so long as we ALWAYS return the same name! **/
X
X	/** Another note: modified to return the argument as all lowercase
X	    always, unless shift_lower is FALSE... **/
X
X	char single_address[LONG_SLEN];
X	register int i, loc, index = 0;
X
X	dprint2(6,"get_return_name called with (%s, <>, shift=%s)\n", 
X		   address, onoff(shift_lower));
X
X	/* First step - copy address up to a comma, space, or EOLN */
X
X	for (i=0; address[i] != ',' && ! whitespace(address[i]) && 
X	     address[i] != '\0'; i++)
X	  single_address[i] = address[i];
X	single_address[i] = '\0';
X
X	/* Now is it an ARPA address?? */
X
X	if ((loc = chloc(single_address, '@')) != -1) {	  /* Yes */
X
X	  /* At this point the algorithm is to keep shifting our copy 
X	     window left until we hit a '!'.  The login name is then
X             located between the '!' and the first metacharacter to 
X	     it's right (ie '%', ':' or '@'). */
X
X	  for (i=loc; single_address[i] != '!' && i > -1; i--)
X	      if (single_address[i] == '%' || 
X	          single_address[i] == ':' ||
X	          single_address[i] == '.' ||	/* no domains */
X		  single_address[i] == '@') loc = i-1;
X	
X	  if (i < 0 || single_address[i] == '!') i++;
X
X	  for (index = 0; index < loc - i + 1; index++)
X	    if (shift_lower)
X	      name[index] = tolower(single_address[index+i]);
X	    else
X	      name[index] = single_address[index+i];
X	  name[index] = '\0';
X	}
X	else {	/* easier - standard USENET address */
X
X	  /* This really is easier - we just cruise left from the end of
X	     the string until we hit either a '!' or the beginning of the
X             line.  No sweat. */
X
X	  loc = strlen(single_address)-1; 	/* last char */
X
X	  for (i = loc; single_address[i] != '!' && single_address[i] != '.' 
X	       && i > -1; i--)
X	     if (shift_lower)
X	       name[index++] = tolower(single_address[i]);
X	     else
X	       name[index++] = single_address[i];
X	  name[index] = '\0';
X	  reverse(name);
X	}
X}
X
Xint
Xbreak_down_tolist(buf, index, address, comment)
Xchar *buf, *address, *comment;
Xint  *index;
X{
X	/** This routine steps through "buf" and extracts a single address
X	    entry.  This entry can be of any of the following forms;
X
X		address (name)
X		name <address>
X		address
X	
X	    Once it's extracted a single entry, it will then return it as
X	    two tokens, with 'name' (e.g. comment) surrounded by parens.
X	    Returns ZERO if done with the string...
X	**/
X
X	char buffer[LONG_STRING];
X	register int i, loc = 0;
X
X	if (*index > strlen(buf)) return(FALSE);
X
X	while (whitespace(buf[*index])) (*index)++;
X
X	if (*index > strlen(buf)) return(FALSE);
X
X	/** Now we're pointing at the first character of the token! **/
X
X	while (buf[*index] != ',' && buf[*index] != '\0')
X	  buffer[loc++] = buf[(*index)++];
X
X	(*index)++;
X
X	while (whitespace(buffer[loc])) loc--;	/* remove trailing whitespace */
X
X	buffer[loc] = '\0';
X
X	if (strlen(buffer) == 0) return(FALSE);
X
X	dprint1(5, "\n* got \"%s\"\n", buffer);
X
X	if (buffer[loc-1] == ')') {	/*   address (name)  format */
X	  for (loc = 0;buffer[loc] != '(' && loc < strlen(buffer); loc++)
X		/* get to the opening comment character... */ ;
X
X	  loc--;	/* back up to just before the paren */
X	  while (whitespace(buffer[loc])) loc--;	/* back up */
X
X	  /** get the address field... **/
X
X	  for (i=0; i <= loc; i++)
X	    address[i] = buffer[i];
X	  address[i] = '\0';
X
X	  /** now get the comment field, en toto! **/
X
X	  loc = 0;
X
X	  for (i = chloc(buffer, '('); i < strlen(buffer); i++)
X	    comment[loc++] = buffer[i];
X	  comment[loc] = '\0';
X	}
X	else if (buffer[loc-1] == '>') {	/*   name <address>  format */
X	  dprint0(7, "\tcomment <address>\n");
X	  for (loc = 0;buffer[loc] != '<' && loc < strlen(buffer); loc++)
X		/* get to the opening comment character... */ ;
X	  while (whitespace(buffer[loc])) loc--;	/* back up */
X
X	  /** get the comment field... **/
X
X	  comment[0] = '(';
X	  for (i=1; i < loc; i++)
X	    comment[i] = buffer[i-1];
X	  comment[i++] = ')';
X	  comment[i] = '\0';
X
X	  /** now get the address field, en toto! **/
X
X	  loc = 0;
X
X	  for (i = chloc(buffer,'<') + 1; i < strlen(buffer) - 1; i++)
X	    address[loc++] = buffer[i];
X	
X	  address[loc] = '\0';
X	}
X	else {
X	  strcpy(address, buffer);
X	  comment[0] = '\0';
X	}
X
X	dprint2(5,"-- returning '%s' '%s'\n", address, comment);
X
X	return(TRUE);
X}
END_OF_reply.c
if test 13964 -ne `wc -c <reply.c`; then
    echo shar: \"reply.c\" unpacked with wrong size!?
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0