]> diplodocus.org Git - nmh/blob - uip/msgchk.c
Fix stupid accidental dependence on a bash quirk in previous
[nmh] / uip / msgchk.c
1
2 /*
3 * msgchk.c -- check for mail
4 *
5 * $Id$
6 *
7 * This code is Copyright (c) 2002, by the authors of nmh. See the
8 * COPYRIGHT file in the root directory of the nmh distribution for
9 * complete copyright information.
10 */
11
12 #include <h/mh.h>
13 #include <h/mts.h>
14 #include <h/tws.h>
15 #include <pwd.h>
16
17 #ifdef POP
18 # include <h/popsbr.h>
19 #endif
20
21 #ifdef HESIOD
22 # include <hesiod.h>
23 #endif
24
25 #ifndef POP
26 # define POPminc(a) (a)
27 #else
28 # define POPminc(a) 0
29 #endif
30
31 #ifndef RPOP
32 # define RPOPminc(a) (a)
33 #else
34 # define RPOPminc(a) 0
35 #endif
36
37 #ifndef APOP
38 # define APOPminc(a) (a)
39 #else
40 # define APOPminc(a) 0
41 #endif
42
43 #ifndef KPOP
44 # define KPOPminc(a) (a)
45 #else
46 # define KPOPminc(a) 0
47 #endif
48
49 #ifndef CYRUS_SASL
50 # define SASLminc(a) (a)
51 #else
52 # define SASLminc(a) 0
53 #endif
54
55 static struct swit switches[] = {
56 #define DATESW 0
57 { "date", 0 },
58 #define NDATESW 1
59 { "nodate", 0 },
60 #define NOTESW 2
61 { "notify type", 0 },
62 #define NNOTESW 3
63 { "nonotify type", 0 },
64 #define HOSTSW 4
65 { "host hostname", POPminc (-4) },
66 #define USERSW 5
67 { "user username", POPminc (-4) },
68 #define APOPSW 6
69 { "apop", APOPminc (-4) },
70 #define NAPOPSW 7
71 { "noapop", APOPminc (-6) },
72 #define RPOPSW 8
73 { "rpop", RPOPminc (-4) },
74 #define NRPOPSW 9
75 { "norpop", RPOPminc (-6) },
76 #define VERSIONSW 10
77 { "version", 0 },
78 #define HELPSW 11
79 { "help", 0 },
80 #define SNOOPSW 12
81 { "snoop", -5 },
82 #define KPOPSW 13
83 { "kpop", KPOPminc (-4) },
84 #define SASLSW 14
85 { "sasl", SASLminc(-4) },
86 #define SASLMECHSW 15
87 { "saslmech", SASLminc(-5) },
88 #define PROXYSW 16
89 { "proxy command", POPminc(-5) },
90 { NULL, 0 }
91 };
92
93 /*
94 * Maximum numbers of users we can check (plus
95 * one for the NULL vector at the end).
96 */
97 #define MAXVEC 51
98
99 #define NT_NONE 0x0
100 #define NT_MAIL 0x1
101 #define NT_NMAI 0x2
102 #define NT_ALL (NT_MAIL | NT_NMAI)
103
104 #define NONEOK 0x0
105 #define UUCPOLD 0x1
106 #define UUCPNEW 0x2
107 #define UUCPOK (UUCPOLD | UUCPNEW)
108 #define MMDFOLD 0x4
109 #define MMDFNEW 0x8
110 #define MMDFOK (MMDFOLD | MMDFNEW)
111
112
113 /*
114 * static prototypes
115 */
116 static int donote (char *, int);
117 static int checkmail (char *, char *, int, int, int);
118
119 #ifdef POP
120 static int remotemail (char *, char *, char *, int, int, int, int, int, int, char *);
121 #endif
122
123
124 int
125 main (int argc, char **argv)
126 {
127 int datesw = 1, notifysw = NT_ALL;
128 int rpop, status = 0;
129 int kpop = 0, sasl = 0;
130 int snoop = 0, vecp = 0;
131 uid_t uid;
132 char *cp, *host = NULL, *user, *proxy = NULL;
133 char buf[BUFSIZ], *saslmech = NULL;
134 char **argp, **arguments, *vec[MAXVEC];
135 struct passwd *pw;
136
137 #ifdef HESIOD
138 struct hes_postoffice *po;
139 char *tmphost;
140 #endif
141
142 #ifdef LOCALE
143 setlocale(LC_ALL, "");
144 #endif
145 invo_name = r1bindex (argv[0], '/');
146
147 /* read user profile/context */
148 context_read();
149
150 mts_init (invo_name);
151 uid = getuid ();
152 user = getusername();
153
154 arguments = getarguments (invo_name, argc, argv, 1);
155 argp = arguments;
156
157 #ifdef POP
158 if ((cp = getenv ("MHPOPDEBUG")) && *cp)
159 snoop++;
160 #endif
161
162 rpop = 0;
163
164 while ((cp = *argp++)) {
165 if (*cp == '-') {
166 switch (smatch (++cp, switches)) {
167 case AMBIGSW:
168 ambigsw (cp, switches);
169 done (1);
170 case UNKWNSW:
171 adios (NULL, "-%s unknown", cp);
172
173 case HELPSW:
174 snprintf (buf, sizeof(buf), "%s [switches] [users ...]",
175 invo_name);
176 print_help (buf, switches, 1);
177 done (1);
178 case VERSIONSW:
179 print_version(invo_name);
180 done (1);
181
182 case DATESW:
183 datesw++;
184 continue;
185 case NDATESW:
186 datesw = 0;
187 continue;
188
189 case NOTESW:
190 if (!(cp = *argp++) || *cp == '-')
191 adios (NULL, "missing argument to %s", argp[-2]);
192 notifysw |= donote (cp, 1);
193 continue;
194 case NNOTESW:
195 if (!(cp = *argp++) || *cp == '-')
196 adios (NULL, "missing argument to %s", argp[-2]);
197 notifysw &= ~donote (cp, 0);
198 continue;
199
200 case HOSTSW:
201 if (!(host = *argp++) || *host == '-')
202 adios (NULL, "missing argument to %s", argp[-2]);
203 continue;
204 case USERSW:
205 if (!(cp = *argp++) || *cp == '-')
206 adios (NULL, "missing argument to %s", argp[-2]);
207 if (vecp >= MAXVEC-1)
208 adios (NULL, "you can only check %d users at a time", MAXVEC-1);
209 else
210 vec[vecp++] = cp;
211 continue;
212
213 case APOPSW:
214 rpop = -1;
215 continue;
216 case NAPOPSW:
217 rpop = 0;
218 continue;
219
220 case RPOPSW:
221 rpop = 1;
222 continue;
223 case NRPOPSW:
224 rpop = 0;
225 continue;
226
227 case KPOPSW:
228 kpop = 1;
229 continue;
230
231 case SNOOPSW:
232 snoop++;
233 continue;
234
235 case SASLSW:
236 sasl++;
237 continue;
238
239 case SASLMECHSW:
240 if (!(saslmech = *argp++) || *saslmech == '-')
241 adios (NULL, "missing argument to %s", argp[-2]);
242 continue;
243
244 case PROXYSW:
245 if (!(proxy = *argp++) || *proxy == '-')
246 adios (NULL, "missing argument to %s", argp[-2]);
247 continue;
248 }
249 }
250 if (vecp >= MAXVEC-1)
251 adios (NULL, "you can only check %d users at a time", MAXVEC-1);
252 else
253 vec[vecp++] = cp;
254 }
255
256 #ifdef POP
257 /*
258 * If -host is not specified by user
259 */
260 if (!host || !*host) {
261 # ifdef HESIOD
262 /*
263 * Scheme is:
264 * use MAILHOST environment variable if present,
265 * else try Hesiod.
266 * If that fails, use the default (if any)
267 * provided by mts.conf in mts_init()
268 */
269 if ((tmphost = getenv("MAILHOST")) != NULL)
270 pophost = tmphost;
271 else if ((po = hes_getmailhost(vecp ? vec[0] : user)) != NULL &&
272 strcmp(po->po_type, "POP") == 0)
273 pophost = po->po_host;
274 # endif /* HESIOD */
275 /*
276 * If "pophost" is specified in mts.conf,
277 * use it as default value.
278 */
279 if (pophost && *pophost)
280 host = pophost;
281 }
282 if (!host || !*host)
283 host = NULL;
284 if (!host || rpop <= 0)
285 setuid (uid);
286 #endif /* POP */
287
288 if (vecp != 0)
289 vec[vecp] = NULL;
290
291 #ifdef POP
292 if (host) {
293 if ( strcmp( POPSERVICE, "kpop" ) == 0 ) {
294 kpop = 1;
295 }
296 if (vecp == 0) {
297 status = remotemail (host, user, proxy, rpop, kpop, notifysw, 1,
298 snoop, sasl, saslmech);
299 } else {
300 for (vecp = 0; vec[vecp]; vecp++)
301 status += remotemail (host, vec[vecp], proxy, rpop, kpop,
302 notifysw, 0, snoop, sasl, saslmech);
303 }
304 } else {
305 #endif /* POP */
306
307 if (vecp == 0) {
308 char *home;
309
310 home = (uid = geteuid()) ? home = getenv ("HOME") : NULL;
311 if (home == NULL) {
312 pw = getpwnam (user);
313 if (pw == NULL)
314 adios (NULL, "unable to get information about user");
315 if (home == NULL)
316 home = pw->pw_dir;
317 }
318 status = checkmail (user, home, datesw, notifysw, 1);
319 } else {
320 for (vecp = 0; vec[vecp]; vecp++) {
321 if ((pw = getpwnam (vec[vecp])))
322 status += checkmail (pw->pw_name, pw->pw_dir, datesw, notifysw, 0);
323 else
324 advise (NULL, "no such user as %s", vec[vecp]);
325 }
326 }
327 #ifdef POP
328 } /* host == NULL */
329 #endif
330
331 return done (status);
332 }
333
334
335 static struct swit ntswitches[] = {
336 #define NALLSW 0
337 { "all", 0 },
338 #define NMAISW 1
339 { "mail", 0 },
340 #define NNMAISW 2
341 { "nomail", 0 },
342 { NULL, 0 }
343 };
344
345
346 static int
347 donote (char *cp, int ntflag)
348 {
349 switch (smatch (cp, ntswitches)) {
350 case AMBIGSW:
351 ambigsw (cp, ntswitches);
352 done (1);
353 case UNKWNSW:
354 adios (NULL, "-%snotify %s unknown", ntflag ? "" : "no", cp);
355
356 case NALLSW:
357 return NT_ALL;
358 case NMAISW:
359 return NT_MAIL;
360 case NNMAISW:
361 return NT_NMAI;
362 }
363
364 return 0; /* Before 1999-07-15, garbage was returned if control got here. */
365 }
366
367
368 static int
369 checkmail (char *user, char *home, int datesw, int notifysw, int personal)
370 {
371 int mf, status;
372 char buffer[BUFSIZ];
373 struct stat st;
374
375 snprintf (buffer, sizeof(buffer), "%s/%s", mmdfldir[0] ? mmdfldir : home, mmdflfil[0] ? mmdflfil : user);
376 if (datesw) {
377 st.st_size = 0;
378 st.st_atime = st.st_mtime = 0;
379 }
380 mf = (stat (buffer, &st) == NOTOK || st.st_size == 0) ? NONEOK
381 : st.st_atime <= st.st_mtime ? MMDFNEW : MMDFOLD;
382
383 if ((mf & UUCPOK) || (mf & MMDFOK)) {
384 if (notifysw & NT_MAIL) {
385 printf (personal ? "You have " : "%s has ", user);
386 if (mf & UUCPOK)
387 printf ("%s old-style bell", mf & UUCPOLD ? "old" : "new");
388 if ((mf & UUCPOK) && (mf & MMDFOK))
389 printf (" and ");
390 if (mf & MMDFOK)
391 printf ("%s%s", mf & MMDFOLD ? "old" : "new",
392 mf & UUCPOK ? " Internet" : "");
393 printf (" mail waiting");
394 } else {
395 notifysw = 0;
396 }
397 status = 0;
398 }
399 else {
400 if (notifysw & NT_NMAI)
401 printf (personal ? "You don't %s%s" : "%s doesn't %s",
402 personal ? "" : user, "have any mail waiting");
403 else
404 notifysw = 0;
405
406 status = 1;
407 }
408
409 if (notifysw)
410 if (datesw && st.st_atime)
411 printf ("; last read on %s", dtime (&st.st_atime, 1));
412 if (notifysw)
413 printf ("\n");
414
415 return status;
416 }
417
418
419 #ifdef POP
420 extern char response[];
421
422 static int
423 remotemail (char *host, char *user, char *proxy, int rpop, int kpop, int notifysw, int personal, int snoop, int sasl, char *saslmech)
424 {
425 int nmsgs, nbytes, status;
426 char *pass = NULL;
427
428 if (user == NULL)
429 user = getusername ();
430 if (kpop || sasl || (rpop > 0))
431 pass = getusername ();
432 else
433 ruserpass (host, &user, &pass);
434
435 /* open the POP connection */
436 if (pop_init (host, user, pass, proxy, snoop, kpop ? 1 : rpop, kpop,
437 sasl, saslmech) == NOTOK
438 || pop_stat (&nmsgs, &nbytes) == NOTOK /* check for messages */
439 || pop_quit () == NOTOK) { /* quit POP connection */
440 advise (NULL, "%s", response);
441 return 1;
442 }
443
444 if (nmsgs) {
445 if (notifysw & NT_MAIL) {
446 printf (personal ? "You have " : "%s has ", user);
447 printf ("%d message%s (%d bytes)",
448 nmsgs, nmsgs != 1 ? "s" : "", nbytes);
449 }
450 else
451 notifysw = 0;
452
453 status = 0;
454 } else {
455 if (notifysw & NT_NMAI)
456 printf (personal ? "You don't %s%s" : "%s doesn't %s",
457 personal ? "" : user, "have any mail waiting");
458 else
459 notifysw = 0;
460 status = 1;
461 }
462 if (notifysw)
463 printf (" on %s\n", host);
464
465 return status;
466 }
467 #endif /* POP */