Fixed a possible uninitialized variable access.
[mmh] / uip / whom.c
1 /*
2 ** whom.c -- list recipients of message
3 **
4 ** This code is Copyright (c) 2012, by the authors of mmh.  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/addrsbr.h>
11 #include <h/fmt_scan.h>
12 #include <h/utils.h>
13
14 static struct swit switches[] = {
15 #define VERSIONSW 0
16         { "Version", 0 },
17 #define HELPSW 1
18         { "help", 0 },
19 #define TOCCSW 2
20         { "tocc", 0 },
21 #define NTOCCSW 3
22         { "notocc", 2 },
23 #define BCCSW 4
24         { "bcc", 0 },
25 #define NBCCSW 5
26         { "nobcc", 2 },
27 #define ALISW 6
28         { "alias", 0 },
29 #define NALISW 7
30         { "noalias", 2 },
31         { NULL, 0 }
32 };
33
34
35 #define NFILES 32
36
37 #define HRESENT (1<<1)
38 #define HTO (1<<2)
39 #define HCC (1<<3)
40 #define HBCC (1<<4)
41
42 struct mailname head = {0};
43 struct mailname *mp = &head;
44
45 static char *cmd;
46
47 static int resent = 0;  /* consider normal or resent headers */
48 static int toccsw = 1;  /* list sighted recipients */
49 static int bccsw = 1;  /* list hidden recipients */
50 static int alisw = 1;  /* expand aliases on rcpt addrs */
51
52 static char *separator = "\t==BCC==";
53
54
55 /*
56 ** static prototypes
57 */
58 static int process(char *);
59 static void proc_hdr(char *, char *);
60 static int print(void);
61 static int printbcc(void);
62 static void printone(struct mailname *);
63
64
65 int
66 main(int argc, char **argv)
67 {
68         int filep=0, naddrs=0, n;
69         char *cp;
70         char buf[BUFSIZ], **argp;
71         char **arguments, *files[NFILES];
72         FILE *in;
73
74         setlocale(LC_ALL, "");
75         invo_name = mhbasename(argv[0]);
76
77         /* read user profile/context */
78         context_read();
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
90                         case UNKWNSW:
91                                 adios(NULL, "-%s unknown", cp);
92
93                         case HELPSW:
94                                 snprintf(buf, sizeof(buf),
95                                                 "%s [switches] file ...",
96                                                 invo_name);
97                                 print_help(buf, switches, 1);
98                                 done(1);
99                         case VERSIONSW:
100                                 print_version(invo_name);
101                                 done(1);
102
103                         case TOCCSW:
104                                 toccsw = 1;
105                                 continue;
106                         case NTOCCSW:
107                                 toccsw = 0;
108                                 continue;
109
110                         case BCCSW:
111                                 bccsw = 1;
112                                 continue;
113                         case NBCCSW:
114                                 bccsw = 0;
115                                 continue;
116
117                         case ALISW:
118                                 alisw = 1;
119                                 continue;
120                         case NALISW:
121                                 alisw = 0;
122                                 continue;
123                         }
124                 }
125                 if (filep > NFILES) {
126                         adios(NULL, "too many files (more than %d)",
127                                         NFILES);
128                 } else {
129                         files[filep++] = cp;
130                 }
131         }
132         files[filep] = NULL;
133         if (!filep) {
134                 adios(NULL, "usage: %s [switches] file ...", invo_name);
135         }
136         if (!toccsw && !bccsw) {
137                 adios(NULL, "give -tocc or -bcc or both to produce output");
138         }
139         for (filep=0; files[filep]; filep++) {
140                 process(files[filep]);
141         }
142
143         cmd = add("ali -list", NULL);
144         if ((n=print()) && alisw) {
145                 if (!(in = popen(cmd, "r"))) {
146                         adios("popen", "unable to");
147                 }
148                 while (fgets(buf, sizeof buf, in)) {
149                         fputs(buf, stdout);
150                 }
151                 pclose(in);
152         }
153         free(cmd);
154         naddrs += n;
155
156         cmd = add("ali -list", NULL);
157         if ((n=printbcc()) && alisw) {
158                 if (!(in = popen(cmd, "r"))) {
159                         adios("popen", "unable to");
160                 }
161                 while (fgets(buf, sizeof buf, in)) {
162                         fputs(buf, stdout);
163                 }
164                 pclose(in);
165         }
166         free(cmd);
167         naddrs += n;
168         return naddrs ? 0 : 1;
169 }
170
171
172 static int
173 process(char *file)
174 {
175         int state, compnum;
176         char *cp = NULL;
177         char buf[BUFSIZ], name[NAMESZ];
178         FILE *in;
179
180
181         if ((in = fopen(file, "r")) == NULL) {
182                 adios(file, "unable to open");
183         }
184
185         for (compnum = 1, state = FLD;;) {
186                 switch (state = m_getfld(state, name, buf, sizeof(buf), in)) {
187                 case FLD:
188                         compnum++;
189                         proc_hdr(name, buf);
190                         continue;
191
192                 case FLDPLUS:
193                         compnum++;
194                         cp = add(buf, cp);
195                         while (state == FLDPLUS) {
196                                 state = m_getfld(state, name, buf,
197                                                 sizeof(buf), in);
198                                 cp = add(buf, cp);
199                         }
200                         proc_hdr(name, cp);
201                         free(cp);
202                         continue;
203
204                 case BODY:
205                 case FILEEOF:
206                         break;
207
208                 case LENERR:
209                 case FMTERR:
210                         adios(NULL, "message format error in component #%d",
211                                         compnum);
212
213                 default:
214                         adios(NULL, "getfld() returned %d", state);
215                 }
216                 break;
217         }
218         fclose(in);
219         return 0;
220 }
221
222
223 /*
224 ** Check if the header contains addresses we're interested in.
225 ** If so, extract the addresses and add them to the global list.
226 */
227 static void
228 proc_hdr(char *name, char *val)
229 {
230         char *cp;
231         int type = 0;
232
233         while (*val==' ' || *val=='\t' || *val=='\n') {
234                 val++;
235         }
236         if (strncasecmp(name, "resent-", 7)==0) {
237                 resent = HRESENT;
238         }
239         if (mh_strcasecmp(name, "to")==0) {
240                 type = HTO;
241         } else if (mh_strcasecmp(name, "cc")==0) {
242                 type = HCC;
243         } else if (mh_strcasecmp(name, "bcc")==0) {
244                 type = HBCC;
245         } else if (mh_strcasecmp(name, "resent-to")==0) {
246                 type = (HRESENT | HTO);
247         } else if (mh_strcasecmp(name, "resent-cc")==0) {
248                 type = (HRESENT | HCC);
249         } else if (mh_strcasecmp(name, "resent-bcc")==0) {
250                 type = (HRESENT | HBCC);
251         }
252         /* ignore non-recpient headers */
253         if (!type) {
254                 return;
255         }
256         /* ignore recipient headers we are not interested in */ 
257         if ((type&HTO || type&HCC) && !toccsw) {
258                 return;
259         }
260         if ((type&HBCC) && !bccsw) {
261                 return;
262         }
263
264         while ((cp = getname(val))) {
265                 if (!(mp->m_next = getm(cp, NULL, 0, AD_NAME, NULL))) {
266                         adios(NULL, "illegal address: %s", cp);
267                 }
268                 mp = mp->m_next;
269                 if (mp->m_type == BADHOST) {
270                         admonish(NULL, "bad address `%s'", mp->m_text);
271                         continue;
272                 }
273                 mp->m_type = type;
274         }
275 }
276
277
278 /*
279 ** Walk through the list of addresses and print the right ones.
280 */
281 static int
282 print(void)
283 {
284         int naddrs = 0;
285
286         for (mp=head.m_next; mp; mp=mp->m_next) {
287                 /* skip unless both are resent or neither one is */
288                 if (resent != (mp->m_type&HRESENT)) {
289                         continue;
290                 }
291                 if (mp->m_type & (HTO|HCC)) {
292                         naddrs++;
293                         printone(mp);
294                 }
295         }
296         return naddrs;
297 }
298
299 /*
300 ** Walk through the list of addresses and print the right ones.
301 */
302 static int
303 printbcc(void)
304 {
305         int naddrs = 0;
306
307         for (mp=head.m_next; mp; mp=mp->m_next) {
308                 /* skip unless both are resent or neither one is */
309                 if (resent != (mp->m_type&HRESENT)) {
310                         continue;
311                 }
312                 if (mp->m_type & HBCC) {
313                         if (!naddrs && toccsw) {
314                                 puts(separator);
315                         }
316                         naddrs++;
317                         printone(mp);
318                 }
319         }
320         return naddrs;
321 }
322
323
324 /*
325 ** Print one single address in appropriate form.
326 */
327 static void
328 printone(struct mailname *mp)
329 {
330         char buf[BUFSIZ];
331
332         if (mp->m_host) {
333                 snprintf(buf, sizeof buf, " %s@%s", mp->m_mbox, mp->m_host);
334         } else {
335                 snprintf(buf, sizeof buf, " %s", mp->m_mbox);
336         }
337         if (alisw) {
338                 cmd = add(buf, cmd);
339         } else {
340                 puts(buf+1);
341         }
342 }