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