[comp.mail.elm] Elm 2.1 PL1 Part 22 of 22

syd@dsinc.UUCP (Syd Weinstein) (12/16/88)

---- Cut Here and unpack ----
#!/bin/sh
# this is part 22 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file utils/newmail.c continued
#
CurArch=22
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
     exit 1; fi
( read Scheck
  if test "$Scheck" != $CurArch
  then echo "Please unpack part $Scheck next!"
       exit 1;
  else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file utils/newmail.c"
sed 's/^X//' << 'SHAR_EOF' >> utils/newmail.c
X	       buffer[i] != '('; i++)
X	    temp[j++] = buffer[i];
X	  temp[j] = '\0';
X	}
X	else if (lastch(buffer) == ')') {
X	  for (i=strlen(buffer)-2; buffer[i] != '\0' && buffer[i] != '(' &&
X	       buffer[i] != '<'; i--)
X	    temp[j++] = buffer[i];
X	  temp[j] = '\0';
X	  reverse(temp);
X	}
X	  
X	if (strlen(temp) > 0) {		/* mess with buffer... */
X
X	  /* remove leading spaces... */
X
X	  while (whitespace(temp[0]))
X	    temp = (char *) (temp + 1);		/* increment address! */
X
X	  /* remove trailing spaces... */
X
X	  i = strlen(temp) - 1;
X
X	  while (whitespace(temp[i]))
X	   temp[i--] = '\0';
X
X	  /* if anything is left, let's change 'from' value! */
X
X	  if (strlen(temp) > 0)
X	    strcpy(newfrom, temp);
X	}
X}
X
Xreverse(string)
Xchar *string;
X{
X	/** reverse string... pretty trivial routine, actually! **/
X
X	char buffer[SLEN];
X	register int i, j = 0;
X
X	for (i = strlen(string)-1; i >= 0; i--)
X	  buffer[j++] = string[i];
X
X	buffer[j] = '\0';
X
X	strcpy(string, buffer);
X}
X
Xlong
Xbytes(name)
Xchar *name;
X{
X	/** return the number of bytes in the specified file.  This
X	    is to check to see if new mail has arrived....  **/
X
X	int ok = 1;
X	extern int errno;	/* system error number! */
X	struct stat buffer;
X
X	if (stat(name, &buffer) != 0)
X	  if (errno != 2) {
X	    fprintf(stderr,"Error %d attempting fstat on %s", errno, name);
X	    exit(1);
X	  }
X	  else
X	    ok = 0;
X	
X	return(ok ? buffer.st_size : 0);
X}
X
Xchar  *getusername()
X{
X	/** Getting the username on some systems is a real pain, so...
X	   This routine is guaranteed to return a usable username **/
X
X	char *return_value, *getlogin();
X
X	if ((return_value = getlogin()) == NULL)
X	  if ((return_value = getlogin()) == NULL) {
X	    printf("Newmail: I can't get username!\n");
X	    exit(1);
X	  }
X
X	return( (char *) return_value);
X}
X
Xusage()
X{
X	/* print a nice friendly usage message */
X
X	fprintf(stderr, 
X"\nUsage: %s [-d] [-i interval] [-w] {folders}\n");
X	fprintf(stderr, "\nWhere:\n");
X	fprintf(stderr, "  -d\tturns on debugging output\n");
X	fprintf(stderr,
X"  -i D\tsets the interval checking time to 'D' seconds\n");
X	fprintf(stderr,
X"  -w\tforces 'window'-style output, and bypasses auto-background\n\n");
X	fprintf(stderr,
X"folders can be specified by relative or absolute path names, can be the name\n");
X	fprintf(stderr,
X"of a mailbox in the incoming mail directory to check, or can have one of the\n");
X	fprintf(stderr,
X"standard Elm mail directory prefix chars (e.g. '+', '=' or '%').\n");
X	fprintf(stderr,
X"Furthermore, any folder can have '=string' as a suffix to indicate a folder\n");
X	fprintf(stderr,
X"identifier other than the basename of the file\n\n");
X}
X
X
Xexpand_filename(name, store_space)
Xchar *name, *store_space;
X{
X	strcpy(store_space, name);
X	if (expand(store_space) == 0) {
X	  fprintf(stderr,"Sorry, but I couldn't expand \"%s\"\n",name);
X	  exit(1);
X	}
X}
X
Xpad_prefixes()
X{
X	/** This simple routine is to ensure that we have a nice
X	    output format.  What it does is whip through the different
X	    prefix strings we've been given, figures out the maximum
X	    length, then space pads the other prefixes to match.
X	**/
X
X	register int i, j, len = 0;
X
X	for (i=0; i < total_folders; i++)
X	  if (len < (j=strlen(folders[i].prefix)))
X	    len = j;
X	
X	for (i=0; i < total_folders; i++)
X	  for (j = strlen(folders[i].prefix); j < len; j++)
X	    strcat(folders[i].prefix, " ");
X}
SHAR_EOF
echo "File utils/newmail.c is complete"
chmod 0444 utils/newmail.c || echo "restore of utils/newmail.c fails"
echo "x - extracting utils/postmail.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > utils/postmail.c &&
X
Xstatic char rcsid[] = "@(#)$Id: postmail.c,v 2.1 88/09/15 21:07:37 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
X *
X *  (C) Copyright 1987, Dave Taylor
X *  (C) Copyright 1987, Hewlett-Packard Labs
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Eric D. Christensen  -  edc@altnet.ALTOS.COM 
X *				uunet!altnet!edc
X *
X *******************************************************************************
X * $Log:	postmail.c,v $
X * Revision 2.1  88/09/15  21:07:37  syd
X * checked in with -k by syd at 88.09.15.21.07.37.
X * 
X * Revision 2.1  88/07/21  10:01:57  edc
X * Final hacks and cleanup to the 2.1 alpha test release
X * 
X * Revision 2.0  88/06/27  16:54:13  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** This program is designed to allow mailing lists to easily gateway into
X    netnews groups by accepting from stdin a mail message, reformatting it,
X    and invoking "inews" to submit it to the specified newsgroup.  Over
X    and above other programs of this nature, this preserves the following
X    header information if present:
X	
X	Organization:
X
X    and rewrites the From: field to properly fit in with the inews
X    perception of what it should look like (e.g user@hostname.domain).
X    The actual return address will be included as the "Reply-To:"
X    header.
X
X    This program will also be able to scan the subject line and compare
X    it to other notes posted to the specified group, extracting 
X    references if possible...
X
X**/
X
X#include <stdio.h>
X#include <ctype.h>
X#include <errno.h>
X
X#define  SLEN		256
X#define  NLEN		40
X
X#define  INEWS		"/usr/local/lib/news/inews"
X
X#define  TEMPFILE	"/tmp/postmail."
X
X#define  BOGUS_ADDRESS	"@hplabs.HP.COM"
X#define  UUCP_HOSTNAME	"hplabs"
X
X#define  DEFAULT_DOMAIN	".HPL.HP.COM"
X
X/** if these are going into a moderated group, then you'll want to
X    define "INCLUDE_APPROPED_LINE" to have it add an appropriate
X    header to the posting.
X**/
X
X#define INCLUDE_APPROVED_LINE
X
X#ifdef INCLUDE_APPROVED_LINE
X#define  APPROVAL	"postmail@hplabs"
X#endif
X
X/** and some headers for future reference and all... **/
X
X#define  FROM		"From:"
X#define  FROMLEN	5
X
X#define  SUBJ   	"Subj:"
X#define  SUBJLEN	5
X
X#define  SUBJECT	"Subject:"
X#define  SUBJECTLEN	8
X
X#define  ORGANIZATION	"Organization"
X#define  ORGANISATION 	"Organisation"
X#define  ORGLEN	        12
X
X#define  FULLNAME	"Fullname:"
X#define  FULLNAMELEN	9
X
X#define  equal(a,b,c)	(strncmp(a,b,c) == 0)
X#define  whitespace(c)	(c == ' ' || c == '\t')
X#define  valid_char(c)	( isalnum(c) || c == '_' || c == '-' || c == '.')
X
Xint   debug = 0;			/* shall we output debugging info? */
Xchar  from_line[SLEN],			/* space to save the From: line    */
X      fullname[SLEN],			/*   and the fullname piece of it  */
X      alt_fullname[SLEN],		/*           ...the Fullname: line */
X      clunky_from_line[SLEN],		/*              ... the From_ line */
X      subject_line[SLEN],		/*           ... the Subject: line */
X      organization[SLEN];		/*      and the Organization: line */
X      
Xextern int errno;
X
Xmain(argc, argv)
Xchar *argv[];
X{
X	FILE   *outfd;			/* tempfile file descriptor        */
X	char   newsgroup[NLEN],		/* what netnews group to post to?  */
X	       buffer[SLEN],		/* buffer for reading message      */
X	       tempfilename[NLEN],	/* some space for temp storage...  */
X	       c;			/* for starting arg parsing	   */
X	register int lines = 0,		/* number of lines in message      */
X	       in_headers = 1;		/* for breaking message into 2 pts */
X
X	extern int optind;		/* for starting argument parsing.. */
X
X	/** get the starting parameters... **/
X
X	while ((c = getopt(argc, argv, "d")) != EOF) {
X	  switch (c) {
X	    case 'd' : debug++;		break;
X	    case '?' : printf("Usage: %s [-d] newsgroup < mail-message\n", 
X			      argv[0]);
X		       exit(1);
X	  }
X	}
X
X	/** did the user remember to specify a newsgroup? **/
X	
X	if (optind != argc-1) {
X	  printf("You need to specify a newsgroup to post this to;\n");
X	  printf("Usage: %s [-d] newsgroup < mail-message\n", argv[0]);
X	  exit(1);
X	}
X
X	strcpy(newsgroup, argv[optind]);
X
X	/** now let's see if it's a valid newsgroup... **/
X
X	if (! valid_newsgroup(newsgroup)) {
X	  printf("Sorry, but \"%s\" isn't a valid newsgroup!\n", newsgroup);
X	  exit(1);
X	}
X
X	/** now let's open a tempfile and, extract the headers we're 
X	    interested in, save the message to it... **/
X
X	sprintf(tempfilename, "%s%d", TEMPFILE, getpid());
X
X	if ((outfd = fopen(tempfilename, "w")) == NULL) {
X	  printf("Sorry, but I couldn't open \"%s\" for writing...\n",
X		tempfilename);
X	  exit(1);
X	}
X
X	while (gets(buffer) != NULL) {
X	  if (in_headers) {
X	    if (lines++ == 0)
X	       strcpy(clunky_from_line, buffer);	/* always .. */
X	    if (equal(buffer, FROM, FROMLEN))
X	       strcpy(from_line, buffer);		/* what a deal! */
X	    else if (equal(buffer, SUBJ, SUBJLEN) ||
X	             equal(buffer, SUBJECT, SUBJECTLEN))
X	      strcpy(subject_line, buffer);
X	    else if (equal(buffer, ORGANIZATION, ORGLEN) ||
X	             equal(buffer, ORGANISATION, ORGLEN))
X	      strcpy(organization, buffer);		/* got it too! */
X	    else if (equal(buffer, FULLNAME, FULLNAMELEN))
X	      strcpy(alt_fullname, (char *) buffer + FULLNAMELEN + 1);
X	    else if (strlen(buffer) < 2)
X	      break;
X	  }
X	}
X
X	/** We'll leave the file descriptor there while we go and figure
X	    out how to format these headers and add them to the temporary
X	    output file...
X	**/
X
X	/** The order of our headers lines will be:
X	      From:
X	      Newsgroups:
X	      Subject:
X	      Reply-To:
X	      Organization:
X	      Approved: 
X	**/
X	     
X	output_from_line(clunky_from_line, from_line, outfd);
X
X	fprintf(outfd, "Newsgroups: %s\n", newsgroup);
X
X	if (strlen(subject_line) > 0)
X	  fprintf(outfd, "%s\n", subject_line);
X	else
X	  fprintf(outfd, "Subject: <none>\n");
X
X	output_reply_to(clunky_from_line, outfd);
X
X	if (strlen(organization) > 0)
X	  fprintf(outfd, "%s\n", organization);
X
X#ifdef INCLUDE_APPROVED_LINE
X	fprintf(outfd, "Approved: %s\n\n", APPROVAL);
X#else
X	fprintf(outfd, "\n");
X#endif
X		
X	while (gets(buffer) != NULL)
X	  fprintf(outfd, "%s\n", buffer);
X	fclose(outfd);
X
X	/** now we've a temp file that is all ready to post, so
X	    let's go ahead and post it!
X	**/
X
X	sprintf(buffer, "%s -M -h -n %s < %s", INEWS, newsgroup, tempfilename);
X
X	if (system(buffer) != 0) {
X	  fprintf(stderr,"Postmail failed!  Got error #%d trying:\n", errno);
X	  fprintf(stderr,"> %s\n", buffer);
X	}
X	else
X	  (void) unlink(tempfilename);
X
X	exit(0);
X}
X
Xint
Xvalid_newsgroup(newsgroup)
Xchar *newsgroup;
X{
X	/* this will check to see if it's a valid newsgroup or not */
X
X	return(1);
X}
X
Xoutput_from_line(from_, from_colon, outfd)
Xchar *from_, *from_colon;
XFILE *outfd;
X{
X	/** given the From_ and From: lines from the message, try to 
X	    figure out the optimal `user@hostname.domain (fullname)'
X	    style From: line to output to the file, and do so.
X	**/
X
X	char raw_address[SLEN], *p, *p2;
X	register int i = 0, j = 0;
X	
X	fullname[0] = raw_address[0] = '\0';
X
X	if (strlen(from_colon) == 0)
X	  sscanf(from_, "%*s %s", raw_address);
X	else {
X	  p = from_colon + strlen(from_colon) - 1;
X	  if (*p == '>') {
X	     while (*p != '<') p--;
X	     p++;	/* skip the leading '<' please */
X	     for (p2 = from_colon + FROMLEN; *p2 != '<'; )
X	       if (i == 0 && whitespace(*p2)) 
X	          p2++; 
X	       else 
X		  fullname[i++] = *p2++;
X	     while (*p != '>')	
X	       if (j == 0 && whitespace(*p))
X	         p++;
X	       else
X	         raw_address[j++] = *p++;
X	  }
X	  else {
X	    for (p2 = from_colon + FROMLEN; *p2 != '(' && *p2 > '\0'; )
X	      if (j == 0 && whitespace(*p2))
X	        p2++;
X	      else
X	        raw_address[j++] = *p2++;
X	    if (*p2 == '(')
X	      while (*++p2 != ')') 
X	        fullname[i++] = *p2;
X	  }
X	  fullname[i] = raw_address[j] = '\0';
X	  
X	  /**  let's remove trailing white space, if any **/
X
X	  for (p = fullname + strlen(fullname) - 1; whitespace(*p); 
X	       *p-- ='\0')  ;
X
X	  for (p = raw_address + strlen(raw_address) - 1; whitespace(*p); 
X	       *p-- ='\0')  ;
X
X	  /** and now for debugging purposes... **/
X
X	  if (debug)
X	    printf("got fullname=\"%s\" and raw_address=\"%s\"\n",
X		  fullname, raw_address);
X	}
X
X	clean_up_raw_address(raw_address);
X
X	if (strlen(alt_fullname) > 0) 
X	  strcpy(fullname, alt_fullname);
X	
X	if (strlen(fullname) > 0)
X	  fprintf(outfd, "From: %s (%s)\n", raw_address, fullname);
X	else
X	  fprintf(outfd, "From: %s\n", raw_address);
X}
X
Xoutput_reply_to(clunky_from_line, outfd)
Xchar *clunky_from_line;
XFILE *outfd;
X{
X	/** Output a Reply-To: line that is the return address of the mail **/
X
X	char buffer[SLEN], newbuffer[SLEN], *p;
X
X	sscanf(clunky_from_line, "%*s %s", buffer);
X
X	if (occurances_of('!', buffer) && occurances_of('@', buffer)) {
X	   for (p = buffer + strlen(buffer) - 1; *p != '@'; p--) ;
X	   if (strcmp(p, BOGUS_ADDRESS) == 0) {
X	      *p = '\0';
X	      sprintf(newbuffer, "%s!%s", UUCP_HOSTNAME, buffer);
X	      strcpy(buffer, newbuffer);
X	   }
X	}
X
X	if (strlen(fullname) > 0)
X	  fprintf(outfd, "Reply-To: %s (%s)\n", buffer, fullname);
X	else
X	  fprintf(outfd, "Reply-To: %s\n", buffer);
X}
X
X#define  no			!
X
Xclean_up_raw_address(address)
Xchar *address;
X{	
X	/** This turns out to be an interesting routine: it takes an
X	    address of any form and attempts to extract the user@host
X	    core of it.  When it has done this, it will then check to
X	    see if the host had a domain specified with it.  If so, then
X	    it will simply return "user@host.domain", otherwise it will
X	    append the default domain to the host and return something
X	    more on the order of "user@host.<domain>".
X
X	    (this algorithm is out of the HP Labs PostOffice system)
X
X	    ==========================================================
X
X	    Given an email address this routine will attempt to prune
X	    it down to a base user@host or host!user format.  The 
X	    possible address formats include:
X
X	   	#     example input	       desired output
X	       --- ------------------------   ----------------
X		1. hosta!hostb!hostc!user	<hostc!user>
X		2. hosta!hostb!user@hostd	<hostb!user>  [*]
X	  	3. user%hosta%hostb@hostc	<user%hosta@hostb>
X		4. @hosta:user@hostb		<user@hostb>
X
X	    [*] note that we consider all mixed mode addresses to have
X	        the UUCP notational part added first...
X	**/
X	
X	char     username[SLEN], hostname[SLEN], new_address[SLEN];
X	register int i, j = 0, bangs_in_address, at_signs_in_address,
X		     percents_in_address;
X
X	bangs_in_address    = occurances_of('!', address);
X	at_signs_in_address = occurances_of('@', address);
X	percents_in_address = occurances_of('%', address);
X
X	/* this deals with mixed mode addresses and all... */
X
X	if (bangs_in_address && at_signs_in_address == 1) {
X	   /* remove the entire @host and/or %host@host part */
X	   for (i=strlen(address); address[i] != '!'; i--) ;
X	   i++; /* skip past the '!' please */
X	   while (valid_char(address[i])) i++;
X	   address[i] = '\0';
X	   percents_in_address = at_signs_in_address = 0;
X	   i = 0;
X	}
X
X	if (debug)
X	  printf("! count = %d, @ count = %d, %% count = %d\n", 
X		bangs_in_address, at_signs_in_address, percents_in_address);
X	
X	/* and now to the normal test and testing, please */
X
X	if (no at_signs_in_address) {	      /* #1: pure 'uucp' address  */
X	  if (bangs_in_address > 1) {
X	    for (i=strlen(address); address[i] != '!'; i--)	;
X	    i--;	/* skip this bang */
X	    while (address[i] != '!') i--;
X	    j = 0;
X	    for (i++; address[i] != '\0'; new_address[j++] = address[i++]) ;
X	    new_address[j] = '\0';
X	  }
X	  else 	/* simple too - only one hop */
X	    strcpy(new_address, address);
X	}
X	else {
X	  if (no percents_in_address) {  /* either #2 or #4..same algorithm */
X	    for (i=strlen(address); address[i] != '@'; i--)	;
X	    i--; /* back up to before the '@' sign too */
X	    while (valid_char(address[i]) && i > -1) i--;
X	    j = 0;
X	    for (++i; address[i] != '\0'; new_address[j++] = address[i++]) ;
X	    new_address[j] = '\0';
X	  }
X	  else {			/* case #3, of course... */
X	    /** get to the leftmost percent sign... **/
X	    for (i=0; address[i] != '%'; i++) ;
X	    /** now back up to include username... **/
X	    i--;	/* include this percent sign */
X	    while (valid_char(address[i]) && i > -1) i--;
X	    i++;  j = 0;
X	    /* now copy over until we hit the an '@' sign... */
X	    while (address[i] != '@')
X	      new_address[j++] = address[i++];
X	    new_address[j] = '\0';
X	    /** finally, back up and change the rightmost '%' to an '@' **/
X	    while (new_address[j] != '%') j--;
X	    new_address[j] = '@';	/* replace '%' with '@' please */
X	  }
X	}
X
X	if (occurances_of('!', new_address) != 0) {
X	  for (i=0; new_address[i] != '!'; i++)
X	    hostname[i] = new_address[i];
X	  hostname[i] = '\0';
X	  j = 0;
X	  while (new_address[++i] != '\0')
X	    username[j++] = new_address[i];
X	  username[j] = '\0';
X	  sprintf(new_address, "%s@%s", username, hostname);
X	}
X
X	if (occurances_of('@', new_address) == 0) 	/* NONE? */
X	   strcat(new_address, BOGUS_ADDRESS);
X
X	if (occurances_of('.', new_address) == 0)
X	   strcat(new_address, DEFAULT_DOMAIN);
X
X	if (debug)
X	  printf("ended up with base address: \"%s\"\n", new_address);
X
X	strcpy(address, new_address);
X}
X
Xint
Xoccurances_of(c, string)
Xchar c, *string;
X{
X	/** returns the number of times 'c' occurs in the string **/
X
X	register int i, count = 0;
X
X	for (i=0; i < strlen(string); i++)
X	  if (string[i] == c) count++;
X
X	return(count);
X}
SHAR_EOF
chmod 0444 utils/postmail.c || echo "restore of utils/postmail.c fails"
echo "x - extracting utils/readmsg.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > utils/readmsg.c &&
X
Xstatic char rcsid[] = "@(#)$Id: readmsg.c,v 2.1 88/09/15 21:07:39 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
X *
X * 			Copyright (c) 1985 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Eric D. Christensen  -  edc@altnet.ALTOS.COM 
X *				uunet!altnet!edc
X *
X *******************************************************************************
X * $Log:	readmsg.c,v $
X * Revision 2.1  88/09/15  21:07:39  syd
X * checked in with -k by syd at 88.09.15.21.07.39.
X * 
X * Revision 2.1  88/07/21  10:02:00  edc
X * Final hacks and cleanup to the 2.1 alpha test release
X * 
X * Revision 2.0  88/06/27  16:54:14  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** This routine adds the functionality of the "~r" command to the Elm mail 
X    system while still allowing the user to use the editor of their choice.
X
X    The program, without any arguments, tries to read a file in the users home 
X    directory called ".readmsg" (actually defined in the sysdefs.h system 
X    defines file) and if it finds it reads the current message.  If it doesn't 
X    find it, it will return a usage error.
X
X    The program can also be called with an explicit message number, list of 
X    message numbers, or a string to match in the message (including the header).
X    NOTE that when you use the string matching option it will match the first 
X    message containing that EXACT (case sensitive) string and then exit.
X
X    Changed 5/86 to SORT the input list of message numbers to ensure that
X    they're in first-to-last order...
X	
X    Added the "weed" option as the default.  This is inspired by the mail
X    system used at NASA RIACS.  If THEY can do it, so can we!!
X
X    Also added '*' as a flag - indicating ALL messages in the mailbox.
X
X**/
X
X#include <stdio.h>
X#include <ctype.h>
X
X#include "defs.h"
X
X/** three defines for what level of headers to display **/
X
X#define ALL		1
X#define WEED		2
X#define NONE		3
X
X#define metachar(c)	(c == '=' || c == '+' || c == '%')
X
Xstatic char ident[] = { WHAT_STRING };
X
X#define  MAX_LIST	25		/* largest single list of arguments */
X
X#define  LAST_MESSAGE	9999		/* last message in list ('$' char)  */
X#define  LAST_CHAR	'$'		/* char to delimit last message..   */
X#define  STAR		'*'		/* char to delimit all messages...  */
X
Xint read_message[MAX_LIST]; 		/* list of messages to read	    */
Xint messages = 0;			/* index into list of messages      */
X
Xint numcmp();				/* strcmp, but for numbers          */
Xchar *words(),				/* function defined below...        */
X     *expand_define();			/*     ditto...                     */
X
X#define DONE	0			/* for use with the getopt	    */
X#define ERROR   -1			/*   library call...		    */
X
Xextern char *optional_arg;		/* for parsing the ... 		    */
Xextern int   opt_index;			/*  .. starting arguments           */
X
Xchar *getenv();				/* keep lint happy */
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	FILE *file;			        /* generic file descriptor! */
X	char filename[SLEN], 			/* filename buffer          */
X	     infile[SLEN],			/* input filename	    */
X	     buffer[SLEN], 			/* file reading buffer      */
X	     string[SLEN];			/* string match buffer      */
X
X	int current_in_queue = 0, 		/* these are used for...     */
X	    current = 0,			/* ...going through msgs     */
X	    list_all_messages = 0,		/* just list 'em all??       */
X	    num, 				/* for argument parsing      */
X	    page_breaks = 0,			/* use "^L" breaks??         */
X            total,				/* number of msgs current    */
X	    include_headers = WEED, 		/* flag: include msg header? */
X	    last_message = 0, 			/* flag: read last message?  */
X	    not_in_header = 0,			/* flag: in msg header?      */
X	    string_match = 0;			/* flag: using string match? */
X
X	/**** start of the actual program ****/
X
X	while ((num = get_options(argc, argv, "nhf:p")) > 0) {
X	  switch (num) {
X	    case 'n' : include_headers = NONE;		break;
X	    case 'h' : include_headers = ALL;		break;
X	    case 'f' : strcpy(infile, optional_arg);	
X		       if (metachar(infile[0]))
X	                 if (expand(infile) == 0)
X	                   printf("%s: couldn't expand filename %s!\n", 
X			          argv[0], infile);
X		       break;
X	    case 'p' : page_breaks++;			break;
X	  }
X	}
X	
X	if (num == ERROR) {
X	  printf("Usage: %s [-n|-h] [-f filename] [-p] <message list>\n",
X		  argv[0]);
X	  exit(1);
X	}
X
X	/** whip past the starting arguments so that we're pointing
X	    to the right stuff... **/
X
X	*argv++;	/* past the program name... */
X
X	while (opt_index-- > 1) {
X	  *argv++;
X	  argc--;
X	}
X
X	/** now let's figure out the parameters to the program... **/
X
X	if (argc == 1) {	/* no arguments... called from 'Elm'? */
X	  sprintf(filename, "%s/%s", getenv("HOME"), readmsg_file);
X	  if ((file = fopen(filename, "r")) != NULL) {
X	    fscanf(file, "%d", &(read_message[messages++]));
X	    fclose(file);
X	  }
X	  else {	/* no arguments AND no .readmsg file!! */
X	    fprintf(stderr,
X	        "Usage: readmsg [-n|-h] [-f filename] [-p] <message list>\n");
X	    exit(1);
X	  }
X	}
X	else if (! isdigit(*argv[0]) && *argv[0] != LAST_CHAR && 
X	         *argv[0] != STAR) {  
X	  string_match++;
X	 
X	  while (*argv)
X	    sprintf(string, "%s%s%s", string, string[0] == '\0'? "" : " ",
X		    *argv++);
X	}
X	else if (*argv[0] == STAR) 		/* all messages....   */
X	  list_all_messages++;
X	else { 					  /* list of nums   */
X
X	  while (--argc > 0) {
X	    num = -1;
X
X	    sscanf(*argv,"%d", &num);
X
X	    if (num < 0) {
X	      if (*argv[0] == LAST_CHAR) {
X	        last_message++;
X		num = LAST_MESSAGE;
X	      }
X	      else {
X	        fprintf(stderr,"I don't understand what '%s' means...\n",
X			*argv); 
X	       	exit(1); 
X	      }
X	    }
X	    else if (num == 0) {	/* another way to say "last" */
X	      last_message++;
X	      num = LAST_MESSAGE;
X	    }
X
X	    *argv++; 
X
X	    read_message[messages++] = num;
X	  }
X
X	  /** and now sort 'em to ensure they're in a reasonable order... **/
X
X	  qsort(read_message, messages, sizeof(int), numcmp);
X	}
X
X	/** Now let's get to the mail file... **/
X
X	if (strlen(infile) == 0) 
X	  sprintf(infile, "%s/%s", mailhome, getenv("LOGNAME"));
X
X	if ((file = fopen(infile, "r")) == NULL) {
X	  printf("But you have no mail! [ file = %d ]\n", infile);
X	  exit(0);
X	}
X
X	/** Now it's open, let's display some 'ole messages!! **/
X
X	if (string_match || last_message) {   /* pass through it once */
X
X	  if (last_message) {
X	    total = count_messages(file);	/* instantiate count */
X	    for (num=0; num < messages; num++)
X	      if (read_message[num] == LAST_MESSAGE)
X		read_message[num] = total;
X	  }
X	  else if (string_match)
X	    match_string(file, string);		/* stick msg# in list */
X
X	  if (total == 0 && ! string_match) {
X	    printf("There aren't any messages to read!\n");
X	    exit(0);
X	  }
X	}
X
X 	/** now let's have some fun! **/
X	
X	while (fgets(buffer, SLEN, file) != NULL) {
X	  if (strncmp(buffer, "From ", 5) == 0) {
X	    if (! list_all_messages) {
X	      if (current == read_message[current_in_queue])
X	        current_in_queue++;
X	      if (current_in_queue >= messages) 
X	        exit(0);
X	    }
X	    current++;
X	    not_in_header = 0;	/* we're in the header! */
X	  }
X	  if (current == read_message[current_in_queue] || list_all_messages)
X	    if (include_headers==ALL || not_in_header)
X	      printf("%s", buffer);
X	    else if (strlen(buffer) < 2) {
X	      not_in_header++;
X	      if (include_headers==WEED) 
X		list_saved_headers(page_breaks);
X	    }
X	    else if (include_headers==WEED)
X	      possibly_save(buffer); 	/* check to see if we want this */ 
X	}
X	
X	exit(0);
X}
X
Xint
Xcount_messages(file)
XFILE *file;
X{
X	/** Returns the number of messages in the file **/
X
X	char buffer[SLEN];
X	int  count = 0;
X
X	while (fgets(buffer, SLEN, file) != NULL)
X	  if (strncmp(buffer, "From ", 5) == 0)
X	    count++;
X
X	rewind( file );
X	return( count );
X}
X
Xmatch_string(mailfile, string)
XFILE *mailfile;
Xchar *string;
X{
X	/** Increment "messages" and put the number of the message
X	    in the message_count[] buffer until we match the specified 
X	    string... **/
X
X	char buffer[SLEN];
X	int  message_count;
X
X	while (fgets(buffer, SLEN, mailfile) != NULL) {
X	  if (strncmp(buffer, "From ", 5) == 0)
X	    message_count++;
X
X	  if (in_string(buffer, string)) {
X	    read_message[messages++] = message_count;
X	    rewind(mailfile);	
X	    return;
X	  }
X	}
X
X	fprintf(stderr,"Couldn't find message containing '%s'\n", string);
X	exit(1);
X}
X
Xint 
Xnumcmp(a, b)
Xint *a, *b;
X{
X	/** compare 'a' to 'b' returning less than, equal, or greater
X	    than, accordingly.
X	 **/
X
X	return(*a - *b);
X}
X
Xstatic char from[SLEN], subject[SLEN], date[SLEN], to[SLEN];
X
Xpossibly_save(buffer)
Xchar *buffer;
X{
X	/** Check to see what "buffer" is...save it if it looks 
X	    interesting... We'll always try to get SOMETHING
X	    by tearing apart the "From " line...  **/
X
X	if (strncmp(buffer, "Date:", 5) == 0)
X	  strcpy(date, buffer);
X	else if (strncmp(buffer, "Subject:", 8) == 0)
X	  strcpy(subject,buffer);
X	else if (strncmp(buffer,"From:", 5) == 0)
X	  strcpy(from, buffer);
X	else if (strncmp(buffer,"To: ", 3) == 0)
X	  strncpy(to, buffer, SLEN);
X	else if (strncmp(buffer,"From ", 5) == 0) {
X	  sprintf(from, "From: %s\n", words(2,1, buffer));	
X	  sprintf(date,"Date: %s",    words(3,7, buffer));
X	  to[0] = '\0';
X	}
X}
X
Xlist_saved_headers(page_break)
Xint page_break;
X{
X	/** This routine will display the information saved from the
X	    message being listed...If it displays anything it'll end
X	    with a blank line... **/
X
X	register int displayed_line = FALSE;
X	static int messages_listed = 0;
X
X	if (messages_listed++) 
X	  if (page_break)
X	    putchar(FORMFEED);	
X	  else
X	    printf(
X"\n--------------------------------------------------------------------\n\n\n");
X
X	if (strlen(from)    > 0) { printf("%s", from);    displayed_line++;}
X	if (strlen(subject) > 0) { printf("%s", subject); displayed_line++;}
X	if (strlen(to)      > 0) { printf("%s", to);      displayed_line++;}
X	if (strlen(date)    > 0) { printf("%s", date);    displayed_line++;}
X	
X	if (displayed_line)
X	   putchar('\n');
X}
X
Xchar *words(word, num_words, buffer)
Xint word, num_words;
Xchar *buffer;
X{
X	/** Return a buffer starting at 'word' and containing 'num_words'
X	    words from buffer.  Assume white space will delimit each word.
X	**/
X
X	static char internal_buffer[SLEN];
X	char   *wordptr, *bufptr, mybuffer[SLEN], *strtok();
X	int    wordnumber = 0, copying_words = 0;
X
X	internal_buffer[0] = '\0';	/* initialize */
X
X	strcpy(mybuffer, buffer);
X	bufptr = (char *) mybuffer;	/* and setup */
X
X	while ((wordptr = strtok(bufptr, " \t")) != NULL) {
X	  if (++wordnumber == word) {
X	    strcpy(internal_buffer, wordptr);
X	    copying_words++;
X	    num_words--;
X	  }
X	  else if (copying_words) {
X	    strcat(internal_buffer, " ");
X	    strcat(internal_buffer, wordptr);
X	    num_words--;
X	  }
X
X	  if (num_words < 1) 
X	    return((char *) internal_buffer);
X
X	  bufptr = NULL;
X	}
X
X	return( (char *) internal_buffer);
X}
X
Xint
Xexpand(infile)
Xchar *infile;
X{
X	/** Expand the filename since the first character is a meta-
X	    character that should expand to the "maildir" variable
X	    in the users ".elmrc" file...
X
X	    Note: this is a brute force way of getting the entry out 
X	    of the .elmrc file, and isn't recommended for the faint 
X	    of heart!
X	**/
X
X	FILE *rcfile;
X	char  buffer[SLEN], *expanded_dir, *home, *getenv(), *bufptr;
X	int   foundit = 0;
X
X	bufptr = (char *) buffer;		/* same address */
X	
X	if ((home = getenv("HOME")) == NULL) {
X	  printf(
X	     "Can't expand environment variable $HOME to find .elmrc file!\n");
X	  exit(1);
X	}
X
X	sprintf(buffer, "%s/%s", home, elmrcfile);
X
X	if ((rcfile = fopen(buffer, "r")) == NULL) {
X	  printf("Can't open your \".elmrc\" file (%s) for reading!\n",
X		 buffer);
X	  exit(1);
X	}
X
X	while (fgets(buffer, SLEN, rcfile) != NULL && ! foundit) {
X	  if (strncmp(buffer, "maildir", 7) == 0 ||
X	      strncmp(buffer, "folders", 7) == 0) {
X	    while (*bufptr != '=' && *bufptr) 
X	      bufptr++;
X	    bufptr++;			/* skip the equals sign */
X	    while (whitespace(*bufptr) && *bufptr)
X	      bufptr++; 
X	    home = bufptr;		/* remember this address */
X
X	    while (! whitespace(*bufptr) && *bufptr != '\n')
X	      bufptr++;
X
X	    *bufptr = '\0';		/* remove trailing space */
X	     foundit++;
X	  }
X	}
X
X	fclose(rcfile);			/* be nice... */
X
X	if (! foundit) {
X	  printf("Couldn't find \"maildir\" in your .elmrc file!\n");
X	  exit(1);
X	}
X
X	/** Home now points to the string containing your maildir, with
X	    no leading or trailing white space...
X	**/
X
X	expanded_dir = expand_define(home);
X
X	sprintf(buffer, "%s%s%s", expanded_dir, 
X		(expanded_dir[strlen(expanded_dir)-1] == '/' ||
X		infile[0] == '/') ? "" : "/", (char *) infile+1);
X
X	strcpy(infile, buffer);
X}
X
Xchar *expand_define(maildir)
Xchar *maildir;
X{
X	/** This routine expands any occurances of "~" or "$var" in
X	    the users definition of their maildir directory out of
X	    their .elmrc file.
X
X	    Again, another routine not for the weak of heart or staunch
X	    of will!
X	**/
X
X	static char buffer[SLEN];	/* static buffer AIEE!! */
X	char   name[SLEN],		/* dynamic buffer!! (?) */
X	       *nameptr,	       /*  pointer to name??     */
X	       *value;		      /* char pointer for munging */
X
X	if (*maildir == '~') 
X	  sprintf(buffer, "%s%s", getenv("HOME"), ++maildir);
X	else if (*maildir == '$') { 	/* shell variable */
X
X	  /** break it into a single word - the variable name **/
X
X	  strcpy(name, (char *) maildir + 1);	/* hurl the '$' */
X	  nameptr = (char *) name;
X	  while (*nameptr != '/' && *nameptr) nameptr++;
X	  *nameptr = '\0';	/* null terminate */
X	  
X	  /** got word "name" for expansion **/
X
X	  if ((value = getenv(name)) == NULL) {
X	    printf("Couldn't expand shell variable $%s in .elmrc!\n", name);
X	    exit(1);
X	  }
X	  sprintf(buffer, "%s%s", value, maildir + strlen(name) + 1);
X	}
X	else
X	   strcpy(buffer, maildir);
X
X	return( ( char *) buffer);
X}
X
SHAR_EOF
chmod 0444 utils/readmsg.c || echo "restore of utils/readmsg.c fails"
rm -f s2_seq_.tmp
echo "You have unpacked the last part"
exit 0
-- 
=====================================================================
Sydney S. Weinstein, CDP, CCP                   Elm Coordinator
Datacomp Systems, Inc.				Voice: (215) 947-9900
{allegra,bellcore,bpa,vu-vlsi}!dsinc!syd	FAX:   (215) 938-0235