message-id.c revision bcb4e51a409d94ae670de96afb8483a4f7855294
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include "lib.h"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include "str.h"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include "rfc822-parser.h"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include "message-id.h"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic bool get_untokenized_msgid(const char **msgid_p, string_t *msgid)
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen{
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen struct rfc822_parser_context parser;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen int ret;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen rfc822_parser_init(&parser, (const unsigned char *)*msgid_p,
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen strlen(*msgid_p), NULL);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen /*
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen id-left = dot-atom-text / no-fold-quote / obs-id-left
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen id-right = dot-atom-text / no-fold-literal / obs-id-right
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen no-fold-quote = DQUOTE *(qtext / quoted-pair) DQUOTE
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen no-fold-literal = "[" *(dtext / quoted-pair) "]"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen */
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen rfc822_skip_lwsp(&parser);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen if (*parser.data == '"')
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen ret = rfc822_parse_quoted_string(&parser, msgid);
1346b1f0388f4100bb3c2a2bb23bc881769c020cTom Gundersen else
f5be560181d092c5f52a2b819aedcd48220f36abTom Gundersen ret = rfc822_parse_dot_atom(&parser, msgid);
5c1d3fc93d91384bbac29adf01074fa4375317eaUmut Tezduyar Lindskog if (ret <= 0)
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen return FALSE;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen if (*parser.data != '@')
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen return FALSE;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen str_append_c(msgid, '@');
06f021a8048583d66202e3ac5cd0a12386d33ac2Tom Gundersen parser.data++;
2cc412b59353576cece2d5b30c6a39c70552f0a0Tom Gundersen rfc822_skip_lwsp(&parser);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
aba496a58acf9d9c61314de71353550e579f85eeUmut Tezduyar Lindskog if (rfc822_parse_dot_atom(&parser, msgid) <= 0)
aba496a58acf9d9c61314de71353550e579f85eeUmut Tezduyar Lindskog return FALSE;
1a436809498faf6486815baa0338fb6b8e5def07Tom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen if (*parser.data != '>')
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen return FALSE;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen *msgid_p = (const char *)parser.data + 1;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen return TRUE;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen}
52433f6b65eccd1c54606dde999610640f3458acTom Gundersen
02b59d57e0c08231645120077f651151f5bb2babTom Gundersenstatic void strip_lwsp(char *str)
52433f6b65eccd1c54606dde999610640f3458acTom Gundersen{
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen /* @UNSAFE */
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen char *dest;
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen
52433f6b65eccd1c54606dde999610640f3458acTom Gundersen /* find the first lwsp */
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen while (*str != ' ' && *str != '\t' && *str != '\r' && *str != '\n') {
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen if (*str == '\0')
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersen return;
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersen str++;
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersen }
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersen
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersen for (dest = str; *str != '\0'; str++) {
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersen if (*str != ' ' && *str != '\t' && *str != '\r' && *str != '\n')
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersen *dest++ = *str;
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersen }
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersen *dest = '\0';
1a436809498faf6486815baa0338fb6b8e5def07Tom Gundersen}
52433f6b65eccd1c54606dde999610640f3458acTom Gundersen
52433f6b65eccd1c54606dde999610640f3458acTom Gundersenconst char *message_id_get_next(const char **msgid_p)
54abf461d6b10dc270c4bb2aeac65f240ff1c5cdTom Gundersen{
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersen const char *msgid = *msgid_p;
7951dea20911969287878e6897b3eca348721adeSusant Sahani const char *p;
7951dea20911969287878e6897b3eca348721adeSusant Sahani string_t *str = NULL;
7951dea20911969287878e6897b3eca348721adeSusant Sahani bool found_at;
10142d75cce10a92889cc11b7b1af07fecc78c5dSusant Sahani
52433f6b65eccd1c54606dde999610640f3458acTom Gundersen if (*msgid_p == NULL)
52433f6b65eccd1c54606dde999610640f3458acTom Gundersen return NULL;
1a436809498faf6486815baa0338fb6b8e5def07Tom Gundersen
52433f6b65eccd1c54606dde999610640f3458acTom Gundersen for (;;) {
1a436809498faf6486815baa0338fb6b8e5def07Tom Gundersen /* skip until '<' */
52433f6b65eccd1c54606dde999610640f3458acTom Gundersen while (*msgid != '<') {
52433f6b65eccd1c54606dde999610640f3458acTom Gundersen if (*msgid == '\0') {
52433f6b65eccd1c54606dde999610640f3458acTom Gundersen *msgid_p = msgid;
2cc7e981af27b12a6a3d4f08728281febeb450c9Tom Gundersen return NULL;
52433f6b65eccd1c54606dde999610640f3458acTom Gundersen }
52433f6b65eccd1c54606dde999610640f3458acTom Gundersen msgid++;
1a436809498faf6486815baa0338fb6b8e5def07Tom Gundersen }
52433f6b65eccd1c54606dde999610640f3458acTom Gundersen msgid++;
1a436809498faf6486815baa0338fb6b8e5def07Tom Gundersen
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen /* check it through quickly to see if it's already normalized */
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen p = msgid; found_at = FALSE;
14b746f72132324e637c4e39694bd474f85e19f7Tom Gundersen for (;; p++) {
14b746f72132324e637c4e39694bd474f85e19f7Tom Gundersen if ((unsigned char)*p >= 'A') /* matches most */
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen continue;
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen
edbb03e95a3c31bf719d5c6c46eec14d0bcb9c8fTom Gundersen if (*p == '@')
edbb03e95a3c31bf719d5c6c46eec14d0bcb9c8fTom Gundersen found_at = TRUE;
edbb03e95a3c31bf719d5c6c46eec14d0bcb9c8fTom Gundersen if (*p == '>' || *p == '"' || *p == '(' || *p == '[')
edbb03e95a3c31bf719d5c6c46eec14d0bcb9c8fTom Gundersen break;
c0dda18697e0994272c0c9616d36f6777b60e2c7Tom Gundersen
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen if (*p == '\0') {
af4e9e2c563047d524b207e0e3d6816385693a16Tom Gundersen *msgid_p = p;
10142d75cce10a92889cc11b7b1af07fecc78c5dSusant Sahani return NULL;
7951dea20911969287878e6897b3eca348721adeSusant Sahani }
1a436809498faf6486815baa0338fb6b8e5def07Tom Gundersen }
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen
672682a6b9d6fb6a3722c3fea1a93b4831747b54Tom Gundersen if (*p == '>') {
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersen *msgid_p = p+1;
54abf461d6b10dc270c4bb2aeac65f240ff1c5cdTom Gundersen if (found_at) {
50add2909c2e4b13a04d285b058b1c2270137656Tom Gundersen char *s;
1a436809498faf6486815baa0338fb6b8e5def07Tom Gundersen
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen s = p_strdup_until(unsafe_data_stack_pool,
7951dea20911969287878e6897b3eca348721adeSusant Sahani msgid, p);
7951dea20911969287878e6897b3eca348721adeSusant Sahani strip_lwsp(s);
7951dea20911969287878e6897b3eca348721adeSusant Sahani return s;
7951dea20911969287878e6897b3eca348721adeSusant Sahani }
7951dea20911969287878e6897b3eca348721adeSusant Sahani } else {
52433f6b65eccd1c54606dde999610640f3458acTom Gundersen /* ok, do it the slow way */
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen *msgid_p = msgid;
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen if (str == NULL) {
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen /* allocate only once, so we don't leak
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen with multiple invalid message IDs */
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen str = t_str_new(256);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen }
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen if (get_untokenized_msgid(msgid_p, str))
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen return str_c(str);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen }
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen /* invalid message id, see if there's another valid one */
2cc412b59353576cece2d5b30c6a39c70552f0a0Tom Gundersen msgid = *msgid_p;
2cc412b59353576cece2d5b30c6a39c70552f0a0Tom Gundersen }
2cc412b59353576cece2d5b30c6a39c70552f0a0Tom Gundersen}
edbb03e95a3c31bf719d5c6c46eec14d0bcb9c8fTom Gundersen