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