xref: /plan9/sys/src/cmd/ip/imap4d/mutf7.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
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