1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <auth.h>
5 #include "imap4d.h"
6
7 /*
8 * modified utf-7, as per imap4 spec
9 * like utf-7, but substitues , for / in base 64,
10 * does not allow escaped ascii characters.
11 *
12 * /lib/rfc/rfc2152 is utf-7
13 * /lib/rfc/rfc1642 is obsolete utf-7
14 *
15 * test sequences from rfc1642
16 * 'A≢Α.' 'A&ImIDkQ-.'
17 * 'Hi Mom ☺!" 'Hi Mom &Jjo-!'
18 * '日本語' '&ZeVnLIqe-'
19 */
20
21 static uchar mt64d[256];
22 static char mt64e[64];
23
24 static void
initm64(void)25 initm64(void)
26 {
27 int c, i;
28
29 memset(mt64d, 255, 256);
30 memset(mt64e, '=', 64);
31 i = 0;
32 for(c = 'A'; c <= 'Z'; c++){
33 mt64e[i] = c;
34 mt64d[c] = i++;
35 }
36 for(c = 'a'; c <= 'z'; c++){
37 mt64e[i] = c;
38 mt64d[c] = i++;
39 }
40 for(c = '0'; c <= '9'; c++){
41 mt64e[i] = c;
42 mt64d[c] = i++;
43 }
44 mt64e[i] = '+';
45 mt64d['+'] = i++;
46 mt64e[i] = ',';
47 mt64d[','] = i;
48 }
49
50 int
encmutf7(char * out,int lim,char * in)51 encmutf7(char *out, int lim, char *in)
52 {
53 Rune rr;
54 ulong r, b;
55 char *start = out;
56 char *e = out + lim;
57 int nb;
58
59 if(mt64e[0] == 0)
60 initm64();
61 for(;;){
62 r = *(uchar*)in;
63
64 if(r < ' ' || r >= Runeself){
65 if(r == '\0')
66 break;
67 if(out + 1 >= e)
68 return -1;
69 *out++ = '&';
70 b = 0;
71 nb = 0;
72 for(;;){
73 in += chartorune(&rr, in);
74 r = rr;
75 if(r == '\0' || r >= ' ' && r < Runeself)
76 break;
77 b = (b << 16) | r;
78 for(nb += 16; nb >= 6; nb -= 6){
79 if(out + 1 >= e)
80 return -1;
81 *out++ = mt64e[(b>>(nb-6))&0x3f];
82 }
83 }
84 for(; nb >= 6; nb -= 6){
85 if(out + 1 >= e)
86 return -1;
87 *out++ = mt64e[(b>>(nb-6))&0x3f];
88 }
89 if(nb){
90 if(out + 1 >= e)
91 return -1;
92 *out++ = mt64e[(b<<(6-nb))&0x3f];
93 }
94
95 if(out + 1 >= e)
96 return -1;
97 *out++ = '-';
98 if(r == '\0')
99 break;
100 }else
101 in++;
102 if(out + 1 >= e)
103 return -1;
104 *out = r;
105 out++;
106 if(r == '&')
107 *out++ = '-';
108 }
109
110 if(out >= e)
111 return -1;
112 *out = '\0';
113 return out - start;
114 }
115
116 int
decmutf7(char * out,int lim,char * in)117 decmutf7(char *out, int lim, char *in)
118 {
119 Rune rr;
120 char *start = out;
121 char *e = out + lim;
122 int c, b, nb;
123
124 if(mt64e[0] == 0)
125 initm64();
126 for(;;){
127 c = *in;
128
129 if(c < ' ' || c >= Runeself){
130 if(c == '\0')
131 break;
132 return -1;
133 }
134 if(c != '&'){
135 if(out + 1 >= e)
136 return -1;
137 *out++ = c;
138 in++;
139 continue;
140 }
141 in++;
142 if(*in == '-'){
143 if(out + 1 >= e)
144 return -1;
145 *out++ = '&';
146 in++;
147 continue;
148 }
149
150 b = 0;
151 nb = 0;
152 while((c = *in++) != '-'){
153 c = mt64d[c];
154 if(c >= 64)
155 return -1;
156 b = (b << 6) | c;
157 nb += 6;
158 if(nb >= 16){
159 rr = b >> (nb - 16);
160 nb -= 16;
161 if(out + UTFmax + 1 >= e && out + runelen(rr) + 1 >= e)
162 return -1;
163 out += runetochar(out, &rr);
164 }
165 }
166 if(b & ((1 << nb) - 1))
167 return -1;
168 }
169
170 if(out >= e)
171 return -1;
172 *out = '\0';
173 return out - start;
174 }
175