1 /* Copyright (c) University of Cambridge 1995 - 2018 */
2 /* See the file NOTICE for conditions of use and distribution. */
9 imap_utf7_encode(uschar
*string
, const uschar
*charset
, uschar sep
,
10 uschar
*specials
, uschar
**error
)
12 static uschar encode_base64
[64] =
13 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
16 gstring
* yield
= NULL
;
17 int i
= 0; /* compiler quietening */
18 uschar c
= 0; /* compiler quietening */
19 BOOL base64mode
= FALSE
;
25 uschar
*outptr
= outbuf
;
30 if (!specials
) specials
= US
"";
32 /* Pass over the string. If it consists entirely of "normal" characters
33 (possibly with leading seps), return it as is. */
34 for (s
= string
; *s
; s
++)
36 if (s
== string
&& *s
== sep
)
42 || Ustrchr(specials
, *s
)
51 slen
= Ustrlen(string
);
54 if ((icd
= iconv_open("UTF-16BE", CCS charset
)) == (iconv_t
)-1)
56 *error
= string_sprintf(
57 "imapfolder: iconv_open(\"UTF-16BE\", \"%s\") failed: %s%s",
58 charset
, strerror(errno
),
59 errno
== EINVAL
? " (maybe unsupported conversion)" : "");
67 size_t left
= sizeof(utf16buf
);
70 if ( iconv(icd
, (ICONV_ARG2_TYPE
)&sptr
, &slen
, CSS
&utf16ptr
, &left
)
75 *error
= string_sprintf("imapfolder: iconv() failed to convert from %s: %s",
76 charset
, strerror(errno
));
81 for (utf16ptr
= utf16buf
;
82 slen
> 0 && (utf16ptr
- utf16buf
) < sizeof(utf16buf
);
83 utf16ptr
+= 2, slen
--, sptr
++)
93 /* Now encode utf16buf as modified UTF-7 */
97 || (Ustrchr(specials
, s
[1]) && s
[1] != sep
)
101 /* Encode as modified BASE64 */
109 for (int j
= 0; j
< 2; j
++, s
++) switch (i
++)
112 /* Top 6 bits of the first octet */
113 *outptr
++ = encode_base64
[(*s
>> 2) & 0x3F];
114 c
= (*s
& 0x03); break;
116 /* Bottom 2 bits of the first octet, and top 4 bits of the second */
117 *outptr
++ = encode_base64
[(c
<< 4) | ((*s
>> 4) & 0x0F)];
118 c
= (*s
& 0x0F); break;
120 /* Bottom 4 bits of the second octet and top 2 bits of the third */
121 *outptr
++ = encode_base64
[(c
<< 2) | ((*s
>> 6) & 0x03)];
122 /* Bottom 6 bits of the third octet */
123 *outptr
++ = encode_base64
[*s
& 0x3F];
128 else if ( (s
[1] != '.' && s
[1] != '/')
132 /* Encode as self (almost) */
138 /* Remaining bottom 2 bits of the last octet */
139 *outptr
++ = encode_base64
[c
<< 4];
142 /* Remaining bottom 4 bits of the last octet */
143 *outptr
++ = encode_base64
[c
<< 2];
169 *error
= string_sprintf("imapfolder: illegal character '%c'", s
[1]);
173 if (outptr
> outbuf
+ sizeof(outbuf
) - 3)
175 yield
= string_catn(yield
, outbuf
, outptr
- outbuf
);
180 } /* End of input string */
187 /* Remaining bottom 2 bits of the last octet */
188 *outptr
++ = encode_base64
[c
<< 4];
191 /* Remaining bottom 4 bits of the last octet */
192 *outptr
++ = encode_base64
[c
<< 2];
201 yield
= string_catn(yield
, outbuf
, outptr
- outbuf
);
203 if (yield
->s
[yield
->ptr
-1] == '.')
206 return string_from_gstring(yield
);
209 #endif /* whole file */