17c478bd9Sstevel@tonic-gate /*
24c031281Sjbeck  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
448bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
57c478bd9Sstevel@tonic-gate  *
67c478bd9Sstevel@tonic-gate  *	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
77c478bd9Sstevel@tonic-gate  *	  All Rights Reserved
87c478bd9Sstevel@tonic-gate  */
97c478bd9Sstevel@tonic-gate 
107c478bd9Sstevel@tonic-gate /*
117c478bd9Sstevel@tonic-gate  *  Vacation
127c478bd9Sstevel@tonic-gate  *  Copyright (c) 1983  Eric P. Allman
137c478bd9Sstevel@tonic-gate  *  Berkeley, California
147c478bd9Sstevel@tonic-gate  *
157c478bd9Sstevel@tonic-gate  *  Copyright (c) 1983 Regents of the University of California.
167c478bd9Sstevel@tonic-gate  *  All rights reserved.  The Berkeley software License Agreement
177c478bd9Sstevel@tonic-gate  *  specifies the terms and conditions for redistribution.
187c478bd9Sstevel@tonic-gate  */
197c478bd9Sstevel@tonic-gate 
207c478bd9Sstevel@tonic-gate #include <stdio.h>
217c478bd9Sstevel@tonic-gate #include <stdarg.h>
227c478bd9Sstevel@tonic-gate #include <stdlib.h>
237c478bd9Sstevel@tonic-gate #include <unistd.h>
247c478bd9Sstevel@tonic-gate #include <sysexits.h>
257c478bd9Sstevel@tonic-gate #include <pwd.h>
267c478bd9Sstevel@tonic-gate #include <ndbm.h>
277c478bd9Sstevel@tonic-gate #include <string.h>
287c478bd9Sstevel@tonic-gate #include <ctype.h>
297c478bd9Sstevel@tonic-gate #include <fcntl.h>
307c478bd9Sstevel@tonic-gate #include <strings.h>
317c478bd9Sstevel@tonic-gate #include <errno.h>
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate /*
347c478bd9Sstevel@tonic-gate  *  VACATION -- return a message to the sender when on vacation.
357c478bd9Sstevel@tonic-gate  *
367c478bd9Sstevel@tonic-gate  *	This program could be invoked as a message receiver
377c478bd9Sstevel@tonic-gate  *	when someone is on vacation.  It returns a message
387c478bd9Sstevel@tonic-gate  *	specified by the user to whoever sent the mail, taking
397c478bd9Sstevel@tonic-gate  *	care not to return a message too often to prevent
407c478bd9Sstevel@tonic-gate  *	"I am on vacation" loops.
417c478bd9Sstevel@tonic-gate  *
427c478bd9Sstevel@tonic-gate  *	For best operation, this program should run setuid to
437c478bd9Sstevel@tonic-gate  *	root or uucp or someone else that sendmail will believe
447c478bd9Sstevel@tonic-gate  *	a -f flag from.  Otherwise, the user must be careful
4548bbca81SDaniel Hoffman  *	to include a header on their .vacation.msg file.
467c478bd9Sstevel@tonic-gate  *
477c478bd9Sstevel@tonic-gate  *	Positional Parameters:
487c478bd9Sstevel@tonic-gate  *		the user to collect the vacation message from.
497c478bd9Sstevel@tonic-gate  *
507c478bd9Sstevel@tonic-gate  *	Flag Parameters:
517c478bd9Sstevel@tonic-gate  *		-I	initialize the database.
527c478bd9Sstevel@tonic-gate  *		-d	turn on debugging.
537c478bd9Sstevel@tonic-gate  *		-tT	set the timeout to T.  messages arriving more
547c478bd9Sstevel@tonic-gate  *			often than T will be ignored to avoid loops.
557c478bd9Sstevel@tonic-gate  *
567c478bd9Sstevel@tonic-gate  *	Side Effects:
577c478bd9Sstevel@tonic-gate  *		A message is sent back to the sender.
587c478bd9Sstevel@tonic-gate  *
597c478bd9Sstevel@tonic-gate  *	Author:
607c478bd9Sstevel@tonic-gate  *		Eric Allman
617c478bd9Sstevel@tonic-gate  *		UCB/INGRES
627c478bd9Sstevel@tonic-gate  */
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate #define	MAXLINE	256	/* max size of a line */
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate #define	ONEWEEK	(60L*60L*24L*7L)
677c478bd9Sstevel@tonic-gate #define	MsgFile "/.vacation.msg"
687c478bd9Sstevel@tonic-gate #define	FilterFile "/.vacation.filter"
697c478bd9Sstevel@tonic-gate #define	DbFileBase "/.vacation"
707c478bd9Sstevel@tonic-gate #define	_PATH_TMP	"/tmp/vacation.XXXXXX"
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate typedef int bool;
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate #define	FALSE	0
757c478bd9Sstevel@tonic-gate #define	TRUE	1
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate static time_t	Timeout = ONEWEEK;	/* timeout between notices per user */
787c478bd9Sstevel@tonic-gate static DBM	*db;
797c478bd9Sstevel@tonic-gate static bool	Debug = FALSE;
8091c7793eSjbeck static bool	ListMode = FALSE;
817c478bd9Sstevel@tonic-gate static bool	AnswerAll = FALSE;	/* default: answer if in To:/Cc: only */
827c478bd9Sstevel@tonic-gate static char	*Subject = NULL;	/* subject in message header */
837c478bd9Sstevel@tonic-gate static char	*EncodedSubject = NULL;	/* subject in message header */
847c478bd9Sstevel@tonic-gate static char	Charset[MAXLINE];	/* for use in reply message */
857c478bd9Sstevel@tonic-gate static char	*AliasList[MAXLINE];	/* list of aliases to allow */
867c478bd9Sstevel@tonic-gate static int	AliasCount = 0;
877c478bd9Sstevel@tonic-gate static char	*myname;		/* name of person "on vacation" */
887c478bd9Sstevel@tonic-gate static char	*homedir;		/* home directory of said person */
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate extern time_t	convtime(char *, char);
917c478bd9Sstevel@tonic-gate extern bool	decode_rfc2047(char *, char *, char *);
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate static bool	ask(char *);
947c478bd9Sstevel@tonic-gate static bool	junkmail(char *);
957c478bd9Sstevel@tonic-gate static bool	filter_ok(char *, char *);
967c478bd9Sstevel@tonic-gate static bool	knows(char *);
977c478bd9Sstevel@tonic-gate static bool	sameword(char *, char *);
987c478bd9Sstevel@tonic-gate static char	*getfrom(char **);
997c478bd9Sstevel@tonic-gate static char	*newstr(char *);
1007c478bd9Sstevel@tonic-gate static void	AutoInstall();
1017c478bd9Sstevel@tonic-gate static void	initialize(char *);
1027c478bd9Sstevel@tonic-gate static void	sendmessage(char *, char *, char *);
1037c478bd9Sstevel@tonic-gate static void	setknows(char *);
10491c7793eSjbeck static void	dumplist();
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate void	usrerr(const char *, ...);
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate int
main(argc,argv)1097c478bd9Sstevel@tonic-gate main(argc, argv)
1107c478bd9Sstevel@tonic-gate 	int argc;
1117c478bd9Sstevel@tonic-gate 	char **argv;
1127c478bd9Sstevel@tonic-gate {
1137c478bd9Sstevel@tonic-gate 	char *from;
1147c478bd9Sstevel@tonic-gate 	char *p, *at, *c;
1157c478bd9Sstevel@tonic-gate 	struct passwd *pw;
1167c478bd9Sstevel@tonic-gate 	char *shortfrom;
1177c478bd9Sstevel@tonic-gate 	char buf[MAXLINE];
1187c478bd9Sstevel@tonic-gate 	char *message_file = MsgFile;
1197c478bd9Sstevel@tonic-gate 	char *db_file_base = DbFileBase;
1207c478bd9Sstevel@tonic-gate 	char *filter_file = FilterFile;
1217c478bd9Sstevel@tonic-gate 	char *sender;
1227c478bd9Sstevel@tonic-gate 	bool sender_oob = FALSE;
1237c478bd9Sstevel@tonic-gate 	bool initialize_only = FALSE;
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	/* process arguments */
1267c478bd9Sstevel@tonic-gate 	while (--argc > 0 && (p = *++argv) != NULL && *p == '-')
1277c478bd9Sstevel@tonic-gate 	{
1287c478bd9Sstevel@tonic-gate 		switch (*++p)
1297c478bd9Sstevel@tonic-gate 		{
1307c478bd9Sstevel@tonic-gate 		    case 'a':	/* add this to list of acceptable aliases */
1317c478bd9Sstevel@tonic-gate 			AliasList[AliasCount++] = argv[1];
1327c478bd9Sstevel@tonic-gate 			if (argc > 0) {
1337c478bd9Sstevel@tonic-gate 				argc--; argv++;
1347c478bd9Sstevel@tonic-gate 			}
1357c478bd9Sstevel@tonic-gate 			break;
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 		    case 'd':	/* debug */
1387c478bd9Sstevel@tonic-gate 			Debug = TRUE;
1397c478bd9Sstevel@tonic-gate 			break;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 		    case 'e':	/* alternate filter file */
1427c478bd9Sstevel@tonic-gate 			filter_file = argv[1];
1437c478bd9Sstevel@tonic-gate 			if (argc > 0) {
1447c478bd9Sstevel@tonic-gate 				argc--; argv++;
1457c478bd9Sstevel@tonic-gate 			}
1467c478bd9Sstevel@tonic-gate 			break;
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 		    case 'f':	/* alternate database file name base */
1497c478bd9Sstevel@tonic-gate 			db_file_base = argv[1];
1507c478bd9Sstevel@tonic-gate 			if (argc > 0) {
1517c478bd9Sstevel@tonic-gate 				argc--; argv++;
1527c478bd9Sstevel@tonic-gate 			}
1537c478bd9Sstevel@tonic-gate 			break;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 		    case 'I':	/* initialize */
1567c478bd9Sstevel@tonic-gate 			initialize_only = TRUE;
1577c478bd9Sstevel@tonic-gate 			break;
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 		    case 'j':	/* answer all mail, even if not in To/Cc */
1607c478bd9Sstevel@tonic-gate 			AnswerAll = TRUE;
1617c478bd9Sstevel@tonic-gate 			break;
1627c478bd9Sstevel@tonic-gate 
16391c7793eSjbeck 		    case 'l':	/* list all respondees */
16491c7793eSjbeck 			ListMode = TRUE;
16591c7793eSjbeck 			break;
16691c7793eSjbeck 
1677c478bd9Sstevel@tonic-gate 		    case 'm':	/* alternate message file */
1687c478bd9Sstevel@tonic-gate 			message_file = argv[1];
1697c478bd9Sstevel@tonic-gate 			if (argc > 0) {
1707c478bd9Sstevel@tonic-gate 				argc--; argv++;
1717c478bd9Sstevel@tonic-gate 			}
1727c478bd9Sstevel@tonic-gate 			break;
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 		    case 's':	/* sender: use this instead of getfrom() */
1757c478bd9Sstevel@tonic-gate 			sender = argv[1];
1767c478bd9Sstevel@tonic-gate 			sender_oob = TRUE;
1777c478bd9Sstevel@tonic-gate 			if (argc > 0) {
1787c478bd9Sstevel@tonic-gate 				argc--; argv++;
1797c478bd9Sstevel@tonic-gate 			}
1807c478bd9Sstevel@tonic-gate 			break;
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 		    case 't':	/* set timeout */
1837c478bd9Sstevel@tonic-gate 			Timeout = convtime(++p, 'w');
1847c478bd9Sstevel@tonic-gate 			break;
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 		    default:
1877c478bd9Sstevel@tonic-gate 			usrerr("Unknown flag -%s", p);
1887c478bd9Sstevel@tonic-gate 			exit(EX_USAGE);
1897c478bd9Sstevel@tonic-gate 		}
1907c478bd9Sstevel@tonic-gate 	}
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	if (initialize_only)
1937c478bd9Sstevel@tonic-gate 	{
1947c478bd9Sstevel@tonic-gate 		initialize(db_file_base);
1957c478bd9Sstevel@tonic-gate 		exit(EX_OK);
1967c478bd9Sstevel@tonic-gate 	}
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	/* verify recipient argument */
19991c7793eSjbeck 	if (argc == 0 && !ListMode)
2007c478bd9Sstevel@tonic-gate 		AutoInstall();
2017c478bd9Sstevel@tonic-gate 
20291c7793eSjbeck 	if (argc != 1 && !ListMode)
2037c478bd9Sstevel@tonic-gate 	{
20491c7793eSjbeck 		usrerr("Usage:\tvacation username\n\tvacation -I\n"
20591c7793eSjbeck 		    "\tvacation -l");
2067c478bd9Sstevel@tonic-gate 		exit(EX_USAGE);
2077c478bd9Sstevel@tonic-gate 	}
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	myname = p;
2107c478bd9Sstevel@tonic-gate 	Charset[0] = '\0';
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	/* find user's home directory */
21391c7793eSjbeck 	if (ListMode)
21491c7793eSjbeck 		pw = getpwuid(getuid());
21591c7793eSjbeck 	else
21691c7793eSjbeck 		pw = getpwnam(myname);
2177c478bd9Sstevel@tonic-gate 	if (pw == NULL)
2187c478bd9Sstevel@tonic-gate 	{
2197c478bd9Sstevel@tonic-gate 		usrerr("user %s look up failed, name services outage ?",
2207c478bd9Sstevel@tonic-gate 		    myname);
2217c478bd9Sstevel@tonic-gate 		exit(EX_TEMPFAIL);
2227c478bd9Sstevel@tonic-gate 	}
2237c478bd9Sstevel@tonic-gate 	homedir = newstr(pw->pw_dir);
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "%s%s%s", homedir,
2267c478bd9Sstevel@tonic-gate 			(db_file_base[0] == '/') ? "" : "/", db_file_base);
2277c478bd9Sstevel@tonic-gate 	if (!(db = dbm_open(buf, O_RDWR, 0))) {
2287c478bd9Sstevel@tonic-gate 		usrerr("%s: %s\n", buf, strerror(errno));
2297c478bd9Sstevel@tonic-gate 		exit(EX_DATAERR);
2307c478bd9Sstevel@tonic-gate 	}
2317c478bd9Sstevel@tonic-gate 
23291c7793eSjbeck 	if (ListMode) {
23391c7793eSjbeck 		dumplist();
23491c7793eSjbeck 		exit(EX_OK);
23591c7793eSjbeck 	}
23691c7793eSjbeck 
2377c478bd9Sstevel@tonic-gate 	if (sender_oob)
2387c478bd9Sstevel@tonic-gate 	{
2397c478bd9Sstevel@tonic-gate 		at = strchr(sender, '@');
2407c478bd9Sstevel@tonic-gate 		if (at != NULL)
2417c478bd9Sstevel@tonic-gate 			for (c = at + 1; *c; c++)
2427c478bd9Sstevel@tonic-gate 				*c = (char)tolower((char)*c);
2437c478bd9Sstevel@tonic-gate 		from = sender;
2447c478bd9Sstevel@tonic-gate 		shortfrom = sender;
2457c478bd9Sstevel@tonic-gate 	}
2467c478bd9Sstevel@tonic-gate 	else
2477c478bd9Sstevel@tonic-gate 		/* read message from standard input (just from line) */
2487c478bd9Sstevel@tonic-gate 		from = getfrom(&shortfrom);
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	/* check if junk mail or this person is already informed */
2517c478bd9Sstevel@tonic-gate 	if (!junkmail(shortfrom) && filter_ok(shortfrom, filter_file) &&
2527c478bd9Sstevel@tonic-gate 	    !knows(shortfrom))
2537c478bd9Sstevel@tonic-gate 	{
2547c478bd9Sstevel@tonic-gate 		/* mark this person as knowing */
2557c478bd9Sstevel@tonic-gate 		setknows(shortfrom);
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 		/* send the message back */
2587c478bd9Sstevel@tonic-gate 		(void) strlcpy(buf, homedir, sizeof (buf));
2597c478bd9Sstevel@tonic-gate 		if (message_file[0] != '/')
2607c478bd9Sstevel@tonic-gate 		    (void) strlcat(buf, "/", sizeof (buf));
2617c478bd9Sstevel@tonic-gate 		(void) strlcat(buf, message_file, sizeof (buf));
2627c478bd9Sstevel@tonic-gate 		if (Debug)
2637c478bd9Sstevel@tonic-gate 			printf("Sending %s to %s\n", buf, from);
2647c478bd9Sstevel@tonic-gate 		else
2657c478bd9Sstevel@tonic-gate 		{
2667c478bd9Sstevel@tonic-gate 			sendmessage(buf, from, myname);
2677c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
2687c478bd9Sstevel@tonic-gate 		}
2697c478bd9Sstevel@tonic-gate 	}
2704c031281Sjbeck 	while (fgets(buf, MAXLINE, stdin) != NULL)
2714c031281Sjbeck 		continue; /* drain input */
2727c478bd9Sstevel@tonic-gate 	return (EX_OK);
2737c478bd9Sstevel@tonic-gate }
2747c478bd9Sstevel@tonic-gate 
27591c7793eSjbeck struct entry {
27691c7793eSjbeck 	time_t	when;
27791c7793eSjbeck 	long	when_size;
27891c7793eSjbeck 	char	*who;
27991c7793eSjbeck 	long	who_size;
28091c7793eSjbeck 	struct	entry *next;
28191c7793eSjbeck 	struct	entry *prev;
28291c7793eSjbeck };
28391c7793eSjbeck 
28491c7793eSjbeck static void
dump_content(key_size,key_ptr,content_size,content_ptr)28591c7793eSjbeck dump_content(key_size, key_ptr, content_size, content_ptr)
28691c7793eSjbeck 	long key_size, content_size;
28791c7793eSjbeck 	char *key_ptr, *content_ptr;
28891c7793eSjbeck {
28991c7793eSjbeck 	time_t then;
29091c7793eSjbeck 
29191c7793eSjbeck 	if (content_size == sizeof (then)) {
29291c7793eSjbeck 		bcopy(content_ptr, (char *)&then, sizeof (then));
29391c7793eSjbeck 		(void) printf("%-53.40*s: %s", (int)key_size, key_ptr,
29491c7793eSjbeck 		    ctime(&then));
29591c7793eSjbeck 	} else {
29691c7793eSjbeck 		(void) fprintf(stderr, "content size error: %d\n",
29791c7793eSjbeck 		    (int)content_size);
29891c7793eSjbeck 	}
29991c7793eSjbeck }
30091c7793eSjbeck 
30191c7793eSjbeck static void
dump_all_content(first)30291c7793eSjbeck dump_all_content(first)
30391c7793eSjbeck 	struct entry *first;
30491c7793eSjbeck {
30591c7793eSjbeck 	struct entry *which;
30691c7793eSjbeck 
30791c7793eSjbeck 	for (which = first; which != NULL; which = which->next) {
30891c7793eSjbeck 		dump_content(which->who_size, which->who, which->when_size,
30991c7793eSjbeck 		    (char *)&(which->when));
31091c7793eSjbeck 	}
31191c7793eSjbeck }
31291c7793eSjbeck 
31391c7793eSjbeck static void
dumplist()31491c7793eSjbeck dumplist()
31591c7793eSjbeck {
31691c7793eSjbeck 	datum content, key;
31791c7793eSjbeck 	struct entry *first = NULL, *last = NULL, *new_entry, *curr;
31891c7793eSjbeck 
31991c7793eSjbeck 	for (key = dbm_firstkey(db); key.dptr != NULL; key = dbm_nextkey(db)) {
32091c7793eSjbeck 		content = dbm_fetch(db, key);
32191c7793eSjbeck 		new_entry = (struct entry *)malloc(sizeof (struct entry));
32291c7793eSjbeck 		if (new_entry == NULL)
32391c7793eSjbeck 			perror("out of memory");
32491c7793eSjbeck 		new_entry->next = NULL;
32591c7793eSjbeck 		new_entry->who = (char *)malloc(key.dsize);
32691c7793eSjbeck 		if (new_entry->who == NULL)
32791c7793eSjbeck 			perror("out of memory");
32891c7793eSjbeck 		new_entry->who_size = key.dsize;
32991c7793eSjbeck 		(void) strlcpy(new_entry->who, key.dptr, key.dsize);
33091c7793eSjbeck 		bcopy(content.dptr, (char *)&(new_entry->when),
33191c7793eSjbeck 		    sizeof (new_entry->when));
33291c7793eSjbeck 		new_entry->when_size = content.dsize;
33391c7793eSjbeck 		if (first == NULL) { /* => so is last */
33491c7793eSjbeck 			new_entry->prev = NULL;
33591c7793eSjbeck 			new_entry->next = NULL;
33691c7793eSjbeck 			first = new_entry;
33791c7793eSjbeck 			last = new_entry;
33891c7793eSjbeck 		} else {
33991c7793eSjbeck 			for (curr = first; curr != NULL &&
34091c7793eSjbeck 			    new_entry->when > curr->when; curr = curr->next)
34191c7793eSjbeck 				;
34291c7793eSjbeck 			if (curr == NULL) {
34391c7793eSjbeck 				last->next = new_entry;
34491c7793eSjbeck 				new_entry->prev = last;
34591c7793eSjbeck 				new_entry->next = NULL;
34691c7793eSjbeck 				last = new_entry;
34791c7793eSjbeck 			} else {
34891c7793eSjbeck 				new_entry->next = curr;
34991c7793eSjbeck 				new_entry->prev = curr->prev;
35091c7793eSjbeck 				if (curr->prev == NULL)
35191c7793eSjbeck 					first = new_entry;
35291c7793eSjbeck 				else
35391c7793eSjbeck 					curr->prev->next = new_entry;
35491c7793eSjbeck 				curr->prev = new_entry;
35591c7793eSjbeck 			}
35691c7793eSjbeck 		}
35791c7793eSjbeck 	}
35891c7793eSjbeck 	dump_all_content(first);
35991c7793eSjbeck 	dbm_close(db);
36091c7793eSjbeck }
36191c7793eSjbeck 
3627c478bd9Sstevel@tonic-gate /*
3637c478bd9Sstevel@tonic-gate  *  GETFROM -- read message from standard input and return sender
3647c478bd9Sstevel@tonic-gate  *
3657c478bd9Sstevel@tonic-gate  *	Parameters:
3667c478bd9Sstevel@tonic-gate  *		none.
3677c478bd9Sstevel@tonic-gate  *
3687c478bd9Sstevel@tonic-gate  *	Returns:
3697c478bd9Sstevel@tonic-gate  *		pointer to the sender address.
3707c478bd9Sstevel@tonic-gate  *
3717c478bd9Sstevel@tonic-gate  *	Side Effects:
3727c478bd9Sstevel@tonic-gate  *		Reads first line from standard input.
3737c478bd9Sstevel@tonic-gate  */
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate static char *
getfrom(shortp)3767c478bd9Sstevel@tonic-gate getfrom(shortp)
3777c478bd9Sstevel@tonic-gate char **shortp;
3787c478bd9Sstevel@tonic-gate {
3797c478bd9Sstevel@tonic-gate 	static char line[MAXLINE];
3807c478bd9Sstevel@tonic-gate 	char *p, *start, *at, *bang, *c;
3817c478bd9Sstevel@tonic-gate 	char saveat;
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	/* read the from line */
3847c478bd9Sstevel@tonic-gate 	if (fgets(line, sizeof (line), stdin) == NULL ||
385*fad16a7eSToomas Soome 	    strncmp(line, "From ", 5) != 0)
3867c478bd9Sstevel@tonic-gate 	{
3877c478bd9Sstevel@tonic-gate 		usrerr("No initial From line");
3887c478bd9Sstevel@tonic-gate 		exit(EX_PROTOCOL);
3897c478bd9Sstevel@tonic-gate 	}
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	/* find the end of the sender address and terminate it */
3927c478bd9Sstevel@tonic-gate 	start = &line[5];
3937c478bd9Sstevel@tonic-gate 	p = strchr(start, ' ');
3947c478bd9Sstevel@tonic-gate 	if (p == NULL)
3957c478bd9Sstevel@tonic-gate 	{
3967c478bd9Sstevel@tonic-gate 		usrerr("Funny From line '%s'", line);
3977c478bd9Sstevel@tonic-gate 		exit(EX_PROTOCOL);
3987c478bd9Sstevel@tonic-gate 	}
3997c478bd9Sstevel@tonic-gate 	*p = '\0';
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	/*
4027c478bd9Sstevel@tonic-gate 	 * Strip all but the rightmost UUCP host
4037c478bd9Sstevel@tonic-gate 	 * to prevent loops due to forwarding.
4047c478bd9Sstevel@tonic-gate 	 * Start searching leftward from the leftmost '@'.
4057c478bd9Sstevel@tonic-gate 	 *	a!b!c!d yields a short name of c!d
4067c478bd9Sstevel@tonic-gate 	 *	a!b!c!d@e yields a short name of c!d@e
4077c478bd9Sstevel@tonic-gate 	 *	e@a!b!c yields the same short name
4087c478bd9Sstevel@tonic-gate 	 */
4097c478bd9Sstevel@tonic-gate #ifdef VDEBUG
4107c478bd9Sstevel@tonic-gate printf("start='%s'\n", start);
4117c478bd9Sstevel@tonic-gate #endif /* VDEBUG */
4127c478bd9Sstevel@tonic-gate 	*shortp = start;			/* assume whole addr */
4137c478bd9Sstevel@tonic-gate 	if ((at = strchr(start, '@')) == NULL)	/* leftmost '@' */
4147c478bd9Sstevel@tonic-gate 		at = p;				/* if none, use end of addr */
4157c478bd9Sstevel@tonic-gate 	saveat = *at;
4167c478bd9Sstevel@tonic-gate 	*at = '\0';
4177c478bd9Sstevel@tonic-gate 	if ((bang = strrchr(start, '!')) != NULL) {	/* rightmost '!' */
4187c478bd9Sstevel@tonic-gate 		char *bang2;
4197c478bd9Sstevel@tonic-gate 		*bang = '\0';
4207c478bd9Sstevel@tonic-gate 		/* 2nd rightmost '!' */
4217c478bd9Sstevel@tonic-gate 		if ((bang2 = strrchr(start, '!')) != NULL)
4227c478bd9Sstevel@tonic-gate 			*shortp = bang2 + 1;		/* move past ! */
4237c478bd9Sstevel@tonic-gate 		*bang = '!';
4247c478bd9Sstevel@tonic-gate 	}
4257c478bd9Sstevel@tonic-gate 	*at = saveat;
4267c478bd9Sstevel@tonic-gate #ifdef VDEBUG
4277c478bd9Sstevel@tonic-gate printf("place='%s'\n", *shortp);
4287c478bd9Sstevel@tonic-gate #endif /* VDEBUG */
4297c478bd9Sstevel@tonic-gate 	for (c = at + 1; *c; c++)
4307c478bd9Sstevel@tonic-gate 		*c = (char)tolower((char)*c);
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	/* return the sender address */
4337c478bd9Sstevel@tonic-gate 	return (start);
4347c478bd9Sstevel@tonic-gate }
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate /*
4377c478bd9Sstevel@tonic-gate  *  JUNKMAIL -- read the header and tell us if this is junk/bulk mail.
4387c478bd9Sstevel@tonic-gate  *
4397c478bd9Sstevel@tonic-gate  *	Parameters:
4407c478bd9Sstevel@tonic-gate  *		from -- the Return-Path of the sender.  We assume that
4417c478bd9Sstevel@tonic-gate  *			anything from "*-REQUEST@*" is bulk mail.
4427c478bd9Sstevel@tonic-gate  *
4437c478bd9Sstevel@tonic-gate  *	Returns:
4447c478bd9Sstevel@tonic-gate  *		TRUE -- if this is junk or bulk mail (that is, if the
4457c478bd9Sstevel@tonic-gate  *			sender shouldn't receive a response).
4467c478bd9Sstevel@tonic-gate  *		FALSE -- if the sender deserves a response.
4477c478bd9Sstevel@tonic-gate  *
4487c478bd9Sstevel@tonic-gate  *	Side Effects:
4497c478bd9Sstevel@tonic-gate  *		May read the header from standard input.  When this
4507c478bd9Sstevel@tonic-gate  *		returns the position on stdin is undefined.
4517c478bd9Sstevel@tonic-gate  */
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate static bool
junkmail(from)4547c478bd9Sstevel@tonic-gate junkmail(from)
4557c478bd9Sstevel@tonic-gate 	char *from;
4567c478bd9Sstevel@tonic-gate {
4577c478bd9Sstevel@tonic-gate 	register char *p;
4587c478bd9Sstevel@tonic-gate 	char buf[MAXLINE+1];
4597c478bd9Sstevel@tonic-gate 	bool inside, onlist;
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	/* test for inhuman sender */
4627c478bd9Sstevel@tonic-gate 	p = strrchr(from, '@');
4637c478bd9Sstevel@tonic-gate 	if (p != NULL)
4647c478bd9Sstevel@tonic-gate 	{
4657c478bd9Sstevel@tonic-gate 		*p = '\0';
4667c478bd9Sstevel@tonic-gate 		if (sameword(&p[-8],  "-REQUEST") ||
4677c478bd9Sstevel@tonic-gate 		    sameword(&p[-10], "Postmaster") ||
4687c478bd9Sstevel@tonic-gate 		    sameword(&p[-13], "MAILER-DAEMON"))
4697c478bd9Sstevel@tonic-gate 		{
4707c478bd9Sstevel@tonic-gate 			*p = '@';
4717c478bd9Sstevel@tonic-gate 			return (TRUE);
4727c478bd9Sstevel@tonic-gate 		}
4737c478bd9Sstevel@tonic-gate 		*p = '@';
4747c478bd9Sstevel@tonic-gate 	}
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate #define	Delims " \n\t:,:;()<>@!"
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	/* read the header looking for "interesting" lines */
4797c478bd9Sstevel@tonic-gate 	inside = FALSE;
4807c478bd9Sstevel@tonic-gate 	onlist = FALSE;
4817c478bd9Sstevel@tonic-gate 	while (fgets(buf, MAXLINE, stdin) != NULL && buf[0] != '\n')
4827c478bd9Sstevel@tonic-gate 	{
4837c478bd9Sstevel@tonic-gate 		if (buf[0] != ' ' && buf[0] != '\t' && strchr(buf, ':') == NULL)
4847c478bd9Sstevel@tonic-gate 			return (FALSE);			/* no header found */
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 		p = strtok(buf, Delims);
4877c478bd9Sstevel@tonic-gate 		if (p == NULL)
4887c478bd9Sstevel@tonic-gate 			continue;
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 		if (sameword(p, "To") || sameword(p, "Cc"))
4917c478bd9Sstevel@tonic-gate 		{
4927c478bd9Sstevel@tonic-gate 			inside = TRUE;
4937c478bd9Sstevel@tonic-gate 			p = strtok((char *)NULL, Delims);
4947c478bd9Sstevel@tonic-gate 			if (p == NULL)
4957c478bd9Sstevel@tonic-gate 				continue;
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 		} else				/* continuation line? */
4987c478bd9Sstevel@tonic-gate 		    if (inside)
4997c478bd9Sstevel@tonic-gate 			inside =  (buf[0] == ' ' || buf[0] == '\t');
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 		if (inside) {
5027c478bd9Sstevel@tonic-gate 		    int i;
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 		    do {
5057c478bd9Sstevel@tonic-gate 			if (sameword(p, myname))
5067c478bd9Sstevel@tonic-gate 				onlist = TRUE;		/* I am on the list */
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 			for (i = 0; i < AliasCount; i++)
5097c478bd9Sstevel@tonic-gate 			    if (sameword(p, AliasList[i]))
5107c478bd9Sstevel@tonic-gate 				onlist = TRUE;		/* alias on list */
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 		    } while (p = strtok((char *)NULL, Delims));
5137c478bd9Sstevel@tonic-gate 		    continue;
5147c478bd9Sstevel@tonic-gate 		}
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 		if (sameword(p, "Precedence"))
5177c478bd9Sstevel@tonic-gate 		{
5187c478bd9Sstevel@tonic-gate 			/* find the value of this field */
5197c478bd9Sstevel@tonic-gate 			p = strtok((char *)NULL, Delims);
5207c478bd9Sstevel@tonic-gate 			if (p == NULL)
5217c478bd9Sstevel@tonic-gate 				continue;
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 			/* see if it is "junk" or "bulk" */
5247c478bd9Sstevel@tonic-gate 			p[4] = '\0';
5257c478bd9Sstevel@tonic-gate 			if (sameword(p, "junk") || sameword(p, "bulk"))
5267c478bd9Sstevel@tonic-gate 				return (TRUE);
5277c478bd9Sstevel@tonic-gate 		}
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 		if (sameword(p, "Subject"))
5307c478bd9Sstevel@tonic-gate 		{
5317c478bd9Sstevel@tonic-gate 			char *decoded_subject;
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 			Subject = newstr(buf+9);
5347c478bd9Sstevel@tonic-gate 			if (p = strrchr(Subject, '\n'))
5357c478bd9Sstevel@tonic-gate 				*p = '\0';
5367c478bd9Sstevel@tonic-gate 			EncodedSubject = newstr(Subject);
5377c478bd9Sstevel@tonic-gate 			decoded_subject = newstr(Subject);
5387c478bd9Sstevel@tonic-gate 			if (decode_rfc2047(Subject, decoded_subject, Charset))
5397c478bd9Sstevel@tonic-gate 				Subject = decoded_subject;
5407c478bd9Sstevel@tonic-gate 			else
5417c478bd9Sstevel@tonic-gate 				Charset[0] = '\0';
5427c478bd9Sstevel@tonic-gate 			if (Debug)
5437c478bd9Sstevel@tonic-gate 				printf("Subject=%s\n", Subject);
5447c478bd9Sstevel@tonic-gate 		}
5457c478bd9Sstevel@tonic-gate 	}
5467c478bd9Sstevel@tonic-gate 	if (AnswerAll)
5477c478bd9Sstevel@tonic-gate 		return (FALSE);
5487c478bd9Sstevel@tonic-gate 	else
5497c478bd9Sstevel@tonic-gate 		return (!onlist);
5507c478bd9Sstevel@tonic-gate }
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate /*
5537c478bd9Sstevel@tonic-gate  *  FILTER_OK -- see if the Return-Path is in the filter file.
5547c478bd9Sstevel@tonic-gate  *		 Note that a non-existent filter file means everything
5557c478bd9Sstevel@tonic-gate  *		 is OK, but an empty file means nothing is OK.
5567c478bd9Sstevel@tonic-gate  *
5577c478bd9Sstevel@tonic-gate  *	Parameters:
5587c478bd9Sstevel@tonic-gate  *		from -- the Return-Path of the sender.
5597c478bd9Sstevel@tonic-gate  *
5607c478bd9Sstevel@tonic-gate  *	Returns:
5617c478bd9Sstevel@tonic-gate  *		TRUE -- if this is in the filter file
5627c478bd9Sstevel@tonic-gate  *			(sender should receive a response).
5637c478bd9Sstevel@tonic-gate  *		FALSE -- if the sender does not deserve a response.
5647c478bd9Sstevel@tonic-gate  */
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate static bool
filter_ok(from,filter_file)5677c478bd9Sstevel@tonic-gate filter_ok(from, filter_file)
5687c478bd9Sstevel@tonic-gate 	char *from;
5697c478bd9Sstevel@tonic-gate 	char *filter_file;
5707c478bd9Sstevel@tonic-gate {
5717c478bd9Sstevel@tonic-gate 	char file[MAXLINE];
5727c478bd9Sstevel@tonic-gate 	char line[MAXLINE];
573d5e7c3fcSgww 	char *match_start;
5747c478bd9Sstevel@tonic-gate 	size_t line_len, from_len;
5757c478bd9Sstevel@tonic-gate 	bool result = FALSE;
576d5e7c3fcSgww 	bool negated = FALSE;
5777c478bd9Sstevel@tonic-gate 	FILE *f;
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	from_len = strlen(from);
5807c478bd9Sstevel@tonic-gate 	(void) strlcpy(file, homedir, sizeof (file));
5817c478bd9Sstevel@tonic-gate 	if (filter_file[0] != '/')
5827c478bd9Sstevel@tonic-gate 	    (void) strlcat(file, "/", sizeof (file));
5837c478bd9Sstevel@tonic-gate 	(void) strlcat(file, filter_file, sizeof (file));
5847c478bd9Sstevel@tonic-gate 	f = fopen(file, "r");
5857c478bd9Sstevel@tonic-gate 	if (f == NULL) {
5867c478bd9Sstevel@tonic-gate 		/*
5877c478bd9Sstevel@tonic-gate 		 * If the file does not exist, then there is no filter to
5887c478bd9Sstevel@tonic-gate 		 * apply, so we simply return TRUE.
5897c478bd9Sstevel@tonic-gate 		 */
5907c478bd9Sstevel@tonic-gate 		if (Debug)
5917c478bd9Sstevel@tonic-gate 			(void) printf("%s does not exist, filter ok.\n",
5927c478bd9Sstevel@tonic-gate 			    file);
5937c478bd9Sstevel@tonic-gate 		return (TRUE);
5947c478bd9Sstevel@tonic-gate 	}
5957c478bd9Sstevel@tonic-gate 	while (fgets(line, MAXLINE, f)) {
5967c478bd9Sstevel@tonic-gate 		line_len = strlen(line);
5977c478bd9Sstevel@tonic-gate 		/* zero out trailing newline */
5987c478bd9Sstevel@tonic-gate 		if (line[line_len - 1] == '\n')
5997c478bd9Sstevel@tonic-gate 			line[--line_len] = '\0';
6007c478bd9Sstevel@tonic-gate 		/* skip blank lines */
6017c478bd9Sstevel@tonic-gate 		if (line_len == 0)
6027c478bd9Sstevel@tonic-gate 			continue;
6037c478bd9Sstevel@tonic-gate 		/* skip comment lines */
6047c478bd9Sstevel@tonic-gate 		if (line[0] == '#')
6057c478bd9Sstevel@tonic-gate 			continue;
606d5e7c3fcSgww 		if (line[0] == '!') {
607d5e7c3fcSgww 			negated = TRUE;
608d5e7c3fcSgww 			match_start = &line[1];
609d5e7c3fcSgww 			line_len--;
610d5e7c3fcSgww 		} else {
611d5e7c3fcSgww 			negated = FALSE;
612d5e7c3fcSgww 			match_start = &line[0];
613d5e7c3fcSgww 		}
6147c478bd9Sstevel@tonic-gate 		if (strchr(line, '@') != NULL) {
6157c478bd9Sstevel@tonic-gate 			/* @ => full address */
616d5e7c3fcSgww 			if (strcasecmp(match_start, from) == 0) {
6177c478bd9Sstevel@tonic-gate 				result = TRUE;
6187c478bd9Sstevel@tonic-gate 				if (Debug)
6197c478bd9Sstevel@tonic-gate 					(void) printf("filter match on %s\n",
6207c478bd9Sstevel@tonic-gate 					    line);
6217c478bd9Sstevel@tonic-gate 				break;
6227c478bd9Sstevel@tonic-gate 			}
6237c478bd9Sstevel@tonic-gate 		} else {
6247c478bd9Sstevel@tonic-gate 			/* no @ => domain */
6257c478bd9Sstevel@tonic-gate 			if (from_len <= line_len)
6267c478bd9Sstevel@tonic-gate 				continue;
6277c478bd9Sstevel@tonic-gate 			/*
6287c478bd9Sstevel@tonic-gate 			 * Make sure the last part of from is the domain line
6297c478bd9Sstevel@tonic-gate 			 * and that the character immediately preceding is an
6307c478bd9Sstevel@tonic-gate 			 * '@' or a '.', otherwise we could get false positives
6317c478bd9Sstevel@tonic-gate 			 * from e.g. twinsun.com for sun.com .
6327c478bd9Sstevel@tonic-gate 			 */
633d5e7c3fcSgww 			if (strncasecmp(&from[from_len - line_len],
634d5e7c3fcSgww 			    match_start, line_len) == 0 &&
6357c478bd9Sstevel@tonic-gate 			    (from[from_len - line_len -1] == '@' ||
6367c478bd9Sstevel@tonic-gate 			    from[from_len - line_len -1] == '.')) {
6377c478bd9Sstevel@tonic-gate 				result = TRUE;
6387c478bd9Sstevel@tonic-gate 				if (Debug)
6397c478bd9Sstevel@tonic-gate 					(void) printf("filter match on %s\n",
6407c478bd9Sstevel@tonic-gate 					    line);
6417c478bd9Sstevel@tonic-gate 				break;
6427c478bd9Sstevel@tonic-gate 			}
6437c478bd9Sstevel@tonic-gate 		}
6447c478bd9Sstevel@tonic-gate 	}
6457c478bd9Sstevel@tonic-gate 	(void) fclose(f);
6467c478bd9Sstevel@tonic-gate 	if (Debug && !result)
6477c478bd9Sstevel@tonic-gate 		(void) printf("no filter match\n");
648d5e7c3fcSgww 	return (!negated && result);
6497c478bd9Sstevel@tonic-gate }
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate /*
6527c478bd9Sstevel@tonic-gate  *  KNOWS -- predicate telling if user has already been informed.
6537c478bd9Sstevel@tonic-gate  *
6547c478bd9Sstevel@tonic-gate  *	Parameters:
6557c478bd9Sstevel@tonic-gate  *		user -- the user who sent this message.
6567c478bd9Sstevel@tonic-gate  *
6577c478bd9Sstevel@tonic-gate  *	Returns:
6587c478bd9Sstevel@tonic-gate  *		TRUE if 'user' has already been informed that the
6597c478bd9Sstevel@tonic-gate  *			recipient is on vacation.
6607c478bd9Sstevel@tonic-gate  *		FALSE otherwise.
6617c478bd9Sstevel@tonic-gate  *
6627c478bd9Sstevel@tonic-gate  *	Side Effects:
6637c478bd9Sstevel@tonic-gate  *		none.
6647c478bd9Sstevel@tonic-gate  */
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate static bool
knows(user)6677c478bd9Sstevel@tonic-gate knows(user)
6687c478bd9Sstevel@tonic-gate 	char *user;
6697c478bd9Sstevel@tonic-gate {
6707c478bd9Sstevel@tonic-gate 	datum key, data;
6717c478bd9Sstevel@tonic-gate 	time_t now, then;
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	(void) time(&now);
6747c478bd9Sstevel@tonic-gate 	key.dptr = user;
6757c478bd9Sstevel@tonic-gate 	key.dsize = strlen(user) + 1;
6767c478bd9Sstevel@tonic-gate 	data = dbm_fetch(db, key);
6777c478bd9Sstevel@tonic-gate 	if (data.dptr == NULL)
6787c478bd9Sstevel@tonic-gate 		return (FALSE);
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	bcopy(data.dptr, (char *)&then, sizeof (then));
6817c478bd9Sstevel@tonic-gate 	if (then + Timeout < now)
6827c478bd9Sstevel@tonic-gate 		return (FALSE);
6837c478bd9Sstevel@tonic-gate 	if (Debug)
6847c478bd9Sstevel@tonic-gate 		printf("User %s already knows\n", user);
6857c478bd9Sstevel@tonic-gate 	return (TRUE);
6867c478bd9Sstevel@tonic-gate }
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate /*
6897c478bd9Sstevel@tonic-gate  *  SETKNOWS -- set that this user knows about the vacation.
6907c478bd9Sstevel@tonic-gate  *
6917c478bd9Sstevel@tonic-gate  *	Parameters:
6927c478bd9Sstevel@tonic-gate  *		user -- the user who should be marked.
6937c478bd9Sstevel@tonic-gate  *
6947c478bd9Sstevel@tonic-gate  *	Returns:
6957c478bd9Sstevel@tonic-gate  *		none.
6967c478bd9Sstevel@tonic-gate  *
6977c478bd9Sstevel@tonic-gate  *	Side Effects:
6987c478bd9Sstevel@tonic-gate  *		The dbm file is updated as appropriate.
6997c478bd9Sstevel@tonic-gate  */
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate static void
setknows(user)7027c478bd9Sstevel@tonic-gate setknows(user)
7037c478bd9Sstevel@tonic-gate 	char *user;
7047c478bd9Sstevel@tonic-gate {
7057c478bd9Sstevel@tonic-gate 	datum key, data;
7067c478bd9Sstevel@tonic-gate 	time_t now;
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	key.dptr = user;
7097c478bd9Sstevel@tonic-gate 	key.dsize = strlen(user) + 1;
7107c478bd9Sstevel@tonic-gate 	(void) time(&now);
7117c478bd9Sstevel@tonic-gate 	data.dptr = (char *)&now;
7127c478bd9Sstevel@tonic-gate 	data.dsize = sizeof (now);
7137c478bd9Sstevel@tonic-gate 	dbm_store(db, key, data, DBM_REPLACE);
7147c478bd9Sstevel@tonic-gate }
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate static bool
any8bitchars(line)7177c478bd9Sstevel@tonic-gate any8bitchars(line)
7187c478bd9Sstevel@tonic-gate 	char *line;
7197c478bd9Sstevel@tonic-gate {
7207c478bd9Sstevel@tonic-gate 	char *c;
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	for (c = line; *c; c++)
7237c478bd9Sstevel@tonic-gate 		if (*c & 0x80)
7247c478bd9Sstevel@tonic-gate 			return (TRUE);
7257c478bd9Sstevel@tonic-gate 	return (FALSE);
7267c478bd9Sstevel@tonic-gate }
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate /*
7297c478bd9Sstevel@tonic-gate  *  SENDMESSAGE -- send a message to a particular user.
7307c478bd9Sstevel@tonic-gate  *
7317c478bd9Sstevel@tonic-gate  *	Parameters:
7327c478bd9Sstevel@tonic-gate  *		msgf -- filename containing the message.
7337c478bd9Sstevel@tonic-gate  *		user -- user who should receive it.
7347c478bd9Sstevel@tonic-gate  *
7357c478bd9Sstevel@tonic-gate  *	Returns:
7367c478bd9Sstevel@tonic-gate  *		none.
7377c478bd9Sstevel@tonic-gate  *
7387c478bd9Sstevel@tonic-gate  *	Side Effects:
7397c478bd9Sstevel@tonic-gate  *		sends mail to 'user' using /usr/lib/sendmail.
7407c478bd9Sstevel@tonic-gate  */
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate static void
sendmessage(msgf,user,myname)7437c478bd9Sstevel@tonic-gate sendmessage(msgf, user, myname)
7447c478bd9Sstevel@tonic-gate 	char *msgf;
7457c478bd9Sstevel@tonic-gate 	char *user;
7467c478bd9Sstevel@tonic-gate 	char *myname;
7477c478bd9Sstevel@tonic-gate {
7487c478bd9Sstevel@tonic-gate 	FILE *f, *fpipe, *tmpf;
7497c478bd9Sstevel@tonic-gate 	char line[MAXLINE];
7507c478bd9Sstevel@tonic-gate 	char *p, *tmpf_name;
7517c478bd9Sstevel@tonic-gate 	int i, pipefd[2], tmpfd;
7527c478bd9Sstevel@tonic-gate 	bool seen8bitchars = FALSE;
7537c478bd9Sstevel@tonic-gate 	bool in_header = TRUE;
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	/* find the message to send */
7567c478bd9Sstevel@tonic-gate 	f = fopen(msgf, "r");
7577c478bd9Sstevel@tonic-gate 	if (f == NULL)
7587c478bd9Sstevel@tonic-gate 	{
7597c478bd9Sstevel@tonic-gate 		f = fopen("/etc/mail/vacation.def", "r");
760a4771893SToomas Soome 		if (f == NULL) {
7617c478bd9Sstevel@tonic-gate 			usrerr("No message to send");
7627c478bd9Sstevel@tonic-gate 			exit(EX_OSFILE);
763a4771893SToomas Soome 		}
7647c478bd9Sstevel@tonic-gate 	}
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	if (pipe(pipefd) < 0) {
7677c478bd9Sstevel@tonic-gate 		usrerr("pipe() failed");
7687c478bd9Sstevel@tonic-gate 		exit(EX_OSERR);
7697c478bd9Sstevel@tonic-gate 	}
7707c478bd9Sstevel@tonic-gate 	i = fork();
7717c478bd9Sstevel@tonic-gate 	if (i < 0) {
7727c478bd9Sstevel@tonic-gate 		usrerr("fork() failed");
7737c478bd9Sstevel@tonic-gate 		exit(EX_OSERR);
7747c478bd9Sstevel@tonic-gate 	}
7757c478bd9Sstevel@tonic-gate 	if (i == 0) {
7767c478bd9Sstevel@tonic-gate 		dup2(pipefd[0], 0);
7777c478bd9Sstevel@tonic-gate 		close(pipefd[0]);
7787c478bd9Sstevel@tonic-gate 		close(pipefd[1]);
7797c478bd9Sstevel@tonic-gate 		fclose(f);
7807c478bd9Sstevel@tonic-gate 		execl("/usr/lib/sendmail", "sendmail", "-eq", "-f", myname,
7817c478bd9Sstevel@tonic-gate 			"--", user, NULL);
7827c478bd9Sstevel@tonic-gate 		usrerr("can't exec /usr/lib/sendmail");
7837c478bd9Sstevel@tonic-gate 		exit(EX_OSERR);
7847c478bd9Sstevel@tonic-gate 	}
7857c478bd9Sstevel@tonic-gate 	close(pipefd[0]);
7867c478bd9Sstevel@tonic-gate 	fpipe = fdopen(pipefd[1], "w");
7877c478bd9Sstevel@tonic-gate 	if (fpipe == NULL) {
7887c478bd9Sstevel@tonic-gate 		usrerr("fdopen() failed");
7897c478bd9Sstevel@tonic-gate 		exit(EX_OSERR);
7907c478bd9Sstevel@tonic-gate 	}
7917c478bd9Sstevel@tonic-gate 	fprintf(fpipe, "To: %s\n", user);
7927c478bd9Sstevel@tonic-gate 	fputs("Auto-Submitted: auto-replied\n", fpipe);
7937c478bd9Sstevel@tonic-gate 	fputs("X-Mailer: vacation %I%\n", fpipe);
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	/*
7967c478bd9Sstevel@tonic-gate 	 * We used to write directly to the pipe.  But now we need to know
7977c478bd9Sstevel@tonic-gate 	 * what character set to use, and we need to examine the entire
7987c478bd9Sstevel@tonic-gate 	 * message to determine this.  So write to a temp file first.
7997c478bd9Sstevel@tonic-gate 	 */
8007c478bd9Sstevel@tonic-gate 	tmpf_name = strdup(_PATH_TMP);
8017c478bd9Sstevel@tonic-gate 	if (tmpf_name == NULL) {
8027c478bd9Sstevel@tonic-gate 		usrerr("newstr: cannot alloc memory");
8037c478bd9Sstevel@tonic-gate 		exit(EX_OSERR);
8047c478bd9Sstevel@tonic-gate 	}
8057c478bd9Sstevel@tonic-gate 	tmpfd = -1;
8067c478bd9Sstevel@tonic-gate 	tmpfd = mkstemp(tmpf_name);
8077c478bd9Sstevel@tonic-gate 	if (tmpfd == -1) {
8087c478bd9Sstevel@tonic-gate 		usrerr("can't open temp file %s", tmpf_name);
8097c478bd9Sstevel@tonic-gate 		exit(EX_OSERR);
8107c478bd9Sstevel@tonic-gate 	}
8117c478bd9Sstevel@tonic-gate 	tmpf = fdopen(tmpfd, "w");
8127c478bd9Sstevel@tonic-gate 	if (tmpf == NULL) {
8137c478bd9Sstevel@tonic-gate 		usrerr("can't open temp file %s", tmpf_name);
8147c478bd9Sstevel@tonic-gate 		exit(EX_OSERR);
8157c478bd9Sstevel@tonic-gate 	}
8167c478bd9Sstevel@tonic-gate 	while (fgets(line, MAXLINE, f)) {
8177c478bd9Sstevel@tonic-gate 		/*
8187c478bd9Sstevel@tonic-gate 		 * Check for a line with no ':' character.  If it's just \n,
8197c478bd9Sstevel@tonic-gate 		 * we're at the end of the headers and all is fine.  Or if
8207c478bd9Sstevel@tonic-gate 		 * it starts with white-space, then it's a continuation header.
8217c478bd9Sstevel@tonic-gate 		 * Otherwise, it's the start of the body, which means the
8227c478bd9Sstevel@tonic-gate 		 * header/body separator was skipped.  So output it.
8237c478bd9Sstevel@tonic-gate 		 */
8247c478bd9Sstevel@tonic-gate 		if (in_header && line[0] != '\0' && strchr(line, ':') == NULL) {
8257c478bd9Sstevel@tonic-gate 			if (line[0] == '\n')
8267c478bd9Sstevel@tonic-gate 				in_header = FALSE;
8277c478bd9Sstevel@tonic-gate 			else if (!isspace(line[0])) {
8287c478bd9Sstevel@tonic-gate 				in_header = FALSE;
8297c478bd9Sstevel@tonic-gate 				fputs("\n", tmpf);
8307c478bd9Sstevel@tonic-gate 			}
8317c478bd9Sstevel@tonic-gate 		}
8327c478bd9Sstevel@tonic-gate 		p = strchr(line, '$');
8337c478bd9Sstevel@tonic-gate 		if (p && strncmp(p, "$SUBJECT", 8) == 0) {
8347c478bd9Sstevel@tonic-gate 			*p = '\0';
8357c478bd9Sstevel@tonic-gate 			seen8bitchars |= any8bitchars(line);
8367c478bd9Sstevel@tonic-gate 			fputs(line, tmpf);
8377c478bd9Sstevel@tonic-gate 			if (Subject) {
8387c478bd9Sstevel@tonic-gate 				if (in_header)
8397c478bd9Sstevel@tonic-gate 					fputs(EncodedSubject, tmpf);
8407c478bd9Sstevel@tonic-gate 				else {
8417c478bd9Sstevel@tonic-gate 					seen8bitchars |= any8bitchars(Subject);
8427c478bd9Sstevel@tonic-gate 					fputs(Subject, tmpf);
8437c478bd9Sstevel@tonic-gate 				}
8447c478bd9Sstevel@tonic-gate 			}
8457c478bd9Sstevel@tonic-gate 			seen8bitchars |= any8bitchars(p+8);
8467c478bd9Sstevel@tonic-gate 			fputs(p+8, tmpf);
8477c478bd9Sstevel@tonic-gate 			continue;
8487c478bd9Sstevel@tonic-gate 		}
8497c478bd9Sstevel@tonic-gate 		seen8bitchars |= any8bitchars(line);
8507c478bd9Sstevel@tonic-gate 		fputs(line, tmpf);
8517c478bd9Sstevel@tonic-gate 	}
8527c478bd9Sstevel@tonic-gate 	fclose(f);
8537c478bd9Sstevel@tonic-gate 	fclose(tmpf);
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 	/*
8567c478bd9Sstevel@tonic-gate 	 * If we haven't seen a funky Subject with Charset, use the default.
8577c478bd9Sstevel@tonic-gate 	 * If we have and it's us-ascii, 8-bit chars in the message file will
8587c478bd9Sstevel@tonic-gate 	 * still result in iso-8859-1.
8597c478bd9Sstevel@tonic-gate 	 */
8607c478bd9Sstevel@tonic-gate 	if (Charset[0] == '\0')
8617c478bd9Sstevel@tonic-gate 		(void) strlcpy(Charset, (seen8bitchars) ? "iso-8859-1" :
8627c478bd9Sstevel@tonic-gate 		    "us-ascii", sizeof (Charset));
8637c478bd9Sstevel@tonic-gate 	else if ((strcasecmp(Charset, "us-ascii") == 0) && seen8bitchars)
8647c478bd9Sstevel@tonic-gate 		(void) strlcpy(Charset, "iso-8859-1", sizeof (Charset));
8657c478bd9Sstevel@tonic-gate 	if (Debug)
8667c478bd9Sstevel@tonic-gate 		printf("Charset is %s\n", Charset);
8677c478bd9Sstevel@tonic-gate 	fprintf(fpipe, "Content-Type: text/plain; charset=%s\n", Charset);
8687c478bd9Sstevel@tonic-gate 	fputs("Mime-Version: 1.0\n", fpipe);
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	/*
8717c478bd9Sstevel@tonic-gate 	 * Now read back in from the temp file and write to the pipe.
8727c478bd9Sstevel@tonic-gate 	 */
8737c478bd9Sstevel@tonic-gate 	tmpf = fopen(tmpf_name, "r");
8747c478bd9Sstevel@tonic-gate 	if (tmpf == NULL) {
8757c478bd9Sstevel@tonic-gate 		usrerr("can't open temp file %s", tmpf_name);
8767c478bd9Sstevel@tonic-gate 		exit(EX_OSERR);
8777c478bd9Sstevel@tonic-gate 	}
8787c478bd9Sstevel@tonic-gate 	while (fgets(line, MAXLINE, tmpf))
8797c478bd9Sstevel@tonic-gate 		fputs(line, fpipe);
8807c478bd9Sstevel@tonic-gate 	fclose(fpipe);
8817c478bd9Sstevel@tonic-gate 	fclose(tmpf);
8827c478bd9Sstevel@tonic-gate 	(void) unlink(tmpf_name);
8837c478bd9Sstevel@tonic-gate 	free(tmpf_name);
8847c478bd9Sstevel@tonic-gate }
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate /*
8877c478bd9Sstevel@tonic-gate  *  INITIALIZE -- initialize the database before leaving for vacation
8887c478bd9Sstevel@tonic-gate  *
8897c478bd9Sstevel@tonic-gate  *	Parameters:
8907c478bd9Sstevel@tonic-gate  *		none.
8917c478bd9Sstevel@tonic-gate  *
8927c478bd9Sstevel@tonic-gate  *	Returns:
8937c478bd9Sstevel@tonic-gate  *		none.
8947c478bd9Sstevel@tonic-gate  *
8957c478bd9Sstevel@tonic-gate  *	Side Effects:
8967c478bd9Sstevel@tonic-gate  *		Initializes the files .vacation.{pag,dir} in the
8977c478bd9Sstevel@tonic-gate  *		caller's home directory.
8987c478bd9Sstevel@tonic-gate  */
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate static void
initialize(db_file_base)9017c478bd9Sstevel@tonic-gate initialize(db_file_base)
9027c478bd9Sstevel@tonic-gate 	char *db_file_base;
9037c478bd9Sstevel@tonic-gate {
9047c478bd9Sstevel@tonic-gate 	char *homedir;
9057c478bd9Sstevel@tonic-gate 	char buf[MAXLINE];
9067c478bd9Sstevel@tonic-gate 	DBM *db;
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 	setgid(getgid());
9097c478bd9Sstevel@tonic-gate 	setuid(getuid());
9107c478bd9Sstevel@tonic-gate 	homedir = getenv("HOME");
9117c478bd9Sstevel@tonic-gate 	if (homedir == NULL) {
9127c478bd9Sstevel@tonic-gate 		usrerr("No home!");
9137c478bd9Sstevel@tonic-gate 		exit(EX_NOUSER);
9147c478bd9Sstevel@tonic-gate 	}
9157c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "%s%s%s", homedir,
9167c478bd9Sstevel@tonic-gate 		(db_file_base[0] == '/') ? "" : "/", db_file_base);
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 	if (!(db = dbm_open(buf, O_WRONLY|O_CREAT|O_TRUNC, 0644))) {
9197c478bd9Sstevel@tonic-gate 		usrerr("%s: %s\n", buf, strerror(errno));
9207c478bd9Sstevel@tonic-gate 		exit(EX_DATAERR);
9217c478bd9Sstevel@tonic-gate 	}
9227c478bd9Sstevel@tonic-gate 	dbm_close(db);
9237c478bd9Sstevel@tonic-gate }
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate /*
9267c478bd9Sstevel@tonic-gate  *  USRERR -- print user error
9277c478bd9Sstevel@tonic-gate  *
9287c478bd9Sstevel@tonic-gate  *	Parameters:
9297c478bd9Sstevel@tonic-gate  *		f -- format.
9307c478bd9Sstevel@tonic-gate  *
9317c478bd9Sstevel@tonic-gate  *	Returns:
9327c478bd9Sstevel@tonic-gate  *		none.
9337c478bd9Sstevel@tonic-gate  *
9347c478bd9Sstevel@tonic-gate  *	Side Effects:
9357c478bd9Sstevel@tonic-gate  *		none.
9367c478bd9Sstevel@tonic-gate  */
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate /* PRINTFLIKE1 */
9397c478bd9Sstevel@tonic-gate void
usrerr(const char * f,...)9407c478bd9Sstevel@tonic-gate usrerr(const char *f, ...)
9417c478bd9Sstevel@tonic-gate {
9427c478bd9Sstevel@tonic-gate 	va_list alist;
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 	va_start(alist, f);
9457c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "vacation: ");
9467c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, f, alist);
9477c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\n");
9487c478bd9Sstevel@tonic-gate 	va_end(alist);
9497c478bd9Sstevel@tonic-gate }
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate /*
9527c478bd9Sstevel@tonic-gate  *  NEWSTR -- copy a string
9537c478bd9Sstevel@tonic-gate  *
9547c478bd9Sstevel@tonic-gate  *	Parameters:
9557c478bd9Sstevel@tonic-gate  *		s -- the string to copy.
9567c478bd9Sstevel@tonic-gate  *
9577c478bd9Sstevel@tonic-gate  *	Returns:
9587c478bd9Sstevel@tonic-gate  *		A copy of the string.
9597c478bd9Sstevel@tonic-gate  *
9607c478bd9Sstevel@tonic-gate  *	Side Effects:
9617c478bd9Sstevel@tonic-gate  *		none.
9627c478bd9Sstevel@tonic-gate  */
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate static char *
newstr(s)9657c478bd9Sstevel@tonic-gate newstr(s)
9667c478bd9Sstevel@tonic-gate 	char *s;
9677c478bd9Sstevel@tonic-gate {
9687c478bd9Sstevel@tonic-gate 	char *p;
9697c478bd9Sstevel@tonic-gate 	size_t s_sz = strlen(s);
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	p = malloc(s_sz + 1);
9727c478bd9Sstevel@tonic-gate 	if (p == NULL)
9737c478bd9Sstevel@tonic-gate 	{
9747c478bd9Sstevel@tonic-gate 		usrerr("newstr: cannot alloc memory");
9757c478bd9Sstevel@tonic-gate 		exit(EX_OSERR);
9767c478bd9Sstevel@tonic-gate 	}
9777c478bd9Sstevel@tonic-gate 	(void) strlcpy(p, s, s_sz + 1);
9787c478bd9Sstevel@tonic-gate 	return (p);
9797c478bd9Sstevel@tonic-gate }
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate /*
9827c478bd9Sstevel@tonic-gate  *  SAMEWORD -- return TRUE if the words are the same
9837c478bd9Sstevel@tonic-gate  *
9847c478bd9Sstevel@tonic-gate  *	Ignores case.
9857c478bd9Sstevel@tonic-gate  *
9867c478bd9Sstevel@tonic-gate  *	Parameters:
9877c478bd9Sstevel@tonic-gate  *		a, b -- the words to compare.
9887c478bd9Sstevel@tonic-gate  *
9897c478bd9Sstevel@tonic-gate  *	Returns:
9907c478bd9Sstevel@tonic-gate  *		TRUE if a & b match exactly (modulo case)
9917c478bd9Sstevel@tonic-gate  *		FALSE otherwise.
9927c478bd9Sstevel@tonic-gate  *
9937c478bd9Sstevel@tonic-gate  *	Side Effects:
9947c478bd9Sstevel@tonic-gate  *		none.
9957c478bd9Sstevel@tonic-gate  */
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate static bool
sameword(a,b)9987c478bd9Sstevel@tonic-gate sameword(a, b)
9997c478bd9Sstevel@tonic-gate 	register char *a, *b;
10007c478bd9Sstevel@tonic-gate {
10017c478bd9Sstevel@tonic-gate 	char ca, cb;
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 	do
10047c478bd9Sstevel@tonic-gate 	{
10057c478bd9Sstevel@tonic-gate 		ca = *a++;
10067c478bd9Sstevel@tonic-gate 		cb = *b++;
10077c478bd9Sstevel@tonic-gate 		if (isascii(ca) && isupper(ca))
10087c478bd9Sstevel@tonic-gate 			ca = ca - 'A' + 'a';
10097c478bd9Sstevel@tonic-gate 		if (isascii(cb) && isupper(cb))
10107c478bd9Sstevel@tonic-gate 			cb = cb - 'A' + 'a';
10117c478bd9Sstevel@tonic-gate 	} while (ca != '\0' && ca == cb);
10127c478bd9Sstevel@tonic-gate 	return (ca == cb);
10137c478bd9Sstevel@tonic-gate }
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate /*
10167c478bd9Sstevel@tonic-gate  * When invoked with no arguments, we fall into an automatic installation
10177c478bd9Sstevel@tonic-gate  * mode, stepping the user through a default installation.
10187c478bd9Sstevel@tonic-gate  */
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate static void
AutoInstall()10217c478bd9Sstevel@tonic-gate AutoInstall()
10227c478bd9Sstevel@tonic-gate {
10237c478bd9Sstevel@tonic-gate 	char file[MAXLINE];
10247c478bd9Sstevel@tonic-gate 	char forward[MAXLINE];
10257c478bd9Sstevel@tonic-gate 	char cmd[MAXLINE];
10267c478bd9Sstevel@tonic-gate 	char line[MAXLINE];
10277c478bd9Sstevel@tonic-gate 	char *editor;
10287c478bd9Sstevel@tonic-gate 	FILE *f;
10297c478bd9Sstevel@tonic-gate 	struct passwd *pw;
10307c478bd9Sstevel@tonic-gate 	extern mode_t umask(mode_t cmask);
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 	umask(022);
10337c478bd9Sstevel@tonic-gate 	pw = getpwuid(getuid());
10347c478bd9Sstevel@tonic-gate 	if (pw == NULL) {
10357c478bd9Sstevel@tonic-gate 		usrerr("User ID unknown");
10367c478bd9Sstevel@tonic-gate 		exit(EX_NOUSER);
10377c478bd9Sstevel@tonic-gate 	}
10387c478bd9Sstevel@tonic-gate 	myname = strdup(pw->pw_name);
10397c478bd9Sstevel@tonic-gate 	if (myname == NULL) {
10407c478bd9Sstevel@tonic-gate 		usrerr("Out of memory");
10417c478bd9Sstevel@tonic-gate 		exit(EX_OSERR);
10427c478bd9Sstevel@tonic-gate 	}
10437c478bd9Sstevel@tonic-gate 	homedir = getenv("HOME");
10447c478bd9Sstevel@tonic-gate 	if (homedir == NULL) {
10457c478bd9Sstevel@tonic-gate 		usrerr("Home directory unknown");
10467c478bd9Sstevel@tonic-gate 		exit(EX_NOUSER);
10477c478bd9Sstevel@tonic-gate 	}
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 	printf("This program can be used to answer your mail automatically\n");
10507c478bd9Sstevel@tonic-gate 	printf("when you go away on vacation.\n");
10517c478bd9Sstevel@tonic-gate 	(void) strlcpy(file, homedir, sizeof (file));
10527c478bd9Sstevel@tonic-gate 	(void) strlcat(file, MsgFile, sizeof (file));
10537c478bd9Sstevel@tonic-gate 	do {
10547c478bd9Sstevel@tonic-gate 		f = fopen(file, "r");
10557c478bd9Sstevel@tonic-gate 		if (f) {
10567c478bd9Sstevel@tonic-gate 			printf("You have a message file in %s.\n", file);
10577c478bd9Sstevel@tonic-gate 			if (ask("Would you like to see it")) {
10587c478bd9Sstevel@tonic-gate 				(void) snprintf(cmd, sizeof (cmd),
10597c478bd9Sstevel@tonic-gate 				    "/usr/bin/more %s", file);
10607c478bd9Sstevel@tonic-gate 				system(cmd);
10617c478bd9Sstevel@tonic-gate 			}
10627c478bd9Sstevel@tonic-gate 			if (ask("Would you like to edit it"))
10637c478bd9Sstevel@tonic-gate 				f = NULL;
10647c478bd9Sstevel@tonic-gate 		} else {
10657c478bd9Sstevel@tonic-gate 			printf("You need to create a message file"
106691c7793eSjbeck 			    " in %s first.\n", file);
10677c478bd9Sstevel@tonic-gate 			f = fopen(file, "w");
10687c478bd9Sstevel@tonic-gate 			if (f == NULL) {
10697c478bd9Sstevel@tonic-gate 				usrerr("Cannot open %s", file);
10707c478bd9Sstevel@tonic-gate 				exit(EX_CANTCREAT);
10717c478bd9Sstevel@tonic-gate 			}
10727c478bd9Sstevel@tonic-gate 			fprintf(f, "Subject: away from my mail\n");
10737c478bd9Sstevel@tonic-gate 			fprintf(f, "\nI will not be reading my mail"
107491c7793eSjbeck 			    " for a while.\n");
10757c478bd9Sstevel@tonic-gate 			fprintf(f, "Your mail regarding \"$SUBJECT\" will"
107691c7793eSjbeck 			    " be read when I return.\n");
10777c478bd9Sstevel@tonic-gate 			fclose(f);
10787c478bd9Sstevel@tonic-gate 			f = NULL;
10797c478bd9Sstevel@tonic-gate 		}
10807c478bd9Sstevel@tonic-gate 		if (f == NULL) {
10817c478bd9Sstevel@tonic-gate 			editor = getenv("VISUAL");
10827c478bd9Sstevel@tonic-gate 			if (editor == NULL)
10837c478bd9Sstevel@tonic-gate 				editor = getenv("EDITOR");
10847c478bd9Sstevel@tonic-gate 			if (editor == NULL)
10857c478bd9Sstevel@tonic-gate 				editor = "/usr/bin/vi";
10867c478bd9Sstevel@tonic-gate 			(void) snprintf(cmd, sizeof (cmd), "%s %s", editor,
10877c478bd9Sstevel@tonic-gate 			    file);
10887c478bd9Sstevel@tonic-gate 			printf("Please use your editor (%s)"
108991c7793eSjbeck 			    " to edit this file.\n", editor);
10907c478bd9Sstevel@tonic-gate 			system(cmd);
10917c478bd9Sstevel@tonic-gate 		}
10927c478bd9Sstevel@tonic-gate 	} while (f == NULL);
10937c478bd9Sstevel@tonic-gate 	fclose(f);
10947c478bd9Sstevel@tonic-gate 	(void) strlcpy(forward, homedir, sizeof (forward));
10957c478bd9Sstevel@tonic-gate 	(void) strlcat(forward, "/.forward", sizeof (forward));
10967c478bd9Sstevel@tonic-gate 	f = fopen(forward, "r");
10977c478bd9Sstevel@tonic-gate 	if (f) {
10987c478bd9Sstevel@tonic-gate 		printf("You have a .forward file"
109991c7793eSjbeck 		    " in your home directory containing:\n");
11007c478bd9Sstevel@tonic-gate 		while (fgets(line, MAXLINE, f))
11017c478bd9Sstevel@tonic-gate 			printf("    %s", line);
11027c478bd9Sstevel@tonic-gate 		fclose(f);
11037c478bd9Sstevel@tonic-gate 		if (!ask("Would you like to remove it and"
110491c7793eSjbeck 		    " disable the vacation feature"))
11057c478bd9Sstevel@tonic-gate 			exit(EX_OK);
11067c478bd9Sstevel@tonic-gate 		if (unlink(forward))
11077c478bd9Sstevel@tonic-gate 			perror("Error removing .forward file:");
11087c478bd9Sstevel@tonic-gate 		else
11097c478bd9Sstevel@tonic-gate 			printf("Back to normal reception of mail.\n");
11107c478bd9Sstevel@tonic-gate 		exit(EX_OK);
11117c478bd9Sstevel@tonic-gate 	}
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 	printf("To enable the vacation feature"
111491c7793eSjbeck 	    " a \".forward\" file is created.\n");
11157c478bd9Sstevel@tonic-gate 	if (!ask("Would you like to enable the vacation feature")) {
11167c478bd9Sstevel@tonic-gate 		printf("OK, vacation feature NOT enabled.\n");
11177c478bd9Sstevel@tonic-gate 		exit(EX_OK);
11187c478bd9Sstevel@tonic-gate 	}
11197c478bd9Sstevel@tonic-gate 	f = fopen(forward, "w");
11207c478bd9Sstevel@tonic-gate 	if (f == NULL) {
11217c478bd9Sstevel@tonic-gate 		perror("Error opening .forward file");
11227c478bd9Sstevel@tonic-gate 		exit(EX_CANTCREAT);
11237c478bd9Sstevel@tonic-gate 	}
11247c478bd9Sstevel@tonic-gate 	fprintf(f, "\\%s, \"|/usr/bin/vacation %s\"\n", myname, myname);
11257c478bd9Sstevel@tonic-gate 	fclose(f);
11267c478bd9Sstevel@tonic-gate 	printf("Vacation feature ENABLED."
112791c7793eSjbeck 	    " Please remember to turn it off when\n");
11287c478bd9Sstevel@tonic-gate 	printf("you get back from vacation. Bon voyage.\n");
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 	initialize(DbFileBase);
11317c478bd9Sstevel@tonic-gate 	exit(EX_OK);
11327c478bd9Sstevel@tonic-gate }
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate /*
11367c478bd9Sstevel@tonic-gate  * Ask the user a question until we get a reasonable answer
11377c478bd9Sstevel@tonic-gate  */
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate static bool
ask(prompt)11407c478bd9Sstevel@tonic-gate ask(prompt)
11417c478bd9Sstevel@tonic-gate 	char *prompt;
11427c478bd9Sstevel@tonic-gate {
11437c478bd9Sstevel@tonic-gate 	char line[MAXLINE];
11447c478bd9Sstevel@tonic-gate 	char *res;
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 	for (;;) {
11477c478bd9Sstevel@tonic-gate 		printf("%s? ", prompt);
11487c478bd9Sstevel@tonic-gate 		fflush(stdout);
11497c478bd9Sstevel@tonic-gate 		res = fgets(line, sizeof (line), stdin);
11507c478bd9Sstevel@tonic-gate 		if (res == NULL)
11517c478bd9Sstevel@tonic-gate 			return (FALSE);
11527c478bd9Sstevel@tonic-gate 		if (res[0] == 'y' || res[0] == 'Y')
11537c478bd9Sstevel@tonic-gate 			return (TRUE);
11547c478bd9Sstevel@tonic-gate 		if (res[0] == 'n' || res[0] == 'N')
11557c478bd9Sstevel@tonic-gate 			return (FALSE);
11567c478bd9Sstevel@tonic-gate 		printf("Please reply \"yes\" or \"no\" (\'y\' or \'n\')\n");
11577c478bd9Sstevel@tonic-gate 	}
11587c478bd9Sstevel@tonic-gate }
1159