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