Initial revision
[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     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
320
321 static int
322 checkmail (char *user, char *home, int datesw, int notifysw, int personal)
323 {
324     int mf, status;
325     char buffer[BUFSIZ];
326     struct stat st;
327
328     snprintf (buffer, sizeof(buffer), "%s/%s", mmdfldir[0] ? mmdfldir : home, mmdflfil[0] ? mmdflfil : user);
329     if (datesw) {
330         st.st_size = 0;
331         st.st_atime = st.st_mtime = 0;
332     }
333     mf = (stat (buffer, &st) == NOTOK || st.st_size == 0) ? NONEOK
334         : st.st_atime <= st.st_mtime ? MMDFNEW : MMDFOLD;
335
336     if ((mf & UUCPOK) || (mf & MMDFOK)) {
337         if (notifysw & NT_MAIL) {
338             printf (personal ? "You have " : "%s has ", user);
339             if (mf & UUCPOK)
340                 printf ("%s old-style bell", mf & UUCPOLD ? "old" : "new");
341             if ((mf & UUCPOK) && (mf & MMDFOK))
342                 printf (" and ");
343             if (mf & MMDFOK)
344                 printf ("%s%s", mf & MMDFOLD ? "old" : "new",
345                         mf & UUCPOK ? " Internet" : "");
346             printf (" mail waiting");
347         } else {
348             notifysw = 0;
349         }
350         status = 0;
351     }
352     else {
353         if (notifysw & NT_NMAI)
354             printf (personal ? "You don't %s%s" : "%s doesn't %s",
355                     personal ? "" : user, "have any mail waiting");
356         else
357             notifysw = 0;
358
359         status = 1;
360     }
361
362     if (notifysw)
363         if (datesw && st.st_atime)
364             printf ("; last read on %s", dtime (&st.st_atime, 1));
365     if (notifysw)
366         printf ("\n");
367
368     return status;
369 }
370
371
372 #ifdef POP
373 extern char response[];
374
375 static int
376 remotemail (char *host, char *user, int rpop, int notifysw, int personal, int snoop)
377 {
378     int nmsgs, nbytes, status;
379     char *pass = NULL;
380
381     if (user == NULL)
382         user = getusername ();
383     if (rpop > 0)
384         pass = getusername ();
385     else
386         ruserpass (host, &user, &pass);
387
388     /* open the POP connection */
389     if (pop_init (host, user, pass, snoop, rpop) == NOTOK
390             || pop_stat (&nmsgs, &nbytes) == NOTOK      /* check for messages  */
391             || pop_quit () == NOTOK) {                  /* quit POP connection */
392         advise (NULL, "%s", response);
393         return 1;
394     }
395
396     if (nmsgs) {
397         if (notifysw & NT_MAIL) {
398             printf (personal ? "You have " : "%s has ", user);
399             printf ("%d message%s (%d bytes)",
400                     nmsgs, nmsgs != 1 ? "s" : "", nbytes);
401         }
402         else
403             notifysw = 0;
404
405         status = 0;
406     } else {
407         if (notifysw & NT_NMAI)
408             printf (personal ? "You don't %s%s" : "%s doesn't %s",
409                     personal ? "" : user, "have any mail waiting");
410         else
411             notifysw = 0;
412         status = 1;
413     }
414     if (notifysw)
415         printf (" on %s\n", host);
416
417     return status;
418 }
419 #endif /* POP */