2 * message-id.c -- construct the body of a Message-ID or Content-ID
5 * This code is Copyright (c) 2012, by the authors of nmh. See the
6 * COPYRIGHT file in the root directory of the nmh distribution for
7 * complete copyright information.
11 #include <unistd.h> /* for getpid() */
12 #include <sys/time.h> /* for gettimeofday() */
16 #define NMH_MESSAGE_ID_LOCALNAME 0
17 #define NMH_MESSAGE_ID_RANDOM 1
19 static int message_id_style = NMH_MESSAGE_ID_LOCALNAME;
20 static char message_id_[BUFSIZ];
23 /* Convert name of message id style to integer value and store it. */
25 save_message_id_style (const char *value) {
26 if (! mh_strcasecmp (value, "localname")) {
27 message_id_style = NMH_MESSAGE_ID_LOCALNAME;
29 } else if (! mh_strcasecmp (value, "random")) {
30 message_id_style = NMH_MESSAGE_ID_RANDOM;
39 message_id (time_t tclock, int content_id) {
40 if (message_id_style == NMH_MESSAGE_ID_LOCALNAME) {
41 char *format = content_id ? "<%d.%ld.%%d@%s>" : "<%d.%ld@%s>";
43 snprintf (message_id_, sizeof message_id_, format,
44 (int) getpid (), (long) tclock, LocalName (1));
45 } else if (message_id_style == NMH_MESSAGE_ID_RANDOM) {
46 char *format = content_id
47 ? "<%d-%ld.%06ld%%d@%.*s.%.*s.%.*s>"
48 : "<%d-%ld.%06ld@%.*s.%.*s.%.*s>";
49 /* Use a sequence of digits divisible by 3 because that will
50 expand to base64 without any waste. Must be shorter than 58,
53 /* The part after the '@' is divided into thirds. The base64
54 encoded string will be 4/3 the size of rnd. */
55 size_t one_third = sizeof rnd * 4/3/3;
57 if (m_rand (rnd, sizeof rnd) == 0) {
59 /* All we really need is 4 * [sizeof rnd/3] + 2, as long as the
60 base64 encoding stays shorter than 76 bytes so embedded
61 newlines aren't necessary. But use double the sizeof rnd
63 unsigned char rnd_base64[2 * sizeof rnd];
66 writeBase64 (rnd, sizeof rnd, rnd_base64);
68 for (i = strlen ((const char *) rnd_base64) - 1;
69 i > 0 && iscntrl (rnd_base64[i]);
71 /* Remove trailing newline. rnd_base64 had better be shorter
72 than 76 characters, so don't bother to look for embedded
79 /* Try to make the base64 string look a little more like a
80 hostname by replacing + with - and / with _. Also, the
81 format string inserts a couple of dots. */
82 for (cp = (char *) rnd_base64; *cp; ++cp) {
84 if ((plus = strchr (cp, '+'))) {
86 } else if ((slash = strchr (cp, '/'))) {
94 /* gettimeofday() and getpid() shouldn't fail on POSIX platforms. */
95 gettimeofday (&now, 0);
97 snprintf (message_id_, sizeof message_id_, format,
98 getpid (), (long) now.tv_sec, (long) now.tv_usec,
99 one_third, rnd_base64,
100 one_third, &rnd_base64[one_third],
101 one_third, &rnd_base64[2*one_third]);
104 /* Should never get here. */
105 adios (0, "invalid message id style \"%s\"", message_id_style);