d0a6dd9dbd2da36dc2183124fbc88c4bef24cd42
[mmh] / 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 <unistd.h>   /* for getpid() */
12 #include <sys/time.h> /* for gettimeofday() */
13 #include <stdio.h>
14
15
16 #define NMH_MESSAGE_ID_LOCALNAME 0
17 #define NMH_MESSAGE_ID_RANDOM 1
18
19 static int message_id_style = NMH_MESSAGE_ID_LOCALNAME;
20 static char message_id_[BUFSIZ];
21
22
23 /* Convert name of message id style to integer value and store it. */
24 int
25 save_message_id_style (const char *value) {
26   if (! mh_strcasecmp (value, "localname")) {
27     message_id_style = NMH_MESSAGE_ID_LOCALNAME;
28     return 0;
29   } else if (! mh_strcasecmp (value, "random")) {
30     message_id_style = NMH_MESSAGE_ID_RANDOM;
31     return 0;
32   } else {
33     return 1;
34   }
35 }
36
37
38 char *
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>";
42
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 ? "<%d-%ld.%06ld%%d@%s>" : "<%d-%ld.%06ld@%s>";
47     /* Use a sequence of digits divisible by 3 because that will
48        expand to base64 without any waste.  Must be shorter than 58,
49        see below. */
50     unsigned char rnd[12];
51
52     if (m_rand (rnd, sizeof rnd) == 0) {
53       pid_t pid;
54       struct timeval now;
55       /* All we really need is 4 * [sizeof rnd/3] + 2, as long as the
56          base64 encoding stays shorter than 76 bytes so embedded
57          newlines aren't necessary.  But use double the sizeof rnd
58          just to be safe. */
59       unsigned char rnd_base64[2 * sizeof rnd];
60       int i;
61
62       writeBase64 (rnd, sizeof rnd, rnd_base64);
63
64       for (i = strlen ((const char *) rnd_base64) - 1;
65            i > 0  &&  iscntrl (rnd_base64[i]);
66            --i) {
67         /* Remove trailing newline.  rnd_base64 had better be shorter
68            than 76 characters, so don't bother to look for embedded
69            newlines. */
70         rnd_base64[i] = '\0';
71       }
72
73       /* Neither of these can fail according to the POSIX spec. */
74       pid = getpid ();
75       gettimeofday (&now, 0);
76
77       snprintf (message_id_, sizeof message_id_, format,
78                 pid, (long) now.tv_sec, (long) now.tv_usec, rnd_base64);
79     }
80   } else {
81     /* Should never get here. */
82     adios (0, "invalid message id style \"%s\"", message_id_style);
83   }
84
85
86   return message_id_;
87 }