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