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