bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen#include "lib.h"
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen#include "str.h"
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen#include "rfc822-parser.h"
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen#include "message-id.h"
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainenstatic bool get_untokenized_msgid(const char **msgid_p, string_t *msgid)
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen{
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen struct rfc822_parser_context parser;
94fc6781711341cb3af587af236d85c74e5b1a1dTimo Sirainen int ret;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen rfc822_parser_init(&parser, (const unsigned char *)*msgid_p,
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen strlen(*msgid_p), NULL);
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen /*
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen id-left = dot-atom-text / no-fold-quote / obs-id-left
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen id-right = dot-atom-text / no-fold-literal / obs-id-right
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen no-fold-quote = DQUOTE *(qtext / quoted-pair) DQUOTE
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen no-fold-literal = "[" *(dtext / quoted-pair) "]"
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen */
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
4e8d6d03c2ff85448df79b181a2ea850fb5d4199Timo Sirainen rfc822_skip_lwsp(&parser);
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
94fc6781711341cb3af587af236d85c74e5b1a1dTimo Sirainen if (*parser.data == '"')
94fc6781711341cb3af587af236d85c74e5b1a1dTimo Sirainen ret = rfc822_parse_quoted_string(&parser, msgid);
94fc6781711341cb3af587af236d85c74e5b1a1dTimo Sirainen else
94fc6781711341cb3af587af236d85c74e5b1a1dTimo Sirainen ret = rfc822_parse_dot_atom(&parser, msgid);
94fc6781711341cb3af587af236d85c74e5b1a1dTimo Sirainen if (ret <= 0)
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen return FALSE;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen if (*parser.data != '@')
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen return FALSE;
2d84942c22d30cf7b3e53943bce1e3ad024c7c88Timo Sirainen str_append_c(msgid, '@');
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen parser.data++;
4e8d6d03c2ff85448df79b181a2ea850fb5d4199Timo Sirainen rfc822_skip_lwsp(&parser);
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen if (rfc822_parse_dot_atom(&parser, msgid) <= 0)
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen return FALSE;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen if (*parser.data != '>')
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen return FALSE;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen *msgid_p = (const char *)parser.data + 1;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen return TRUE;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen}
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainenstatic void strip_lwsp(char *str)
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen{
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen /* @UNSAFE */
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen char *dest;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen /* find the first lwsp */
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen while (*str != ' ' && *str != '\t' && *str != '\r' && *str != '\n') {
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen if (*str == '\0')
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen return;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen str++;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen }
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen for (dest = str; *str != '\0'; str++) {
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen if (*str != ' ' && *str != '\t' && *str != '\r' && *str != '\n')
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen *dest++ = *str;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen }
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen *dest = '\0';
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen}
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainenconst char *message_id_get_next(const char **msgid_p)
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen{
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen const char *msgid = *msgid_p;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen const char *p;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen string_t *str = NULL;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen bool found_at;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen if (*msgid_p == NULL)
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen return NULL;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen for (;;) {
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen /* skip until '<' */
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen while (*msgid != '<') {
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen if (*msgid == '\0') {
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen *msgid_p = msgid;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen return NULL;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen }
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen msgid++;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen }
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen msgid++;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen /* check it through quickly to see if it's already normalized */
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen p = msgid; found_at = FALSE;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen for (;; p++) {
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen if ((unsigned char)*p >= 'A') /* matches most */
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen continue;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen if (*p == '@')
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen found_at = TRUE;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen if (*p == '>' || *p == '"' || *p == '(' || *p == '[')
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen break;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen if (*p == '\0') {
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen *msgid_p = p;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen return NULL;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen }
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen }
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen if (*p == '>') {
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen *msgid_p = p+1;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen if (found_at) {
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen char *s;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen s = p_strdup_until(unsafe_data_stack_pool,
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen msgid, p);
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen strip_lwsp(s);
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen return s;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen }
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen } else {
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen /* ok, do it the slow way */
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen *msgid_p = msgid;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen if (str == NULL) {
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen /* allocate only once, so we don't leak
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen with multiple invalid message IDs */
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen str = t_str_new(256);
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen }
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen if (get_untokenized_msgid(msgid_p, str))
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen return str_c(str);
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen }
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen /* invalid message id, see if there's another valid one */
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen msgid = *msgid_p;
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen }
53e8721fd333043c4a18dc4ae7af4557e7a1d5f1Timo Sirainen}