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