DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T r

⟦91bc4650a⟧ TextFile

    Length: 15594 (0x3cea)
    Types: TextFile
    Names: »rcvtrip.c«

Derivation

└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
    └─⟦dc59850a2⟧ »EurOpenD22/pp5.0/pp-5.tar.Z« 
        └─⟦e5a54fb17⟧ 
            └─⟦this⟧ »pp-5.0/Uip/rcvtrip/rcvtrip.c« 

TextFile

/* rcvtrip.c: trip reporting program */

# ifndef lint
static char Rcsid[] = "@(#)$Header: /cs/research/pp/hubris/pp-beta/Uip/rcvtrip/RCS/rcvtrip.c,v 5.0 90/09/20 16:34:22 pp Exp Locker: pp $";
# endif

/*
 * $Header: /cs/research/pp/hubris/pp-beta/Uip/rcvtrip/RCS/rcvtrip.c,v 5.0 90/09/20 16:34:22 pp Exp Locker: pp $
 *
 * $Log:	rcvtrip.c,v $
 * Revision 5.0  90/09/20  16:34:22  pp
 * rcsforce : 5.0 public release
 * 
 */



#include	"util.h"
#include	"retcode.h"
#include	"adr.h"
#include	"ap.h"
#include	"chan.h"
#include 	"alias.h"
#include	<pwd.h>

#define		NONFATAL	0	/* Nonfatal reports		 */
#define		FATAL		1	/* Fatal reports (exit)		 */
#define		TRACE		2	/* General info for debug	 */

#define		EX_SENT		1
#define		EX_DUP		2
#define		EX_NOT_DIR	3
#define		EX_PARSE_ERR	4
#define		EX_ERR		99

#define		SENT		0	/* Sent out a reply		 */
#define		UNSENT		1	/* No reply sent - just
					 * note	 */

#define		REPLIED		'+'	/* A reply was sent		 */
#define		NOT_REPLIED	'-'	/* A reply wasn't sent		 */

#define		HDR_NAM		1
#define 	HDR_EOH		2
#define		HDR_MOR		3
#define		HDR_NEW		4

#define		DAYS	* (60 * 60 * 24)

#ifndef	MAX_HEAD_LINES
#define	MAX_HEAD_LINES	10
#endif	/* MAX_HEAD_LINES */

extern int ap_outtype;

extern char *index ();
extern char *strcpy ();
extern char *strncpy ();
extern char *fgets ();
extern char *strcat ();
extern char *compress ();

int     debug = FALSE;		/* output trace messages?	   */
int	repeat_interval = 14 DAYS; /* repeat after this interval   */
int     found_1 = FALSE;	/* true if message was sent to	   */
int	head_lines = 0;
int	exit_alg = -1;		/* algorithm to deiced on the exit code */
int	exit_code = 1;

 /* directly to recipient	   */
char    subj_field[LINESIZE];	/* contents of subject field	   */
char    _username[LINESIZE];	/* space for the users username	   */
char    *username = (char *) 0;	/* the users username		   */
char    *msg_note = "tripnote";/* where to get reply message from */
char    *wholoc = "triplog";	/* where to note incoming messages */
char    *sigloc = ".signature";/* where to find user's name	   */
char    *tripsig = "MESSAGE AGENT";

/* signature of the returned message */

AP_ptr  from_adr = NULLAP;	/* address tree for from address   */
AP_ptr  sndr_adr = NULLAP;	/* - " -	    sender	   */
AP_ptr  repl_adr = NULLAP;	/* - " -	    reply-to	   */

ADDR	*user_adr;

char   *find_sig ();
static int exit_rc();

struct passwd *getpwuid ();

/*
 *	This message is output before the users file message
 */
char   *text_message[MAX_HEAD_LINES+1] = {
	"\tThis is an automatic reply.  Feel free to send additional",
	"mail, as only this one notice will be generated.  The following",
	"is a prerecorded message, sent for ", 0
};

/*
 *	This message is output if the users file is not readable or doesn't
 *	exist. (This is where you can have some fun!)
 */
