summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--man/mhdr.137
-rwxr-xr-xmcomp22
-rw-r--r--mhdr.c188
3 files changed, 186 insertions, 61 deletions
diff --git a/man/mhdr.1 b/man/mhdr.1
index 31648fc..48672fe 100644
--- a/man/mhdr.1
+++ b/man/mhdr.1
@@ -1,4 +1,4 @@
-.Dd July 22, 2016
+.Dd July 28, 2016
 .Dt MHDR 1
 .Os
 .Sh NAME
@@ -6,7 +6,10 @@
 .Nd show mail headers
 .Sh SYNOPSIS
 .Nm
-.Op Fl Ar header
+.Op Fl h Ar header
+.Op Fl d
+.Op Fl M
+.Op Fl A | Fl D
 .Op Ar msgs\ ...
 .Sh DESCRIPTION
 .Nm
@@ -24,16 +27,36 @@ will default to the current message.
 .Pp
 The options are as follows:
 .Bl -tag -width Ds
-.It Fl Ar header
-Only print the value of the header
-.Sq Ar header Ns Li \&: .
-.Pp
-By default, print all headers in normalized form (lowercase and unfolded).
+.It Fl h Ar header
+Only print the values of the headers in the colon-separated list
+.Ar header .
+.It Fl d
+Decode the headers according to RFC 2047.
+.It Fl M
+Search for all occurrences of the headers
+(default: only the first).
+.It Fl A
+Scan for RFC 5322 addresses in the headers and print them line by line.
+.It Fl D
+Assume header contains RFC 5322 date and print as Unix timestamp.
 .El
 .Sh EXIT STATUS
 .Ex -std
 .Sh SEE ALSO
 .Xr mmsg 7
+.Rs
+.%A N. Freed
+.%A N. Borenstein
+.%B MIME (Multipurpose Internet Mail Extensions) Part Three: Message Header Extensions for Non-ASCII Text
+.%R RFC 2047
+.%D November 1996
+.Re
+.Rs
+.%A P. Resnick (ed.)
+.%B Internet Message Format
+.%R RFC 5322
+.%D October 2008
+.Re
 .Sh AUTHORS
 .An Christian Neukirchen Aq Mt chneukirchen@gmail.com
 .Sh LICENSE
diff --git a/mcomp b/mcomp
index c8d41ac..66980f4 100755
--- a/mcomp
+++ b/mcomp
@@ -19,7 +19,7 @@ draft="snd.$i"
 		echo "Cc: "
 		echo "Bcc: "
 		echo "Subject: "
-		from=$(mhdr -local-mailbox ~/.santoku/profile)
+		from=$(mhdr -h local-mailbox ~/.santoku/profile)
 		[ "$from" ] && echo "From: $from"
 		cat ~/.santoku/headers 2>/dev/null
 		echo
@@ -28,30 +28,30 @@ draft="snd.$i"
 	*mrepl*)
 		[ "$#" -eq 0 ] && set -- .
 		# XXX reply-all
-		echo "To: $(mhdr -from "$1")"
+		echo "To: $(mhdr -h from "$1")"
 		echo "Cc: "
 		echo "Bcc: "
-		s=$(mhdr -subject "$1")
+		s=$(mhdr -d -h subject "$1")
 		os=
 		while [ "$os" != "$s" ]; do
 			os=$s
