xref: /original-bsd/usr.bin/vacation/vacation.c (revision c0e889e7)
1 # include <pwd.h>
2 # include <stdio.h>
3 # include <sysexits.h>
4 # include <ctype.h>
5 # include "useful.h"
6 # include "userdbm.h"
7 
8 SCCSID(@(#)vacation.c	3.7		05/31/82);
9 
10 /*
11 **  VACATION -- return a message to the sender when on vacation.
12 **
13 **	This program could be invoked as a message receiver
14 **	when someone is on vacation.  It returns a message
15 **	specified by the user to whoever sent the mail, taking
16 **	care not to return a message too often to prevent
17 **	"I am on vacation" loops.
18 **
19 **	For best operation, this program should run setuid to
20 **	root or uucp or someone else that sendmail will believe
21 **	a -f flag from.  Otherwise, the user must be careful
22 **	to include a header on his .vacation.msg file.
23 **
24 **	Positional Parameters:
25 **		the user to collect the vacation message from.
26 **
27 **	Flag Parameters:
28 **		-I	initialize the database.
29 **		-tT	set the timeout to T.  messages arriving more
30 **			often than T will be ignored to avoid loops.
31 **
32 **	Side Effects:
33 **		A message is sent back to the sender.
34 **
35 **	Author:
36 **		Eric Allman
37 **		UCB/INGRES
38 */
39 
40 # define MAXLINE	256	/* max size of a line */
41 # define MAXNAME	128	/* max size of one name */
42 
43 # define ONEWEEK	(60L*60L*24L*7L)
44 
45 long	Timeout = ONEWEEK;	/* timeout between notices per user */
46 
47 struct dbrec
48 {
49 	long	sentdate;
50 };
51 
52 main(argc, argv)
53 	char **argv;
54 {
55 	char *from;
56 	register char *p;
57 	struct passwd *pw;
58 	char *homedir;
59 	char *myname;
60 	char buf[MAXLINE];
61 	extern struct passwd *getpwnam();
62 	extern char *newstr();
63 	extern char *getfrom();
64 	extern bool knows();
65 	extern long convtime();
66 
67 	/* process arguments */
68 	while (--argc > 0 && (p = *++argv) != NULL && *p == '-')
69 	{
70 		switch (*++p)
71 		{
72 		  case 'I':	/* initialize */
73 			initialize();
74 			exit(EX_OK);
75 
76 		  case 't':	/* set timeout */
77 			Timeout = convtime(++p);
78 			break;
79 
80 		  default:
81 			usrerr("Unknown flag -%s", p);
82 			exit(EX_USAGE);
83 		}
84 	}
85 
86 	/* verify recipient argument */
87 	if (argc != 1)
88 	{
89 		usrerr("Usage: vacation username (or) vacation -I");
90 		exit(EX_USAGE);
91 	}
92 
93 	myname = p;
94 
95 	/* find user's home directory */
96 	pw = getpwnam(myname);
97 	if (pw == NULL)
98 	{
99 		usrerr("Unknown user %s", myname);
100 		exit(EX_NOUSER);
101 	}
102 	homedir = newstr(pw->pw_dir);
103 	(void) strcpy(buf, homedir);
104 	(void) strcat(buf, "/.vacation");
105 	dbminit(buf);
106 
107 	/* read message from standard input (just from line) */
108 	from = getfrom();
109 
110 	/* check if this person is already informed */
111 	if (!knows(from))
112 	{
113 		/* mark this person as knowing */
114 		setknows(from, buf);
115 
116 		/* send the message back */
117 		(void) strcat(buf, ".msg");
118 		sendmessage(buf, from, myname);
119 		/* never returns */
120 	}
121 	exit (EX_OK);
122 }
123 /*
124 **  GETFROM -- read message from standard input and return sender
125 **
126 **	Parameters:
127 **		none.
128 **
129 **	Returns:
130 **		pointer to the sender address.
131 **
132 **	Side Effects:
133 **		Reads first line from standard input.
134 */
135 
136 char *
137 getfrom()
138 {
139 	static char line[MAXLINE];
140 	register char *p;
141 
142 	/* read the from line */
143 	if (fgets(line, sizeof line, stdin) == NULL ||
144 	    strncmp(line, "From ", 5) != NULL)
145 	{
146 		usrerr("No initial From line");
147 		exit(EX_USAGE);
148 	}
149 
150 	/* find the end of the sender address and terminate it */
151 	p = index(&line[5], ' ');
152 	if (p == NULL)
153 	{
154 		usrerr("Funny From line '%s'", line);
155 		exit(EX_USAGE);
156 	}
157 	*p = '\0';
158 
159 	/* return the sender address */
160 	return (&line[5]);
161 }
162 /*
163 **  KNOWS -- predicate telling if user has already been informed.
164 **
165 **	Parameters:
166 **		user -- the user who sent this message.
167 **
168 **	Returns:
169 **		TRUE if 'user' has already been informed that the
170 **			recipient is on vacation.
171 **		FALSE otherwise.
172 **
173 **	Side Effects:
174 **		none.
175 */
176 
177 bool
178 knows(user)
179 	char *user;
180 {
181 	DATUM k, d;
182 	long now;
183 
184 	time(&now);
185 	k.dptr = user;
186 	k.dsize = strlen(user) + 1;
187 	d = fetch(k);
188 	if (d.dptr == NULL || ((struct dbrec *) d.dptr)->sentdate + Timeout < now)
189 		return (FALSE);
190 	return (TRUE);
191 }
192 /*
193 **  SETKNOWS -- set that this user knows about the vacation.
194 **
195 **	Parameters:
196 **		user -- the user who should be marked.
197 **
198 **	Returns:
199 **		none.
200 **
201 **	Side Effects:
202 **		The dbm file is updated as appropriate.
203 */
204 
205 setknows(user)
206 	char *user;
207 {
208 	register int i;
209 	DATUM k, d;
210 	struct dbrec xrec;
211 
212 	k.dptr = user;
213 	k.dsize = strlen(user) + 1;
214 	time(&xrec.sentdate);
215 	d.dptr = (char *) &xrec;
216 	d.dsize = sizeof xrec;
217 	store(k, d);
218 }
219 /*
220 **  SENDMESSAGE -- send a message to a particular user.
221 **
222 **	Parameters:
223 **		msgf -- filename containing the message.
224 **		user -- user who should receive it.
225 **
226 **	Returns:
227 **		none.
228 **
229 **	Side Effects:
230 **		sends mail to 'user' using /usr/lib/sendmail.
231 */
232 
233 sendmessage(msgf, user, myname)
234 	char *msgf;
235 	char *user;
236 	char *myname;
237 {
238 	FILE *f;
239 
240 	/* find the message to send */
241 	f = freopen(msgf, "r", stdin);
242 	if (f == NULL)
243 	{
244 		f = freopen("/usr/lib/vacation.def", "r", stdin);
245 		if (f == NULL)
246 			syserr("No message to send");
247 	}
248 
249 	execl("/usr/lib/sendmail", "sendmail", "-f", myname, "-n", user, NULL);
250 	syserr("Cannot exec /usr/lib/sendmail");
251 }
252 /*
253 **  INITIALIZE -- initialize the database before leaving for vacation
254 **
255 **	Parameters:
256 **		none.
257 **
258 **	Returns:
259 **		none.
260 **
261 **	Side Effects:
262 **		Initializes the files .vacation.{pag,dir} in the
263 **		caller's home directory.
264 */
265 
266 initialize()
267 {
268 	char *homedir;
269 	char buf[MAXLINE];
270 
271 	setgid(getgid());
272 	setuid(getuid());
273 	homedir = getenv("HOME");
274 	if (homedir == NULL)
275 		syserr("No home!");
276 	(void) strcpy(buf, homedir);
277 	(void) strcat(buf, "/.vacation.dir");
278 	if (close(creat(buf, 0644)) < 0)
279 		syserr("Cannot create %s", buf);
280 	(void) strcpy(buf, homedir);
281 	(void) strcat(buf, "/.vacation.pag");
282 	if (close(creat(buf, 0644)) < 0)
283 		syserr("Cannot create %s", buf);
284 }
285 /*
286 **  USRERR -- print user error
287 **
288 **	Parameters:
289 **		f -- format.
290 **		p -- first parameter.
291 **
292 **	Returns:
293 **		none.
294 **
295 **	Side Effects:
296 **		none.
297 */
298 
299 usrerr(f, p)
300 	char *f;
301 	char *p;
302 {
303 	fprintf(stderr, "vacation: ");
304 	_doprnt(f, &p, stderr);
305 	fprintf(stderr, "\n");
306 }
307 /*
308 **  SYSERR -- print system error
309 **
310 **	Parameters:
311 **		f -- format.
312 **		p -- first parameter.
313 **
314 **	Returns:
315 **		none.
316 **
317 **	Side Effects:
318 **		none.
319 */
320 
321 syserr(f, p)
322 	char *f;
323 	char *p;
324 {
325 	fprintf(stderr, "vacation: ");
326 	_doprnt(f, &p, stderr);
327 	fprintf(stderr, "\n");
328 	exit(EX_USAGE);
329 }
330