/*
* Babcia Padlina Ltd. Cellular Phone Notifier
*
* STRONGLY BASED ON ERIC ALLMAN'S VACATION 
*
* $Log: notify.c,v $
* Revision 1.1.1.1  2001/05/21 15:38:58  venglin
* initial import into CVS
*
* Revision 1.6  1999/11/06 09:03:17  venglin
* Using "From: " instead of UUCP-like "From "
*
* Revision 1.5  1999/10/09 19:12:02  venglin
* Small optimization.
*
* Revision 1.4  1999/08/09 13:51:57  venglin
* Syntax error :)
*
* Revision 1.3  1999/08/09 13:50:47  venglin
* Fixed Subject: parsing error
*
* Revision 1.2  1999/08/09 12:47:00  venglin
* Syntax error :)
*
* Revision 1.1  1999/08/09 12:36:44  venglin
* Initial revision
*
*/

#include <sys/param.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pwd.h>
#include <time.h>
#include <syslog.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <paths.h>

#define	MAXLINE	1024
#define MAILCOMMAND "/usr/sbin/sendmail -oem -t"

static const char rcsid[] =
   "$Id: notify.c,v 1.1.1.1 2001/05/21 15:38:58 venglin Exp $";

typedef struct alias {
	struct alias *next;
	char *name;
} ALIAS;
ALIAS *names;

char from[MAXLINE];
char rcpt[MAXLINE];
char subj[MAXLINE];
char *av0;

static int	isdelim		__P((int));
static int	junkmail	__P((void));
static int	nsearch		__P((char *, char *));
static void	readheaders	__P((void));
static void	sendmessage	__P((void));
static void	usage		__P((void));

int
main(argc, argv)
	int argc;
	char **argv;
{
	extern int optind, opterr;
	extern char *optarg;
	struct passwd *pw;
	ALIAS *cur;
	int ch, rflag;

	if (strchr(argv[0], '/'))
		av0 = strrchr(argv[0], '/') + 1;
	else
		av0 = argv[0];

	opterr = rflag = 0;
	while ((ch = getopt(argc, argv, "a:r:")) != -1)
		switch((char)ch) {
		case 'a':
			if (!(cur = (ALIAS *)malloc((u_int)sizeof(ALIAS))))
				break;
			cur->name = optarg;
			cur->next = names;
			names = cur;
			break;
		case 'r':
			rflag = 1;
			strncat(rcpt, optarg, MAXLINE);
			break;
		case '?':
		default:
			usage();
		}
	argc -= optind;
	argv += optind;


	if ((argc < 1) || (!rflag)) usage();

	if (!(pw = getpwuid(getuid()))) {
		syslog(LOG_ERR,
			"%s: no such user uid %u.\n", av0, getuid());
		exit(1);
	}
	else if (!(pw = getpwnam(*argv))) {
		syslog(LOG_ERR, "%s: no such user %s.\n", av0, *argv);
		exit(1);
	}
	if (chdir(pw->pw_dir)) {
		syslog(LOG_NOTICE,
		    "%s: no such directory %s.\n", av0, pw->pw_dir);
		exit(1);
	}

	if (!(cur = malloc((u_int)sizeof(ALIAS))))
		exit(1);
	cur->name = pw->pw_name;
	cur->next = names;
	names = cur;

	readheaders();
	sendmessage();
	exit(0);
}

static void
readheaders()
{
	register ALIAS *cur;
	register char *p;
	int tome, cont;
	char buf[MAXLINE];

	cont = tome = 0;
	while (fgets(buf, sizeof(buf), stdin) && *buf != '\n')
		switch(*buf) {
		case 'F':
			cont = 0;
			if (!strncmp(buf, "From: ", 6)) {
				for (p = buf + 6; *p; ++p);
				*p = '\0';
				(void)strcpy(from, buf + 6);
				if ((p = index(from, '\n')))
					*p = '\0';
				if (junkmail())
					exit(0);
			}
			break;
		case 'S':
			cont = 0;
			if (!strncasecmp(buf, "Subject: ", 9)) {
				for (p = buf + 9; *p; ++p);
				*p = '\0';
				(void)strncpy(subj, buf + 9, MAXLINE);
				if ((p = index(subj, '\n')))
					*p = '\0';
			}
			break;

		case 'P':
			cont = 0;
			if (strncasecmp(buf, "Precedence", 10) ||
			    (buf[10] != ':' && buf[10] != ' ' && buf[10] != '\t'))
				break;
			if (!(p = index(buf, ':')))
				break;
			while (*++p && isspace(*p));
			if (!*p)
				break;
			if (!strncasecmp(p, "junk", 4) ||
			    !strncasecmp(p, "bulk", 4) ||
			    !strncasecmp(p, "list", 4))
				exit(0);
			break;
		case 'C':
			if (strncmp(buf, "Cc:", 3))
				break;
			cont = 1;
			goto findme;
		case 'T':
			if (strncmp(buf, "To:", 3))
				break;
			cont = 1;
			goto findme;
		default:
			if (!isspace(*buf) || !cont || tome) {
				cont = 0;
				break;
			}
findme:			for (cur = names; !tome && cur; cur = cur->next)
				tome += nsearch(cur->name, buf);
		}
	if (!tome)
		exit(0);
	if (!*from) {
		syslog(LOG_NOTICE, "%s: no initial \"From\" line.\n", av0);
		exit(1);
	}
}

static int
nsearch(name, str)
	register char *name, *str;
{
	register int len;

	for (len = strlen(name); *str; ++str)
		if (*str == *name &&
		    !strncasecmp(name, str, len) &&
		    isdelim((unsigned char)str[len]))
			return(1);
	return(0);
}

static int
junkmail()
{
	static struct ignore {
		char	*name;
		int	len;
	} ignore[] = {
		{"-request", 8},	{"postmaster", 10},	{"uucp", 4},
		{"mailer-daemon", 13},	{"mailer", 6},		{"-relay", 6},
		{NULL, 0},
	};
	register struct ignore *cur;
	register int len;
	register char *p;

	if (!(p = index(from, '%')))
		if (!((p = index(from, '@')))) {
			if ((p = rindex(from, '!')))
				++p;
			else
				p = from;
			for (; *p; ++p);
		}
	len = p - from;
	for (cur = ignore; cur->name; ++cur)
		if (len >= cur->len &&
		    !strncasecmp(cur->name, p - cur->len, cur->len))
			return(1);
	return(0);
}

static void
sendmessage(void)
{
	FILE *mailc;

	if((mailc = popen(MAILCOMMAND, "w")) == NULL) {
		syslog(LOG_ERR, "%s: cannot open pipe to %s (%m)", av0, MAILCOMMAND);
		exit(1);
	} 

	fprintf(mailc, "To: %s\n\n", rcpt);
	fprintf(mailc, "Nowy email!\n%s\n%s\n", from, subj);	

  if(pclose(mailc))
    syslog(LOG_WARNING, "%s: cannot close pipe to %s (%m)", av0, MAILCOMMAND);

}

static void
usage()
{
	syslog(LOG_NOTICE, "uid %u: usage: %s <-r rcpt> [-a alias] login\n",
	    getuid(), av0);
	exit(1);
}

static int
isdelim(c)
	int c;
{
	if (isalnum(c))
		return(0);
	if (c == '_' || c == '-' || c == '.')
		return(0);
	return(1);
}

