36edccb4e0499457907b766f6273bad6a35db456
[mmh] / uip / msgchk.c
1 /*
2 ** msgchk.c -- check for mail
3 **
4 ** This code is Copyright (c) 2002, by the authors of nmh.  See the
5 ** COPYRIGHT file in the root directory of the nmh distribution for
6 ** complete copyright information.
7 */
8
9 #include <h/mh.h>
10 #include <h/mts.h>
11 #include <h/tws.h>
12 #include <pwd.h>
13
14 static struct swit switches[] = {
15 #define DATESW  0
16         { "date", 0 },
17 #define NDATESW  1
18         { "nodate", 0 },
19 #define NOTESW  2
20         { "notify type", 0 },
21 #define NNOTESW  3
22         { "nonotify type", 0 },
23 #define VERSIONSW  4
24         { "version", 0 },
25 #define HELPSW  5
26         { "help", 0 },
27 };
28
29 /*
30 ** Maximum numbers of users we can check (plus
31 ** one for the NULL vector at the end).
32 */
33 #define MAXVEC  51
34
35 #define NT_NONE  0x0
36 #define NT_MAIL  0x1
37 #define NT_NMAI  0x2
38 #define NT_ALL   (NT_MAIL | NT_NMAI)
39
40 #define NONEOK   0x0
41 #define UUCPOLD  0x1
42 #define UUCPNEW  0x2
43 #define UUCPOK   (UUCPOLD | UUCPNEW)
44 #define MMDFOLD  0x4
45 #define MMDFNEW  0x8
46 #define MMDFOK   (MMDFOLD | MMDFNEW)
47
48
49 /*
50 ** static prototypes
51 */
52 static int donote(char *, int);
53 static int checkmail(char *, char *, int, int, int);
54
55
56 int
57 main(int argc, char **argv)
58 {
59         int datesw = 1, notifysw = NT_ALL;
60         int status = 0;
61         int vecp = 0;
62         uid_t uid;
63         char buf[BUFSIZ];
64         char *user, *cp;
65         char **argp, **arguments, *vec[MAXVEC];
66         struct passwd *pw;
67
68 #ifdef LOCALE
69         setlocale(LC_ALL, "");
70 #endif
71         invo_name = mhbasename(argv[0]);
72
73         /* read user profile/context */
74         context_read();
75
76         mts_init(invo_name);
77         uid = getuid();
78         user = getusername();
79
80         arguments = getarguments(invo_name, argc, argv, 1);
81         argp = arguments;
82
83         while ((cp = *argp++)) {
84                 if (*cp == '-') {
85                         switch (smatch(++cp, switches)) {
86                         case AMBIGSW:
87                                 ambigsw(cp, switches);
88                                 done(1);
89                         case UNKWNSW:
90                                 adios(NULL, "-%s unknown", cp);
91
92                         case HELPSW:
93                                 snprintf(buf, sizeof(buf), "%s [switches] [users ...]", invo_name);
94                                 print_help(buf, switches, 1);
95                                 done(1);
96                         case VERSIONSW:
97                                 print_version(invo_name);
98                                 done(1);
99
100                         case DATESW:
101                                 datesw++;
102                                 continue;
103                         case NDATESW:
104                                 datesw = 0;
105                                 continue;
106
107                         case NOTESW:
108                                 if (!(cp = *argp++) || *cp == '-')
109                                         adios(NULL, "missing argument to %s",
110                                                         argp[-2]);
111                                 notifysw |= donote(cp, 1);
112                                 continue;
113                         case NNOTESW:
114                                 if (!(cp = *argp++) || *cp == '-')
115                                         adios(NULL, "missing argument to %s",
116                                                         argp[-2]);
117                                 notifysw &= ~donote(cp, 0);
118                                 continue;
119                         }
120                 }
121                 if (vecp >= MAXVEC-1)
122                         adios(NULL, "you can only check %d users at a time",
123                                         MAXVEC-1);
124                 else
125                         vec[vecp++] = cp;
126         }
127
128         if (vecp != 0)
129                 vec[vecp] = NULL;
130
131         if (vecp == 0) {
132                 char *home;
133
134                 /* Not sure this check makes sense... */
135                 if (!geteuid() || NULL == (home = getenv("HOME"))) {
136                         pw = getpwnam(user);
137                         if (pw == NULL)
138                                 adios(NULL, "unable to get information about user");
139                         home = pw->pw_dir;
140                 }
141                 status = checkmail(user, home, datesw, notifysw, 1);
142         } else {
143                 for (vecp = 0; vec[vecp]; vecp++) {
144                         if ((pw = getpwnam(vec[vecp])))
145                                 status += checkmail(pw->pw_name, pw->pw_dir,
146                                                 datesw, notifysw, 0);
147                         else
148                                 advise(NULL, "no such user as %s", vec[vecp]);
149                 }
150         }
151
152         done(status);
153         return 1;
154 }
155
156
157 static struct swit ntswitches[] = {
158 #define NALLSW  0
159         { "all", 0 },
160 #define NMAISW  1
161         { "mail", 0 },
162 #define NNMAISW  2
163         { "nomail", 0 },
164         { NULL, 0 }
165 };
166
167
168 static int
169 donote(char *cp, int ntflag)
170 {
171         switch (smatch(cp, ntswitches)) {
172         case AMBIGSW:
173                 ambigsw(cp, ntswitches);
174                 done(1);
175         case UNKWNSW:
176                 adios(NULL, "-%snotify %s unknown", ntflag ? "" : "no", cp);
177
178         case NALLSW:
179                 return NT_ALL;
180         case NMAISW:
181                 return NT_MAIL;
182         case NNMAISW:
183                 return NT_NMAI;
184         }
185
186         /* Before 1999-07-15, garbage was returned if control got here. */
187         return 0;
188 }
189
190
191 static int
192 checkmail(char *user, char *home, int datesw, int notifysw, int personal)
193 {
194         int mf, status;
195         char buffer[BUFSIZ];
196         struct stat st;
197
198         snprintf(buffer, sizeof(buffer), "%s/%s",
199                         mmdfldir[0] ? mmdfldir : home,
200                         mmdflfil[0] ? mmdflfil : user);
201         if (datesw) {
202                 st.st_size = 0;
203                 st.st_atime = st.st_mtime = 0;
204         }
205         mf = (stat(buffer, &st) == NOTOK || st.st_size == 0) ? NONEOK
206                 : st.st_atime <= st.st_mtime ? MMDFNEW : MMDFOLD;
207
208         if ((mf & UUCPOK) || (mf & MMDFOK)) {
209                 if (notifysw & NT_MAIL) {
210                         printf(personal ? "You have " : "%s has ", user);
211                         if (mf & UUCPOK)
212                                 printf("%s old-style bell",
213                                                 mf & UUCPOLD ? "old" : "new");
214                         if ((mf & UUCPOK) && (mf & MMDFOK))
215                                 printf(" and ");
216                         if (mf & MMDFOK)
217                                 printf("%s%s", mf & MMDFOLD ? "old" : "new",
218                                                 mf & UUCPOK ? " Internet" : "");
219                         printf(" mail waiting");
220                 } else {
221                         notifysw = 0;
222                 }
223                 status = 0;
224         }
225         else {
226                 if (notifysw & NT_NMAI)
227                         printf(personal ? "You don't %s%s" : "%s doesn't %s",
228                                         personal ? "" : user,
229                                         "have any mail waiting");
230                 else
231                         notifysw = 0;
232
233                 status = 1;
234         }
235
236         if (notifysw)
237                 if (datesw && st.st_atime)
238                         printf("; last read on %s", dtime(&st.st_atime, 1));
239         if (notifysw)
240                 printf("\n");
241
242         return status;
243 }