LDAP: Fix debug messages
[exim.git] / src / src / imap_utf7.c
CommitLineData
ed0512a1
JH
1#include "exim.h"
2
3#ifdef EXPERIMENTAL_INTERNATIONAL
4
5uschar *
6imap_utf7_encode(uschar *string, const uschar *charset, uschar sep,
7 uschar *specials, uschar **error)
8{
9static uschar encode_base64[64] =
10 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
11int ptr = 0;
12int size = 0;
13size_t slen;
14uschar *sptr, *yield = NULL;
0539a19d
JH
15int i = 0, j; /* compiler quietening */
16uschar c = 0; /* compiler quietening */
ed0512a1
JH
17BOOL base64mode = FALSE;
18BOOL lastsep = FALSE;
19uschar utf16buf[256];
20uschar *utf16ptr;
21uschar *s;
22uschar outbuf[256];
23uschar *outptr = outbuf;
24#if HAVE_ICONV
25iconv_t icd;
26#endif
27
fc362fc5 28if (!specials) specials = US"";
ed0512a1
JH
29
30/* Pass over the string. If it consists entirely of "normal" characters
31 (possibly with leading seps), return it as is. */
32for (s = string; *s; s++)
33 {
34 if (s == string && *s == sep)
35 string++;
36 if ( *s >= 0x7f
37 || *s < 0x20
38 || strchr("./&", *s)
39 || *s == sep
fc362fc5 40 || Ustrchr(specials, *s)
ed0512a1
JH
41 )
42 break;
43 }
44
45if (!*s)
46 return string;
47
48sptr = string;
49slen = Ustrlen(string);
50
51#if HAVE_ICONV
fc362fc5 52if ((icd = iconv_open("UTF-16BE", CCS charset)) == (iconv_t)-1)
ed0512a1
JH
53 {
54 *error = string_sprintf(
55 "imapfolder: iconv_open(\"UTF-16BE\", \"%s\") failed: %s%s",
56 charset, strerror(errno),
57 errno == EINVAL ? " (maybe unsupported conversion)" : "");
58 return NULL;
59 }
94431adb 60#endif
ed0512a1
JH
61
62while (slen > 0)
63 {
64#if HAVE_ICONV
65 size_t left = sizeof(utf16buf);
66 utf16ptr = utf16buf;
67
68 if ( iconv(icd, (ICONV_ARG2_TYPE)&sptr, &slen, CSS &utf16ptr, &left)
69 == (size_t)-1
70 && errno != E2BIG
71 )
72 {
73 *error = string_sprintf("imapfolder: iconv() failed to convert from %s: %s",
74 charset, strerror(errno));
75 iconv_close(icd);
76 return NULL;
77 }
78#else
94431adb 79 for (utf16ptr = utf16buf;
ed0512a1
JH
80 slen > 0 && (utf16ptr - utf16buf) < sizeof(utf16buf);
81 utf16ptr += 2, slen--, sptr++)
82 {
83 *utf16ptr = *sptr;
84 *(utf16ptr+1) = '\0';
85 }
86#endif
87
88 s = utf16buf;
89 while (s < utf16ptr)
90 {
91 /* Now encode utf16buf as modified UTF-7 */
92 if ( s[0] != 0
93 || s[1] >= 0x7f
94 || s[1] < 0x20
0539a19d 95 || (Ustrchr(specials, s[1]) && s[1] != sep)
ed0512a1
JH
96 )
97 {
98 lastsep = FALSE;
99 /* Encode as modified BASE64 */
94431adb 100 if (!base64mode)
ed0512a1
JH
101 {
102 *outptr++ = '&';
103 base64mode = TRUE;
104 i = 0;
105 }
106
94431adb 107 for (j = 0; j < 2; j++, s++) switch (i++)
ed0512a1
JH
108 {
109 case 0:
110 /* Top 6 bits of the first octet */
111 *outptr++ = encode_base64[(*s >> 2) & 0x3F];
112 c = (*s & 0x03); break;
113 case 1:
114 /* Bottom 2 bits of the first octet, and top 4 bits of the second */
115 *outptr++ = encode_base64[(c << 4) | ((*s >> 4) & 0x0F)];
116 c = (*s & 0x0F); break;
117 case 2:
118 /* Bottom 4 bits of the second octet and top 2 bits of the third */
119 *outptr++ = encode_base64[(c << 2) | ((*s >> 6) & 0x03)];
120 /* Bottom 6 bits of the third octet */
121 *outptr++ = encode_base64[*s & 0x3F];
122 i = 0;
123 }
124 }
125
126 else if ( (s[1] != '.' && s[1] != '/')
127 || s[1] == sep
128 )
129 {
130 /* Encode as self (almost) */
131 if (base64mode)
132 {
94431adb 133 switch (i)
ed0512a1
JH
134 {
135 case 1:
136 /* Remaining bottom 2 bits of the last octet */
137 *outptr++ = encode_base64[c << 4];
138 break;
139 case 2:
140 /* Remaining bottom 4 bits of the last octet */
141 *outptr++ = encode_base64[c << 2];
142 }
143 *outptr++ = '-';
144 base64mode = FALSE;
145 }
146
147 if (*++s == sep)
148 {
149 if (!lastsep)
150 {
151 *outptr++ = '.';
152 lastsep = TRUE;
153 }
154 }
155 else
156 {
157 *outptr++ = *s;
158 if (*s == '&')
159 *outptr++ = '-';
160 lastsep = FALSE;
161 }
162
163 s++;
164 }
165 else
166 {
167 *error = string_sprintf("imapfolder: illegal character '%c'", s[1]);
168 if (yield) store_reset(yield);
169 return NULL;
170 }
171
172 if (outptr > outbuf + sizeof(outbuf) - 3)
173 {
174 yield = string_cat(yield, &size, &ptr, outbuf, outptr - outbuf);
175 outptr = outbuf;
176 }
177
178 }
94431adb 179 } /* End of input string */
ed0512a1 180
94431adb 181if (base64mode)
ed0512a1 182 {
94431adb 183 switch (i)
ed0512a1
JH
184 {
185 case 1:
186 /* Remaining bottom 2 bits of the last octet */
187 *outptr++ = encode_base64[c << 4];
188 break;
189 case 2:
190 /* Remaining bottom 4 bits of the last octet */
191 *outptr++ = encode_base64[c << 2];
192 }
193 *outptr++ = '-';
194 }
195
196#if HAVE_ICONV
197iconv_close(icd);
198#endif
199
200yield = string_cat(yield, &size, &ptr, outbuf, outptr - outbuf);
201if (yield[ptr-1] == '.')
202 ptr--;
203yield[ptr] = '\0';
204
205return yield;
206}
207
208#endif /* whole file */
209/* vi: aw ai sw=2
210*/