expand() filenames given to the ~@ tilde escape..
[s-mailx.git] / base64.c
blob6af8f38cee074f4c65bbdb8ecc316a592f889c49
1 /*
2 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 */
6 /*
7 * These base64 routines are derived from the metamail-2.7 sources which
8 * state the following copyright notice:
10 * Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
12 * Permission to use, copy, modify, and distribute this material
13 * for any purpose and without fee is hereby granted, provided
14 * that the above copyright notice and this permission notice
15 * appear in all copies, and that the name of Bellcore not be
16 * used in advertising or publicity pertaining to this
17 * material without the specific, prior written permission
18 * of an authorized representative of Bellcore. BELLCORE
19 * MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY
20 * OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS",
21 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
24 #ifndef lint
25 #ifdef DOSCCS
26 static char sccsid[] = "@(#)base64.c 2.14 (gritter) 4/21/06";
27 #endif
28 #endif /* not lint */
31 * Mail -- a mail program
33 * base64 functions
36 #include "rcv.h"
37 #include "extern.h"
39 static const char b64table[] =
40 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
41 static const signed char b64index[] = {
42 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
43 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
44 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
45 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
46 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
47 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
48 -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
49 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
52 #define char64(c) ((c) < 0 ? -1 : b64index[(int)(c)])
54 static signed char *ctob64(unsigned char *p, int pad);
57 * Convert three characters to base64.
59 static signed char *
60 ctob64(unsigned char *p, int pad)
62 static signed char b64[4];
64 b64[0] = b64table[p[0] >> 2];
65 b64[1] = b64table[((p[0] & 0x3) << 4) | ((p[1] & 0xF0) >> 4)];
66 if (pad == 2) {
67 b64[1] = b64table[(p[0] & 0x3) << 4];
68 b64[2] = b64[3] = '=';
69 } else if (pad == 1) {
70 b64[2] = b64table[((p[1] & 0xF) << 2)];
71 b64[3] = '=';
72 } else {
73 b64[2] = b64table[((p[1] & 0xF) << 2) | ((p[2] & 0xC0) >> 6)];
74 b64[3] = b64table[p[2] & 0x3F];
76 return b64;
79 char *
80 strtob64(const char *p)
82 return memtob64(p, strlen(p));
85 char *
86 memtob64(const void *vp, size_t isz)
88 char q[3];
89 const char *p = vp;
90 signed char *h;
91 size_t c = 0;
92 int i, l = 0, sz = 0, pads;
93 char *rs = NULL;
95 if (isz == 0) {
96 rs = smalloc(1);
97 *rs = '\0';
98 return rs;
100 do {
101 for (pads = 2, i = 0; i <= 2; i++, pads--) {
102 q[i] = p[c++];
103 if (c == isz)
104 break;
106 h = ctob64((unsigned char *)q, pads);
107 if (l + 5 >= sz)
108 rs = srealloc(rs, sz = l + 100);
109 for (i = 0; i < 4; i++)
110 rs[l++] = h[i];
111 } while (c < isz);
112 rs[l] = '\0';
113 return rs;
117 * Write to a file converting to base64. The input must be aligned
118 * e.g. at 972 character bounds.
120 size_t
121 mime_write_tob64(struct str *in, FILE *fo, int is_header)
123 char *p, *upper, q[3];
124 signed char *h;
125 int i, l, pads;
126 size_t sz;
128 sz = 0;
129 upper = in->s + in->l;
130 for (p = in->s, l = 0; p < upper; ) {
131 for (pads = 2, i = 0; i <= 2; i++, pads--) {
132 q[i] = *p++;
133 if (p == upper)
134 break;
136 h = ctob64((unsigned char *)q, pads);
137 fwrite(h, sizeof(char), 4, fo);
138 sz += 4, l += 4;
139 if (l >= 71) {
140 putc('\n', fo), sz++;
141 l = 0;
144 if (l != 0 && !is_header) {
145 putc('\n', fo), sz++;
147 return sz;
151 * Decode from base64.
153 void
154 mime_fromb64(struct str *in, struct str *out, int is_text)
156 char *p, *q, *upper;
157 signed char c, d, e, f, g;
158 int done = 0, newline = 0;
160 out->s = smalloc(in->l * 3 / 4 + 2);
161 out->l = 0;
162 upper = in->s + in->l;
163 for (p = in->s, q = out->s; p < upper; ) {
164 while (c = *p++, whitechar(c));
165 if (p >= upper) break;
166 if (done) continue;
167 while (d = *p++, whitechar(d));
168 if (p >= upper) break;
169 while (e = *p++, whitechar(e));
170 if (p >= upper) break;
171 while (f = *p++, whitechar(f));
172 if (c == '=' || d == '=') {
173 done = 1;
174 continue;
176 c = char64(c);
177 d = char64(d);
178 g = ((c << 2) | ((d & 0x30) >> 4));
179 if (is_text) {
180 if (g == '\r') {
181 newline = 1;
182 } else if (g == '\n' && newline) {
183 q--;
184 out->l--;
185 newline = 0;
186 } else {
187 newline = 0;
190 *q++ = g;
191 out->l++;
192 if (e == '=') {
193 done = 1;
194 } else {
195 e = char64(e);
196 g = (((d & 0xF) << 4) | ((e & 0x3C) >> 2));
197 if (is_text) {
198 if (g == '\r') {
199 newline = 1;
200 } else if (g == '\n' && newline) {
201 q--;
202 out->l--;
203 newline = 0;
204 } else {
205 newline = 0;
208 *q++ = g;
209 out->l++;
210 if (f == '=') {
211 done = 1;
212 } else {
213 f = char64(f);
214 g = (((e & 0x03) << 6) | f);
215 if (is_text) {
216 if (g == '\r') {
217 newline = 1;
218 } else if (g == '\n' && newline) {
219 q--;
220 out->l--;
221 newline = 0;
222 } else {
223 newline = 0;
226 *q++ = g;
227 out->l++;
231 return;
235 * Buffer the base64 input so mime_fromb64 gets always multiples of
236 * 4 characters.
237 * As we have only one buffer, this function is not reentrant.
239 void
240 mime_fromb64_b(struct str *in, struct str *out, int is_text, FILE *f)
242 static signed char b[4];
243 static int n;
244 static FILE *f_b = (FILE *)-1;
245 signed char c;
246 int i;
247 struct str nin;
249 nin.s = smalloc(in->l + n);
250 if (n != 0 && f_b == f) {
251 for (nin.l = 0; nin.l < n; nin.l++)
252 nin.s[nin.l] = b[nin.l];
253 } else {
254 nin.l = 0;
255 n = 0;
258 for (i = 0; i <= in->l; i++) {
259 c = in->s[i];
260 if (char64(c) == -1 && c != '=')
261 continue;
262 b[n] = nin.s[nin.l++] = c;
263 if (n >= 3)
264 n = 0;
265 else
266 n++;
268 nin.l -= n;
269 mime_fromb64(&nin, out, is_text);
270 free(nin.s);
271 f_b = f;