1 /* Copyright (c) The Exim Maintainers 2023 */
2 /* Copyright (c) University of Cambridge 1995 - 2018 */
3 /* See the file NOTICE for conditions of use and distribution. */
4 /* SPDX-License-Identifier: GPL-2.0-or-later */
11 imap_utf7_encode(uschar *string, const uschar *charset, uschar sep,
12 uschar *specials, uschar **error)
14 static uschar encode_base64[64] =
15 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
18 gstring * yield = NULL;
19 int i = 0; /* compiler quietening */
20 uschar c = 0; /* compiler quietening */
21 BOOL base64mode = FALSE;
27 uschar *outptr = outbuf;
32 if (!specials) specials = US"";
34 /* Pass over the string. If it consists entirely of "normal" characters
35 (possibly with leading seps), return it as is. */
36 for (s = string; *s; s++)
38 if (s == string && *s == sep)
44 || Ustrchr(specials, *s)
53 slen = Ustrlen(string);
56 if ((icd = iconv_open("UTF-16BE", CCS charset)) == (iconv_t)-1)
58 *error = string_sprintf(
59 "imapfolder: iconv_open(\"UTF-16BE\", \"%s\") failed: %s%s",
60 charset, strerror(errno),
61 errno == EINVAL ? " (maybe unsupported conversion)" : "");
69 size_t left = sizeof(utf16buf);
72 if ( iconv(icd, (ICONV_ARG2_TYPE)&sptr, &slen, CSS &utf16ptr, &left)
77 *error = string_sprintf("imapfolder: iconv() failed to convert from %s: %s",
78 charset, strerror(errno));
83 for (utf16ptr = utf16buf;
84 slen > 0 && (utf16ptr - utf16buf) < sizeof(utf16buf);
85 utf16ptr += 2, slen--, sptr++)
95 /* Now encode utf16buf as modified UTF-7 */
99 || (Ustrchr(specials, s[1]) && s[1] != sep)
103 /* Encode as modified BASE64 */
111 for (int j = 0; j < 2; j++, s++) switch (i++)
114 /* Top 6 bits of the first octet */
115 *outptr++ = encode_base64[(*s >> 2) & 0x3F];
116 c = (*s & 0x03); break;
118 /* Bottom 2 bits of the first octet, and top 4 bits of the second */
119 *outptr++ = encode_base64[(c << 4) | ((*s >> 4) & 0x0F)];
120 c = (*s & 0x0F); break;
122 /* Bottom 4 bits of the second octet and top 2 bits of the third */
123 *outptr++ = encode_base64[(c << 2) | ((*s >> 6) & 0x03)];
124 /* Bottom 6 bits of the third octet */
125 *outptr++ = encode_base64[*s & 0x3F];
130 else if ( (s[1] != '.' && s[1] != '/')
134 /* Encode as self (almost) */
140 /* Remaining bottom 2 bits of the last octet */
141 *outptr++ = encode_base64[c << 4];
144 /* Remaining bottom 4 bits of the last octet */
145 *outptr++ = encode_base64[c << 2];
171 *error = string_sprintf("imapfolder: illegal character '%c'", s[1]);
175 if (outptr > outbuf + sizeof(outbuf) - 3)
177 yield = string_catn(yield, outbuf, outptr - outbuf);
182 } /* End of input string */
189 /* Remaining bottom 2 bits of the last octet */
190 *outptr++ = encode_base64[c << 4];
193 /* Remaining bottom 4 bits of the last octet */
194 *outptr++ = encode_base64[c << 2];
203 yield = string_catn(yield, outbuf, outptr - outbuf);
204 gstring_trim_trailing(yield, '.');
206 return string_from_gstring(yield);
209 #endif /* whole file */