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