X-Git-Url: http://git.marmaro.de/?p=mmh;a=blobdiff_plain;f=uip%2Fwhom.c;h=c4e7e8f87497fa1bee07e0ed603280babc472441;hp=aeb8d3b660ea3b167e6c2e72c202e73422a1e1ac;hb=a87df3543d3bc128ba4079d1f95638476ba5ca50;hpb=1691e80890e5d8ba258c51c214a3e91880e1db2b diff --git a/uip/whom.c b/uip/whom.c index aeb8d3b..c4e7e8f 100644 --- a/uip/whom.c +++ b/uip/whom.c @@ -1,189 +1,392 @@ - /* - * whom.c -- report to whom a message would be sent - * - * $Id$ - */ +** whom.c -- list recipients of message +** +** This code is Copyright (c) 2012, by the authors of mmh. See the +** COPYRIGHT file in the root directory of the nmh distribution for +** complete copyright information. +*/ #include -#include -#include +#include +#include +#include +#include +#include static struct swit switches[] = { -#define ALIASW 0 - { "alias aliasfile", 0 }, -#define CHKSW 1 - { "check", 0 }, -#define NOCHKSW 2 - { "nocheck", 0 }, -#define DRAFTSW 3 - { "draft", 0 }, -#define DFOLDSW 4 - { "draftfolder +folder", 6 }, -#define DMSGSW 5 - { "draftmessage msg", 6 }, -#define NDFLDSW 6 - { "nodraftfolder", 0 }, -#define VERSIONSW 7 - { "version", 0 }, -#define HELPSW 8 - { "help", 4 }, -#define CLIESW 9 - { "client host", -6 }, -#define SERVSW 10 - { "server host", -6 }, -#define SNOOPSW 11 - { "snoop", -5 }, - { NULL, 0 } +#define VERSIONSW 0 + { "Version", 0 }, +#define HELPSW 1 + { "help", 0 }, +#define TOCCSW 2 + { "tocc", 0 }, +#define NTOCCSW 3 + { "notocc", 2 }, +#define DCCSW 4 + { "dcc", 0 }, +#define NDCCSW 5 + { "nodcc", 2 }, +#define BCCSW 6 + { "bcc", 0 }, +#define NBCCSW 7 + { "nobcc", 2 }, +#define ALISW 8 + { "alias", 0 }, +#define NALISW 9 + { "noalias", 2 }, + { NULL, 0 } }; +#define NFILES 32 + +#define HRESENT (1<<1) +#define HTO (1<<2) +#define HCC (1<<3) +#define HDCC (1<<4) +#define HBCC (1<<5) + +struct mailname head = {0}; +struct mailname *mp = &head; + +static char *cmd; + +static int resent = 0; /* consider normal or resent headers */ +static int toccsw = 1; /* list sighted recipients */ +static int dccsw = 1; /* list hidden dcc recipients */ +static int bccsw = 1; /* list hidden bcc recipients */ +static int alisw = 1; /* expand aliases on rcpt addrs */ + +static char *dccsep = "\t==DCC=="; +static char *bccsep = "\t==BCC=="; + + +/* +** static prototypes +*/ +static int process(char *); +static void proc_hdr(char *, char *); +static int print(void); +static int printdcc(void); +static int printbcc(void); +static void printone(struct mailname *); + + int -main (int argc, char **argv) +main(int argc, char **argv) +{ + int filep=0, naddrs=0, n; + char *cp; + char buf[BUFSIZ], **argp; + char **arguments, *files[NFILES]; + FILE *in; + + setlocale(LC_ALL, ""); + invo_name = mhbasename(argv[0]); + + /* read user profile/context */ + context_read(); + + arguments = getarguments(invo_name, argc, argv, 1); + argp = arguments; + + while ((cp = *argp++)) { + if (*cp == '-') { + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + exit(EX_USAGE); + + case UNKWNSW: + adios(EX_USAGE, NULL, "-%s unknown", cp); + + case HELPSW: + snprintf(buf, sizeof(buf), + "%s [switches] file ...", + invo_name); + print_help(buf, switches, 1); + exit(argc == 2 ? EX_OK : EX_USAGE); + case VERSIONSW: + print_version(invo_name); + exit(argc == 2 ? EX_OK : EX_USAGE); + + case TOCCSW: + toccsw = 1; + continue; + case NTOCCSW: + toccsw = 0; + continue; + + case DCCSW: + dccsw = 1; + continue; + case NDCCSW: + dccsw = 0; + continue; + + case BCCSW: + bccsw = 1; + continue; + case NBCCSW: + bccsw = 0; + continue; + + case ALISW: + alisw = 1; + continue; + case NALISW: + alisw = 0; + continue; + } + } + if (filep > NFILES) { + adios(EX_USAGE, NULL, "too many files (more than %d)", + NFILES); + } else { + files[filep++] = cp; + } + } + files[filep] = NULL; + if (!filep) { + adios(EX_USAGE, NULL, "usage: %s [switches] file ...", invo_name); + } + if (!toccsw && !dccsw && !bccsw) { + adios(EX_USAGE, NULL, "use at least one of: -tocc -dcc -bcc"); + } + for (filep=0; files[filep]; filep++) { + process(files[filep]); + } + + cmd = add("ali -list", NULL); + if ((n=print()) && alisw) { + if (!(in = popen(cmd, "r"))) { + adios(EX_IOERR, "popen", "unable to"); + } + while (fgets(buf, sizeof buf, in)) { + fputs(buf, stdout); + } + pclose(in); + } + free(cmd); + naddrs += n; + + cmd = add("ali -list", NULL); + if ((n=printdcc()) && alisw) { + if (!(in = popen(cmd, "r"))) { + adios(EX_IOERR, "popen", "unable to"); + } + while (fgets(buf, sizeof buf, in)) { + fputs(buf, stdout); + } + pclose(in); + } + free(cmd); + naddrs += n; + + cmd = add("ali -list", NULL); + if ((n=printbcc()) && alisw) { + if (!(in = popen(cmd, "r"))) { + adios(EX_IOERR, "popen", "unable to"); + } + while (fgets(buf, sizeof buf, in)) { + fputs(buf, stdout); + } + pclose(in); + } + free(cmd); + naddrs += n; + + return naddrs ? 0 : 1; +} + + +static int +process(char *file) +{ + enum state state; + struct field f = free_field; + int compnum; + FILE *in; + + + if ((in = fopen(file, "r")) == NULL) { + adios(EX_IOERR, file, "unable to open"); + } + + for (compnum=1, state=FLD2;; compnum++) { + switch (state = m_getfld2(state, &f, in)) { + case FLD2: + proc_hdr(f.name, f.value); + continue; + + case BODY2: + case FILEEOF2: + break; + + case LENERR2: + case FMTERR2: + case IOERR2: + adios(EX_DATAERR, NULL, "message format error in component #%d", + compnum); + + default: + adios(EX_SOFTWARE, NULL, "getfld() returned %d", state); + } + break; + } + fclose(in); + return 0; +} + + +/* +** Check if the header contains addresses we're interested in. +** If so, extract the addresses and add them to the global list. +*/ +static void +proc_hdr(char *name, char *val) +{ + char *cp; + int type = 0; + + while (*val==' ' || *val=='\t' || *val=='\n') { + val++; + } + if (strncasecmp(name, "resent-", 7)==0) { + resent = HRESENT; + } + if (mh_strcasecmp(name, "to")==0) { + type = HTO; + } else if (mh_strcasecmp(name, "cc")==0) { + type = HCC; + } else if (mh_strcasecmp(name, "dcc")==0) { + type = HDCC; + } else if (mh_strcasecmp(name, "bcc")==0) { + type = HBCC; + } else if (mh_strcasecmp(name, "resent-to")==0) { + type = (HRESENT | HTO); + } else if (mh_strcasecmp(name, "resent-cc")==0) { + type = (HRESENT | HCC); + } else if (mh_strcasecmp(name, "resent-dcc")==0) { + type = (HRESENT | HDCC); + } else if (mh_strcasecmp(name, "resent-bcc")==0) { + type = (HRESENT | HBCC); + } + /* ignore non-recpient headers */ + if (!type) { + return; + } + /* ignore recipient headers we are not interested in */ + if ((type&HTO || type&HCC) && !toccsw) { + return; + } + if ((type&HDCC) && !dccsw) { + return; + } + if ((type&HBCC) && !bccsw) { + return; + } + + while ((cp = getname(val))) { + if (!(mp->m_next = getm(cp, NULL, 0, AD_NAME, NULL))) { + adios(EX_DATAERR, NULL, "illegal address: %s", cp); + } + mp = mp->m_next; + if (mp->m_type == BADHOST) { + admonish(NULL, "bad address `%s'", mp->m_text); + continue; + } + mp->m_type = type; + } +} + + +/* +** Walk through the list of addresses and print the right ones. +*/ +static int +print(void) { - pid_t child_id; - int i, status, isdf = 0; - int distsw = 0, vecp = 0; - char *cp, *dfolder = NULL, *dmsg = NULL; - char *msg = NULL, **ap, **argp, backup[BUFSIZ]; - char buf[BUFSIZ], **arguments, *vec[MAXARGS]; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); - - arguments = getarguments (invo_name, argc, argv, 1); - argp = arguments; - - vec[vecp++] = invo_name; - vec[vecp++] = "-whom"; - vec[vecp++] = "-library"; - vec[vecp++] = getcpy (m_maildir ("")); - - while ((cp = *argp++)) { - if (*cp == '-') { - switch (smatch (++cp, switches)) { - case AMBIGSW: - ambigsw (cp, switches); - done (1); - case UNKWNSW: - adios (NULL, "-%s unknown", cp); - - case HELPSW: - snprintf (buf, sizeof(buf), "%s [switches] [file]", invo_name); - print_help (buf, switches, 1); - done (1); - case VERSIONSW: - print_version(invo_name); - done (1); - - case CHKSW: - case NOCHKSW: - case SNOOPSW: - vec[vecp++] = --cp; - continue; - - case DRAFTSW: - msg = draft; - continue; - - case DFOLDSW: - if (dfolder) - adios (NULL, "only one draft folder at a time!"); - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - dfolder = path (*cp == '+' || *cp == '@' ? cp + 1 : cp, - *cp != '@' ? TFOLDER : TSUBCWF); - continue; - case DMSGSW: - if (dmsg) - adios (NULL, "only one draft message at a time!"); - if (!(dmsg = *argp++) || *dmsg == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; - case NDFLDSW: - dfolder = NULL; - isdf = NOTOK; - continue; - - case ALIASW: - case CLIESW: - case SERVSW: - vec[vecp++] = --cp; - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - vec[vecp++] = cp; - continue; - } - } - if (msg) - adios (NULL, "only one draft at a time!"); - else - vec[vecp++] = msg = cp; - } - - /* allow Aliasfile: profile entry */ - if ((cp = context_find ("Aliasfile"))) { - char *dp = NULL; - - for (ap = brkstring(dp = getcpy(cp), " ", "\n"); ap && *ap; ap++) { - vec[vecp++] = "-alias"; - vec[vecp++] = *ap; - } - } - - if (msg == NULL) { -#ifdef WHATNOW - if (dfolder || (cp = getenv ("mhdraft")) == NULL || *cp == '\0') -#endif /* WHATNOW */ - cp = getcpy (m_draft (dfolder, dmsg, 1, &isdf)); - msg = vec[vecp++] = cp; - } - if ((cp = getenv ("mhdist")) - && *cp - && (distsw = atoi (cp)) - && (cp = getenv ("mhaltmsg")) - && *cp) { - if (distout (msg, cp, backup) == NOTOK) - done (1); - vec[vecp++] = "-dist"; - distsw++; - } - vec[vecp] = NULL; - - closefds (3); - - if (distsw) { - for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++) - sleep (5); - } - - switch (distsw ? child_id : OK) { - case NOTOK: - advise (NULL, "unable to fork, so checking directly..."); - case OK: - execvp (postproc, vec); - fprintf (stderr, "unable to exec "); - perror (postproc); - _exit (-1); - - default: - SIGNAL (SIGHUP, SIG_IGN); - SIGNAL (SIGINT, SIG_IGN); - SIGNAL (SIGQUIT, SIG_IGN); - SIGNAL (SIGTERM, SIG_IGN); - - status = pidwait(child_id, OK); - - unlink (msg); - if (rename (backup, msg) == NOTOK) - adios (msg, "unable to rename %s to", backup); - done (status); - } - - exit (-1); /* NOT REACHED */ + int naddrs = 0; + + for (mp=head.m_next; mp; mp=mp->m_next) { + /* skip unless both are resent or neither one is */ + if (resent != (mp->m_type&HRESENT)) { + continue; + } + if (mp->m_type & (HTO|HCC)) { + naddrs++; + printone(mp); + } + } + return naddrs; +} + +/* +** Walk through the list of addresses and print the right ones. +*/ +static int +printdcc(void) +{ + int naddrs = 0; + + for (mp=head.m_next; mp; mp=mp->m_next) { + /* skip unless both are resent or neither one is */ + if (resent != (mp->m_type&HRESENT)) { + continue; + } + if (mp->m_type & HDCC) { + if (!naddrs && (toccsw || bccsw)) { + puts(dccsep); + } + naddrs++; + printone(mp); + } + } + return naddrs; +} + +/* +** Walk through the list of addresses and print the right ones. +*/ +static int +printbcc(void) +{ + int naddrs = 0; + + for (mp=head.m_next; mp; mp=mp->m_next) { + /* skip unless both are resent or neither one is */ + if (resent != (mp->m_type&HRESENT)) { + continue; + } + if (mp->m_type & HBCC) { + if (!naddrs && (toccsw || dccsw)) { + puts(bccsep); + } + naddrs++; + printone(mp); + } + } + return naddrs; +} + + +/* +** Print one single address in appropriate form. +*/ +static void +printone(struct mailname *mp) +{ + char buf[BUFSIZ]; + + if (mp->m_host) { + snprintf(buf, sizeof buf, " %s@%s", mp->m_mbox, mp->m_host); + } else { + snprintf(buf, sizeof buf, " %s", mp->m_mbox); + } + if (alisw) { + cmd = add(buf, cmd); + } else { + puts(buf+1); + } }