BSD 4_2 release
[unix-history] / usr / src / usr.lib / sendmail / aux / vacation.c
CommitLineData
d34d58b1
EA
1# include <pwd.h>
2# include <stdio.h>
3# include <sysexits.h>
613a94da 4# include <ctype.h>
d34d58b1
EA
5# include "useful.h"
6# include "userdbm.h"
7
0f4556f1 8SCCSID(@(#)vacation.c 4.1 7/25/83);
d34d58b1
EA
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**
1f5b97ad
EA
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**
d34d58b1 24** Positional Parameters:
1f5b97ad 25** the user to collect the vacation message from.
d34d58b1
EA
26**
27** Flag Parameters:
28** -I initialize the database.
1f5b97ad
EA
29** -tT set the timeout to T. messages arriving more
30** often than T will be ignored to avoid loops.
d34d58b1
EA
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
613a94da
EA
43# define ONEWEEK (60L*60L*24L*7L)
44
1a9a5fb7 45time_t Timeout = ONEWEEK; /* timeout between notices per user */
613a94da 46
d34d58b1
EA
47struct dbrec
48{
49 long sentdate;
50};
51
52main(argc, argv)
53 char **argv;
54{
55 char *from;
56 register char *p;
57 struct passwd *pw;
1f5b97ad
EA
58 char *homedir;
59 char *myname;
d34d58b1
EA
60 char buf[MAXLINE];
61 extern struct passwd *getpwnam();
62 extern char *newstr();
63 extern char *getfrom();
64 extern bool knows();
1a9a5fb7 65 extern time_t convtime();
d34d58b1
EA
66
67 /* process arguments */
68 while (--argc > 0 && (p = *++argv) != NULL && *p == '-')
69 {
70 switch (*++p)
71 {
72 case 'I': /* initialize */
1f5b97ad 73 initialize();
d34d58b1
EA
74 exit(EX_OK);
75
613a94da
EA
76 case 't': /* set timeout */
77 Timeout = convtime(++p);
78 break;
79
d34d58b1
EA
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
1f5b97ad
EA
93 myname = p;
94
d34d58b1 95 /* find user's home directory */
1f5b97ad 96 pw = getpwnam(myname);
d34d58b1
EA
97 if (pw == NULL)
98 {
1f5b97ad 99 usrerr("Unknown user %s", myname);
d34d58b1
EA
100 exit(EX_NOUSER);
101 }
102 homedir = newstr(pw->pw_dir);
f9566d23
EA
103 (void) strcpy(buf, homedir);
104 (void) strcat(buf, "/.vacation");
d34d58b1
EA
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 */
1a9a5fb7 114 setknows(from);
d34d58b1
EA
115
116 /* send the message back */
1a9a5fb7
EA
117 (void) strcpy(buf, homedir);
118 (void) strcat(buf, "/.vacation.msg");
1f5b97ad 119 sendmessage(buf, from, myname);
d34d58b1
EA
120 /* never returns */
121 }
c71905a3 122 exit (EX_OK);
d34d58b1
EA
123}
124\f/*
125** GETFROM -- read message from standard input and return sender
126**
127** Parameters:
128** none.
129**
130** Returns:
131** pointer to the sender address.
132**
133** Side Effects:
134** Reads first line from standard input.
135*/
136
137char *
138getfrom()
139{
140 static char line[MAXLINE];
141 register char *p;
142
143 /* read the from line */
144 if (fgets(line, sizeof line, stdin) == NULL ||
145 strncmp(line, "From ", 5) != NULL)
146 {
147 usrerr("No initial From line");
148 exit(EX_USAGE);
149 }
150
151 /* find the end of the sender address and terminate it */
152 p = index(&line[5], ' ');
153 if (p == NULL)
154 {
155 usrerr("Funny From line '%s'", line);
156 exit(EX_USAGE);
157 }
158 *p = '\0';
159
160 /* return the sender address */
161 return (&line[5]);
162}
163\f/*
164** KNOWS -- predicate telling if user has already been informed.
165**
166** Parameters:
167** user -- the user who sent this message.
168**
169** Returns:
170** TRUE if 'user' has already been informed that the
171** recipient is on vacation.
172** FALSE otherwise.
173**
174** Side Effects:
175** none.
176*/
177
d34d58b1
EA
178bool
179knows(user)
180 char *user;
181{
182 DATUM k, d;
183 long now;
184
185 time(&now);
186 k.dptr = user;
187 k.dsize = strlen(user) + 1;
188 d = fetch(k);
613a94da 189 if (d.dptr == NULL || ((struct dbrec *) d.dptr)->sentdate + Timeout < now)
d34d58b1
EA
190 return (FALSE);
191 return (TRUE);
192}
193\f/*
194** SETKNOWS -- set that this user knows about the vacation.
195**
196** Parameters:
197** user -- the user who should be marked.
198**
199** Returns:
200** none.
201**
202** Side Effects:
203** The dbm file is updated as appropriate.
204*/
205
206setknows(user)
207 char *user;
208{
d34d58b1
EA
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\f/*
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
1f5b97ad 233sendmessage(msgf, user, myname)
d34d58b1
EA
234 char *msgf;
235 char *user;
1f5b97ad 236 char *myname;
d34d58b1
EA
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
85bfb58b 249 execl("/usr/lib/sendmail", "sendmail", "-f", myname, user, NULL);
d34d58b1
EA
250 syserr("Cannot exec /usr/lib/sendmail");
251}
252\f/*
1f5b97ad
EA
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
266initialize()
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!");
f9566d23
EA
276 (void) strcpy(buf, homedir);
277 (void) strcat(buf, "/.vacation.dir");
1f5b97ad
EA
278 if (close(creat(buf, 0644)) < 0)
279 syserr("Cannot create %s", buf);
f9566d23
EA
280 (void) strcpy(buf, homedir);
281 (void) strcat(buf, "/.vacation.pag");
1f5b97ad
EA
282 if (close(creat(buf, 0644)) < 0)
283 syserr("Cannot create %s", buf);
284}
285\f/*
d34d58b1
EA
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
299usrerr(f, p)
300 char *f;
301 char *p;
302{
303 fprintf(stderr, "vacation: ");
304 _doprnt(f, &p, stderr);
305 fprintf(stderr, "\n");
306}
307\f/*
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
321syserr(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}
1a9a5fb7
EA
330\f/*
331** NEWSTR -- copy a string
332**
333** Parameters:
334** s -- the string to copy.
335**
336** Returns:
337** A copy of the string.
338**
339** Side Effects:
340** none.
341*/
342
343char *
344newstr(s)
345 char *s;
346{
347 char *p;
348
349 p = malloc(strlen(s) + 1);
350 if (p == NULL)
351 {
352 syserr("newstr: cannot alloc memory");
353 exit(EX_OSERR);
354 }
355 strcpy(p, s);
356 return (p);
357}