char   *error_txt[] = {
	"\tIt appears that the person in question hasn't left a\n",
	"message file, so the purpose of this message is unknown.\n",
	"However it is assumed that as I, a daemon process,\n",
	"have been called into existance that the person in question\n",
	"is probably away for some time and won't be replying to your\n",
	"message straight away.\n\nCheers,\n\tThe Mail System\n", 0
};

main (argc, argv)
int     argc;
char  **argv;
{
	init (argc, argv);
	parsemsg ();
	doreplies ();
	exit (exit_rc(exit_code));
}

/*
 *	Initialisation - get user, setup flags etc.
 */

init (argc, argv)
int     argc;
char  **argv;
{
	register struct passwd 	*pwdptr;
	int			opt;
	extern int		optind;
	extern char		*optarg;
	RP_Buf			rp;

	uip_init (argv[0]);

	ap_outtype = AP_PARSE_822;	/* standardise on 822 */

	while ((opt = getopt (argc, argv, "de:Ff:l:n:s:t:u:")) != EOF)
		switch (opt) {
		case 'd': debug = 1;			break;
		case 'e': exit_alg = atoi(optarg);	break;
		case 'F': found_1 = 1;			break;
		case 'f': tripsig = optarg;		break;
		case 'l': wholoc = optarg;		break;
		case 'n': msg_note = optarg;		break;
		/* This is disapbled for the momet ... */
		case 'r': opt = atoi(optarg);
			  if (!opt && *optarg != '0')	break;
			  repeat_interval = opt DAYS;	break;
		case 's': sigloc = optarg;		break;
		case 't': if (head_lines < MAX_HEAD_LINES)
				text_message[head_lines++] = optarg; break;
		case 'u': username = optarg;		break;
		}
	argv += optind;
	argc -= optind;

	if (argc > 0)		/* we have a command line sender
				 * address */
		parse_addr (*argv, &sndr_adr);

	if (username)
		;
	else if ((pwdptr = getpwuid (getuid ())) == (struct passwd *) 0)
		report (FATAL, EX_ERR, "Can't Identify user");
	else
		strcpy (username = _username, pwdptr->pw_name);

	if (head_lines) error_txt[head_lines] = (char *) 0;

	user_adr = adr_new (username, AD_ANY_TYPE, 0);
	if (rp_isbad (ad_parse (user_adr, &rp, CH_USA_PREF)))
		report (FATAL, EX_PARSE_ERR, "Can't parse you as a mail user");
}

/*
 *	parse message - just a front end to the real parser
 */

parsemsg ()
{
	if (rp_isbad (hdr_fil (stdin)))
		report (FATAL, EX_PARSE_ERR, "parse of message failed");
}

/*************** Routines to despatch messages ***************/

/*
 *	Send replies to reply-to address if specified else
 *		from and sender address.
 */

doreplies ()
{
	if (found_1 != TRUE)
		report (FATAL, EX_NOT_DIR, "Not sent directly to %s", username);

	if (repl_adr == NULLAP && from_adr == NULLAP && sndr_adr == NULLAP)
		report (FATAL, EX_PARSE_ERR, "No parsable from or sender lines");

/*
 *	If there were any reply-to lines, use those in preference.
 */
	if (repl_adr != NULLAP)
		replyto (repl_adr);
	else {			/* send to both from && sender if
				 * they exist */
		if (from_adr != NULLAP)
			replyto (from_adr);
		if (sndr_adr != NULLAP)
			replyto (sndr_adr);
	}
}

/*
 *	Actually do the work of sending the reply.
 */

