bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2008-2018 Dovecot authors, see the included COPYING file */
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainenstatic const unsigned char imap_b64dec[256] = {
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,62, 63,XX,XX,XX,
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen 52,53,54,55, 56,57,58,59, 60,61,XX,XX, XX,XX,XX,XX,
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen 15,16,17,18, 19,20,21,22, 23,24,25,XX, XX,XX,XX,XX,
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen XX,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen 41,42,43,44, 45,46,47,48, 49,50,51,XX, XX,XX,XX,XX,
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainenmbase64_encode(string_t *dest, const unsigned char *in, size_t len)
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen str_append_c(dest, imap_b64enc[((in[0] & 3) << 4) |
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen str_append_c(dest, imap_b64enc[((in[1] & 0x0f) << 2) |
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen str_append_c(dest, imap_b64enc[in[2] & 0x3f]);
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen str_append_c(dest, imap_b64enc[(in[0] & 0x03) << 4]);
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen str_append_c(dest, imap_b64enc[((in[0] & 0x03) << 4) |
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen str_append_c(dest, imap_b64enc[(in[1] & 0x0f) << 2]);
09c8ed62f3460ed6c6b8fdd97f54ad5d93894857Timo Sirainenstatic const char *imap_utf8_first_encode_char(const char *str)
09c8ed62f3460ed6c6b8fdd97f54ad5d93894857Timo Sirainen const char *p;
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainenint imap_utf8_to_utf7(const char *src, string_t *dest)
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen const char *p;
09c8ed62f3460ed6c6b8fdd97f54ad5d93894857Timo Sirainen /* no characters that need to be encoded */
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen /* at least one encoded character */
e7d0bea63a08b08c47c4b5c187d2cb7127859657Timo Sirainen utf16 = t_malloc0(MALLOC_MULTIPLY(strlen(p), 2));
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen while (*p != '\0') {
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen if (*p == '&') {
4de99500799c3518fa697cbc249bea4b266153adPhil Carmody while (*p != '\0' && (*p < 0x20 || *p >= 0x7f)) {
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen /* @UNSAFE */
09c8ed62f3460ed6c6b8fdd97f54ad5d93894857Timo Sirainenint t_imap_utf8_to_utf7(const char *src, const char **dest_r)
09c8ed62f3460ed6c6b8fdd97f54ad5d93894857Timo Sirainen if (imap_utf8_first_encode_char(src) == NULL) {
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainenstatic int utf16buf_to_utf8(string_t *dest, const unsigned char output[4],
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen high = (output[pos % 4] << 8) | output[(pos+1) % 4];
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen /* single byte */
3fbc12d56ede063e9e049496b620a1e2934e418eTimo Sirainen /* Encoded NUL isn't going to work in Dovecot code,
3fbc12d56ede063e9e049496b620a1e2934e418eTimo Sirainen even though it's technically valid. Return failure
3fbc12d56ede063e9e049496b620a1e2934e418eTimo Sirainen so the callers don't even get a chance to handle the
3fbc12d56ede063e9e049496b620a1e2934e418eTimo Sirainen NUL in the string inconsistently. */
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen /* missing the second character */
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen low = (output[(pos+2)%4] << 8) | output[(pos+3) % 4];
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen if (low < UTF16_SURROGATE_LOW_FIRST || low > UTF16_SURROGATE_LOW_LAST)
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen (((high & UTF16_SURROGATE_MASK) << UTF16_SURROGATE_SHIFT) |
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainenstatic int mbase64_decode_to_utf8(string_t *dest, const char **_src)
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen output[outpos % 4] = (input[0] << 2) | (input[1] >> 4);
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen if (utf16buf_to_utf8(dest, output, &outstart, 4) < 0)
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen output[outpos % 4] = (input[1] << 4) | (input[2] >> 2);
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen if (utf16buf_to_utf8(dest, output, &outstart, 4) < 0)
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen output[outpos % 4] = ((input[2] << 6) & 0xc0) | input[3];
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen if (utf16buf_to_utf8(dest, output, &outstart, 4) < 0)
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen /* found ending '-' */
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainenint imap_utf7_to_utf8(const char *src, string_t *dest)
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen const char *p;
807d831b2625cc45b55f9576aa744e8a038b1bfcPhil Carmody if (*p == '&')
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen if (*p == '\0') {
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen /* no IMAP-UTF-7 encoded characters */
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen /* at least one encoded character */
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen while (*p != '\0') {
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen if (*p == '&') {
250eaa188a7c95a4fe25525943830bda35030ba6Timo Sirainen if (*++p == '-') {
fba71f7f73279a9d65c4eef0c3eb9c7fa715c3e5Timo Sirainen const char *p;
807d831b2625cc45b55f9576aa744e8a038b1bfcPhil Carmody if (*p == '&') {
fba71f7f73279a9d65c4eef0c3eb9c7fa715c3e5Timo Sirainen /* slow scan */