[net.sources] checkmail - a mail sifting program

garym@telesoft.UUCP (Gary Morris @favorite) (09/26/86)

This is a program I wrote called "checkmail".  It summarizes the mail in
your spool file for you, by displaying who it's from and subject.  It allows
you to select only new, unread or all mail.  This program has only been
tested on Sun Unix 2.3 (BSD 4.2), and I don't know what else it will run on.
For you C hackers, please excuse the Ada-like syntax, I usually use Ada
instead of C.  Bugs and comments to "ucbvax!sdcsvax!telesoft!garym".
Standard disclaimers apply.

Gary Morris --	UUCP:	seismo!s3sun!gould9!telesoft!garym
N6FRT			decvax!ucbvax!sdcsvax!telesoft!garym
		ARPA:	telesoft!garym@sdcsvax.ARPA
		CIS:	76317,520	 
"Always listen to experts.  They'll tell you what can't be done
 and why.  Then do it."		-- Lazarus Long


#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Makefile
#	checkmail.1
#	checkmail.c
# This archive created: Thu Sep 25 22:01:19 1986
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Makefile'" '(55 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
checkmail: checkmail.c
	cc -O checkmail.c -o checkmail
SHAR_EOF
if test 55 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 55 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'checkmail.1'" '(2452 characters)'
if test -f 'checkmail.1'
then
	echo shar: will not over-write existing file "'checkmail.1'"
else
cat << \SHAR_EOF > 'checkmail.1'
.TH CHECKMAIL 1 "March 4, 1986" "TeleSoft Inc." "UNIX User's Manual"
.\" $Compile: iroff -man.new %f
.SH NAME
checkmail \- prints who your mail is from and the subjects
.SH USAGE
.B checkmail
[-unaqo] [file]
.SH DESCRIPTION
.I checkmail
is a program that will tell you about the mail in your mailbox. 
It lists who each letter is from (without path or domain), the date received,
and the subject, one line per letter.
Using options listed below you may check for new mail or list only new
mail and also check files and mail folders other than your spool file.
.I Checkmail
with default options is similar to the 
.I from
program except that subjects are also displayed.

Normally a status of 0 is returned, unless the file isn't found in which case
a status of 1 is returned.

When the 
.I -q
option is used a status of 0 is returned if there is mail and 1 if there
isn't mail. 

.I Checkmail
normally displays outgoing mail (mail you have sent) found in the
file, you may choose ignore outgoing mail by using the 
.I -o
option.
.de OP
.TP
.B -\\$1 \\$2
..
.OP u
List only unread mail.  That is, mail that you haven't read yet. 
.OP n
List only new mail.  That is, mail that you haven't read or seen the
header of.  When you enter the mail program all the mail is marked as
no longer new but still unread.
.OP a
List all mail, regardless of status (read, unread, or new).  May be used
to override an option already given on the command line.
.OP o
Exclude outgoing mail from the display or search.
.OP q
Quiet operation.  Tells checkmail to only report whether it had any mail 
to display.  The status result is 0 if there was mail and 1 if there wasn't
any mail.  Useful in combination with 
.I -n
or 
.I -u
option to check for new or unread mail in a .login script.
.TP
.B file
Uses
.I file
instead of the default file /usr/spool/mail/$USER.
You may specify a mail folder by prefixing the folder name with "+" as
is done with the mail program.

.SH "EXAMPLES"
The following csh line could be used in your .login file to run the mail
program only if you have unread mail in your spool file.

  if { checkmail -qu } mail

Or the following could be used to display who new mail is from and the
subjects:

  if { checkmail -qn } then
      echo '===== NEW MAIL ====='
      checkmail -n
  endif

.SH "FILES"
/usr/spool/mail/$USER \- your mail spool file (default file)

.SH "SEE ALSO"
from, mail
.SH AUTHOR
Gary Morris (sdcsvax!telesoft!gm)
.SH BUGS
n/a
SHAR_EOF
if test 2452 -ne "`wc -c < 'checkmail.1'`"
then
	echo shar: error transmitting "'checkmail.1'" '(should have been 2452 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'checkmail.c'" '(6169 characters)'
if test -f 'checkmail.c'
then
	echo shar: will not over-write existing file "'checkmail.c'"
else
cat << \SHAR_EOF > 'checkmail.c'
/************************************************************************/
/*  checkmail [-unaoq] [file]						*/
/*									*/
/*  This program lists the mail found in your mail spool file and 	*/
/*  tells you who it's from and the subject, one line per letter.	*/
/*									*/
/*  -u		causes it to only list the unread mail.			*/
/*  -n		causes it to only list the NEW mail.			*/
/*  -a		causes it to list all mail in the file. (default)	*/
/*  -o		causes it to skip outgoing mail (from yourself)		*/
/*  -q		causes it to work quietly, returns 0 exit status if	*/
/*		have mail and 1 if you have no mail (-n applies here)	*/
/*  file	causes it to use a file other that your spool file	*/
/*		use + in front of the name to indicate a folder		*/
/*									*/
/* Copyright 1986 Gary Morris.  Unlimited non-commercial use permitted  */
/* Author: ucbvax!sdcsvax!telesoft!gmorris				*/
/* $Header: RCS/checkmail.c,v 1.8 86/08/20  garym rel $ 		*/
/************************************************************************/

#include <stdio.h>
#include <strings.h>

/* Defines for Ada-like syntax */
#define then	{
#define or_else	} else {
#define elsif	} else if
#define begin   {
#define end	}
#define endif	}
#define loop	{
#define endloop	}
#define endswitch }
#define MAXLINE	1000
#define false	0
#define true	1

typedef enum { all_mail, new_mail, unread_mail } options;
options option = all_mail;

int show_outgoing = true;
int quiet = false;	/* set true if result reported via exit code */
char *USER;


main(argc,argv)
int argc;
char **argv;
begin
    FILE *fp, *fopen();
    extern char *getenv();
    extern int quiet;
    extern options option;
    extern char *USER;
    extern int show_outgoing;
    extern int optind;
    extern char *optarg;
    int argch;
    int have_mail = false;
    char mailbox[255];

    USER = getenv("USER");

    /*** default mailbox file ***/
    strcpy( mailbox, "/usr/spool/mail/" );
    strcat( mailbox, USER );

    while ( (argch=getopt(argc,argv,"anuqo")) != EOF ) loop
	switch (argch) begin
	    case 'o':
		show_outgoing = false;
		break;
	    case 'a':
		option = all_mail;
		break;
	    case 'n':
		option = new_mail;
	    	break;
	    case 'u':
		option = unread_mail;
	    	break;
	    case 'q':
		quiet = true;
		break;
	    case '?':
		fprintf( stderr, "Usage: %s [-qnuao] [filename]\n", *argv );
		exit(1);
	endswitch
    endloop
    if ( optind < argc ) then
	if ( argv[optind][0] == '+' ) then
	    strcpy( mailbox, getenv("folder") );
	    strcat( mailbox, "/" );
	    strdel( argv[optind], 0, 1 );
	    strcat( mailbox, argv[optind] );
	or_else
	    strcpy( mailbox, argv[optind] );
	endif
    endif

    if ( (fp=fopen(mailbox,"r")) != NULL ) then
	have_mail = HeaderCheck(fp);
    elsif ( ! quiet ) then
	/* ok to not find file, when -q, just no mail there since no file */
	fprintf( stderr, "Error: File not found: %s\n", mailbox );
	exit(1);
    endif

    exit( quiet && !have_mail );
end

int HeaderCheck(fp)		/* returns true if there is mail */
FILE *fp;
begin
    extern options option;
    extern int quiet;
    extern char *USER;
    char input[MAXLINE];	/* current input line */
    char output[MAXLINE];	/* current output line */
    char who_from[80];		/* user name mail is from */
    typedef enum { unknown = 0, in_header = 1, in_body = 2 } states;
    states state = unknown;
    char status = 'N';		/* statuses are: New, Old, Read */
    int have_mail = false;
    int outgoing = false;
    char* p1;
    char* p2;

    while ( fgets(input,MAXLINE,fp) != NULL ) loop
	switch (input[0]) begin
	case 'F':
	    if (strlen(input) >= 5) then
		if ( ((state==unknown) || (state==in_body)) &&
		     (input[1]=='r') && (input[2]=='o') &&
		     (input[3]=='m') && (input[4]==' ') ) then
		    state = in_header;
		    status = 'N';
		    strdel( input, strlen(input)-1, 1 );
		    /* delete any uucp path names in front of name */
		    while ( p1 = index( input, '!' ) ) loop
			strdel( input, 5, p1 - &input[5] + 1 );
		    endloop
		    /* delete any domain type stuff after name */
		    if ( p1 = index( input, '@' ) ) then
			p2 = index( p1, ' ' );
			if ( p2 == 0 ) p2 = index( p1, '\n' );
			if ( p2 != 0 ) strdel( input, p1 - input, p2 - p1 );
		    endif
		    /* see who it's from, if from self ignore it (maybe) */
		    p1 = index( &input[5], ' ' );
		    if ( p1 == 0 ) p1 = index( &input[5], '\n' );
		    strncpy( who_from, &input[5], p1 - &input[5] );
		    who_from[ p1-&input[5] ] = '\0';
		    outgoing = strcmp( who_from, USER ) == 0;
		    strcpy( output, input );
		endif
	    endif
	    break;
	case 'S':
	    if (strlen(input) >= 9) then
		switch (input[1]) begin
		case 'u':
		    if ( (state==in_header) &&
			 (input[1]=='u') && (input[2]=='b') &&
			 (input[3]=='j') && (input[4]=='e') &&
			 (input[5]=='c') && (input[6]=='t') &&
			 (input[7]==':') && (input[8]==' ') ) then
			strdel( input, 0, 9 ); 	/* del: Subject: */
		        strdel( input, strlen(input)-1, 1 );
			strcat( output, " \"" );
			strcat( output, input );
			strcat( output, "\"" );
		    endif
		    break;
		case 't':
		    if ( (state==in_header) &&
			 (input[1]=='t') && (input[2]=='a') &&
			 (input[3]=='t') && (input[4]=='u') &&
			 (input[5]=='s') && (input[6]==':') &&
			 (input[7]==' ') ) then
			status = input[8];
		    endif
		    break;
		endswitch
	    endif
	    break;
	case '\n':
	    if (state == in_header) then
		state = in_body;
	      if ( show_outgoing || !outgoing ) then
		if ( (option==new_mail && status=='N') ||
		     (option==unread_mail && (status=='N' || status=='O')) ||
		     (option==all_mail) ) then
		    /* there is some mail (new or otherwise) */
		    have_mail = true;
		    if ( quiet ) then
			return have_mail;
		    or_else
			strcat( output, "\n" );
			fputs( output, stdout );
		    endif
		endif
	      endif
	    endif
	    break;
	default:
	    break;
	endswitch
    endloop
    return have_mail;
end

strdel( s, index, length )
char *s;
int index;
int length;
begin
    char *src = s+index+length;
    char *dest= s+index;
    int count = (strlen(s)+1)-(index+length);
    for (; count>0; count--) loop
        *dest++ = *src++;
    endloop
end
SHAR_EOF
if test 6169 -ne "`wc -c < 'checkmail.c'`"
then
	echo shar: error transmitting "'checkmail.c'" '(should have been 6169 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0