Commit | Line | Data |
---|---|---|
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 | 8 | SCCSID(@(#)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 | 45 | time_t Timeout = ONEWEEK; /* timeout between notices per user */ |
613a94da | 46 | |
d34d58b1 EA |
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; | |
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 | ||
137 | char * | |
138 | getfrom() | |
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 |
178 | bool |
179 | knows(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 | ||
206 | setknows(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 | 233 | sendmessage(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 | ||
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!"); | |
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 | ||
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 | \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 | ||
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 | } | |
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 | ||
343 | char * | |
344 | newstr(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 | } |