Mercurial > dovecot > core-2.2
view src/lib-imap/imap-quote.c @ 17130:add8c00fb3cc
Updated copyright notices to include year 2014.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 04 Feb 2014 16:23:22 -0500 |
parents | 720c7d01ad8a |
children | 3009a1a6f6d5 |
line wrap: on
line source
/* Copyright (c) 2002-2014 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "str.h" #include "imap-arg.h" #include "imap-quote.h" /* If we have quoted-specials (<">, <\>) in a string, the minimum quoted-string overhead is 3 bytes ("\") while the minimum literal overhead is 5 bytes ("{n}\r\n"). But the literal overhead also depends on the string size. If the string length is less than 10, literal catches up to quoted-string after 3 quoted-specials. If the string length is 10..99, it catches up after 4 quoted-specials, and so on. We'll assume that the string lengths are usually in double digits, so we'll switch to literals after seeing 4 quoted-specials. */ #define QUOTED_MAX_ESCAPE_CHARS 4 void imap_append_string(string_t *dest, const char *src) { i_assert(src != NULL); imap_append_nstring(dest, src); } void imap_append_astring(string_t *dest, const char *src) { unsigned int i; i_assert(src != NULL); for (i = 0; src[i] != '\0'; i++) { if (!IS_ASTRING_CHAR(src[i])) { imap_append_string(dest, src); return; } } /* don't mix up NIL and "NIL"! */ if (i == 0 || strcasecmp(src, "NIL") == 0) imap_append_string(dest, src); else str_append(dest, src); } static void imap_append_literal(string_t *dest, const char *src, unsigned int pos) { unsigned int full_len = pos + strlen(src+pos); str_printfa(dest, "{%u}\r\n", full_len); buffer_append(dest, src, full_len); } void imap_append_nstring(string_t *dest, const char *src) { unsigned int i, escape_count = 0; if (src == NULL) { str_append(dest, "NIL"); return; } /* first check if we can (or want to) write this as quoted or as literal. quoted-specials = DQUOTE / "\" QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials TEXT-CHAR = <any CHAR except CR and LF> */ for (i = 0; src[i] != '\0'; i++) { switch (src[i]) { case '"': case '\\': if (escape_count++ < QUOTED_MAX_ESCAPE_CHARS) break; /* fall through */ case 13: case 10: imap_append_literal(dest, src, i); return; default: if ((unsigned char)src[i] >= 0x80) { imap_append_literal(dest, src, i); return; } break; } } imap_append_quoted(dest, src); } void imap_append_quoted(string_t *dest, const char *src) { str_append_c(dest, '"'); for (; *src != '\0'; src++) { switch (*src) { case 13: case 10: /* not allowed */ break; case '"': case '\\': str_append_c(dest, '\\'); str_append_c(dest, *src); break; default: if ((unsigned char)*src >= 0x80) { /* 8bit input not allowed in dquotes */ break; } str_append_c(dest, *src); break; } } str_append_c(dest, '"'); } void imap_append_string_for_humans(string_t *dest, const unsigned char *src, size_t size) { size_t i, pos, remove_count = 0; bool whitespace_prefix = TRUE, last_lwsp = TRUE, modify = FALSE; /* first check if there is anything to change */ for (i = 0; i < size; i++) { switch (src[i]) { case 0: /* convert NUL to #0x80 */ last_lwsp = FALSE; modify = TRUE; break; case '\t': modify = TRUE; /* fall through */ case ' ': if (last_lwsp) { modify = TRUE; remove_count++; } last_lwsp = TRUE; break; case 13: case 10: remove_count++; modify = TRUE; break; case '"': case '\\': modify = TRUE; last_lwsp = FALSE; break; default: if ((src[i] & 0x80) != 0) modify = TRUE; last_lwsp = FALSE; break; } if (!last_lwsp) whitespace_prefix = FALSE; } if (last_lwsp && i > 0 && !whitespace_prefix) { modify = TRUE; remove_count++; } if (!modify) { /* fast path: we can simply write it as quoted string without any escaping */ str_append_c(dest, '"'); str_append_n(dest, src, size); str_append_c(dest, '"'); return; } if (size == remove_count) { /* contained only whitespace */ str_append(dest, "\"\""); return; } str_printfa(dest, "{%"PRIuSIZE_T"}\r\n", size - remove_count); pos = str_len(dest); last_lwsp = TRUE; whitespace_prefix = TRUE; for (i = 0; i < size; i++) { switch (src[i]) { case 0: str_append_c(dest, 128); last_lwsp = FALSE; break; case '\t': case ' ': if (!last_lwsp) str_append_c(dest, ' '); last_lwsp = TRUE; break; case 13: case 10: break; default: last_lwsp = FALSE; str_append_c(dest, src[i]); break; } if (!last_lwsp) whitespace_prefix = FALSE; } if (last_lwsp && i > 0 && !whitespace_prefix) str_truncate(dest, str_len(dest)-1); i_assert(str_len(dest) - pos == size - remove_count); }