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