replyto (aptr)
AP_ptr  aptr;
{
	register char *cp;
	register char **cpp;
	AP_ptr  user, local, domain;
	AP_ptr  norm;
	char   *addr;
	char   *ref;
	char   *person;
	char    buffer[LINESIZE];
	FILE   *fp;
	RP_Buf	rps, *rp = &rps;

#ifdef	PP_DEBUG
	report (TRACE, 0, "replyto()");
#endif

	norm = ap_normalize (aptr, CH_USA_PREF);
	ap_t2p (norm, (AP_ptr *) 0, &user, &local, &domain, (AP_ptr *) 0);
	ref = ap_p2s_nc (NULLAP, NULLAP, local, domain, NULLAP);

#ifdef	PP_DEBUG
	report (TRACE, 0, "normed addr = '%s'", ref);
#endif

	if (user != NULLAP)
		person = user->ap_obvalue;
	else
		person = NULLCP;

	if (checkuser (ref)) {

#ifdef	PP_DEBUG
		report (TRACE, 0, "Seen %s before", ref);
#endif

		noteuser (ref, UNSENT);
		free (ref);
		return;
	}
	if (ap_t2s (norm, &addr) == (AP_ptr) NOTOK) {
		report (NONFATAL, 0, "Parse error for %s", addr);
		noteuser (ref, UNSENT);
		free (ref);
		return;
	}
	buffer[0] = '\0';
	if (!prefix ("re:", subj_field))
		strcpy (buffer, "Re: ");

	strcat (buffer, subj_field);

#ifdef	PP_DEBUG
	report (TRACE, 0, "pps_1adr ('%s' %s)",
		buffer, addr);
#endif

	pps_1adr (buffer, addr, rp);

	if (person != NULLCP) {
		compress (person, person);
		sprintf (buffer, "\nDear %s,\n", person);

#ifdef	PP_DEBUG
		report (TRACE, 0, "1st line %s", buffer);
#endif

		pps_txt (buffer, rp);
	}

#ifdef	PP_DEBUG
	report (TRACE, 0, "start builtin message");
#endif

	for (cpp = text_message; *cpp != NULLCP; cpp++)
	{	if (cpp != text_message) pps_txt ("\n", rp);
		pps_txt (*cpp, rp);
	}
	if ((cp = find_sig ()) != NULLCP)
		pps_txt (cp, rp);
	else
		pps_txt (username);
	pps_txt ("\n\n\n", rp);

	if ((fp = fopen (msg_note, "r")) != (FILE *) 0) {

#ifdef	PP_DEBUG
		report (TRACE, 0, "processing file %s", msg_note);
#endif

		pps_file (fp, rp);
		fclose (fp);
	}
	else {

#ifdef	PP_DEBUG
		report (TRACE, 0, "Sending built in error message");
#endif

		for (cpp = error_txt; *cpp != NULLCP; cpp++)
			pps_txt (*cpp, rp);
	}

#ifdef	PP_DEBUG
	report (TRACE, 0, "ml_end(OK)");
#endif

	if (pps_end (OK, rp) == OK)
		noteuser (ref, SENT);
	else
		noteuser (ref, UNSENT);
	free (ref);
	free (addr);
}

/*************** Routines to pick apart the message ***************/

/*
 *	The actual picking out of headers
 */

hdr_fil (msg)
FILE   *msg;			/* The message file			 */
{
	char    line[LINESIZE];	/* temp buffer			 */
	char    name[LINESIZE];	/* Name of header field		 */
	char    contents[LINESIZE];	/* Contents of header field	 */

#ifdef	PP_DEBUG
	report (TRACE, 0, "hdr_fil()");
#endif

	if (msg == (FILE *) NULL) {
		report (FATAL, EX_PARSE_ERR, "NULL file pointer");
		return (RP_NO);	/* not much point doing anything
				 * else */
	}
/* process the file    */

	for (;;) {
		if (fgets (line, sizeof line, msg) == NULL) {
			report (NONFATAL, 0, "read error on message");
			return (RP_NO);	/* skip and go home */
		}

		switch (hdr_parse (line, name, contents)) {
		    case HDR_NAM:	/* No name so contine
					 * through header */
			continue;

		    case HDR_EOH:	/* End of header - lets go
					 * home */
			return (RP_OK);

		    case HDR_NEW:
		    case HDR_MOR:	/* We have a valid field	    */
			if (lexequ (name, "to") == 0  ||
			    lexequ (name, "cc") == 0||
			    lexequ (name, "resent-to") == 0 ||
			    lexequ (name, "resent-cc") == 0) {
				find_user (contents);
				break;
			}
			else if (lexequ (name, "from") == 0) {
				parse_addr (contents, &from_adr);
				break;
			}
			else if (lexequ (name, "reply-to") == 0) {
				parse_addr (contents, &repl_adr);
				break;
			}
			else if (lexequ (name, "sender") == 0) {
				parse_addr (contents, &sndr_adr);
				break;
			}
			else if (lexequ (name, "subject") == 0) {
				strncpy (subj_field, contents,
					 sizeof contents - 1);
				break;
			}
			else
				continue;
		}
	}
}

