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[] = {
40 char *version=VERSION;
44 #define HRESENT (1<<1)
50 struct mailname head = {0};
51 struct mailname *mp = &head;
55 static int resent = 0; /* consider normal or resent headers */
56 static int toccsw = 1; /* list sighted recipients */
57 static int dccsw = 1; /* list hidden dcc recipients */
58 static int bccsw = 1; /* list hidden bcc recipients */
59 static int alisw = 1; /* expand aliases on rcpt addrs */
61 static char *dccsep = "\t==DCC==";
62 static char *bccsep = "\t==BCC==";
68 static int process(char *);
69 static void proc_hdr(char *, char *);
70 static int print(void);
71 static int printdcc(void);
72 static int printbcc(void);
73 static void printone(struct mailname *);
77 main(int argc, char **argv)
81 char buf[BUFSIZ], **argp;
85 struct msgs_array msgs = {0};
86 struct msgs_array files = {0};
88 setlocale(LC_ALL, "");
89 invo_name = mhbasename(argv[0]);
91 /* read user profile/context */
94 arguments = getarguments(invo_name, argc, argv, 1);
97 while ((cp = *argp++)) {
99 switch (smatch(++cp, switches)) {
101 ambigsw(cp, switches);
105 adios(EX_USAGE, NULL, "-%s unknown", cp);
108 snprintf(buf, sizeof(buf),
109 "%s [switches] file ...",
111 print_help(buf, switches, 1);
112 exit(argc == 2 ? EX_OK : EX_USAGE);
114 print_version(invo_name);
115 exit(argc == 2 ? EX_OK : EX_USAGE);
146 if (*cp == '+' || *cp == '@') {
148 adios(EX_USAGE, NULL, "only one folder at a time!");
150 folder = mh_xstrdup(expandfol(cp));
153 app_msgarg(&msgs, cp);
157 adios(EX_USAGE, NULL, "usage: %s [switches] file ...", invo_name);
159 if (!toccsw && !dccsw && !bccsw) {
160 adios(EX_USAGE, NULL, "use at least one of: -tocc -dcc -bcc");
162 if (parse_msgs(&msgs, folder, &files) < 0) {
165 for (size_t filep = 0; filep < files.size; filep++) {
166 process(files.msgs[filep]);
169 cmd = add("ali -list", NULL);
170 if ((n=print()) && alisw) {
171 if (!(in = popen(cmd, "r"))) {
172 adios(EX_IOERR, "popen", "unable to");
174 while (fgets(buf, sizeof buf, in)) {
182 cmd = add("ali -list", NULL);
183 if ((n=printdcc()) && alisw) {
184 if (!(in = popen(cmd, "r"))) {
185 adios(EX_IOERR, "popen", "unable to");
187 while (fgets(buf, sizeof buf, in)) {
195 cmd = add("ali -list", NULL);
196 if ((n=printbcc()) && alisw) {
197 if (!(in = popen(cmd, "r"))) {
198 adios(EX_IOERR, "popen", "unable to");
200 while (fgets(buf, sizeof buf, in)) {
208 return naddrs ? 0 : 1;
216 struct field f = {{0}};
221 if ((in = fopen(file, "r")) == NULL) {
222 adios(EX_IOERR, file, "unable to open");
225 for (compnum=1, state=FLD2;; compnum++) {
226 switch (state = m_getfld2(state, &f, in)) {
231 proc_hdr(f.name, f.value);
239 advise(NULL, "message format error in component #%d", compnum);
243 adios(EX_DATAERR, NULL, "message format error in component #%d",
247 adios(EX_SOFTWARE, NULL, "getfld() returned %d", state);
257 ** Check if the header contains addresses we're interested in.
258 ** If so, extract the addresses and add them to the global list.
261 proc_hdr(char *name, char *val)
266 while (*val==' ' || *val=='\t' || *val=='\n') {
269 if (strncasecmp(name, "resent-", 7)==0) {
272 if (mh_strcasecmp(name, "to")==0) {
274 } else if (mh_strcasecmp(name, "cc")==0) {
276 } else if (mh_strcasecmp(name, "dcc")==0) {
278 } else if (mh_strcasecmp(name, "bcc")==0) {
280 } else if (mh_strcasecmp(name, "resent-to")==0) {
281 type = (HRESENT | HTO);
282 } else if (mh_strcasecmp(name, "resent-cc")==0) {
283 type = (HRESENT | HCC);
284 } else if (mh_strcasecmp(name, "resent-dcc")==0) {
285 type = (HRESENT | HDCC);
286 } else if (mh_strcasecmp(name, "resent-bcc")==0) {
287 type = (HRESENT | HBCC);
289 /* ignore non-recpient headers */
293 /* ignore recipient headers we are not interested in */
294 if ((type&HTO || type&HCC) && !toccsw) {
297 if ((type&HDCC) && !dccsw) {
300 if ((type&HBCC) && !bccsw) {
304 while ((cp = getname(val))) {
305 if (!(mp->m_next = getm(cp, NULL, 0, AD_NAME, NULL))) {
306 adios(EX_DATAERR, NULL, "illegal address: %s", cp);
309 if (mp->m_type == BADHOST) {
310 admonish(NULL, "bad address `%s'", mp->m_text);
319 ** Walk through the list of addresses and print the right ones.
326 for (mp=head.m_next; mp; mp=mp->m_next) {
327 /* skip unless both are resent or neither one is */
328 if (resent != (mp->m_type&HRESENT)) {
331 if (mp->m_type & (HTO|HCC)) {
340 ** Walk through the list of addresses and print the right ones.
347 for (mp=head.m_next; mp; mp=mp->m_next) {
348 /* skip unless both are resent or neither one is */
349 if (resent != (mp->m_type&HRESENT)) {
352 if (mp->m_type & HDCC) {
353 if (!naddrs && (toccsw || bccsw)) {
364 ** Walk through the list of addresses and print the right ones.
371 for (mp=head.m_next; mp; mp=mp->m_next) {
372 /* skip unless both are resent or neither one is */
373 if (resent != (mp->m_type&HRESENT)) {
376 if (mp->m_type & HBCC) {
377 if (!naddrs && (toccsw || dccsw)) {
389 ** Print one single address in appropriate form.
392 printone(struct mailname *mp)
397 snprintf(buf, sizeof buf, " %s@%s", mp->m_mbox, mp->m_host);
399 snprintf(buf, sizeof buf, " %s", mp->m_mbox);