]> diplodocus.org Git - nmh/blob - sbr/message_id.c
Alter mh-chart(7)'s NAME to be lowercase.
[nmh] / sbr / message_id.c
1 /*
2 * message-id.c -- construct the body of a Message-ID or Content-ID
3 * header field
4 *
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.
8 */
9
10 #include <h/mh.h>
11 #include <sys/time.h> /* for gettimeofday() */
12
13
14 static enum {
15 NMH_MESSAGE_ID_LOCALNAME,
16 NMH_MESSAGE_ID_RANDOM
17 } message_id_style = NMH_MESSAGE_ID_LOCALNAME;
18 static char message_id_[BUFSIZ];
19
20
21 /* Convert name of message id style to integer value and store it. */
22 int
23 save_message_id_style (const char *value) {
24 if (! strcasecmp (value, "localname")) {
25 message_id_style = NMH_MESSAGE_ID_LOCALNAME;
26 return 0;
27 }
28 if (! strcasecmp (value, "random")) {
29 message_id_style = NMH_MESSAGE_ID_RANDOM;
30 return 0;
31 }
32 return 1;
33 }
34
35
36 char *
37 message_id (time_t tclock, int content_id) {
38 switch (message_id_style) {
39 case NMH_MESSAGE_ID_LOCALNAME: {
40 char *format = content_id ? "<%d.%ld.%%d@%s>" : "<%d.%ld@%s>";
41
42 snprintf (message_id_, sizeof message_id_, format,
43 (int) getpid (), (long) tclock, LocalName (1));
44
45 break;
46 }
47
48 case NMH_MESSAGE_ID_RANDOM: {
49 char *format = content_id
50 ? "<%d-%ld.%06ld%%d@%.*s.%.*s.%.*s>"
51 : "<%d-%ld.%06ld@%.*s.%.*s.%.*s>";
52 /* Use a sequence of digits divisible by 3 because that will
53 expand to base64 without any waste. Must be shorter than 58,
54 see below. */
55 unsigned char rnd[9];
56 /* The part after the '@' is divided into thirds. The base64
57 encoded string will be 4/3 the size of rnd. */
58 size_t one_third = sizeof rnd * 4/3/3;
59
60 if (m_rand (rnd, sizeof rnd) == 0) {
61 struct timeval now;
62 /* All we really need is 4 * [sizeof rnd/3] + 2, as long as
63 the base64 encoding stays shorter than 76 bytes so embedded
64 newlines aren't necessary. But use double the sizeof rnd
65 just to be safe. */
66 unsigned char rnd_base64[2 * sizeof rnd];
67 unsigned char *cp;
68 int i;
69
70 writeBase64 (rnd, sizeof rnd, rnd_base64);
71
72 for (i = strlen ((const char *) rnd_base64) - 1;
73 i > 0 && iscntrl (rnd_base64[i]);
74 --i) {
75 /* Remove trailing newline. rnd_base64 had better be
76 shorter than 76 characters, so don't bother to look for
77 embedded newlines. */
78 rnd_base64[i] = '\0';
79 }
80
81 /* Try to make the base64 string look a little more like a
82 hostname by replacing + with - and / with _. */
83 for (cp = rnd_base64; *cp; ++cp) {
84 if (*cp == '+') {
85 *cp = '-';
86 } else if (*cp == '/') {
87 *cp = '_';
88 }
89 }
90
91 /* gettimeofday() and getpid() shouldn't fail on POSIX platforms. */
92 gettimeofday (&now, 0);
93
94 /* The format string inserts a couple of dots, for the benefit
95 of spam filters that want to see a message id with a final
96 part that resembles a hostname. */
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]);
102 }
103
104 break;
105 }
106 }
107
108 return message_id_;
109 }