/*
 *	The real parser
 */

hdr_parse (src, name, contents)	/* parse one header line		 */
register char *src;		/* a line of header text		 */
char   *name,			/* where to put field's name		 */
       *contents;		/* where to put field's contents	 */
{
	extern char *compress ();
	char    linetype;
	register char *dest;

#ifdef	PP_DEBUG
	report (TRACE, 0, "hdr_parse('%*.*s')", strlen(src)-1, strlen(src)-1, src);
#endif

	if (isspace (*src)) {	/* continuation text			 */

#ifdef	PP_DEBUG
		report (TRACE, 0, "hrd_parse -> cmpnt more");
#endif

		if (*src == '\n')
			return (HDR_EOH);
		linetype = HDR_MOR;
	}
	else {			/* copy the name			 */
		linetype = HDR_NEW;
		for (dest = name; *dest = *src++; dest++) {
			if (*dest == ':')
				break;	/* end of the name	 */
			if (*dest == '\n') {	/* oops, end of the
line		 */
				*dest = '\0';
				return (HDR_NAM);
			}
		}
		*dest = '\0';
		compress (name, name);	/* strip extra & trailing
					 * spaces	 */

#ifdef	PP_DEBUG
		report (TRACE, 0, "hdr_parse -> cmpnt name '%s'", name);
#endif
	}

	for (dest = contents; isspace (*src);)
		if (*src++ == '\n') {	/* skip leading white space
	 *//* u
					 * nfulfilled promise, no
					 * contents	 */
			*dest = '\0';
			return ((linetype == HDR_MOR) ? HDR_EOH : linetype);
		}		/* hack to fix up illegal spaces	 */

	while ((*dest = *src) != '\n' && *src != 0)
		src++, dest++;	/* copy contents and then, backup	 */
	while (isspace (*--dest));	/* to eliminate trailing
					 * spaces	 */
	*++dest = '\0';

	return (linetype);
}

/*************** Parsing of addresses got from message ***************/

/*
 *	See if user is in this field. parse address first and
 *		compare mbox's.
 */

find_user (str)
char   *str;
{
	AP_ptr  tree, local, domain;
	ADDR	*ad;
	RP_Buf	rp;
	char   *p;

#ifdef	PP_DEBUG
	report (TRACE, 0, "find_user('%s')", str);
#endif

	if (found_1 == TRUE) {

#ifdef	PP_DEBUG
		report (TRACE, 0, "find_user() name already found\n");
#endif

		return;
	}

	while ((str = ap_s2p (str, &tree, (AP_ptr *) 0, (AP_ptr *) 0, &local,
		     (AP_ptr *) &domain, (AP_ptr *) 0)) != (char *) DONE
	       && str != (char *) NOTOK) {
		p = ap_p2s_nc (NULLAP, NULLAP, local, domain, NULLAP);

		ad = adr_new (p, AD_822_TYPE, 0);
		ap_sqdelete (tree, NULLAP);
		ap_free (tree);

		if (rp_isbad (ad_parse (ad, &rp, CH_USA_PREF))) {
			adr_free (ad);
			continue;
		}
		found_1 = (lexequ (ad -> ad_r822adr, user_adr -> ad_r822adr) == 0 ||
			lexequ (p, username) == 0);
#ifdef	PP_DEBUG
		report (TRACE, 0, "find_user() -> found mbox %s (%s) ->%d",
			p, user_adr -> ad_r822adr, found_1);
#endif
		free (p);
		if (found_1 == TRUE)
			return;
	}
}

/*
 *	Attempt to parse a field into an address tree for later use.
 */

parse_addr (str, aptr)
char   *str;
AP_ptr *aptr;
{

#ifdef	PP_DEBUG
	report (TRACE, 0, "parse_addr('%s')", str);
#endif

	if (*aptr != NULLAP) {

#ifdef	PP_DEBUG
		report (TRACE, 0, "field '%s' rejected, already seen one");
#endif

		return;
	}

	if ((*aptr = ap_s2t (str)) == (AP_ptr) NOTOK)
		report (NONFATAL, 0, "Can't parse address '%s'", str);
}

