Re-added whom(1). This implementation is written from scratch.
authormarkus schnalke <meillo@marmaro.de>
Fri, 6 Jul 2012 15:51:37 +0000 (17:51 +0200)
committermarkus schnalke <meillo@marmaro.de>
Fri, 6 Jul 2012 15:51:37 +0000 (17:51 +0200)
This new version of whom(1) is quite different to the old one,
yet it serves the same purpose: listing the recipients of a message.
It still misses the ability to process +folder and msgs arguments.
As this implementation is new and not much practically tested,
it may change in the future, if flaws appear.

man/Makefile.in
man/whom.man1 [new file with mode: 0644]
uip/Makefile.in
uip/whom.c [new file with mode: 0644]

index cf79c47..5b34a34 100644 (file)
@@ -54,7 +54,7 @@ MAN1SRC = ali. anno. burst. comp. dist. flist. flists. folder. folders.    \
        mhmail. mhparam. mhpath. mhstore. new. fnext.       \
        fprev. unseen. next. packf. pick. prev. prompter. rcvdist. rcvpack. \
        rcvstore. refile. repl. rmf. rmm. scan. send. sendfiles.    \
-       show. slocal. sortm. whatnow.
+       show. slocal. sortm. whatnow. whom.
 
 MAN5SRC = mh-alias. mh-format. mh-mail. mh-profile. mh-tailor.
 
diff --git a/man/whom.man1 b/man/whom.man1
new file mode 100644 (file)
index 0000000..718ef2e
--- /dev/null
@@ -0,0 +1,83 @@
+.\"
+.\" %nmhwarning%
+.\"
+.TH WHOM %manext1% "%nmhdate%" MH.6.8 [%nmhversion%]
+.SH NAME
+whom \- report to whom a message would go
+.SH SYNOPSIS
+.HP 5
+.na
+.B whom
+.RB [ \-tocc " | " \-notocc ]
+.RB [ \-bcc " | " \-nobcc ]
+.RB [ \-alias " | " \-noalias ]
+.RB [ \-Version ]
+.RB [ \-help ]
+.IR file ...
+.ad
+.SH DESCRIPTION
+.B Whom
+is used to list the recipient addresses in the headers of a message.
+.PP
+Per default,
+.B whom
+lists both, sighted and hidden, recipients.
+The
+.BR \-notocc
+option suppresses the listing of sighted recipients.
+The
+.BR \-nobcc
+option suppresses the listing of hidden recipients.
+If both kinds of recipients are requested, they are separated by a
+line similar to ``\0==BCC==''.
+The actual separator may change, but the regular expression
+/^[\0\\t].*BCC/ should always match.
+.PP
+With
+.BR \-alias ,
+aliases for all recipients are expanded, according to the
+alias files given by the `Aliasfile:' profile entry.
+This is somehow similar to running:
+
+.RS 5
+.nf
+ali `whom /path/to/msg`
+.fi
+.RE
+
+.SH FILES
+.fc ^ ~
+.nf
+.ta \w'%etcdir%/ExtraBigFileName  'u
+^$HOME/.mmh/profile~^The user profile
+.fi
+
+.SH "PROFILE COMPONENTS"
+.fc ^ ~
+.nf
+.ta 2.4i
+.ta \w'ExtraBigProfileName  'u
+^Path:~^To determine the user's mail storage
+^Aliasfile:~^For default alias files
+.fi
+
+.SH "SEE ALSO"
+mh\-alias(5), spost(8)
+
+.SH DEFAULTS
+.nf
+.RB ` \-tocc '
+.RB ` \-bcc '
+.RB ` \-alias '
+.fi
+
+.SH CONTEXT
+None
+
+.SH BUGS
+.B whom
+does not (yet) accept
+.I msg
+and
+.I +folder
+arguments.
index 04df405..f0c258e 100644 (file)
@@ -51,7 +51,7 @@ CMDS = ali anno burst comp dist flist folder forw mmh mark \
        mhbuild mhl \
        mhlist mhmail mhparam mhpath mhstore new packf pick \
        print-mimetype prompter rcvdist rcvpack rcvstore refile repl rmf \
-       rmm scan send sendfiles show slocal sortm spost whatnow
+       rmm scan send sendfiles show slocal sortm spost whatnow whom
 
 # commands that are links to other commands
 LCMDS = flists folders next prev fnext fprev unseen
@@ -73,7 +73,7 @@ SRCS = ali.c aliasbr.c anno.c ap.c burst.c comp.c \
        prompter.c rcvdist.c rcvpack.c rcvstore.c \
        refile.c repl.c rmf.c rmm.c scan.c scansbr.c send.c \
        sendfiles.sh slocal.c sortm.c spost.c termsbr.c \
