fix time initialization; move bhinit() from bio.c to main.c
[unix-history] / usr / src / usr.bin / vacation / 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
1f5b97ad 8SCCSID(@(#)vacation.c 3.6 %G%);
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
45long Timeout = ONEWEEK; /* timeout between notices per user */
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();
613a94da 65 extern long 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);
103 strcpy(buf, homedir);
104 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 strcat(buf, ".msg");
1f5b97ad 118 sendmessage(buf, from, myname);
d34d58b1
EA
119 /* never returns */
120 }
c71905a3 121 exit (EX_OK);
d34d58b1
EA
122}
123\f/*
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
136char *
137getfrom()
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\f/*
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
d34d58b1
EA
177bool
178knows(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);
613a94da 188 if (d.dptr == NULL || ((struct dbrec *) d.dptr)->sentdate + Timeout < now)
d34d58b1
EA
189 return (FALSE);
190 return (TRUE);
191}
192\f/*
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
205setknows(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\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
1f5b97ad 249 execl("/usr/lib/sendmail", "sendmail", "-f", myname, "-n", 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!");
276 strcpy(buf, homedir);
277 strcat(buf, "/.vacation.dir");
278 if (close(creat(buf, 0644)) < 0)
279 syserr("Cannot create %s", buf);
280 strcpy(buf, homedir);
281 strcat(buf, "/.vacation.pag");
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}