rfc822-parser.c revision 2de709376eddc50ec5fa470358bb57cf0a87bb1f
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen/* Copyright (C) 2005 Timo Sirainen */
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen#include "lib.h"
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen#include "str.h"
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen#include "rfc822-parser.h"
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen/*
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen atext = ALPHA / DIGIT / ; Any character except controls,
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen "!" / "#" / ; SP, and specials.
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen "$" / "%" / ; Used for atoms
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen "&" / "'" /
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen "*" / "+" /
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen "-" / "/" /
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen "=" / "?" /
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen "^" / "_" /
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen "`" / "{" /
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen "|" / "}" /
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen "~"
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen MIME:
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen or tspecials>
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen tspecials := "(" / ")" / "<" / ">" / "@" /
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen "," / ";" / ":" / "\" / <">
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen "/" / "[" / "]" / "?" / "="
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen So token is same as dot-atom, except stops also at '/', '?' and '='.
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen*/
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen/* atext chars are marked with 1, alpha and digits with 2,
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen atext-but-mime-tspecials with 4 */
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainenstatic unsigned char atext_chars[256] = {
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0-15 */
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16-31 */
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 4, /* 32-47 */
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 4, 0, 4, /* 48-63 */
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 64-79 */
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 1, 1, /* 80-95 */
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 96-111 */
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 0, /* 112-127 */
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen};
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen#define IS_ATEXT(c) \
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen (atext_chars[(int)(unsigned char)(c)] != 0)
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen#define IS_ATEXT_NON_TSPECIAL(c) \
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen ((atext_chars[(int)(unsigned char)(c)] & 3) != 0)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainenvoid rfc822_parser_init(struct rfc822_parser_context *ctx,
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen const unsigned char *data, size_t size,
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen string_t *last_comment)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen{
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen memset(ctx, 0, sizeof(*ctx));
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen ctx->data = data;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen ctx->end = data + size;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen ctx->last_comment = last_comment;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen}
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainenint rfc822_skip_comment(struct rfc822_parser_context *ctx)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen{
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen const unsigned char *start;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen int level = 1;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen i_assert(*ctx->data == '(');
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (ctx->last_comment != NULL)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen str_truncate(ctx->last_comment, 0);
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen start = ++ctx->data;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen for (; ctx->data != ctx->end; ctx->data++) {
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen switch (*ctx->data) {
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen case '(':
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen level++;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen break;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen case ')':
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (--level == 0) {
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (ctx->last_comment != NULL) {
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen str_append_n(ctx->last_comment, start,
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen ctx->data - start);
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen }
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen ctx->data++;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen return ctx->data != ctx->end;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen }
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen break;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen case '\\':
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (ctx->last_comment != NULL) {
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen str_append_n(ctx->last_comment, start,
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen ctx->data - start);
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen }
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen start = ctx->data + 1;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen ctx->data++;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (ctx->data == ctx->end)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen return -1;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen break;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen }
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen }
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen /* missing ')' */
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen return -1;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen}
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainenint rfc822_skip_lwsp(struct rfc822_parser_context *ctx)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen{
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen for (; ctx->data != ctx->end;) {
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (*ctx->data == ' ' || *ctx->data == '\t' ||
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen *ctx->data == '\r' || *ctx->data == '\n') {
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen ctx->data++;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen continue;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen }
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (*ctx->data != '(')
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen break;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (rfc822_skip_comment(ctx) < 0)
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen return -1;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen }
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen return ctx->data != ctx->end;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen}
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainenint rfc822_parse_atom(struct rfc822_parser_context *ctx, string_t *str)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen{
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen const unsigned char *start;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen /*
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen atom = [CFWS] 1*atext [CFWS]
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen atext =
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen ; Any character except controls, SP, and specials.
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen */
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen for (start = ctx->data; ctx->data != ctx->end; ctx->data++) {
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (IS_ATEXT(*ctx->data))
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen continue;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen str_append_n(str, start, ctx->data - start);
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen return rfc822_skip_lwsp(ctx);
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen }
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen str_append_n(str, start, ctx->data - start);
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen return 0;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen}
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainenint rfc822_parse_dot_atom(struct rfc822_parser_context *ctx, string_t *str)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen{
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen const unsigned char *start;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen int ret;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen /*
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen dot-atom = [CFWS] dot-atom-text [CFWS]
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen dot-atom-text = 1*atext *("." 1*atext)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen atext =
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen ; Any character except controls, SP, and specials.
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen For RFC-822 compatibility allow LWSP around '.'
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen */
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen for (start = ctx->data; ctx->data != ctx->end; ctx->data++) {
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (IS_ATEXT(*ctx->data))
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen continue;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen str_append_n(str, start, ctx->data - start);
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if ((ret = rfc822_skip_lwsp(ctx)) <= 0)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen return ret;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (*ctx->data != '.')
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen return 1;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen ctx->data++;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen str_append_c(str, '.');
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if ((ret = rfc822_skip_lwsp(ctx)) <= 0)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen return ret;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen start = ctx->data;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen }
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen str_append_n(str, start, ctx->data - start);
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen return 0;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen}
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainenint rfc822_parse_mime_token(struct rfc822_parser_context *ctx, string_t *str)
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen{
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen const unsigned char *start;
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen for (start = ctx->data; ctx->data != ctx->end; ctx->data++) {
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen if (IS_ATEXT_NON_TSPECIAL(*ctx->data) || *ctx->data == '.')
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen continue;
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen str_append_n(str, start, ctx->data - start);
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen return rfc822_skip_lwsp(ctx);
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen }
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen str_append_n(str, start, ctx->data - start);
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen return 0;
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen}
2de709376eddc50ec5fa470358bb57cf0a87bb1fTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainenint rfc822_parse_quoted_string(struct rfc822_parser_context *ctx, string_t *str)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen{
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen const unsigned char *start;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen i_assert(*ctx->data == '"');
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen ctx->data++;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen for (start = ctx->data; ctx->data != ctx->end; ctx->data++) {
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (*ctx->data == '"') {
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen str_append_n(str, start, ctx->data - start);
e8ef7a8c30741ad30c617d453b1c32d8da0111deTimo Sirainen ctx->data++;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen return rfc822_skip_lwsp(ctx);
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen }
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (*ctx->data != '\\')
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen continue;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen ctx->data++;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (ctx->data == ctx->end)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen return -1;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen str_append_n(str, start, ctx->data - start);
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen start = ctx->data;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen }
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen /* missing '"' */
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen return -1;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen}
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainenint rfc822_parse_phrase(struct rfc822_parser_context *ctx, string_t *str)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen{
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen int ret;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen for (;;) {
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (*ctx->data == '"')
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen ret = rfc822_parse_quoted_string(ctx, str);
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen else
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen ret = rfc822_parse_atom(ctx, str);
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (ret <= 0)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen return ret;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (!IS_ATEXT(*ctx->data) && *ctx->data != '"')
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen break;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen str_append_c(str, ' ');
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen }
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen return rfc822_skip_lwsp(ctx);
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen}
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainenstatic int
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainenrfc822_parse_domain_literal(struct rfc822_parser_context *ctx, string_t *str)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen{
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen const unsigned char *start;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen /*
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen domain-literal = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen dcontent = dtext / quoted-pair
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen dtext = NO-WS-CTL / ; Non white space controls
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen %d33-90 / ; The rest of the US-ASCII
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen %d94-126 ; characters not including "[",
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen ; "]", or "\"
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen */
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen i_assert(*ctx->data == '[');
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen for (start = ctx->data; ctx->data != ctx->end; ctx->data++) {
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (*ctx->data == '\\') {
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen ctx->data++;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (ctx->data == ctx->end)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen break;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen } else if (*ctx->data == ']') {
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen ctx->data++;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen str_append_n(str, start, ctx->data - start);
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen return ctx->data != ctx->end;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen }
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen }
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen /* missing ']' */
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen return -1;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen}
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainenint rfc822_parse_domain(struct rfc822_parser_context *ctx, string_t *str)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen{
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen /*
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen domain = dot-atom / domain-literal / obs-domain
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen domain-literal = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen obs-domain = atom *("." atom)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen */
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen i_assert(*ctx->data == '@');
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen ctx->data++;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (rfc822_skip_lwsp(ctx) <= 0)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen return -1;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (*ctx->data == '[') {
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (rfc822_parse_domain_literal(ctx, str) < 0)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen return -1;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen } else {
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen if (rfc822_parse_dot_atom(ctx, str) < 0)
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen return -1;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen }
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen return ctx->data != ctx->end;
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen}