X-Git-Url: http://git.marmaro.de/?p=mmh;a=blobdiff_plain;f=uip%2Fwhom.c;h=ef0b684d2a011817a34dd01cc7c86ba3b26190a6;hp=b68e3ae5a9a3b5520a69256a7a395f5f1137e477;hb=6e9577f324bef90765a5edc02044eb111ec48072;hpb=a485ed478abbd599d8c9aab48934e7a26733ecb1 diff --git a/uip/whom.c b/uip/whom.c index b68e3ae..ef0b684 100644 --- a/uip/whom.c +++ b/uip/whom.c @@ -1,193 +1,407 @@ /* - * whom.c -- report to whom a message would be sent - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** 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 +#define VERSIONSW 0 + { "Version", 0 }, +#define HELPSW 1 { "help", 0 }, -#define CLIESW 9 - { "client host", -6 }, -#define SERVSW 10 - { "server host", -6 }, -#define SNOOPSW 11 - { "snoop", -5 }, -#define PORTSW 15 - { "port server port name/number", 4 }, +#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 } }; +char *version=VERSION; + +#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) { - 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 + int naddrs=0, n; + char *cp; + char buf[BUFSIZ], **argp; + char **arguments; + char *folder = NULL; + FILE *in; + struct msgs_array msgs = {0}; + struct msgs_array files = {0}; + size_t filep; + setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); + invo_name = mhbasename(argv[0]); /* read user profile/context */ context_read(); - arguments = getarguments (invo_name, argc, argv, 1); + 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: - case PORTSW: - vec[vecp++] = --cp; - if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - vec[vecp++] = cp; - continue; + 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 (msg) - adios (NULL, "only one draft at a time!"); - else - vec[vecp++] = msg = cp; + if (*cp == '+' || *cp == '@') { + if (folder) { + adios(EX_USAGE, NULL, "only one folder at a time!"); + } else { + folder = mh_xstrdup(expandfol(cp)); + } + } else { + app_msgarg(&msgs, cp); + } + } + if (!msgs.size) { + 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"); + } + if (parse_msgs(&msgs, folder, &files) < 0) { + exit(EX_IOERR); + } + for (filep = 0; filep < files.size; filep++) { + process(files.msgs[filep]); } - /* 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; + 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); } + mh_free0(&cmd); + naddrs += n; - 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; + 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); } - if ((cp = getenv ("mhdist")) - && *cp - && (distsw = atoi (cp)) - && (cp = getenv ("mhaltmsg")) - && *cp) { - if (distout (msg, cp, backup) == NOTOK) - done (1); - vec[vecp++] = "-dist"; - distsw++; + mh_free0(&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); } - vec[vecp] = NULL; + mh_free0(&cmd); + naddrs += n; + + return naddrs ? 0 : 1; +} + + +static int +process(char *file) +{ + enum state state; + struct field f = {{0}}; + int compnum; + FILE *in; - closefds (3); - if (distsw) { - for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++) - sleep (5); + if ((in = fopen(file, "r")) == NULL) { + adios(EX_IOERR, file, "unable to open"); } - 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); + for (compnum=1, state=FLD2;; compnum++) { + switch (state = m_getfld2(state, &f, in)) { + case LENERR2: + state = FLD2; + /* FALL */ + case FLD2: + proc_hdr(f.name, f.value); + continue; + + case BODY2: + case FILEEOF2: + break; + + case FMTERR2: + advise(NULL, "message format error in component #%d", compnum); + continue; + + case IOERR2: + adios(EX_DATAERR, NULL, "message format error in component #%d", + compnum); default: - SIGNAL (SIGHUP, SIG_IGN); - SIGNAL (SIGINT, SIG_IGN); - SIGNAL (SIGQUIT, SIG_IGN); - SIGNAL (SIGTERM, SIG_IGN); + adios(EX_SOFTWARE, NULL, "getfld() returned %d", state); + } + break; + } + fclose(in); + return 0; +} + - status = pidwait(child_id, OK); +/* +** 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; - unlink (msg); - if (rename (backup, msg) == NOTOK) - adios (msg, "unable to rename %s to", backup); - done (status); + 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) +{ + 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; +} + - return 0; /* dead code to satisfy the compiler */ +/* +** 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); + } }