428
+ − 1 /*
+ − 2 Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
+ − 3
+ − 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.
+ − 14 */
+ − 15
2993
+ − 16 #ifdef HAVE_CONFIG_H
+ − 17 # include <config.h>
+ − 18 #endif
428
+ − 19 #define NEWLINE_CHAR '\n'
+ − 20 #include <stdlib.h>
+ − 21 #include <stdio.h>
+ − 22 #include <ctype.h>
+ − 23 #include <string.h>
430
+ − 24 #include <errno.h>
428
+ − 25
+ − 26 static void
+ − 27 output64chunk(int c1, int c2, int c3, int pads, FILE *outfile);
+ − 28
+ − 29 static signed char basis_64[] =
+ − 30 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ − 31
+ − 32 static signed char index_64[128] = {
+ − 33 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ − 34 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ − 35 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
+ − 36 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
+ − 37 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
+ − 38 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
+ − 39 -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
+ − 40 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
+ − 41 };
+ − 42
+ − 43 #define char64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)])
+ − 44
+ − 45 /*
+ − 46 char64(c)
+ − 47 char c;
+ − 48 {
+ − 49 char *s = (char *) strchr(basis_64, c);
+ − 50 if (s) return(s-basis_64);
+ − 51 return(-1);
+ − 52 }
+ − 53 */
+ − 54
+ − 55 /* the following gets a character, but fakes it properly into two chars if there's a newline character */
+ − 56 static int InNewline=0;
+ − 57
+ − 58 static int
+ − 59 nextcharin (FILE *infile, int PortableNewlines)
+ − 60 {
+ − 61 int c;
+ − 62
+ − 63 #ifndef NEWLINE_CHAR
+ − 64 return(getc(infile));
+ − 65 #else
+ − 66 if (!PortableNewlines) return(getc(infile));
+ − 67 if (InNewline) {
+ − 68 InNewline = 0;
+ − 69 return(10); /* LF */
+ − 70 }
+ − 71 c = getc(infile);
+ − 72 if (c == NEWLINE_CHAR) {
+ − 73 InNewline = 1;
+ − 74 return(13); /* CR */
+ − 75 }
+ − 76 return(c);
+ − 77 #endif
+ − 78 }
+ − 79
+ − 80 static void
+ − 81 to64(FILE *infile, FILE *outfile, int PortableNewlines)
+ − 82 {
+ − 83 int c1, c2, c3, ct=0;
+ − 84 InNewline = 0; /* always reset it */
+ − 85 while ((c1 = nextcharin(infile, PortableNewlines)) != EOF) {
+ − 86 c2 = nextcharin(infile, PortableNewlines);
+ − 87 if (c2 == EOF) {
+ − 88 output64chunk(c1, 0, 0, 2, outfile);
+ − 89 } else {
+ − 90 c3 = nextcharin(infile, PortableNewlines);
+ − 91 if (c3 == EOF) {
+ − 92 output64chunk(c1, c2, 0, 1, outfile);
+ − 93 } else {
+ − 94 output64chunk(c1, c2, c3, 0, outfile);
+ − 95 }
+ − 96 }
+ − 97 ct += 4;
+ − 98 if (ct > 71) {
+ − 99 putc('\n', outfile);
+ − 100 ct = 0;
+ − 101 }
+ − 102 }
+ − 103 if (ct) putc('\n', outfile);
+ − 104 fflush(outfile);
+ − 105 }
+ − 106
+ − 107 static void
+ − 108 output64chunk(int c1, int c2, int c3, int pads, FILE *outfile)
+ − 109 {
+ − 110 putc(basis_64[c1>>2], outfile);
+ − 111 putc(basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)], outfile);
+ − 112 if (pads == 2) {
+ − 113 putc('=', outfile);
+ − 114 putc('=', outfile);
+ − 115 } else if (pads) {
+ − 116 putc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
+ − 117 putc('=', outfile);
+ − 118 } else {
+ − 119 putc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
+ − 120 putc(basis_64[c3 & 0x3F], outfile);
+ − 121 }
+ − 122 }
+ − 123
+ − 124 static int
+ − 125 PendingBoundary(char *s, char **Boundaries, int *BoundaryCt)
+ − 126 {
+ − 127 int i, len;
+ − 128
+ − 129 if (s[0] != '-' || s[1] != '-') return(0);
+ − 130
+ − 131
+ − 132 for (i=0; i < *BoundaryCt; ++i) {
+ − 133 len = strlen(Boundaries[i]);
+ − 134 if (!strncmp(s, Boundaries[i], len)) {
+ − 135 if (s[len] == '-' && s[len+1] == '-') *BoundaryCt = i;
+ − 136 return(1);
+ − 137 }
+ − 138 }
+ − 139 return(0);
+ − 140 }
+ − 141
+ − 142 /* If we're in portable newline mode, we have to convert CRLF to the
+ − 143 local newline convention on output */
+ − 144
+ − 145 static int CRpending = 0;
+ − 146
+ − 147 #ifdef NEWLINE_CHAR
+ − 148 static void
+ − 149 almostputc(int c, FILE *outfile, int PortableNewlines)
+ − 150 {
+ − 151 if (CRpending) {
+ − 152 if (c == 10) {
+ − 153 putc(NEWLINE_CHAR, outfile);
+ − 154 CRpending = 0;
+ − 155 } else {
+ − 156 putc(13, outfile);
+ − 157 if (c != 13) {
+ − 158 putc(c, outfile);
+ − 159 CRpending = 0;
+ − 160 }
+ − 161 }
+ − 162 } else {
+ − 163 if (PortableNewlines && c == 13) {
+ − 164 CRpending = 1;
+ − 165 } else {
+ − 166 putc(c, outfile);
+ − 167 }
+ − 168 }
+ − 169 }
+ − 170 #else
+ − 171 static void
+ − 172 almostputc(int c, FILE *outfile, int PortableNewlines)
+ − 173 {
+ − 174 putc(c, outfile);
+ − 175 }
+ − 176 #endif
+ − 177
+ − 178 static void
+ − 179 from64(FILE *infile, FILE *outfile,
+ − 180 char **boundaries, int *boundaryct, int PortableNewlines)
+ − 181 {
+ − 182 int c1, c2, c3, c4;
+ − 183 int newline = 1, DataDone = 0;
+ − 184
+ − 185 /* always reinitialize */
+ − 186 CRpending = 0;
+ − 187 while ((c1 = getc(infile)) != EOF) {
+ − 188 if (isspace(c1)) {
+ − 189 if (c1 == '\n') {
+ − 190 newline = 1;
+ − 191 } else {
+ − 192 newline = 0;
+ − 193 }
+ − 194 continue;
+ − 195 }
+ − 196 if (newline && boundaries && c1 == '-') {
+ − 197 char Buf[200];
+ − 198 /* a dash is NOT base 64, so all bets are off if NOT a boundary */
+ − 199 ungetc(c1, infile);
+ − 200 fgets(Buf, sizeof(Buf), infile);
+ − 201 if (boundaries
+ − 202 && (Buf[0] == '-')
+ − 203 && (Buf[1] == '-')
+ − 204 && PendingBoundary(Buf, boundaries, boundaryct)) {
+ − 205 return;
+ − 206 }
+ − 207 fprintf(stderr, "Ignoring unrecognized boundary line: %s\n", Buf);
+ − 208 continue;
+ − 209 }
+ − 210 if (DataDone) continue;
+ − 211 newline = 0;
+ − 212 do {
+ − 213 c2 = getc(infile);
+ − 214 } while (c2 != EOF && isspace(c2));
+ − 215 do {
+ − 216 c3 = getc(infile);
+ − 217 } while (c3 != EOF && isspace(c3));
+ − 218 do {
+ − 219 c4 = getc(infile);
+ − 220 } while (c4 != EOF && isspace(c4));
+ − 221 if (c2 == EOF || c3 == EOF || c4 == EOF) {
+ − 222 fprintf(stderr, "Warning: base64 decoder saw premature EOF!\n");
+ − 223 return;
+ − 224 }
+ − 225 if (c1 == '=' || c2 == '=') {
+ − 226 DataDone=1;
+ − 227 continue;
+ − 228 }
+ − 229 c1 = char64(c1);
+ − 230 c2 = char64(c2);
+ − 231 almostputc(((c1<<2) | ((c2&0x30)>>4)), outfile, PortableNewlines);
+ − 232 if (c3 == '=') {
+ − 233 DataDone = 1;
+ − 234 } else {
+ − 235 c3 = char64(c3);
+ − 236 almostputc((((c2&0XF) << 4) | ((c3&0x3C) >> 2)), outfile, PortableNewlines);
+ − 237 if (c4 == '=') {
+ − 238 DataDone = 1;
+ − 239 } else {
+ − 240 c4 = char64(c4);
+ − 241 almostputc((((c3&0x03) <<6) | c4), outfile, PortableNewlines);
+ − 242 }
+ − 243 }
+ − 244 }
+ − 245 if (CRpending) putc(13, outfile); /* Don't drop a lone trailing char 13 */
+ − 246 }
+ − 247
+ − 248 static signed char basis_hex[] = "0123456789ABCDEF";
+ − 249 static signed char index_hex[128] = {
+ − 250 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ − 251 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ − 252 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ − 253 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1,
+ − 254 -1,10,11,12, 13,14,15,-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,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ − 257 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
+ − 258 };
+ − 259
+ − 260 /* The following version generated complaints on Solaris. */
+ − 261 /* #define hexchar(c) (((c) < 0 || (c) > 127) ? -1 : index_hex[(c)]) */
+ − 262 /* Since we're no longer ever calling it with anything signed, this should work: */
+ − 263 #define hexchar(c) (((c) > 127) ? -1 : index_hex[(c)])
+ − 264
+ − 265 /*
+ − 266 hexchar(c)
+ − 267 char c;
+ − 268 {
+ − 269 char *s;
+ − 270 if (islower(c)) c = toupper(c);
+ − 271 s = (char *) strchr(basis_hex, c);
+ − 272 if (s) return(s-basis_hex);
+ − 273 return(-1);
+ − 274 }
+ − 275 */
+ − 276
+ − 277 static void
+ − 278 toqp(FILE *infile, FILE *outfile)
+ − 279 {
+ − 280 int c, ct=0, prevc=255;
+ − 281 while ((c = getc(infile)) != EOF) {
+ − 282 if ((c < 32 && (c != '\n' && c != '\t'))
+ − 283 || (c == '=')
+ − 284 || (c >= 127)
+ − 285 /* Following line is to avoid single periods alone on lines,
+ − 286 which messes up some dumb smtp implementations, sigh... */
+ − 287 || (ct == 0 && c == '.')) {
+ − 288 putc('=', outfile);
+ − 289 putc(basis_hex[c>>4], outfile);
+ − 290 putc(basis_hex[c&0xF], outfile);
+ − 291 ct += 3;
+ − 292 prevc = 'A'; /* close enough */
+ − 293 } else if (c == '\n') {
+ − 294 if (prevc == ' ' || prevc == '\t') {
+ − 295 putc('=', outfile); /* soft & hard lines */
+ − 296 putc(c, outfile);
+ − 297 }
+ − 298 putc(c, outfile);
+ − 299 ct = 0;
+ − 300 prevc = c;
+ − 301 } else {
+ − 302 if (c == 'F' && prevc == '\n') {
+ − 303 /* HORRIBLE but clever hack suggested by MTR for sendmail-avoidance */
+ − 304 c = getc(infile);
+ − 305 if (c == 'r') {
+ − 306 c = getc(infile);
+ − 307 if (c == 'o') {
+ − 308 c = getc(infile);
+ − 309 if (c == 'm') {
+ − 310 c = getc(infile);
+ − 311 if (c == ' ') {
+ − 312 /* This is the case we are looking for */
+ − 313 fputs("=46rom", outfile);
+ − 314 ct += 6;
+ − 315 } else {
+ − 316 fputs("From", outfile);
+ − 317 ct += 4;
+ − 318 }
+ − 319 } else {
+ − 320 fputs("Fro", outfile);
+ − 321 ct += 3;
+ − 322 }
+ − 323 } else {
+ − 324 fputs("Fr", outfile);
+ − 325 ct += 2;
+ − 326 }
+ − 327 } else {
+ − 328 putc('F', outfile);
+ − 329 ++ct;
+ − 330 }
+ − 331 ungetc(c, infile);
+ − 332 prevc = 'x'; /* close enough -- printable */
+ − 333 } else { /* END horrible hack */
+ − 334 putc(c, outfile);
+ − 335 ++ct;
+ − 336 prevc = c;
+ − 337 }
+ − 338 }
+ − 339 if (ct > 72) {
+ − 340 putc('=', outfile);
+ − 341 putc('\n', outfile);
+ − 342 ct = 0;
+ − 343 prevc = '\n';
+ − 344 }
+ − 345 }
+ − 346 if (ct) {
+ − 347 putc('=', outfile);
+ − 348 putc('\n', outfile);
+ − 349 }
+ − 350 }
+ − 351
+ − 352 static void
+ − 353 fromqp(FILE *infile, FILE *outfile, char **boundaries, int *boundaryct)
+ − 354 {
647
+ − 355 int c1, c2;
428
+ − 356 int sawnewline = 1, neednewline = 0;
+ − 357 /* The neednewline hack is necessary because the newline leading into
+ − 358 a multipart boundary is part of the boundary, not the data */
+ − 359
+ − 360 while ((c1 = getc(infile)) != EOF) {
+ − 361 if (sawnewline && boundaries && (c1 == '-')) {
+ − 362 char Buf[200];
+ − 363 unsigned char *s;
+ − 364
+ − 365 ungetc(c1, infile);
+ − 366 fgets(Buf, sizeof(Buf), infile);
+ − 367 if (boundaries
+ − 368 && (Buf[0] == '-')
+ − 369 && (Buf[1] == '-')
+ − 370 && PendingBoundary(Buf, boundaries, boundaryct)) {
+ − 371 return;
+ − 372 }
+ − 373 /* Not a boundary, now we must treat THIS line as q-p, sigh */
+ − 374 if (neednewline) {
+ − 375 putc('\n', outfile);
+ − 376 neednewline = 0;
+ − 377 }
+ − 378 for (s=(unsigned char *) Buf; *s; ++s) {
+ − 379 if (*s == '=') {
+ − 380 if (!*++s) break;
+ − 381 if (*s == '\n') {
+ − 382 /* ignore it */
+ − 383 sawnewline = 1;
+ − 384 } else {
+ − 385 c1 = hexchar(*s);
+ − 386 if (!*++s) break;
+ − 387 c2 = hexchar(*s);
+ − 388 putc(c1<<4 | c2, outfile);
+ − 389 }
+ − 390 } else {
442
+ − 391 #ifdef WIN32_NATIVE
428
+ − 392 if (*s == '\n')
+ − 393 putc('\r', outfile); /* insert CR for binary-mode write */
+ − 394 #endif
+ − 395 putc(*s, outfile);
+ − 396 }
+ − 397 }
+ − 398 } else {
+ − 399 if (neednewline) {
+ − 400 putc('\n', outfile);
+ − 401 neednewline = 0;
+ − 402 }
+ − 403 if (c1 == '=') {
+ − 404 sawnewline = 0;
+ − 405 c1 = getc(infile);
+ − 406 if (c1 == '\n') {
+ − 407 /* ignore it */
+ − 408 sawnewline = 1;
+ − 409 } else {
+ − 410 c2 = getc(infile);
+ − 411 c1 = hexchar(c1);
+ − 412 c2 = hexchar(c2);
+ − 413 putc(c1<<4 | c2, outfile);
+ − 414 if (c2 == '\n') sawnewline = 1;
+ − 415 }
+ − 416 } else {
+ − 417 if (c1 == '\n') {
+ − 418 sawnewline = 1;
+ − 419 neednewline = 1;
+ − 420 } else {
+ − 421 sawnewline = 0;
+ − 422 putc(c1, outfile);
+ − 423 }
+ − 424 }
+ − 425 }
+ − 426 }
+ − 427 if (neednewline) {
+ − 428 putc('\n', outfile);
+ − 429 neednewline = 0;
+ − 430 }
+ − 431 }
+ − 432
+ − 433
+ − 434 /*
+ − 435 Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
+ − 436
+ − 437 Permission to use, copy, modify, and distribute this material
+ − 438 for any purpose and without fee is hereby granted, provided
+ − 439 that the above copyright notice and this permission notice
+ − 440 appear in all copies, and that the name of Bellcore not be
+ − 441 used in advertising or publicity pertaining to this
+ − 442 material without the specific, prior written permission
+ − 443 of an authorized representative of Bellcore. BELLCORE
+ − 444 MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY
+ − 445 OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS",
+ − 446 WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
+ − 447 */
442
+ − 448 #ifdef WIN32_NATIVE
+ − 449 #include <io.h>
428
+ − 450 #include <fcntl.h>
+ − 451 #endif
+ − 452
+ − 453 #define BASE64 1
+ − 454 #define QP 2 /* quoted-printable */
+ − 455
+ − 456 int main(int argc, char *argv[])
+ − 457 {
+ − 458 int encode = 1, which = BASE64, i, portablenewlines = 0;
+ − 459 FILE *fp = stdin;
+ − 460 FILE *fpo = stdout;
+ − 461
+ − 462 for (i=1; i<argc; ++i) {
+ − 463 if (argv[i][0] == '-') {
+ − 464 switch (argv[i][1]) {
+ − 465 case 'o':
+ − 466 if (++i >= argc) {
+ − 467 fprintf(stderr, "mimencode: -o requires a file name.\n");
+ − 468 exit(-1);
+ − 469 }
+ − 470 fpo = fopen(argv[i], "w");
+ − 471 if (!fpo) {
+ − 472 perror(argv[i]);
+ − 473 exit(-1);
+ − 474 }
+ − 475 break;
+ − 476 case 'u':
+ − 477 encode = 0;
+ − 478 break;
+ − 479 case 'q':
+ − 480 which = QP;
+ − 481 break;
+ − 482 case 'p':
+ − 483 portablenewlines = 1;
+ − 484 break;
+ − 485 case 'b':
+ − 486 which = BASE64;
+ − 487 break;
+ − 488 default:
+ − 489 fprintf(stderr,
+ − 490 "Usage: mmencode [-u] [-q] [-b] [-p] [-o outputfile] [file name]\n");
+ − 491 exit(-1);
+ − 492 }
+ − 493 } else {
442
+ − 494 #ifdef WIN32_NATIVE
428
+ − 495 if (encode)
+ − 496 fp = fopen(argv[i], "rb");
+ − 497 else
+ − 498 {
+ − 499 fp = fopen(argv[i], "rt");
+ − 500 setmode(fileno(fpo), O_BINARY);
+ − 501 } /* else */
+ − 502 #else
+ − 503 fp = fopen(argv[i], "r");
442
+ − 504 #endif /* WIN32_NATIVE */
428
+ − 505 if (!fp) {
+ − 506 perror(argv[i]);
+ − 507 exit(-1);
+ − 508 }
+ − 509 }
+ − 510 }
442
+ − 511 #ifdef WIN32_NATIVE
428
+ − 512 if (fp == stdin) setmode(fileno(fp), O_BINARY);
442
+ − 513 #endif /* WIN32_NATIVE */
428
+ − 514 if (which == BASE64) {
+ − 515 if (encode) {
+ − 516 to64(fp, fpo, portablenewlines);
+ − 517 } else {
+ − 518 from64(fp,fpo, (char **) NULL, (int *) 0, portablenewlines);
+ − 519 }
+ − 520 } else {
+ − 521 if (encode) toqp(fp, fpo); else fromqp(fp, fpo, NULL, 0);
+ − 522 }
+ − 523 return(0);
+ − 524 }
+ − 525