/*************** User Data Base Routines ***************/

/*
 *	Note the fact we did/didnot reply to a given person
 *	and include the subject line for good measure.
 */

noteuser (addr, mode)
char   *addr;
int     mode;
{
	FILE   *fp;
	time_t  now;
	char   *ctime ();
	int     result = NOTOK;

#ifdef	PP_DEBUG
	report (TRACE, 0, "noteuser(%s,%d)", addr, mode);
#endif

	time (&now);

	if ((fp = fopen (wholoc, "a")) != NULL) {
		(void) chmod (wholoc, 0600);
		fprintf (fp, "%c %-30s %19.19s >> %.20s\n",
			 mode == SENT ? REPLIED : NOT_REPLIED,
			 addr, ctime (&now), subj_field);
		(void) fflush (fp);
		result = ferror (fp) ? NOTOK : OK;
		fclose (fp);
		if (result == OK && mode == SENT) exit_code = 0;
	}
	return result;
}

/*
 *	Have we replied to this person before?
 */
checkuser (addr)
char   *addr;
{
	FILE   *fp;
	char    buffer[LINESIZE];
	char    compaddr[LINESIZE];

	if (repeat_interval == 0)	return FALSE;

	if ((fp = fopen (wholoc, "r")) == NULL)
		return FALSE;
	while (fgets (buffer, sizeof buffer, fp) != NULL) {
		if (buffer[0] == NOT_REPLIED)
			continue;
		/* SHOULD parse the date to see whether to repeat */
		getaddress (buffer, compaddr);

#ifdef	PP_DEBUG
		report (TRACE, 0, "checkuser, = '%s' & '%s'?", compaddr, addr);
#endif

		if (lexequ (compaddr, addr) == 0) {
			fclose (fp);
			return TRUE;
		}
	}
	fclose (fp);
	return FALSE;
}


/*************** Some Utility Routines ***************/


/*
 *	Dig out a signature for the user
 */

char   *find_sig ()
{
	FILE   *fp;
	static char buf[LINESIZE];
	static int been_here = FALSE;
	char   *p;

#ifdef	PP_DEBUG
	report (TRACE, 0, "find_sig()");
#endif

	if (been_here == TRUE)	/* cuts off at least 1/4
				 * micro-second */
		return buf;

	if ((fp = fopen (sigloc, "r")) == NULL)
		return NULLCP;
	if (fgets (buf, sizeof (buf), fp) == NULLCP) {
		fclose (fp);
		return NULLCP;
	}
	if ((p = index (buf, '\n')) != NULLCP)
		*p = '\0';
	fclose (fp);
	return buf;
}

getaddress (source, dest)
char   *source, *dest;
{
	register char *p;
	int     depth = 0;

	p = source + 2;		/* skip over reply indicator */
	while (*p) {
		switch (*p) {
		    case '"':	/* in quoted part ? */
			depth = !depth;
			break;
		    case ' ':
		    case '\t':
			if (depth == 0) {
				*dest = '\0';
				return;
			}
			break;
		    case '\\':	/* gobble up next char */
			*dest++ = *p++;
			break;
		}
		*dest++ = *p++;
	}
	*dest = '\0';
}

/*VARARGS2*/
report (mode, rc, fmt, a1, a2, a3, a4)
int     mode;
int	rc;
char   *fmt, *a1, *a2, *a3, *a4;
{
	static FILE *log;

	if (debug == FALSE && mode == TRACE)
		return;

	if (debug == TRUE) {
		fprintf (stderr, "%s\t", mode == TRACE ? "TRACE" :
			 (mode == FATAL ? "FATAL" : "!FATAL"));
		fprintf (stderr, fmt, a1, a2, a3, a4);
		putc ('\n', stderr);
		fflush (stderr);
	}

	if (mode == FATAL)
		exit (exit_rc(rc));	/* die a horrible death */
}

static int exit_rc(num)
int num;
{
	switch (exit_alg)
	{
	case 0:	return RP_MECH;
	case 1:	return 0;
	case 2:	return num;
	default:return 0;
	}
}