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