-			s=${s% }
-			s=${s%[Rr][Ee]:}
-			s=${s%[Aa][Ww]:}
-			s=${s%[Ff][Ww][Dd]:}
+			s=${s# }
+			s=${s#[Rr][Ee]:}
+			s=${s#[Aa][Ww]:}
+			s=${s#[Ff][Ww][Dd]:}
 		done
 		echo "Subject: Re: $s"
 		cat ~/.santoku/headers 2>/dev/null
 		echo -n "References:"
 		{
-			mhdr -references "$1"
-			mhdr -message-id "$1"
+			mhdr -h references "$1"
+			mhdr -h message-id "$1"
 		} | sed 's/^[^<]*//g;s/[^>]*$//g;s/>[^<]*</>\n</g' |
 			uniq | sed 's/^/ /'
-		echo "In-Reply-To: $(mhdr -message-id "$1")"
+		echo "In-Reply-To: $(mhdr -h message-id "$1")"
 		echo
 
-		echo "$(mhdr -from "$1") wrote:"
+		echo "$(mhdr -d -h from "$1") wrote:"
 		mshow -R "$1" |
 			sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' |
 			sed 's/^/> /'
diff --git a/mhdr.c b/mhdr.c
index f177c5e..0820c85 100644
--- a/mhdr.c
+++ b/mhdr.c
@@ -11,22 +11,11 @@
 
 #include "blaze822.h"
 
-static size_t l;
-static char *hdr;
-
-void
-header(char *file)
-{
-	struct message *msg;
-
-	msg = blaze822(file);
-	if (!msg)
-		return;
-
-	char *v = blaze822_hdr_(msg, hdr, l);
-	if (v)
-		printf("%s\n", v);
-}
+static char *hflag;
+static int Aflag;
+static int Dflag;
+static int Mflag;
+static int dflag;
 
 static void
 printhdr(char *hdr)
@@ -43,47 +32,160 @@ printhdr(char *hdr)
 }
 
 void
-headerall(char *file)
+headerall(struct message *msg)
+{
+	char *h = 0;
+	while ((h = blaze822_next_header(msg, h))) {
+		if (dflag) {
+			char d[4096];
+			blaze822_decode_rfc2047(d, h, sizeof d, "UTF-8");
+			printhdr(d);
+		} else {
+			printhdr(h);
+		}
+	}
+
+	blaze822_free(msg);
+}
+
+void
+print_addresses(char *s)
+{
+	char *disp, *addr;
+	while ((s = blaze822_addr(s, &disp, &addr))) {
+		if (disp && addr) {
+			if (dflag) {
+				char d[4096];
+				blaze822_decode_rfc2047(d, disp, sizeof d,
+				    "UTF-8");
+				printf("%s <%s>\n", d, addr);
+			} else {
+				printf("%s <%s>\n", disp, addr);
+			}
+		} else if (addr) {
+			printf("%s\n", addr);
+		}
+	}
+}
+
+void
+print_date(char *s)
+{
+	time_t t = blaze822_date(s);
+	if (t == -1)
+		return;
+	printf("%ld\n", t);
+}
+
+void
+print_decode_header(char *s)
+{
+	char d[4096];
+	blaze822_decode_rfc2047(d, s, sizeof d, "UTF-8");
+	printf("%s\n", d);
+}
+
+void
+print_header(char *v)
+{
+	if (Aflag)
+		print_addresses(v);
+	else if (Dflag)
+		print_date(v);
+	else if (dflag)
+		print_decode_header(v);
+	else
+		printf("%s\n", v);
+}
+
+void
+headermany(struct message *msg)
+{
+	char *hdr = 0;
+	while ((hdr = blaze822_next_header(msg, hdr))) {
+		char *h = hflag;
+		while (*h) {
+			char *n = strchr(h, ':');
+			if (n)
+				*n = 0;
+
+			size_t l = strlen(h);
+			if (strncmp(hdr, h, l) == 0 && hdr[l] == ':') {
+				hdr += l + 1;
+				while (*hdr == ' ' || *hdr == '\t')
+					hdr++;
+				print_header(hdr);
+			}
+
+			if (n) {
+				*n = ':';
+				h = n + 1;
+			} else {
+				break;
+			}
+		}
+	}
+
+	blaze822_free(msg);
+}
+
+void
+header(char *file)
 {
 	struct message *msg;
 
+	while (*file == ' ' || *file == '\t')
+		file++;
+
 	msg = blaze822(file);
 	if (!msg)
 		return;
 
-	char *h = 0;
-	while ((h = blaze822_next_header(msg, h))) {
-		char d[4096];
-		blaze822_decode_rfc2047(d, h, sizeof d, "UTF-8");
-
-		printhdr(d);
+	if (!hflag)
+		return headerall(msg);
+	if (Mflag)
+		return headermany(msg);
+
+	char *h = hflag;
+	while (*h) {
+		char *n = strchr(h, ':');
+		if (n)
+			*n = 0;
+		char *v = blaze822_chdr(msg, h);
+		if (v)
+			print_header(v);
+		if (n) {
+			*n = ':';
+			h = n + 1;
+		} else {
+			break;
+		}
 	}
+
+	blaze822_free(msg);
 }
 
 int
 main(int argc, char *argv[])
 {
-	void (*cb)(char *) = headerall;
-
-	if (argc >= 2 && argv[1][0] == '-') {
-		l = strlen(argv[1])+1;
-		hdr = malloc(l);
-		hdr[0] = 0;
-		char *s = hdr+1;
-		char *t = argv[1]+1;
-		while (*t)
-			*s++ = tolower(*t++);
-		*s = ':';
-
-		cb = header;
-		argc--;
-		argv++;
-	}
-
-	if (argc == 1 && isatty(0))
-		blaze822_loop1(".", cb);
+	int c;
+	while ((c = getopt(argc, argv, "h:ADMdv)) != -1)
+		switch(c) {
+		case 'h': hflag = optarg; break;
+		case 'A': Aflag = 1; break;
+		case 'D': Dflag = 1; break;
+		case 'M': Mflag = 1; break;
+		case 'd': dflag = 1; break;
+		default:
+			fprintf(stderr,
+"Usage: mhdr [-h header] [-d] [-M] [-A|-D] [msgs...]\n");
+			exit(1);
+		}
+
+	if (argc == optind && isatty(0))
+		blaze822_loop1(".", header);
 	else
-		blaze822_loop(argc-1, argv+1, cb);
+		blaze822_loop(argc-optind, argv+optind, header);
 	
 	return 0;
 }