2 * mewencode, mewdecode, and mewcat --- MIME encoding for Mew
4 * Author: Kazu Yamamoto <Kazu@Mew.org>
6 * Revised: Dec 12, 1998
11 static char version_message[] = "mewencode version 0.14 981219 Kazu Yamamoto";
16 #if defined(_WIN32) || defined(OS2)
20 #define ENCODE_NAME "mewencode"
21 #define DECODE_NAME "mewdecode"
22 #define CAT_NAME "mewcat"
53 * "b" is ignored on UNIX.
58 #define STRCMP(str1, str2) strncmp(str1, str2, sizeof(str2) - 1)
61 * long name convention for option
64 struct option longopts [] = {
65 {"encode", 0, 0, 'e'},
66 {"decode", 0, 0, 'd'},
67 {"base64", 0, 0, 'b'},
68 {"quoted-printable", 0, 0, 'q'},
69 {"gzip64", 0, 0, 'z'},
70 {"length", 1, 0, 'l'},
73 {"version", 0, 0, 'v'},
81 fprintf(stderr, "usage: %s [-e|-d] [-b|-q|-g] [-l length] [-t] [infile [outfile]]\n", progname);
84 char *help_message[] = {
85 " -e --encode Encoding <infile>",
86 " -d --decode Decoding <infile> instead of encoding",
87 " Decoding is the default when called with decoding",
89 " -b --base64 MIME base64 en/decoding.",
90 " -q --quoted-printable MIME quoted-printable en/decoding.",
91 " -g --gzip64 MIME gzip64 en/decoding(not yet specified in RFC).",
93 " -l --length Line length into which base64/quoted-printable/gzip64 ",
94 " encoding truncate. The default value is 71.",
95 " -t --text On base64/gzip64 encoding, local newline is treated",
97 " On base/gzip64 decoding,any newline is translated",
98 " into local newline.",
99 " Specify this option only when the input is a line",
100 " based object(e.g. Content-Type: is text/plain or",
101 " application/postscript).",
102 " -h --help Display this help message.",
103 " -v --version Display the version.",
105 "Default is Encoding, Base64, Length = 71, Binary.",
106 "If <infile> is \"-\", it means the standard input.",
107 "If <outfile> is \"-\", it means the standard output.",
115 char **p = help_message;
117 fprintf(stderr, "help: %s\n\n", progname);
118 fprintf(stderr, " A MIME encoder/decoder.\n\n");
120 while (*p) fprintf(stderr, "%s\n", *p++);
127 fprintf(stderr, "version of %s: %s\n", progname, version_message);
135 mewbasename(filename)
140 if ((p = strrchr(filename, FILESEP)) != NULL)
141 filename = p + FILESEPLEN;
150 * 8bit input with line canonicalization
158 static int Incr = OFF, Ineof = OFF;
162 return(getc(stream));
199 * lineless 'ascii' input
202 static char base256[] = {
203 OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB,
205 OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB,
207 OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB, 62, OOB,OOB,OOB, 63,
208 /* 0 1 2 3 4 5 6 7 8 9 = */
209 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,OOB,OOB, OOB,OOB,OOB,OOB,
210 /* A B C D E F G H I J K L M N O*/
211 OOB, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
212 /* P Q R S T U V W X Y Z */
213 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,OOB, OOB,OOB,OOB,OOB,
214 /* a b c d e f g h i j k l m n o*/
215 OOB, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
216 /* p q r s t u v w x y z */
217 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,OOB, OOB,OOB,OOB,OOB,
221 GetChar(FILE *stream, int cannot_be_eof)
224 static int Ineof = OFF;
231 } while ( c == CR || c == LF);
234 if (cannot_be_eof == YES) {
235 fprintf(stderr, "Error: base64 decoder saw premature EOF.");
245 if ((ret = base256[c]) == OOB) {
246 fprintf(stderr, "base64 decoder saw an illegal character.");
254 PutChar(c, stream, text)
259 static int Outcr = OFF, Outeof = OFF;
273 Outcr = OFF; /* xxx */
309 static char base64[] =
310 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
313 base256to64 (c1, c2, c3, padding, outfile)
314 int c1, c2, c3, padding;
317 putc(base64[c1>>2], outfile);
318 putc(base64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)], outfile);
321 putc(base64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
322 putc(base64[c3 & 0x3F], outfile);
325 putc(base64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
326 putc(PADDING, outfile);
329 putc(PADDING, outfile);
330 putc(PADDING, outfile);
336 base64_encode(infile, outfile, text, length)
337 FILE *infile, *outfile;
340 int c1, c2, c3, len = 0;
342 while ((c1 = Getc(infile, text)) != EOF) {
343 if ((c2 = Getc(infile, text)) == EOF)
344 base256to64(c1, 0, 0, 2, outfile);
345 else if ((c3 = Getc(infile, text)) == EOF)
346 base256to64(c1, c2, 0, 1, outfile);
348 base256to64(c1, c2, c3, 0, outfile);
355 if (len) putc('\n', outfile);
361 base64_decode(infile, outfile, text)
362 FILE *infile, *outfile;
367 while ((c1 = GetChar(infile, NO)) != EOF) {
370 if ((c2 = GetChar(infile, YES)) == EOP)
372 PutChar(((c1 << 2) | ((c2 & 0x30) >> 4)), outfile, text);
374 if ((c3 = GetChar(infile, YES)) == EOP)
376 PutChar((((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2)), outfile, text);
378 if ((c4 = GetChar(infile, YES)) == EOP)
380 PutChar((((c3 & 0x03) << 6) | c4), outfile, text);
388 static char base16[] = "0123456789ABCDEF";
389 static char From[] = "\nFrom ";
396 #define softbreak(stream) {putc(EQ, stream); putc(LF, stream);}
399 quoted_printable_encode(infile, outfile, length)
400 FILE *infile, *outfile;
403 int c, len = 0, sp = OFF, lfdot = OFF, Fromix = 1;
405 while ((c = getc(infile)) != EOF) {
406 if ((c == TAB) || (c == SP)) {
407 if (From[Fromix] == c) { /* SP */
409 putc(base16[c >> 4], outfile);
410 putc(base16[c & 0x0f], outfile);
418 if ((++len) > length) {
428 if (sp || (lfdot == DOT))
437 if ((c < SP) || (c == EQ) || (c >= DEL)) {
438 /* exclusive TAB, SP */
441 putc(base16[c >> 4], outfile);
442 putc(base16[c & 0x0f], outfile);
457 if (From[Fromix] == c)
462 if (c == DOT && lfdot == LF)
468 if ((++len) > length) {
476 softbreak(outfile); /* ignored by decoder */
479 static char base128[] = {
480 OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB,
481 OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB,
482 OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB,
483 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,OOB,OOB, OOB,OOB,OOB,OOB,
484 OOB, 10, 11, 12, 13, 14, 15,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB,
485 OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB,
486 OOB, 10, 11, 12, 13, 14, 15,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB,
487 OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB,
491 puthexchar(c1, c2, stream)
496 static int warned = OFF;
498 if (((a1 = base128[c1]) != OOB) && ((a2 = base128[c2]) != OOB)) {
499 putc(((a1 << 4) | a2), stream);
502 if (warned == OFF) { /* warn just once */
503 fprintf(stderr, "Error: can't translate hex to character: %c%c\n",
512 quoted_printable_decode(infile, outfile)
513 FILE *infile, *outfile;
517 /* if an error occurs, print input sequence as it is, anyway, sigh */
519 while((c1 = getc(infile)) != EOF) {
522 if ((c2 = getc(infile)) == EOF) {
523 fprintf(stderr, "Error: end of file after =.\n");
527 if (c2 == LF) continue;
528 if ((c3 = getc(infile)) == EOF) {
529 fprintf(stderr, "Error: end of file after =.\n");
534 if (puthexchar(c2, c3, outfile) == ERROR) {
536 if ((c1 = c2) == EOF) exit(ERROR);
554 gzip64_encode(infile, outfile, text, length)
555 FILE *infile, *outfile;
561 if (pipe(pipes) != 0) {
562 fprintf(stderr, "Can't open pipe\n");
569 fprintf(stderr, "Can't fork.\n");
573 if (childpid > 0) { /* I'm the parent. */
575 if ((infile = fdopen(pipes[READ], FDREAD)) == NULL) {
576 fprintf(stderr, "Can't open read pipe\n");
580 base64_encode(infile, outfile, OFF, length);
593 if (fileno(infile) != READ) {
598 execlp("gzip", "gzip", "-q", "-n", "-c", (char *) 0);
607 if (pipe(pipes2) != 0) {
608 fprintf(stderr, "Can't open pipe\n");
615 fprintf(stderr, "Can't fork.\n");
619 if (childpid2 > 0) { /* I'm the child. */
620 close(pipes2[WRITE]);
624 execlp("gzip", "gzip", "-q", "-n", "-c", (char *) 0);
629 /* I'm the grandchild */
631 _setmode(pipes2[WRITE], O_BINARY);
639 while ((c = Getc(infile, ON)) != EOF)
650 gzip64_decode(infile, outfile, text)
651 FILE *infile, *outfile;
657 if (pipe(pipes) != 0) {
658 fprintf(stderr, "Can't open pipe\n");
665 fprintf(stderr, "Can't fork.\n");
669 if (childpid > 0) { /* I'm the parent. */
677 while ((c = getchar()) != EOF) PutChar(c, outfile, ON);
679 if (fileno(outfile) != WRITE) {
681 dup(fileno(outfile));
683 execlp ("gzip", "gzip", "-q", "-d", "-n", "-c", (char *) 0);
698 if (pipe(pipes2) != 0) {
699 fprintf(stderr, "Can't open pipe\n");
706 fprintf(stderr, "Can't fork.\n");
710 if (childpid2 > 0) { /* I'm the child. */
711 close(pipes2[WRITE]);
717 execlp("gzip", "gzip", "-q", "-d", "-n", "-c", (char *) 0);
722 /* I'm the grandchild */
726 if ((outfile = fdopen(pipes2[WRITE], FDWRITE)) == NULL) {
727 fprintf(stderr, "Can't open write pipe\n");
731 base64_decode(infile, outfile, OFF);
737 if ((outfile = fdopen(pipes[WRITE], FDWRITE)) == NULL) {
738 fprintf(stderr, "Can't open write pipe\n");
742 base64_decode(infile, outfile, OFF);
752 int main (argc, argv)
761 * default option values
764 char encode = BASE64; /* -b -q -g */
765 int length = LINELEN; /* -l num */
766 int text = OFF; /* -t */
767 char *progname = mewbasename(argv[0]), *p;
769 for (p = progname; *p; p++) {
774 _setmode(_fileno(stdin), O_BINARY);
775 _setmode(_fileno(stdout), O_BINARY);
778 _setmode(fileno(stdin), O_BINARY);
779 _setmode(fileno(stdout), O_BINARY);
781 while((optc = getopt_long(argc, argv, "esdbqgzl:thv", longopts,
801 length = atoi(optarg);
820 file_count = argc - optind;
828 if (STRCMP(argv[optind], "-") == 0) {
830 } else if ((infile = fopen(argv[optind], FDREAD)) == NULL) {
831 fprintf(stderr, "Can't open file %s.\n", argv[optind]);
837 if (STRCMP(argv[optind], "-") == 0) {
839 } else if ((infile = fopen(argv[optind], FDREAD)) == NULL) {
840 fprintf(stderr, "Can't open file %s.\n", argv[optind]);
844 if (STRCMP(argv[optind], "-") == 0) {
846 } else if ((outfile = fopen(argv[optind], FDWRITE)) == NULL) {
847 fprintf(stderr, "Can't open file %s.\n", argv[optind]);
857 /* Override argments by progname. */
859 if (STRCMP(progname, DECODE_NAME) == 0)
861 if (STRCMP(progname, CAT_NAME) == 0) {
870 base64_encode(infile, outfile, text, length);
873 quoted_printable_encode(infile, outfile, length);
876 gzip64_encode(infile, outfile, text, length);
883 base64_decode(infile, outfile, text);
886 quoted_printable_decode(infile, outfile);
889 gzip64_decode(infile, outfile, text);
899 * Copyright (C) 1994, 1995, 1996, 1997 Mew developing team.
900 * All rights reserved.
902 * Redistribution and use in source and binary forms, with or without
903 * modification, are permitted provided that the following conditions
906 * 1. Redistributions of source code must retain the above copyright
907 * notice, this list of conditions and the following disclaimer.
908 * 2. Redistributions in binary form must reproduce the above copyright
909 * notice, this list of conditions and the following disclaimer in the
910 * documentation and/or other materials provided with the distribution.
911 * 3. Neither the name of the team nor the names of its contributors
912 * may be used to endorse or promote products derived from this software
913 * without specific prior written permission.
915 * THIS SOFTWARE IS PROVIDED BY THE TEAM AND CONTRIBUTORS ``AS IS'' AND
916 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
917 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
918 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TEAM OR CONTRIBUTORS BE
919 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
920 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
921 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
922 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
923 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
924 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
925 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
929 * mewencode.c ends here