-       whatnow.c whatnowproc.c
+       whatnow.c whatnowproc.c whom.c
 
 # auxiliary files
 AUX = Makefile.in
@@ -220,6 +220,9 @@ spost: spost.o aliasbr.o $(LOCALLIBS)
 whatnow: whatnow.o $(LOCALLIBS)
        $(LINK) whatnow.o $(LINKLIBS)
 
+whom: whom.o $(LOCALLIBS)
+       $(LINK) whom.o $(LINKLIBS)
+
 # ========== DEPENDENCIES FOR INSTALLING ==========
 
 # install everything
diff --git a/uip/whom.c b/uip/whom.c
new file mode 100644 (file)
index 0000000..0451699
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+** 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 <h/mh.h>
+#include <h/addrsbr.h>
+#include <h/fmt_scan.h>
+#include <h/utils.h>
+
+static struct swit switches[] = {
+#define VERSIONSW 0
+       { "Version", 0 },
+#define HELPSW 1
+       { "help", 0 },
+#define TOCCSW 2
+       { "tocc", 0 },
+#define NTOCCSW 3
+       { "notocc", 2 },
+#define BCCSW 4
+       { "bcc", 0 },
+#define NBCCSW 5
+       { "nobcc", 2 },
+#define ALISW 6
+       { "alias", 0 },
+#define NALISW 7
+       { "noalias", 2 },
+       { NULL, 0 }
+};
+
+
+#define NFILES 32
+
+#define HRESENT (1<<1)
+#define HTO (1<<2)
+#define HCC (1<<3)
+#define HBCC (1<<4)
+
+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 bccsw = 1;  /* list hidden recipients */
+static int alisw = 1;  /* expand aliases on rcpt addrs */
+
+static char *separator = "\t==BCC==";
+
+
+/*
+** static prototypes
+*/
+static int process(char *);
+static void proc_hdr(char *, char *);
+static int print(void);
+static int printbcc(void);
+static void printone(struct mailname *);
+
+
+int
+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);
+                               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 TOCCSW:
+                               toccsw = 1;
+                               continue;
+                       case NTOCCSW:
+                               toccsw = 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(NULL, "too many files (more than %d)",
+                                       NFILES);
+               } else {
+                       files[filep++] = cp;
+               }
+       }
+       files[filep] = NULL;
+       if (!filep) {
+               adios(NULL, "usage: %s [switches] file ...", invo_name);
+       }
+       if (!toccsw && !bccsw) {
+               adios(NULL, "give -tocc or -bcc or both to produce output");
+       }
+       for (filep=0; files[filep]; filep++) {
+               process(files[filep]);
+       }
+
+       cmd = add("ali -list", NULL);
+       if ((n=print()) && alisw) {
+               if (!(in = popen(cmd, "r"))) {
+                       adios("popen", "unable to");
+               }
+               while (fgets(buf, sizeof buf, in)) {
+                       fputs(buf, stdout);
+               }
+               pclose(in);
+       }
+       free(cmd);
+       naddrs += n;
+
+       if (toccsw && bccsw) {
+               puts(separator);
+       }
+
+       cmd = add("ali -list", NULL);
+       if ((n=printbcc()) && alisw) {
+               if (!(in = popen(cmd, "r"))) {
+                       adios("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)
+{
+        int state, compnum;
+       char *cp;
+       char buf[BUFSIZ], name[NAMESZ];
+       FILE *in;
+
+
+       if ((in = fopen(file, "r")) == NULL) {
+               adios(file, "unable to open");
+       }
+
+       for (compnum = 1, state = FLD;;) {
+               switch (state = m_getfld(state, name, buf, sizeof(buf), in)) {
+               case FLD:
+                       compnum++;
+                       proc_hdr(name, buf);
+                       continue;
+
+               case FLDPLUS:
+                       compnum++;
+                       cp = add(buf, cp);
+                       while (state == FLDPLUS) {
+                               state = m_getfld(state, name, buf,
+                                               sizeof(buf), in);
+                               cp = add(buf, cp);
+                       }
+                       proc_hdr(name, cp);
+                       free(cp);
+                       continue;
+
+               case BODY:
+               case FILEEOF:
+                       break;
+
+               case LENERR:
+               case FMTERR:
+                       adios(NULL, "message format error in component #%d",
+                                       compnum);
+
+               default:
+                       adios(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, "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-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&HBCC) && !bccsw) {
+               return;
+       }
+
+       while ((cp = getname(val))) {
+               if (!(mp->m_next = getm(cp, NULL, 0, AD_NAME, NULL))) {
+                       adios(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
+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) {
+                       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);
+       }
+}