/* * Heirloom mailx - a mail user agent derived from Berkeley Mail. * * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany. */ /* * These base64 routines are derived from the metamail-2.7 sources which * state the following copyright notice: * * Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore) * * Permission to use, copy, modify, and distribute this material * for any purpose and without fee is hereby granted, provided * that the above copyright notice and this permission notice * appear in all copies, and that the name of Bellcore not be * used in advertising or publicity pertaining to this * material without the specific, prior written permission * of an authorized representative of Bellcore. BELLCORE * MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY * OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS", * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. */ #ifndef lint #ifdef DOSCCS static char sccsid[] = "@(#)base64.c 2.14 (gritter) 4/21/06"; #endif #endif /* not lint */ /* * Mail -- a mail program * * base64 functions */ #include "rcv.h" #include "extern.h" static const char b64table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const signed char b64index[] = { -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 }; #define char64(c) ((c) < 0 ? -1 : b64index[(int)(c)]) static signed char *ctob64(unsigned char *p, int pad); /* * Convert three characters to base64. */ static signed char * ctob64(unsigned char *p, int pad) { static signed char b64[4]; b64[0] = b64table[p[0] >> 2]; b64[1] = b64table[((p[0] & 0x3) << 4) | ((p[1] & 0xF0) >> 4)]; if (pad == 2) { b64[1] = b64table[(p[0] & 0x3) << 4]; b64[2] = b64[3] = '='; } else if (pad == 1) { b64[2] = b64table[((p[1] & 0xF) << 2)]; b64[3] = '='; } else { b64[2] = b64table[((p[1] & 0xF) << 2) | ((p[2] & 0xC0) >> 6)]; b64[3] = b64table[p[2] & 0x3F]; } return b64; } char * strtob64(const char *p) { return memtob64(p, strlen(p)); } char * memtob64(const void *vp, size_t isz) { char q[3]; const char *p = vp; signed char *h; size_t c = 0; int i, l = 0, sz = 0, pads; char *rs = NULL; if (isz == 0) { rs = smalloc(1); *rs = '\0'; return rs; } do { for (pads = 2, i = 0; i <= 2; i++, pads--) { q[i] = p[c++]; if (c == isz) break; } h = ctob64((unsigned char *)q, pads); if (l + 5 >= sz) rs = srealloc(rs, sz = l + 100); for (i = 0; i < 4; i++) rs[l++] = h[i]; } while (c < isz); rs[l] = '\0'; return rs; } /* * Write to a file converting to base64. The input must be aligned * e.g. at 972 character bounds. */ size_t mime_write_tob64(struct str *in, FILE *fo, int is_header) { char *p, *upper, q[3]; signed char *h; int i, l, pads; size_t sz; sz = 0; upper = in->s + in->l; for (p = in->s, l = 0; p < upper; ) { for (pads = 2, i = 0; i <= 2; i++, pads--) { q[i] = *p++; if (p == upper) break; } h = ctob64((unsigned char *)q, pads); fwrite(h, sizeof(char), 4, fo); sz += 4, l += 4; if (l >= 71) { putc('\n', fo), sz++; l = 0; } } if (l != 0 && !is_header) { putc('\n', fo), sz++; } return sz; } /* * Decode from base64. */ void mime_fromb64(struct str *in, struct str *out, int is_text) { char *p, *q, *upper; signed char c, d, e, f, g; int done = 0, newline = 0; out->s = smalloc(in->l * 3 / 4 + 2); out->l = 0; upper = in->s + in->l; for (p = in->s, q = out->s; p < upper; ) { while (c = *p++, whitechar(c)); if (p >= upper) break; if (done) continue; while (d = *p++, whitechar(d)); if (p >= upper) break; while (e = *p++, whitechar(e)); if (p >= upper) break; while (f = *p++, whitechar(f)); if (c == '=' || d == '=') { done = 1; continue; } c = char64(c); d = char64(d); g = ((c << 2) | ((d & 0x30) >> 4)); if (is_text) { if (g == '\r') { newline = 1; } else if (g == '\n' && newline) { q--; out->l--; newline = 0; } else { newline = 0; } } *q++ = g; out->l++; if (e == '=') { done = 1; } else { e = char64(e); g = (((d & 0xF) << 4) | ((e & 0x3C) >> 2)); if (is_text) { if (g == '\r') { newline = 1; } else if (g == '\n' && newline) { q--; out->l--; newline = 0; } else { newline = 0; } } *q++ = g; out->l++; if (f == '=') { done = 1; } else { f = char64(f); g = (((e & 0x03) << 6) | f); if (is_text) { if (g == '\r') { newline = 1; } else if (g == '\n' && newline) { q--; out->l--; newline = 0; } else { newline = 0; } } *q++ = g; out->l++; } } } return; } /* * Buffer the base64 input so mime_fromb64 gets always multiples of * 4 characters. * As we have only one buffer, this function is not reentrant. */ void mime_fromb64_b(struct str *in, struct str *out, int is_text, FILE *f) { static signed char b[4]; static int n; static FILE *f_b = (FILE *)-1; signed char c; int i; struct str nin; nin.s = smalloc(in->l + n); if (n != 0 && f_b == f) { for (nin.l = 0; nin.l < n; nin.l++) nin.s[nin.l] = b[nin.l]; } else { nin.l = 0; n = 0; } for (i = 0; i <= in->l; i++) { c = in->s[i]; if (char64(c) == -1 && c != '=') continue; b[n] = nin.s[nin.l++] = c; if (n >= 3) n = 0; else n++; } nin.l -= n; mime_fromb64(&nin, out, is_text); free(nin.s); f_b = f; }