2 Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
4 Permission to use, copy, modify, and distribute this material
5 for any purpose and without fee is hereby granted, provided
6 that the above copyright notice and this permission notice
7 appear in all copies, and that the name of Bellcore not be
8 used in advertising or publicity pertaining to this
9 material without the specific, prior written permission
10 of an authorized representative of Bellcore. BELLCORE
11 MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY
12 OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS",
13 WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
16 #define NEWLINE_CHAR '\n'
23 static void output64chunk(int c1, int c2, int c3, int pads, FILE * outfile);
25 static signed char basis_64[] =
26 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
28 static signed char index_64[128] = {
29 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
30 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
32 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
33 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
34 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
35 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
36 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
39 #define char64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)])
45 char *s = (char *) strchr(basis_64, c);
46 if (s) return(s-basis_64);
51 /* the following gets a character, but fakes it properly into two chars if there's a newline character */
52 static int InNewline = 0;
54 static int nextcharin(FILE * infile, int PortableNewlines)
59 return (getc(infile));
61 if (!PortableNewlines)
62 return (getc(infile));
68 if (c == NEWLINE_CHAR) {
76 static void to64(FILE * infile, FILE * outfile, int PortableNewlines)
78 int c1, c2, c3, ct = 0;
79 InNewline = 0; /* always reset it */
80 while ((c1 = nextcharin(infile, PortableNewlines)) != EOF) {
81 c2 = nextcharin(infile, PortableNewlines);
83 output64chunk(c1, 0, 0, 2, outfile);
85 c3 = nextcharin(infile, PortableNewlines);
87 output64chunk(c1, c2, 0, 1, outfile);
89 output64chunk(c1, c2, c3, 0, outfile);
103 static void output64chunk(int c1, int c2, int c3, int pads, FILE * outfile)
105 putc(basis_64[c1 >> 2], outfile);
106 putc(basis_64[((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)], outfile);
111 putc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6)], outfile);
114 putc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6)], outfile);
115 putc(basis_64[c3 & 0x3F], outfile);
119 static int PendingBoundary(char *s, char **Boundaries, int *BoundaryCt)
123 if (s[0] != '-' || s[1] != '-')
126 for (i = 0; i < *BoundaryCt; ++i) {
127 len = strlen(Boundaries[i]);
128 if (!strncmp(s, Boundaries[i], len)) {
129 if (s[len] == '-' && s[len + 1] == '-')
137 /* If we're in portable newline mode, we have to convert CRLF to the
138 local newline convention on output */
140 static int CRpending = 0;
143 static void almostputc(int c, FILE * outfile, int PortableNewlines)
147 putc(NEWLINE_CHAR, outfile);
157 if (PortableNewlines && c == 13) {
165 static void almostputc(int c, FILE * outfile, int PortableNewlines)
172 from64(FILE * infile, FILE * outfile,
173 char **boundaries, int *boundaryct, int PortableNewlines)
176 int newline = 1, DataDone = 0;
178 /* always reinitialize */
180 while ((c1 = getc(infile)) != EOF) {
189 if (newline && boundaries && c1 == '-') {
191 /* a dash is NOT base 64, so all bets are off if NOT a boundary */
193 if( fgets(Buf, sizeof(Buf), infile) == NULL) {
195 "Warning: base64 decoder saw premature EOF!\n");
198 if (boundaries && (Buf[0] == '-')
200 && PendingBoundary(Buf, boundaries, boundaryct)) {
204 "Ignoring unrecognized boundary line: %s\n",
213 } while (c2 != EOF && isspace(c2));
216 } while (c3 != EOF && isspace(c3));
219 } while (c4 != EOF && isspace(c4));
220 if (c2 == EOF || c3 == EOF || c4 == EOF) {
222 "Warning: base64 decoder saw premature EOF!\n");
225 if (c1 == '=' || c2 == '=') {
231 almostputc(((c1 << 2) | ((c2 & 0x30) >> 4)), outfile,
237 almostputc((((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2)),
238 outfile, PortableNewlines);
243 almostputc((((c3 & 0x03) << 6) | c4), outfile,
249 putc(13, outfile); /* Don't drop a lone trailing char 13 */
252 static signed char basis_hex[] = "0123456789ABCDEF";
253 static signed char index_hex[128] = {
254 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
255 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
256 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
257 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
258 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
259 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
260 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
261 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
264 /* The following version generated complaints on Solaris. */
265 /* #define hexchar(c) (((c) < 0 || (c) > 127) ? -1 : index_hex[(c)]) */
266 /* Since we're no longer ever calling it with anything signed, this should work: */
267 #define hexchar(c) (((c) > 127) ? -1 : index_hex[(c)])
274 if (islower(c)) c = toupper(c);
275 s = (char *) strchr(basis_hex, c);
276 if (s) return(s-basis_hex);
281 static void toqp(FILE * infile, FILE * outfile)
283 int c, ct = 0, prevc = 255;
284 while ((c = getc(infile)) != EOF) {
285 if ((c < 32 && (c != '\n' && c != '\t'))
288 /* Following line is to avoid single periods alone on lines,
289 which messes up some dumb smtp implementations, sigh... */
290 || (ct == 0 && c == '.')) {
292 putc(basis_hex[c >> 4], outfile);
293 putc(basis_hex[c & 0xF], outfile);
295 prevc = 'A'; /* close enough */
296 } else if (c == '\n') {
297 if (prevc == ' ' || prevc == '\t') {
298 putc('=', outfile); /* soft & hard lines */
305 if (c == 'F' && prevc == '\n') {
306 /* HORRIBLE but clever hack suggested by MTR for sendmail-avoidance */
315 /* This is the case we are looking for */
325 fputs("Fro", outfile);
329 fputs("Fr", outfile);
337 prevc = 'x'; /* close enough -- printable */
338 } else { /* END horrible hack */
358 fromqp(FILE * infile, FILE * outfile, char **boundaries, int *boundaryct)
361 int sawnewline = 1, neednewline = 0;
362 /* The neednewline hack is necessary because the newline leading into
363 a multipart boundary is part of the boundary, not the data */
365 while ((c1 = getc(infile)) != EOF) {
366 if (sawnewline && boundaries && (c1 == '-')) {
371 if ( fgets(Buf, sizeof(Buf), infile) == NULL ) {
373 "Warning: saw premature EOF!\n");
376 if (boundaries && (Buf[0] == '-')
378 && PendingBoundary(Buf, boundaries, boundaryct)) {
381 /* Not a boundary, now we must treat THIS line as q-p, sigh */
386 for (s = (unsigned char *)Buf; *s; ++s) {
398 putc(c1 << 4 | c2, outfile);
419 putc(c1 << 4 | c2, outfile);
441 Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
443 Permission to use, copy, modify, and distribute this material
444 for any purpose and without fee is hereby granted, provided
445 that the above copyright notice and this permission notice
446 appear in all copies, and that the name of Bellcore not be
447 used in advertising or publicity pertaining to this
448 material without the specific, prior written permission
449 of an authorized representative of Bellcore. BELLCORE
450 MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY
451 OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS",
452 WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
455 #define QP 2 /* quoted-printable */
457 int main(int argc, char *argv[])
459 int encode = 1, which = BASE64, i, portablenewlines = 0;
463 for (i = 1; i < argc; ++i) {
464 if (argv[i][0] == '-') {
465 switch (argv[i][1]) {
469 "mimencode: -o requires a file name.\n");
472 fpo = fopen(argv[i], "w");
485 portablenewlines = 1;
492 "Usage: mmencode [-u] [-q] [-b] [-p] [-o outputfile] [file name]\n");
496 fp = fopen(argv[i], "r");
503 if (which == BASE64) {
505 to64(fp, fpo, portablenewlines);
507 from64(fp, fpo, (char **)NULL, (int *)0,
514 fromqp(fp, fpo, NULL, 0);