arrange for a useful error message if the mailer fork fails
[unix-history] / usr / src / usr.bin / vacation / vacation.c
CommitLineData
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 7static 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
32typedef 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 42time_t Timeout = ONEWEEK; /* timeout between notices per user */
613a94da 43
d34d58b1
EA
44struct dbrec
45{
46 long sentdate;
47};
48
8185c987
EA
49typedef struct
50{
51 char *dptr;
52 int dsize;
53} DATUM;
54
55extern DATUM fetch();
56
d34d58b1
EA
57main(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
138char *
139getfrom()
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
180bool
181knows(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
208setknows(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 235sendmessage(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
268initialize()
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
302usrerr(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
324syserr(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
346char *
347newstr(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}