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