rfc822-parser.c revision 0452398b245ac9643f6b47dfc450dc5bf7da51d0
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger/* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger#include "lib.h"
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger#include "str.h"
ee5342a8882c2fc7631fcffb5497e6597747887cTim Reddehase#include "strescape.h"
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger#include "rfc822-parser.h"
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger/*
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger atext = ALPHA / DIGIT / ; Any character except controls,
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger "!" / "#" / ; SP, and specials.
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa "$" / "%" / ; Used for atoms
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger "&" / "'" /
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger "*" / "+" /
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger "-" / "/" /
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger "=" / "?" /
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa "^" / "_" /
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger "`" / "{" /
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger "|" / "}" /
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger "~"
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger
ee5342a8882c2fc7631fcffb5497e6597747887cTim Reddehase MIME:
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger or tspecials>
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger tspecials := "(" / ")" / "<" / ">" / "@" /
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger "," / ";" / ":" / "\" / <">
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger "/" / "[" / "]" / "?" / "="
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa So token is same as dot-atom, except stops also at '/', '?' and '='.
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa*/
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa/* atext chars are marked with 1, alpha and digits with 2,
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa atext-but-mime-tspecials with 4 */
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksaunsigned char rfc822_atext_chars[256] = {
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0-15 */
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16-31 */
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 4, /* 32-47 */
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 4, 0, 4, /* 48-63 */
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 64-79 */
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 1, 1, /* 80-95 */
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 96-111 */
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 0, /* 112-127 */
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger};
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksavoid rfc822_parser_init(struct rfc822_parser_context *ctx,
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa const unsigned char *data, size_t size,
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa string_t *last_comment)
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger{
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger memset(ctx, 0, sizeof(*ctx));
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger ctx->data = data;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger ctx->end = data + size;
ee5342a8882c2fc7631fcffb5497e6597747887cTim Reddehase ctx->last_comment = last_comment;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger}
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornbergerint rfc822_skip_comment(struct rfc822_parser_context *ctx)
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger{
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger const unsigned char *start;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger int level = 1;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa i_assert(*ctx->data == '(');
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger if (ctx->last_comment != NULL)
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger str_truncate(ctx->last_comment, 0);
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger start = ++ctx->data;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger for (; ctx->data != ctx->end; ctx->data++) {
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger switch (*ctx->data) {
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger case '(':
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger level++;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger break;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger case ')':
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger if (--level == 0) {
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger if (ctx->last_comment != NULL) {
ee5342a8882c2fc7631fcffb5497e6597747887cTim Reddehase str_append_n(ctx->last_comment, start,
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger ctx->data - start);
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa }
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger ctx->data++;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger return ctx->data != ctx->end;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger }
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger break;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger case '\\':
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger if (ctx->last_comment != NULL) {
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger str_append_n(ctx->last_comment, start,
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger ctx->data - start);
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger }
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger start = ctx->data + 1;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger ctx->data++;
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa if (ctx->data == ctx->end)
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa return -1;
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa break;
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa }
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa }
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa /* missing ')' */
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa return -1;
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa}
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksaint rfc822_skip_lwsp(struct rfc822_parser_context *ctx)
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa{
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa for (; ctx->data != ctx->end;) {
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa if (*ctx->data == ' ' || *ctx->data == '\t' ||
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa *ctx->data == '\r' || *ctx->data == '\n') {
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa ctx->data++;
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa continue;
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa }
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa if (*ctx->data != '(')
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa break;
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa if (rfc822_skip_comment(ctx) < 0)
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa return -1;
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa }
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa return ctx->data != ctx->end;
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa}
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksaint rfc822_parse_atom(struct rfc822_parser_context *ctx, string_t *str)
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa{
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa const unsigned char *start;
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa /*
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa atom = [CFWS] 1*atext [CFWS]
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa atext =
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa ; Any character except controls, SP, and specials.
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa */
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa if (ctx->data == ctx->end || !IS_ATEXT(*ctx->data))
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa return -1;
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa for (start = ctx->data++; ctx->data != ctx->end; ctx->data++) {
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa if (IS_ATEXT(*ctx->data))
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa continue;
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa str_append_n(str, start, ctx->data - start);
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa return rfc822_skip_lwsp(ctx);
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa }
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa str_append_n(str, start, ctx->data - start);
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa return 0;
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa}
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksaint rfc822_parse_dot_atom(struct rfc822_parser_context *ctx, string_t *str)
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa{
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa const unsigned char *start;
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa int ret;
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa /*
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa dot-atom = [CFWS] dot-atom-text [CFWS]
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa dot-atom-text = 1*atext *("." 1*atext)
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa atext =
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa ; Any character except controls, SP, and specials.
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa For RFC-822 compatibility allow LWSP around '.'
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa */
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa if (ctx->data == ctx->end || !IS_ATEXT(*ctx->data))
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa return -1;
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa for (start = ctx->data++; ctx->data != ctx->end; ctx->data++) {
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa if (IS_ATEXT(*ctx->data))
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa continue;
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa str_append_n(str, start, ctx->data - start);
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa if ((ret = rfc822_skip_lwsp(ctx)) <= 0)
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa return ret;
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa if (*ctx->data != '.')
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa return 1;
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa ctx->data++;
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa str_append_c(str, '.');
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa if ((ret = rfc822_skip_lwsp(ctx)) <= 0)
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa return ret;
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa start = ctx->data;
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa }
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa str_append_n(str, start, ctx->data - start);
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa return 0;
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa}
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksaint rfc822_parse_mime_token(struct rfc822_parser_context *ctx, string_t *str)
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa{
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa const unsigned char *start;
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa for (start = ctx->data; ctx->data != ctx->end; ctx->data++) {
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa if (IS_ATEXT_NON_TSPECIAL(*ctx->data) || *ctx->data == '.')
5ddd457a4e278410e58386a2333f5853f2f2ea8fEugen Kuksa continue;
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa
b2ee879528ace361f0f5a55de48c6b90515b27b0Eugen Kuksa str_append_n(str, start, ctx->data - start);
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger return rfc822_skip_lwsp(ctx);
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger }
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger str_append_n(str, start, ctx->data - start);
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger return 0;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger}
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger
23305f217b86a2ebf90a848af9036908e0070542Eugen Kuksaint rfc822_parse_quoted_string(struct rfc822_parser_context *ctx, string_t *str)
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger{
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger const unsigned char *start;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger size_t len;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger i_assert(*ctx->data == '"');
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger ctx->data++;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger for (start = ctx->data; ctx->data != ctx->end; ctx->data++) {
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger switch (*ctx->data) {
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger case '"':
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger str_append_n(str, start, ctx->data - start);
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger ctx->data++;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger return rfc822_skip_lwsp(ctx);
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger case '\n':
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger /* folding whitespace, remove the (CR)LF */
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger len = ctx->data - start;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger if (len > 0 && start[len-1] == '\r')
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger len--;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger str_append_n(str, start, len);
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger start = ctx->data + 1;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger break;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger case '\\':
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger ctx->data++;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger if (ctx->data == ctx->end)
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger return -1;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger str_append_n(str, start, ctx->data - start);
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger start = ctx->data;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger break;
ee5342a8882c2fc7631fcffb5497e6597747887cTim Reddehase }
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger }
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger
ee5342a8882c2fc7631fcffb5497e6597747887cTim Reddehase /* missing '"' */
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger return -1;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger}
ee5342a8882c2fc7631fcffb5497e6597747887cTim Reddehase
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornbergerstatic int
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornbergerrfc822_parse_atom_or_dot(struct rfc822_parser_context *ctx, string_t *str)
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger{
ee5342a8882c2fc7631fcffb5497e6597747887cTim Reddehase const unsigned char *start;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger /*
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger atom = [CFWS] 1*atext [CFWS]
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger atext =
ee5342a8882c2fc7631fcffb5497e6597747887cTim Reddehase ; Any character except controls, SP, and specials.
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger The difference between this function and rfc822_parse_dot_atom()
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger is that this doesn't just silently skip over all the whitespace.
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger */
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger for (start = ctx->data; ctx->data != ctx->end; ctx->data++) {
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger if (IS_ATEXT(*ctx->data) || *ctx->data == '.')
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger continue;
ee5342a8882c2fc7631fcffb5497e6597747887cTim Reddehase
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger str_append_n(str, start, ctx->data - start);
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger return rfc822_skip_lwsp(ctx);
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger }
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger str_append_n(str, start, ctx->data - start);
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger return 0;
ee5342a8882c2fc7631fcffb5497e6597747887cTim Reddehase}
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornbergerint rfc822_parse_phrase(struct rfc822_parser_context *ctx, string_t *str)
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger{
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger int ret;
ee5342a8882c2fc7631fcffb5497e6597747887cTim Reddehase
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger /*
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger phrase = 1*word / obs-phrase
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger word = atom / quoted-string
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger obs-phrase = word *(word / "." / CFWS)
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger */
ee5342a8882c2fc7631fcffb5497e6597747887cTim Reddehase
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger if (ctx->data == ctx->end)
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger return 0;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger if (*ctx->data == '.')
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger return -1;
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger
65f00d360b7b3fabfc829fcc19a019bfef587595Julian Kornberger for (;;) {
if (*ctx->data == '"')
ret = rfc822_parse_quoted_string(ctx, str);
else
ret = rfc822_parse_atom_or_dot(ctx, str);
if (ret <= 0)
return ret;
if (!IS_ATEXT(*ctx->data) && *ctx->data != '"'
&& *ctx->data != '.')
break;
str_append_c(str, ' ');
}
return rfc822_skip_lwsp(ctx);
}
static int
rfc822_parse_domain_literal(struct rfc822_parser_context *ctx, string_t *str)
{
const unsigned char *start;
/*
domain-literal = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
dcontent = dtext / quoted-pair
dtext = NO-WS-CTL / ; Non white space controls
%d33-90 / ; The rest of the US-ASCII
%d94-126 ; characters not including "[",
; "]", or "\"
*/
i_assert(*ctx->data == '[');
for (start = ctx->data; ctx->data != ctx->end; ctx->data++) {
if (*ctx->data == '\\') {
ctx->data++;
if (ctx->data == ctx->end)
break;
} else if (*ctx->data == ']') {
ctx->data++;
str_append_n(str, start, ctx->data - start);
return rfc822_skip_lwsp(ctx);
}
}
/* missing ']' */
return -1;
}
int rfc822_parse_domain(struct rfc822_parser_context *ctx, string_t *str)
{
/*
domain = dot-atom / domain-literal / obs-domain
domain-literal = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
obs-domain = atom *("." atom)
*/
i_assert(*ctx->data == '@');
ctx->data++;
if (rfc822_skip_lwsp(ctx) <= 0)
return -1;
if (*ctx->data == '[')
return rfc822_parse_domain_literal(ctx, str);
else
return rfc822_parse_dot_atom(ctx, str);
}
int rfc822_parse_content_type(struct rfc822_parser_context *ctx, string_t *str)
{
if (rfc822_skip_lwsp(ctx) <= 0)
return -1;
/* get main type */
if (rfc822_parse_mime_token(ctx, str) <= 0)
return -1;
/* skip over "/" */
if (*ctx->data != '/')
return -1;
ctx->data++;
if (rfc822_skip_lwsp(ctx) <= 0)
return -1;
str_append_c(str, '/');
/* get subtype */
return rfc822_parse_mime_token(ctx, str);
}
int rfc822_parse_content_param(struct rfc822_parser_context *ctx,
const char **key_r, const char **value_r)
{
string_t *tmp;
size_t value_pos;
int ret;
/* .. := *(";" parameter)
parameter := attribute "=" value
attribute := token
value := token / quoted-string
*/
*key_r = NULL;
*value_r = NULL;
if (ctx->data == ctx->end)
return 0;
if (*ctx->data != ';')
return -1;
ctx->data++;
if (rfc822_skip_lwsp(ctx) <= 0)
return -1;
tmp = t_str_new(64);
if (rfc822_parse_mime_token(ctx, tmp) <= 0)
return -1;
str_append_c(tmp, '\0');
value_pos = str_len(tmp);
if (*ctx->data != '=')
return -1;
ctx->data++;
if ((ret = rfc822_skip_lwsp(ctx)) <= 0) {
/* broken / no value */
} else if (*ctx->data == '"') {
ret = rfc822_parse_quoted_string(ctx, tmp);
str_unescape(str_c_modifiable(tmp) + value_pos);
} else {
ret = rfc822_parse_mime_token(ctx, tmp);
}
*key_r = str_c(tmp);
*value_r = *key_r + value_pos;
return ret < 0 ? -1 : 1;
}