[net.sources] MAILAWAY to hanlde your Unix mail while away

jchvr@ihlpg.UUCP (VanRietschote) (04/29/86)

--
A while back I posted a program to handle unix mail while you
were away for a while. Although it did some smart stuff (according to 
me the author), some people wanted things just a little different. So
now there is for those mailaway.C which for each message waiting to
be read, determines things like the author, the size the subject
etc. and then lets you execute a shell routine which can work on
the mail message. (For more details see manual page in next
posting).

Feel free to use or misuse this program.

#------ cut here
/* mailaway.c -*-update-version-*-
** program to auto execute some shell script for each mail message waiting
** HFVR VERSION=Wed Mar 19 08:12:25 1986
*/

#include 	<stdio.h>
#include	<ctype.h>

#define equal		!strcmp
#define equaln		!strncmp
#define	TRUE	1
#define	FALSE	0
#define	TOSIZE		512		/* size of buffer to hold dests */
#define MAXLINES	50		/* max nr of from lines */
#define LINELENGTH	256		/* max length from line */

char	fflag[LINELENGTH];	/* file to include */
char	xflag[LINELENGTH];	/* program to execute file (executor)*/
char	oflag[LINELENGTH];	/* options to program */
int	dflag = FALSE;		/* to debug */

char 	TEMPA[]		= "/usr/tmp/AXXXXXX";	/* message file */
char	TEMPM[]		= "/usr/tmp/MXXXXXX";	/* copy of whole $MAIL */
char	TEMPS[]		= "/usr/tmp/SXXXXXX";	/* file to execute */
char	NAME[]		= "mailaway";		/* program name */
char 	subject[]	= "Subject:";		/* start of subject line */
char	rmtfrom[]	= " remote from ";
char	fwrdmsg[]	= " forwarded by ";
char	from[] 		= "From ";

FILE *f1;				/* input file */
char *lp;				/* pointer for reading file */
char	line[LINELENGTH];		/* line last read from f1 */
int frcnt;				/* nr of from lines in message */
char	frlist[MAXLINES][LINELENGTH];	/* from lines in message */

/* variables to determine from message */
char	SUBJECT[LINELENGTH];	/* whats behind Subject: */
char	SENDER[LINELENGTH];	/* login name of sender */
int	NROFLINES;		/* length of message */
int	SIZE;			/* size in chars. of message */
char	VIA[TOSIZE];		/* full return mail address */
char	MESSAGE[LINELENGTH];	/* filename where message is saved */
char	DEMON[6];		/* TRUE or FALSE */
char	LAST[6];		/* TRUE or FALSE */

/* EXTERNAL ROUTINES FROM OUR LIBRARIES */
extern	char	*strchr(/* s , c */);
/*	char	*s;
**	int	c;
**
** Returns a pointer to the first occurence of character s in string s,
** or a NULL pointer if c does not occur in the string s. 
** The null character terminating the string is considered part of the string.
*/

extern	char	*strrchr(/* s , c */);
/*	char	*s;
**	int	c;
**
** Returns a pointer to the last occurence of character s in string s,
** or a NULL pointer if c does not occur in the string s. 
** The null character terminating the string is considered part of the string.
*/
/* END OF EXTERNAL ROUTINES */

/* sindex looks for an occurance  of the string s2 in the string
** s1. If s2 does not ocurr, sindex returns -1. Otherwise, sindex
** returns the integer offset from s1 where s2 ocurrs.
*/
int sindex(s1,s2)
register char *s1;
register char *s2;
{	
	register char *p1;
	register char *p2;
	register int flag;
	register int ii;

	p1 = &s1[0];
	p2 = &s2[0];
	flag = -1;
	for(ii = 0; ; ii++) {
		while(*p1 == *p2) {
			if(flag < 0) flag = ii;
			if(*p1++ == 0) return(flag);
			p2++;
		}
		if(*p2 == 0) return(flag);
		if(flag >= 0) {
			flag = -1;
			p2 = &s2[0];
		}
		if(*s1++ == 0) return(flag);
		p1 = s1;
	}
}/*sindex*/

/* returns pointer to string with sender address in it
** input is frlist[] with lines like:
**
** [>]From USER DATE 				or
** [>]From USER DATE forwarded by WHOCARES	or
** [>]From USER DATE remote from MACHINE
**
** some lines might be duplicated
** we save only the last USER and string together all MACHINEs
** except if the previous machine equals the current one
** forwarded by lines are simply ignored
** address format is mach!mach!....!user or user
** if flg TRUE then it is also printed to stdout
*/
char *frflsh(flg)
{	
	static char address[TOSIZE] ;
	char user[80];
	char mach1[80]  ;	/* previous machine name */
	char mach2[80]  ; 	/* current machine name */
	register int i;
	register int j;
	register char *p;
	register char *q;

	strcpy(address,"");
	strcpy(mach1,"");

	for (i = 0 ; i < frcnt ; i++) { /* examine every From line */
		p = frlist[i] ;
		if ( *p == '>' ) p++;	/* skip leading > */
		if ( equaln(p, from , 5 ) ) {
			p += 5;			/* skip FromSP */
		} else {
			continue; /* does not match FromSP , try next line */
		}

		/* get user from line and skip past it */
		/* but first skip past spaces and tabs */
		while ( *p == ' ' || *p == '\t' ) p++;
		q = user;
		while ( *p != 10 && *p != '\0' &&  *p != ' ' && *p != '\t' ) {
			*q = *p;
			p++;
			q++;
		}
		*q = '\0';

		/* get machine name */
		strcpy(mach1,mach2);	/* save previous name */

		/* see if 'remote from' in line */
		j = sindex(frlist[i], rmtfrom) ;
		if ( j == -1 ) continue ; /* no so try next line */

		p = &frlist[i][j+sizeof(rmtfrom) -1];	/* skip past remote from */
		while ( *p == ' ' || *p == '\t' ) p++; /* skip spaces */
		q = mach2;
		while ( *p != 10 && *p != '\0' &&  *p != ' ' && *p != '\t' ) {
			*q = *p;
			p++;
			q++;
		}
		*q = '\0';

		/* append to address if different from previous machine mach1 */
		if ( equal(mach1,mach2) ) {
			continue;	/* equal so skip it */
		} else {
			strcat(address,mach2);
			strcat(address,"!");
		}
	}/* for */

	strcat(address,user);
	if (flg) printf("Sender=%s\n",address);
	return(address);
}/*frflsh*/

/* Determine if line is genuine article.
** Should be of 2 forms:
** From.*[0-9][0-9]:[0-9][0-9].*
** 	or
** >From.*[0-9][0-9]:[0-9][0-9].*
**
** The [0-9] stuff is the date representation by ctime.
** Some systems use only the 09:43 part of the time (i.e.
** no seconds representation).
*/
Isfrom(line)
register char *line;	/* line to parse */
{	
	register char *p;

	if(equaln(line, from, 5))
	{
		if((p=strchr(line, ':')) != NULL)
		{
colontest:
			if(	isdigit(p[-2]) &&
			    isdigit(p[-1]) &&
			    isdigit(p[1]) &&
			    isdigit(p[2]))      return(1);
		}
		/*
		 *	If more colons, try again.
		 */
		if(p=strchr(++p, ':'))
			goto colontest;
	}
	return(0);
}/*Isfrom*/

