aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Neukirchen <chneukirchen@gmail.com>2016-08-01 17:21:39 +0200
committerChristian Neukirchen <chneukirchen@gmail.com>2016-08-01 17:21:39 +0200
commit78fec302cb21c2ecb1abc613eaa3f1fb21a32c76 (patch)
treef3315322c9094eb68ee2b48f803b82bdabffcb87
parent400c6793d673c7a978178ae01d718053cdf23cb3 (diff)
downloadmblaze-78fec302cb21c2ecb1abc613eaa3f1fb21a32c76.tar.gz
add mgenmid
-rw-r--r--Makefile3
-rw-r--r--man/mgenmid.158
-rw-r--r--mgenmid.c115
3 files changed, 175 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 2a2ecec..37701d0 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
CFLAGS=-g -O1 -Wall -Wno-switch -Wextra -fstack-protector-strong -D_FORTIFY_SOURCE=2
-ALL = maddr mdeliver mdirs mflag mhdr minc mlist mmime mpick mscan msed mseq mshow msort mthread
+ALL = maddr mdeliver mdirs mflag mgenmid mhdr minc mlist mmime mpick mscan msed mseq mshow msort mthread
all: $(ALL)
@@ -8,6 +8,7 @@ maddr: maddr.o blaze822.o seq.o rfc2047.o mymemmem.o
mdeliver: mdeliver.o blaze822.o mymemmem.o
mdirs: mdirs.o
mflag: mflag.o blaze822.o seq.o mymemmem.o
+mgenmid: mgenmid.o blaze822.o seq.o mymemmem.o
mhdr: mhdr.o blaze822.o seq.o rfc2047.o mymemmem.o
minc: minc.o
mlist: mlist.o
diff --git a/man/mgenmid.1 b/man/mgenmid.1
new file mode 100644
index 0000000..8cf2d96
--- /dev/null
+++ b/man/mgenmid.1
@@ -0,0 +1,58 @@
+.Dd August 1, 2016
+.Dt MGENMID 1
+.Os
+.Sh NAME
+.Nm mgenmid
+.Nd generate a Message-ID
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+.Nm
+generates a fresh Message-ID and prints it.
+The Message-ID consists of a timestamp,
+a random value,
+and a fully qualified domain name.
+.Pp
+The fully qualified domain name is computed by:
+.Bl -enum
+.It
+Using
+.Sq Li "FQDN:"
+from
+.Pa "~/.santoku/profile"
+(if set).
+.It
+Resolving the current hostname.
+.It
+Using the host part of the address in
+.Sq Li "Local-Mailbox:"
+from
+.Pa "~/.santoku/profile"
+(if set).
+.El
+.Pp
+If these steps don't result in a fully qualified domain name,
+.Nm
+fails.
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Rs
+.%A M. Curtin
+.%A J. Zawinski
+.%D July 1998
+.%R draft-ietf-usefor-message-id-01.txt
+.%T Recommendations for generating Message IDs
+.Re
+.Sh AUTHORS
+.An Christian Neukirchen Aq Mt chneukirchen@gmail.com
+.Sh LICENSE
+.Nm
+is in the public domain.
+.Pp
+To the extent possible under law,
+the creator of this work
+has waived all copyright and related or
+neighboring rights to this work.
+.Pp
+.Lk http://creativecommons.org/publicdomain/zero/1.0/
diff --git a/mgenmid.c b/mgenmid.c
new file mode 100644
index 0000000..6122519
--- /dev/null
+++ b/mgenmid.c
@@ -0,0 +1,115 @@
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <fcntl.h>
+#include <netdb.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "blaze822.h"
+
+void
+printb36(uint64_t x)
+{
+ static char const base36[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ char outbuf[16];
+ char *o = outbuf + sizeof outbuf;
+ *o = 0;
+
+ do { *--o = base36[x % 36]; } while (x /= 36);
+ fputs(o, stdout);
+}
+
+int main()
+{
+ char hostbuf[1024];
+ char *host = 0;
+
+ char *f = blaze822_home_file(".santoku/profile");
+ struct message *config = blaze822(f);
+
+ if (config) // try FQDN: first
+ host = blaze822_hdr(config, "fqdn");
+
+ if (!host && gethostname(hostbuf, sizeof hostbuf) == 0) {
+ // termination not posix guaranteed
+ hostbuf[sizeof hostbuf - 1] = 0;
+
+ struct addrinfo hints = { .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_STREAM,
+ .ai_flags = AI_CANONNAME };
+ struct addrinfo *info;
+ if (getaddrinfo(hostbuf, 0, &hints, &info) == 0) {
+ // sanity checks: no (null), at least one dot,
+ // doesn't start with localhost.
+
+ if (info &&
+ info->ai_canonname &&
+ strchr(info->ai_canonname, '.') &&
+ strncmp(info->ai_canonname, "localhost.", 10) != 0)
+ host = info->ai_canonname;
+ }
+ }
+
+ if (!host && config) {
+ // get address part of Local-Mailbox:
+ char *disp, *addr;
+ char *from = blaze822_hdr(config, "local-mailbox");
+ while (from && (from = blaze822_addr(from, &disp, &addr)))
+ if (addr) {
+ host = strchr(addr, '@');
+ if (host) {
+ host++;
+ break;
+ }
+ }
+ }
+
+ if (!host) {
+ fprintf(stderr,
+ "mgenmid: failed to find a FQDN for the Message-ID.\n"
+ " Define 'FQDN:' or 'Local-Mailbox:' in ~/.santoku/profile\n"
+ " or add a FQDN to /etc/hosts.\n");
+ exit(1);
+ }
+
+ struct timespec tp;
+ clock_gettime(CLOCK_REALTIME, &tp);
+
+ uint64_t rnd;
+
+ int rndfd = open("/dev/urandom", O_RDONLY);
+ if (rndfd >= 0) {
+ unsigned char rndb[8];
+ if (read(rndfd, rndb, sizeof rndb) != sizeof rndb)
+ goto fallback;
+ close(rndfd);
+
+ int i;
+ for (i = 0, rnd = 0; i < 8; i++)
+ rnd = rnd*256 + rndb[i];
+ } else {
+fallback:
+ srand48(tp.tv_sec ^ tp.tv_nsec/1000 ^ getpid());
+ rnd = (lrand48() << 32) + lrand48();
+ }
+
+ rnd |= (1LL << 63); // set highest bit to force full width
+
+ putchar('<');
+ printb36(((uint64_t)tp.tv_sec << 16) + (tp.tv_nsec >> 16));
+ putchar('.');
+ printb36(rnd);
+ putchar('@');
+ fputs(host, stdout);
+ putchar('>');
+ putchar('\n');
+
+ return 0;
+}