/* * Copyright (C) 2021 Kevin J. McCarthy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #if HAVE_CONFIG_H # include "config.h" #endif #include "mutt.h" #include "mutt_random.h" static char MsgIdPfx = 'A'; typedef struct msg_id_data { time_t now; struct tm tm; const char *fqdn; } MSG_ID_DATA; static const char *id_format_str (char *dest, size_t destlen, size_t col, int cols, char op, const char *src, const char *fmt, const char *ifstring, const char *elsestring, void *data, format_flag flags) { MSG_ID_DATA *id_data = (MSG_ID_DATA *)data; char tmp[STRING]; unsigned char r_raw[3]; unsigned char r_out[4 + 1]; unsigned char z_raw[12]; /* 32 bit timestamp, plus 64 bit randomness */ unsigned char z_out[16 + 1]; switch (op) { case 'r': mutt_random_bytes ((char *)r_raw, sizeof(r_raw)); mutt_to_base64 (r_out, r_raw, sizeof(r_raw), sizeof(r_out)); mutt_format_s (dest, destlen, fmt, (const char *)r_out); break; case 'x': /* hex encoded random byte */ mutt_random_bytes ((char *)r_raw, sizeof(r_raw[0])); snprintf (dest, destlen, "%02x", r_raw[0]); break; case 'z': /* Convert the four least significant bytes of our timestamp and put it in localpart, with proper endianness (for humans) taken into account. */ for (int i = 0; i < 4; i++) z_raw[i] = (uint8_t) (id_data->now >> (3-i)*8u); mutt_random_bytes ((char *)z_raw + 4, sizeof(z_raw) - 4); mutt_to_base64 (z_out, z_raw, sizeof(z_raw), sizeof(z_out)); mutt_format_s (dest, destlen, fmt, (const char *)z_out); break; case 'Y': snprintf (tmp, sizeof (tmp), "%%%sd", fmt); snprintf (dest, destlen, tmp, id_data->tm.tm_year + 1900); break; case 'm': snprintf (tmp, sizeof (tmp), "%%%sd", fmt); snprintf (dest, destlen, tmp, id_data->tm.tm_mon + 1); break; case 'd': snprintf (tmp, sizeof (tmp), "%%%sd", fmt); snprintf (dest, destlen, tmp, id_data->tm.tm_mday); break; case 'H': snprintf (tmp, sizeof (tmp), "%%%sd", fmt); snprintf (dest, destlen, tmp, id_data->tm.tm_hour); break; case 'M': snprintf (tmp, sizeof (tmp), "%%%sd", fmt); snprintf (dest, destlen, tmp, id_data->tm.tm_min); break; case 'S': snprintf (tmp, sizeof (tmp), "%%%sd", fmt); snprintf (dest, destlen, tmp, id_data->tm.tm_sec); break; case 'c': snprintf (dest, destlen, "%c", MsgIdPfx); MsgIdPfx = (MsgIdPfx == 'Z') ? 'A' : MsgIdPfx + 1; break; case 'p': snprintf (tmp, sizeof (tmp), "%%%su", fmt); snprintf (dest, destlen, tmp, (unsigned int)getpid ()); break; case 'f': mutt_format_s (dest, destlen, fmt, id_data->fqdn); break; } return (src); } char *mutt_gen_msgid (void) { MSG_ID_DATA id_data; BUFFER *buf, *tmp; const char *fmt; char *rv; id_data.now = time (NULL); memcpy (&id_data.tm, gmtime (&id_data.now), sizeof(id_data.tm)); if (!(id_data.fqdn = mutt_fqdn(0))) id_data.fqdn = NONULL(Hostname); fmt = MessageIdFormat; if (!fmt) fmt = "<%z@%f>"; buf = mutt_buffer_pool_get (); mutt_FormatString (buf->data, buf->dsize, 0, buf->dsize, fmt, id_format_str, &id_data, 0); mutt_buffer_fix_dptr (buf); /* this is hardly a thorough check, but at least make sure * we have the angle brackets. */ if (!mutt_buffer_len (buf) || (*buf->data != '<') || (*(buf->dptr - 1) != '>')) { tmp = mutt_buffer_pool_get (); if (!mutt_buffer_len (buf) || *buf->data != '<') mutt_buffer_addch (tmp, '<'); mutt_buffer_addstr (tmp, mutt_b2s (buf)); if (!mutt_buffer_len (buf) || *(buf->dptr - 1) != '>') mutt_buffer_addch (tmp, '>'); mutt_buffer_strcpy (buf, mutt_b2s (tmp)); mutt_buffer_pool_release (&tmp); } rv = safe_strdup (mutt_b2s (buf)); mutt_buffer_pool_release (&buf); return rv; }