/* fillfrom: fills frlist[] with FROM lines and sets frcnt to nr of lines 
** also set all mail variables
*/
int fillfrom()
{ 	
	char *ptr;

	frcnt = 0;
	/* set all message variables to defaults */
	strcpy(SUBJECT,"");
	strcpy(SENDER,"");
	NROFLINES = 0;
	SIZE = 0;
	strcpy(VIA,"");
	strcpy(MESSAGE,"");
	strcpy(DEMON,"FALSE");
	strcpy(LAST,"FALSE");

	/* skip until From is found */
	while ( lp != NULL && !Isfrom(line)) {
		lp = fgets(line, LINELENGTH, f1);
	}
	if ( NULL == lp ) return(FALSE);	/* EOF */

	/* copy in first From line */
	strcpy(frlist[frcnt] , line);
	NROFLINES++;
	SIZE = SIZE + strlen(line);
	frcnt++;

	/* copy in >From lines */
	lp = fgets(line, LINELENGTH, f1);
	while ( lp != NULL && Isfrom(line+1)) {
		strcpy(frlist[frcnt] , line);
		NROFLINES++;
		SIZE = SIZE + strlen(line);
		frcnt++;
		lp = fgets(line, LINELENGTH, f1);
	}
	if  ( NULL == lp ) return(FALSE);	/* EOF */
	strcpy(VIA, frflsh(0));	/* get VIA */

	/* get SENDER */
	ptr = strrchr(VIA,'!');
	if (NULL == ptr) {
		ptr = VIA;
	} else {
		ptr++;
	}/*fi*/
	strcpy(SENDER,ptr);

	/* determine if demon, default = FALSE */
	if ( (equal (ptr , "**NSC**" ))  ||
	    (equaln(ptr , "NUSEND",6))  ||
	    (equal (ptr , "uucp"    ))  ||
	    (equal (ptr , "**RJE**" ))  ||
	    (equal (ptr , "root"    ))  ||
	    (equal (ptr , "nhcms"   ))  ||
	    (equal (ptr , "demon"   ))  ||
	    (equal (ptr , "deamon"  ))  ||
	    (equal (ptr , "daemon"  ))
	    ) {
		strcpy(DEMON,"TRUE");
	}/*fi*/

	/* now look through text until subject or start next message */
	while ( lp != NULL && !Isfrom(line)) {
		if (equaln(line,subject,strlen(subject))) {
			/* skip past spaces */
			ptr = &line[strlen(subject)];
			while (*ptr == ' ') {
				ptr++;
			}
			strcpy(SUBJECT,ptr);
			SUBJECT[strlen(SUBJECT)-1] = '\0'; /* take of CR */
			break;
		}/*fi*/
		NROFLINES++;
		SIZE = SIZE + strlen(line);
		lp = fgets(line, LINELENGTH, f1);
	}

	/* now just look through text until start of next message or EOF */
	while ( lp != NULL && !Isfrom(line)) {
		NROFLINES++;
		SIZE = SIZE + strlen(line);
		lp = fgets(line, LINELENGTH, f1);
	}

	if  ( NULL == lp ) strcpy(LAST,"TRUE");	/* EOF means last message */
	return(TRUE);
}/*fillfrom*/

/* copy mail file to TEMPM so we can process it */
void readmail()
{
	char cmd[80];

	mktemp(TEMPM);
	unlink(TEMPM);
	sprintf(cmd,"/bin/mail -p -r >%s",TEMPM);
	if (dflag) printf("cmd=%s\n",cmd);
	system(cmd);
}/*readmail*/

/* check to see if message was saved okay */
chkmsg()
{
	FILE *f2;

	f2 = fopen(MESSAGE,"r");
	if (f2 = NULL) {
		fprintf(stderr,"%s: ERROR cannot open message file",NAME);
		exit(1);
	}
	fclose(f2);
}/*chkmsg*/

/* save message into temp file after deleting previous version */
savemsg()
{
	char cmd[80];

	unlink(MESSAGE);	/* previous message*/
	strcpy(MESSAGE,TEMPA);
	mktemp(MESSAGE);
	unlink(MESSAGE);
	sprintf(cmd,"echo 's %s' | /bin/mail -r >/dev/null",MESSAGE);
	if (dflag) {
		printf("UNEXECUTED cmd=%s\n",cmd);
	} else {
		system(cmd);
		chkmsg();
	}/*fi*/
}/*savemsg*/

void init()
{
	readmail();
	/* open mail and read first line */
	f1 = fopen(TEMPM,"r");
	if ( NULL == f1 ) {
		fprintf(stderr,"%s: ERROR cannot open copy of mail file\n",NAME);
		exit(1);
	}
	lp = fgets(line, LINELENGTH, f1);
}

