2 ** whom.c -- list recipients of message
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.
10 #include <h/addrsbr.h>
11 #include <h/fmt_scan.h>
16 static struct swit switches[] = {
43 #define HRESENT (1<<1)
49 struct mailname head = {0};
50 struct mailname *mp = &head;
54 static int resent = 0; /* consider normal or resent headers */
55 static int toccsw = 1; /* list sighted recipients */
56 static int dccsw = 1; /* list hidden dcc recipients */
57 static int bccsw = 1; /* list hidden bcc recipients */
58 static int alisw = 1; /* expand aliases on rcpt addrs */
60 static char *dccsep = "\t==DCC==";
61 static char *bccsep = "\t==BCC==";
67 static int process(char *);
68 static void proc_hdr(char *, char *);
69 static int print(void);
70 static int printdcc(void);
71 static int printbcc(void);
72 static void printone(struct mailname *);
76 main(int argc, char **argv)
78 int filep=0, naddrs=0, n;
80 char buf[BUFSIZ], **argp;
81 char **arguments, *files[NFILES];
84 setlocale(LC_ALL, "");
85 invo_name = mhbasename(argv[0]);
87 /* read user profile/context */
90 arguments = getarguments(invo_name, argc, argv, 1);
93 while ((cp = *argp++)) {
95 switch (smatch(++cp, switches)) {
97 ambigsw(cp, switches);
101 adios(EX_USAGE, NULL, "-%s unknown", cp);
104 snprintf(buf, sizeof(buf),
105 "%s [switches] file ...",
107 print_help(buf, switches, 1);
108 exit(argc == 2 ? EX_OK : EX_USAGE);
110 print_version(invo_name);
111 exit(argc == 2 ? EX_OK : EX_USAGE);
142 if (filep > NFILES) {
143 adios(EX_USAGE, NULL, "too many files (more than %d)",
151 adios(EX_USAGE, NULL, "usage: %s [switches] file ...", invo_name);
153 if (!toccsw && !dccsw && !bccsw) {
154 adios(EX_USAGE, NULL, "use at least one of: -tocc -dcc -bcc");
156 for (filep=0; files[filep]; filep++) {
157 process(files[filep]);
160 cmd = add("ali -list", NULL);
161 if ((n=print()) && alisw) {
162 if (!(in = popen(cmd, "r"))) {
163 adios(EX_IOERR, "popen", "unable to");
165 while (fgets(buf, sizeof buf, in)) {
173 cmd = add("ali -list", NULL);
174 if ((n=printdcc()) && alisw) {
175 if (!(in = popen(cmd, "r"))) {
176 adios(EX_IOERR, "popen", "unable to");
178 while (fgets(buf, sizeof buf, in)) {
186 cmd = add("ali -list", NULL);
187 if ((n=printbcc()) && alisw) {
188 if (!(in = popen(cmd, "r"))) {
189 adios(EX_IOERR, "popen", "unable to");
191 while (fgets(buf, sizeof buf, in)) {
199 return naddrs ? 0 : 1;
207 struct field f = {{0}};
212 if ((in = fopen(file, "r")) == NULL) {
213 adios(EX_IOERR, file, "unable to open");
216 for (compnum=1, state=FLD2;; compnum++) {
217 switch (state = m_getfld2(state, &f, in)) {
219 proc_hdr(f.name, f.value);
229 adios(EX_DATAERR, NULL, "message format error in component #%d",
233 adios(EX_SOFTWARE, NULL, "getfld() returned %d", state);
243 ** Check if the header contains addresses we're interested in.
244 ** If so, extract the addresses and add them to the global list.
247 proc_hdr(char *name, char *val)
252 while (*val==' ' || *val=='\t' || *val=='\n') {
255 if (strncasecmp(name, "resent-", 7)==0) {
258 if (mh_strcasecmp(name, "to")==0) {
260 } else if (mh_strcasecmp(name, "cc")==0) {
262 } else if (mh_strcasecmp(name, "dcc")==0) {
264 } else if (mh_strcasecmp(name, "bcc")==0) {
266 } else if (mh_strcasecmp(name, "resent-to")==0) {
267 type = (HRESENT | HTO);
268 } else if (mh_strcasecmp(name, "resent-cc")==0) {
269 type = (HRESENT | HCC);
270 } else if (mh_strcasecmp(name, "resent-dcc")==0) {
271 type = (HRESENT | HDCC);
272 } else if (mh_strcasecmp(name, "resent-bcc")==0) {
273 type = (HRESENT | HBCC);
275 /* ignore non-recpient headers */
279 /* ignore recipient headers we are not interested in */
280 if ((type&HTO || type&HCC) && !toccsw) {
283 if ((type&HDCC) && !dccsw) {
286 if ((type&HBCC) && !bccsw) {
290 while ((cp = getname(val))) {
291 if (!(mp->m_next = getm(cp, NULL, 0, AD_NAME, NULL))) {
292 adios(EX_DATAERR, NULL, "illegal address: %s", cp);
295 if (mp->m_type == BADHOST) {
296 admonish(NULL, "bad address `%s'", mp->m_text);
305 ** Walk through the list of addresses and print the right ones.
312 for (mp=head.m_next; mp; mp=mp->m_next) {
313 /* skip unless both are resent or neither one is */
314 if (resent != (mp->m_type&HRESENT)) {
317 if (mp->m_type & (HTO|HCC)) {
326 ** Walk through the list of addresses and print the right ones.
333 for (mp=head.m_next; mp; mp=mp->m_next) {
334 /* skip unless both are resent or neither one is */
335 if (resent != (mp->m_type&HRESENT)) {
338 if (mp->m_type & HDCC) {
339 if (!naddrs && (toccsw || bccsw)) {
350 ** Walk through the list of addresses and print the right ones.
357 for (mp=head.m_next; mp; mp=mp->m_next) {
358 /* skip unless both are resent or neither one is */
359 if (resent != (mp->m_type&HRESENT)) {
362 if (mp->m_type & HBCC) {
363 if (!naddrs && (toccsw || dccsw)) {
375 ** Print one single address in appropriate form.
378 printone(struct mailname *mp)
383 snprintf(buf, sizeof buf, " %s@%s", mp->m_mbox, mp->m_host);
385 snprintf(buf, sizeof buf, " %s", mp->m_mbox);