wesley.craig@umich.edu did not document his previous KPOP patch, so I did so,
[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 ( strcmp( POPSERVICE, "kpop" ) == 0 ) {
263             kpop = 1;
264         }
265         if (vecp == 0) {
266             status = remotemail (host, user, rpop, kpop, notifysw, 1, snoop);
267         } else {
268             for (vecp = 0; vec[vecp]; vecp++)
269                 status += remotemail (host, vec[vecp], rpop, kpop, notifysw, 0, snoop);
270         }
271     } else {
272 #endif /* POP */
273
274     if (vecp == 0) {
275         char *home;
276
277         home = (uid = geteuid()) ? home = getenv ("HOME") : NULL;
278         if (home == NULL) {
279             pw = getpwnam (user);
280             if (pw == NULL)
281                 adios (NULL, "unable to get information about user");
282             if (home == NULL)
283                 home = pw->pw_dir;
284         }
285         status = checkmail (user, home, datesw, notifysw, 1);
286     } else {
287         for (vecp = 0; vec[vecp]; vecp++) {
288             if ((pw = getpwnam (vec[vecp])))
289                 status += checkmail (pw->pw_name, pw->pw_dir, datesw, notifysw, 0);
290             else
291                 advise (NULL, "no such user as %s", vec[vecp]);
292         }
293     }
294 #ifdef POP
295     }           /* host == NULL */
296 #endif
297
298     return done (status);
299 }
300
301
302 static struct swit ntswitches[] = {
303 #define NALLSW     0
304     { "all", 0 },
305 #define NMAISW     1
306     { "mail", 0 },
307 #define NNMAISW    2
308     { "nomail", 0 },
309     { NULL, 0 }
310 };
311
312
313 static int
314 donote (char *cp, int ntflag)
315 {
316     switch (smatch (cp, ntswitches)) {
317         case AMBIGSW: 
318             ambigsw (cp, ntswitches);
319             done (1);
320         case UNKWNSW: 
321             adios (NULL, "-%snotify %s unknown", ntflag ? "" : "no", cp);
322
323         case NALLSW: 
324             return NT_ALL;
325         case NMAISW: 
326             return NT_MAIL;
327         case NNMAISW: 
328             return NT_NMAI;
329     }
330
331     return 0; /* Before 1999-07-15, garbage was returned if control got here. */
332 }
333
334
335 static int
336 checkmail (char *user, char *home, int datesw, int notifysw, int personal)
337 {
338     int mf, status;
339     char buffer[BUFSIZ];
340     struct stat st;
341
342     snprintf (buffer, sizeof(buffer), "%s/%s", mmdfldir[0] ? mmdfldir : home, mmdflfil[0] ? mmdflfil : user);
343     if (datesw) {
344         st.st_size = 0;
345         st.st_atime = st.st_mtime = 0;
346     }
347     mf = (stat (buffer, &st) == NOTOK || st.st_size == 0) ? NONEOK
348         : st.st_atime <= st.st_mtime ? MMDFNEW : MMDFOLD;
349
350     if ((mf & UUCPOK) || (mf & MMDFOK)) {
351         if (notifysw & NT_MAIL) {
352             printf (personal ? "You have " : "%s has ", user);
353             if (mf & UUCPOK)
354                 printf ("%s old-style bell", mf & UUCPOLD ? "old" : "new");
355             if ((mf & UUCPOK) && (mf & MMDFOK))
356                 printf (" and ");
357             if (mf & MMDFOK)
358                 printf ("%s%s", mf & MMDFOLD ? "old" : "new",
359                         mf & UUCPOK ? " Internet" : "");
360             printf (" mail waiting");
361         } else {
362             notifysw = 0;
363         }
364         status = 0;
365     }
366     else {
367         if (notifysw & NT_NMAI)
368             printf (personal ? "You don't %s%s" : "%s doesn't %s",
369                     personal ? "" : user, "have any mail waiting");
370         else
371             notifysw = 0;
372
373         status = 1;
374     }
375
376     if (notifysw)
377         if (datesw && st.st_atime)
378             printf ("; last read on %s", dtime (&st.st_atime, 1));
379     if (notifysw)
380         printf ("\n");
381
382     return status;
383 }
384
385
386 #ifdef POP
387 extern char response[];
388
389 static int
390 remotemail (char *host, char *user, int rpop, int kpop, int notifysw, int personal, int snoop)
391 {
392     int nmsgs, nbytes, status;
393     char *pass = NULL;
394
395     if (user == NULL)
396         user = getusername ();
397     if (kpop || (rpop > 0))
398         pass = getusername ();
399     else
400         ruserpass (host, &user, &pass);
401
402     /* open the POP connection */
403     if (pop_init (host, user, pass, snoop, kpop ? 1 : rpop, kpop) == NOTOK
404             || pop_stat (&nmsgs, &nbytes) == NOTOK      /* check for messages  */
405             || pop_quit () == NOTOK) {                  /* quit POP connection */
406         advise (NULL, "%s", response);
407         return 1;
408     }
409
410     if (nmsgs) {
411         if (notifysw & NT_MAIL) {
412             printf (personal ? "You have " : "%s has ", user);
413             printf ("%d message%s (%d bytes)",
414                     nmsgs, nmsgs != 1 ? "s" : "", nbytes);
415         }
416         else
417             notifysw = 0;
418
419         status = 0;
420     } else {
421         if (notifysw & NT_NMAI)
422             printf (personal ? "You don't %s%s" : "%s doesn't %s",
423                     personal ? "" : user, "have any mail waiting");
424         else
425             notifysw = 0;
426         status = 1;
427     }
428     if (notifysw)
429         printf (" on %s\n", host);
430
431     return status;
432 }
433 #endif /* POP */