void finit()
{
	unlink(MESSAGE);
	unlink(TEMPM);
}/*finit*/

void usage()
{
	printf("Usage: %s [-d] [-V] [-H] [-f input] [-x prgm] [-o options]\n",NAME);
}/*usage*/

/* parse options */
void options(argc,argv)
int	argc;
char	*argv[];
{
	int	ch;
	extern char *optarg;

	while ((ch=getopt(argc,argv,"vVhHdf:x:o:")) != EOF) {
		switch (ch) {
		case 'V' :
		case 'v' :
			printf("%s: version 0.9\n",NAME);
			exit(0);
			break;
		case 'h' :
		case 'H' :
			usage();
			exit(0);
			break;
		case 'd' :
			dflag = TRUE;
			break;
		case 'f' :
			sscanf(optarg,"%s",fflag);
			break;
		case 'x' :
			sscanf(optarg,"%s",xflag);
			break;
		case 'o' :
			strcpy(oflag,optarg);
			break;
		case '?' :
		default :
			usage();
			exit(1);
			break;
		}/*switch*/
	}/*while*/
}/*options*/

/* return pointer to copy of input but with special characters backslashed */
char *unquote(input)
register char input[];
{
	register int i;
	register int j;
	static char output[TOSIZE];

	i = 0;
	j = 0;
	while (input[i] != '\0') {
		if ( (input[i] == '\"') || 
		    (input[i] == '\\') ||
		    (input[i] == '\$') ||
		    (input[i] == '\`') ) {
			output[j] = '\\';
			j++;
		}
		output[j] = input[i];
		j++;
		i++;
	}/*while*/
	output[j] = '\0';
	return(output);
}/*unquote*/

/* put all variables into file */
void printit(file)
char file[];
{
	FILE *f2;

	f2 = fopen(file,"w");
	if (f2 == NULL) {
		fprintf(stderr,"%s: ERROR cannot create work file",NAME);
		exit(1);
	}
	fprintf(f2,"SUBJECT=\"%s\" ; export SUBJECT\n",unquote(SUBJECT));
	fprintf(f2,"SENDER='%s' ; export SENDER\n",SENDER);
	fprintf(f2,"NROFLINES='%d' ; export NROFLINES\n",NROFLINES);
	fprintf(f2,"SIZE='%d' ; export SIZE\n",SIZE);
	fprintf(f2,"VIA='%s' ; export VIA\n",VIA);
	fprintf(f2,"MESSAGE='%s' ; export MESSAGE\n",MESSAGE);
	fprintf(f2,"DEMON='%s' ; export DEMON\n",DEMON);
	fprintf(f2,"LAST='%s' ; export LAST\n",LAST);
	fprintf(f2,". %s\n",fflag);
	fflush(f2);
	fclose(f2);
}/*printit*/

/* make work file and execute it */
execmsg()
{
	char cmd[80];
	char file[40];

	unlink(file);	/* remove previous version*/
	strcpy(file,TEMPS);
	mktemp(file);
	unlink(file);
	printit(file);
	sprintf(cmd,"%s %s < %s",xflag,oflag,file);
	if (dflag) {
		printf("UNEXECUTED cmd=%s\n",cmd);
		printf("CONTENTS of %s:\n#=======\n",file);
		sprintf(cmd,"/bin/cat %s",file);
		system(cmd);
		printf("#=======\n");
	} else {
		system(cmd);
	}/*fi*/
	unlink(file);
}/*execmsg*/

int main(argc,argv)
int	argc;
char	*argv[];
{
	strcpy(fflag,"$HOME/.mailawayrc");
	strcpy(xflag,"/bin/sh");
	strcpy(oflag,"");
	options(argc,argv);
	init();

	/* now for each message */
	while (fillfrom()) {
		savemsg();
		execmsg();
	}/*while*/

	finit();
	return(0);
}/*main*/