2 * mewencode, mewdecode, and mewcat --- MIME encoding for Mew
4 * Author: Kazu Yamamoto <Kazu@Mew.org>
5 * Shuhei Yamaguchi <yamagus@kw.netlaputa.ne.jp>
7 * Revised: Feb 25, 1998
12 static char version_message[] =
13 "mewencode version 0.13 971113 Kazuhiko Yamamoto";
22 #define ENCODE_NAME "mewencode"
23 #define DECODE_NAME "mewdecode"
24 #define CAT_NAME "mewcat"
25 #define SIGN_NAME "mewsignform"
49 #define Thread __declspec( thread )
50 #define WIN32FSEP '\\'
56 Thread int Incr = OFF;
57 Thread int Ineof = OFF;
58 Thread int Outcr = OFF;
59 Thread int Outeof = OFF;
62 * "b" is ignored on UNIX.
67 #define STRCMP(str1, str2) strncmp(str1, str2, sizeof(str2) - 1)
70 * long name convention for option
73 struct option longopts [] = {
74 {"encode", 0, 0, 'e'},
75 {"decode", 0, 0, 'd'},
76 {"signform", 0, 0, 's'},
77 {"base64", 0, 0, 'b'},
78 {"quoted-printable", 0, 0, 'q'},
79 {"gzip64", 0, 0, 'z'},
80 {"length", 1, 0, 'l'},
83 {"version", 0, 0, 'v'},
91 fprintf(stderr, "usage: %s [-e|-d|-s] [-b|-q|-g] [-l length] [-t] [infile [outfile]]\n", progname);
94 char *help_message[] = {
95 " -e --encode Encoding <infile>",
96 " -d --decode Decoding <infile> instead of encoding",
97 " Decoding is the default when called with decoding",
99 " -b --base64 MIME base64 en/decoding.",
100 " -q --quoted-printable MIME quoted-printable en/decoding.",
101 " -g --gzip64 MIME gzip64 en/decoding(not yet specified in RFC).",
103 " -l --length Line length into which base64/quoted-printable/gzip64 ",
104 " encoding truncate. The default value is 71.",
105 " -t --text On base64/gzip64 encoding, local newline is treated",
107 " On base/gzip64 decoding,any newline is translated",
108 " into local newline.",
109 " Specify this option only when the input is a line",
110 " based object(e.g. Content-Type: is text/plain or",
111 " application/postscript).",
112 " -h --help Display this help message.",
113 " -v --version Display the version.",
115 "Default is Encoding, Base64, Length = 71, Binary.",
116 "If <infile> is \"-\", it means the standard input.",
117 "If <outfile> is \"-\", it means the standard output.",
124 char **p = help_message;
126 fprintf(stderr, "help: %s\n\n", progname);
127 fprintf(stderr, " A MIME encoder/decoder and signature form creator of ISO-2022 family.\n\n");
129 while (*p) fprintf(stderr, "%s\n", *p++);
132 void version(progname)
135 fprintf(stderr, "version of %s: %s\n", progname, version_message);
143 mewbasename(filename)
148 if ((p = strrchr(filename, FILESEP)) != NULL)
149 filename = p + FILESEPLEN;
150 if ((p = strrchr(filename, WIN32FSEP)) != NULL)
151 filename = p + FILESEPLEN;
160 * 8bit input with line canonicalization
171 return(getc(stream));
208 * lineless 'ascii' input
222 } while ( c == CR || c == LF);
231 PutChar(c, stream, text)
248 Outcr = OFF; /* xxx */
284 static char base64[] =
285 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
289 void base256to64 (c1, c2, c3, padding, outfile)
290 int c1, c2, c3, padding;
293 putc(base64[c1>>2], outfile);
294 putc(base64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)], outfile);
297 putc(base64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
298 putc(base64[c3 & 0x3F], outfile);
301 putc(base64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
302 putc(PADDING, outfile);
305 putc(PADDING, outfile);
306 putc(PADDING, outfile);
311 void base64_encode(infile, outfile, text, length)
316 int c1, c2, c3, len = 0;
318 while ((c1 = Getc(infile, text)) != EOF) {
319 if ((c2 = Getc(infile, text)) == EOF)
320 base256to64(c1, 0, 0, 2, outfile);
321 else if ((c3 = Getc(infile, text)) == EOF)
322 base256to64(c1, c2, 0, 1, outfile);
324 base256to64(c1, c2, c3, 0, outfile);
331 if (len) putc('\n', outfile);
338 static char base256[] = {
339 OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB,
341 OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB,
343 OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB, 62, OOB,OOB,OOB, 63,
344 /* 0 1 2 3 4 5 6 7 8 9 = */
345 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,OOB,OOB, OOB,OOB,OOB,OOB,
346 /* A B C D E F G H I J K L M N O*/
347 OOB, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
348 /* P Q R S T U V W X Y Z */
349 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,OOB, OOB,OOB,OOB,OOB,
350 /* a b c d e f g h i j k l m n o*/
351 OOB, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
352 /* p q r s t u v w x y z */
353 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,OOB, OOB,OOB,OOB,OOB,
357 void base64_decode(infile, outfile, text)
364 while ((c1 = GetChar(infile)) != EOF) {
365 if ((c1 = base256[c1]) == OOB) {
366 fprintf(stderr, "Warning: Base64 decoder saw an illegal character.\n");
370 if ((c2 = GetChar(infile)) == EOF) {
371 fprintf(stderr, "Warning: Base64 decoder saw premature EOF.\n");
373 } else if ((c2 = base256[c2]) == OOB) {
374 fprintf(stderr, "Warning: Base64 decoder saw an illegal character.\n");
378 PutChar(((c1 << 2) | ((c2 & 0x30) >> 4)), outfile, text);
380 if ((c3 = GetChar(infile)) == EOF) {
381 fprintf(stderr, "Warning: Base64 decoder saw premature EOF.\n");
383 } else if (c3 == PADDING) {
385 } else if ((c3 = base256[c3]) == OOB) {
386 fprintf(stderr, "Warning: Base64 decoder saw an illegal character.\n");
390 PutChar((((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2)),
393 if ((c4 = GetChar(infile)) == EOF) {
394 fprintf(stderr, "Warning: Base64 decoder saw premature EOF.\n");
396 } else if (c4 == PADDING) {
398 } else if ((c4 = base256[c4]) == OOB) {
399 fprintf(stderr, "Warning: Base64 decoder saw an illegal character.\n");
403 PutChar((((c3 & 0x03) << 6) | c4), outfile, text);
413 static char base16[] = "0123456789ABCDEF";
414 static char From[] = "\nFrom ";
421 #define softbreak(stream) {putc(EQ, stream); putc(LF, stream);}
423 void quoted_printable_encode(infile, outfile, length)
428 int c, len = 0, sp = OFF, lfdot = OFF, Fromix = 1;
430 while ((c = getc(infile)) != EOF) {
431 if ((c == TAB) || (c == SP)) {
432 if (From[Fromix] == c) { /* SP */
434 putc(base16[c >> 4], outfile);
435 putc(base16[c & 0x0f], outfile);
443 if ((++len) > length) {
453 if (sp || (lfdot == DOT))
462 if ((c < SP) || (c == EQ) || (c >= DEL)) {
463 /* exclusive TAB, SP */
466 putc(base16[c >> 4], outfile);
467 putc(base16[c & 0x0f], outfile);
482 if (From[Fromix] == c)
487 if (c == DOT && lfdot == LF)
493 if ((++len) > length) {
501 softbreak(outfile); /* ignored by decoder */
504 static char base128[] = {
505 OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB,
506 OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB,
507 OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB,
508 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,OOB,OOB, OOB,OOB,OOB,OOB,
509 OOB, 10, 11, 12, 13, 14, 15,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB,
510 OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB,
511 OOB, 10, 11, 12, 13, 14, 15,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB,
512 OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB, OOB,OOB,OOB,OOB,
515 int puthexchar(c1, c2, stream)
520 static int warned = OFF;
522 if (((a1 = base128[c1]) != OOB) && ((a2 = base128[c2]) != OOB)) {
523 putc(((a1 << 4) | a2), stream);
526 if (warned == OFF) { /* warn just once */
527 fprintf(stderr, "Error: can't translate hex to character: %c%c\n",
535 void quoted_printable_decode(infile, outfile)
541 /* if an error occurs, print input sequence as it is, anyway, sigh */
543 while((c1 = getc(infile)) != EOF) {
546 if ((c2 = getc(infile)) == EOF) {
547 fprintf(stderr, "Error: end of file after =.\n");
551 if (c2 == LF) continue;
552 if ((c3 = getc(infile)) == EOF) {
553 fprintf(stderr, "Error: end of file after =.\n");
558 if (puthexchar(c2, c3, outfile) == ERROR) {
560 if ((c1 = c2) == EOF) exit(ERROR);
577 DWORD gzip64_encode_input(void* lpArg)
579 FILES* files = (FILES*) lpArg;
582 while ((c = Getc(files->infile, ON)) != EOF) {
583 fputc(c, files->outfile);
586 fclose(files->infile);
587 fclose(files->outfile);
589 return 0UL; /* never reach */
592 void gzip64_encode(infile, outfile, text, length)
597 HANDLE hSaveStdOut, hSaveStdIn;
598 HANDLE hPStdOutRd, hPStdOutWr;
599 HANDLE hPStdInRd, hPStdInWr;
601 SECURITY_ATTRIBUTES saAttr;
602 STARTUPINFO siStartInfo;
603 PROCESS_INFORMATION piProcInfo;
607 FILES tf; /* input/output for child thread */
608 FILE* pin; /* input for parent */
611 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
612 saAttr.bInheritHandle = TRUE;
613 saAttr.lpSecurityDescriptor = NULL;
615 /* save stdin/stdout */
616 hSaveStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
617 hSaveStdIn = GetStdHandle(STD_INPUT_HANDLE);
619 /* stdout for child */
620 if (CreatePipe(&hTmp, &hPStdOutWr, &saAttr, 0) != TRUE) {
621 fprintf(stderr, "Can't open pipe\n");
624 if (SetStdHandle(STD_OUTPUT_HANDLE, hPStdOutWr) != TRUE) {
625 fprintf(stderr, "Can't redirect stdout\n");
628 fRet = DuplicateHandle(GetCurrentProcess(), hTmp,
629 GetCurrentProcess(), &hPStdOutRd, 0, FALSE, DUPLICATE_SAME_ACCESS);
631 fprintf(stderr, "Can't duplicate handle\n");
636 /* stdin for child */
638 if (fileno(infile) != READ) {
639 hPStdInRd = (HANDLE) _get_osfhandle(fileno(infile));
640 if (SetStdHandle(STD_INPUT_HANDLE, hPStdInRd) != TRUE) {
641 fprintf(stderr, "Can't redirect stdin\n");
646 if (CreatePipe(&hPStdInRd, &hTmp, &saAttr, 0) != TRUE) {
647 fprintf(stderr, "Can't open pipe\n");
650 if (SetStdHandle(STD_INPUT_HANDLE, hPStdInRd) != TRUE) {
651 fprintf(stderr, "Can't redirect stdin\n");
654 fRet = DuplicateHandle(GetCurrentProcess(), hTmp,
655 GetCurrentProcess(), &hPStdInWr, 0, FALSE, DUPLICATE_SAME_ACCESS);
657 fprintf(stderr, "Can't duplicate handle\n");
664 memset(&siStartInfo, 0, sizeof(STARTUPINFO));
665 fRet = CreateProcess(NULL, "gzip -q -n -c", NULL, NULL, TRUE, 0,
666 NULL, NULL, &siStartInfo, &piProcInfo);
668 fprintf(stderr, "Can't create process\n");
672 if (SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdOut) != TRUE) {
673 fprintf(stderr, "Can't redirect stdout\n");
676 if (SetStdHandle(STD_INPUT_HANDLE, hSaveStdIn) != TRUE) {
677 fprintf(stderr, "Can't redirect stdin\n");
681 /* input for parent */
682 if ((fd = _open_osfhandle(hPStdOutRd, _O_RDONLY|_O_BINARY)) < 0) {
683 fprintf(stderr, "Can't open read pipe handle\n");
686 if ((pin = fdopen(fd, FDREAD)) == NULL) {
687 fprintf(stderr, "Can't open read pipe\n");
690 CloseHandle(hPStdOutWr);
695 CloseHandle(hPStdInRd);
696 /* input/output for thread */
698 if ((fd = _open_osfhandle(hPStdInWr, _O_WRONLY|_O_BINARY)) < 0) {
699 fprintf(stderr, "Can't open write pipe handle\n");
702 if ((tf.outfile = fdopen(fd, FDWRITE)) == NULL) {
703 fprintf(stderr, "Can't open write pipe\n");
706 hThread = CreateThread(NULL, 0,
707 (LPTHREAD_START_ROUTINE) gzip64_encode_input, (LPVOID) &tf,
709 if (hThread == NULL) {
710 fprintf(stderr, "Can't create thread\n");
715 base64_encode(pin, outfile, OFF, length);
720 DWORD gzip64_decode_output(void* lpArg)
722 FILES* files = (FILES*) lpArg;
725 while ((c = fgetc(files->infile)) != EOF) {
726 PutChar(c, files->outfile, ON);
729 fclose(files->infile);
730 fclose(files->outfile);
732 return 0UL; /* never reach */
735 void gzip64_decode(infile, outfile, text)
740 HANDLE hSaveStdOut, hSaveStdIn;
741 HANDLE hPStdOutRd, hPStdOutWr;
742 HANDLE hPStdInRd, hPStdInWr;
744 SECURITY_ATTRIBUTES saAttr;
745 STARTUPINFO siStartInfo;
746 PROCESS_INFORMATION piProcInfo;
750 FILES tf; /* input/output for child thread */
751 FILE* pout; /* output for parent */
754 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
755 saAttr.bInheritHandle = TRUE;
756 saAttr.lpSecurityDescriptor = NULL;
758 /* save stdin/stdout */
759 hSaveStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
760 hSaveStdIn = GetStdHandle(STD_INPUT_HANDLE);
762 /* stdin for child */
763 if (CreatePipe(&hPStdInRd, &hTmp, &saAttr, 0) != TRUE) {
764 fprintf(stderr, "Can't open pipe\n");
767 if (SetStdHandle(STD_INPUT_HANDLE, hPStdInRd) != TRUE) {
768 fprintf(stderr, "Can't redirect stdin\n");
771 fRet = DuplicateHandle(GetCurrentProcess(), hTmp,
772 GetCurrentProcess(), &hPStdInWr, 0, FALSE, DUPLICATE_SAME_ACCESS);
774 fprintf(stderr, "Can't duplicate handle\n");
780 if (fileno(outfile) != WRITE) {
781 hPStdOutWr = (HANDLE) _get_osfhandle(fileno(outfile));
782 if (SetStdHandle(STD_OUTPUT_HANDLE, hPStdOutWr) != TRUE) {
783 fprintf(stderr, "Can't redirect stdout\n");
788 if (CreatePipe(&hTmp, &hPStdOutWr, &saAttr, 0) != TRUE) {
789 fprintf(stderr, "Can't open pipe\n");
792 if (SetStdHandle(STD_OUTPUT_HANDLE, hPStdOutWr) != TRUE) {
793 fprintf(stderr, "Can't redirect stdout\n");
796 fRet = DuplicateHandle(GetCurrentProcess(), hTmp,
797 GetCurrentProcess(), &hPStdOutRd, 0, FALSE, DUPLICATE_SAME_ACCESS);
799 fprintf(stderr, "Can't duplicate handle\n");
806 memset(&siStartInfo, 0, sizeof(STARTUPINFO));
807 fRet = CreateProcess(NULL, "gzip -q -d -n -c", NULL, NULL, TRUE, 0,
808 NULL, NULL, &siStartInfo, &piProcInfo);
810 fprintf(stderr, "Can't create process\n");
813 if (SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdOut) != TRUE) {
814 fprintf(stderr, "Can't redirect stdout\n");
817 if (SetStdHandle(STD_INPUT_HANDLE, hSaveStdIn) != TRUE) {
818 fprintf(stderr, "Can't redirect stdin\n");
822 /* output for parent */
823 if ((fd = _open_osfhandle(hPStdInWr, _O_WRONLY|_O_BINARY)) < 0) {
824 fprintf(stderr, "Can't open write pipe handle\n");
827 if ((pout = fdopen(fd, FDWRITE)) == NULL) {
828 fprintf(stderr, "Can't open write pipe\n");
831 CloseHandle(hPStdInRd);
836 CloseHandle(hPStdOutWr);
837 /* input/output for thread */
838 tf.outfile = outfile;
840 if ((fd = _open_osfhandle(hPStdOutRd, _O_RDONLY|_O_BINARY)) < 0) {
841 fprintf(stderr, "Can't open read pipe handle\n");
844 if ((tf.infile = fdopen(fd, FDREAD)) == NULL) {
845 fprintf(stderr, "Can't open read pipe\n");
848 hThread = CreateThread(NULL, 0,
849 (LPTHREAD_START_ROUTINE) gzip64_decode_output, (LPVOID) &tf,
851 if (hThread == NULL) {
852 fprintf(stderr, "Can't create thread\n");
857 base64_decode(infile, pout, OFF);
861 WaitForSingleObject(hThread, INFINITE);
867 void sevenbit_signform(infile, outfile)
873 while ((c = Getc(infile, ON)) != EOF) {
883 * Signature form creator
886 int main (argc, argv)
895 * default option values
898 char encode = BASE64; /* -b -q -g */
899 int length = LINELEN; /* -l num */
900 int text = OFF; /* -t */
901 char *progname = mewbasename(argv[0]), *p;
903 for (p = progname; *p; p++) {
907 _setmode(_fileno(stdin), O_BINARY);
908 _setmode(_fileno(stdout), O_BINARY);
910 while((optc = getopt_long(argc, argv, "esdbqgzl:thv", longopts,
933 length = atoi(optarg);
952 file_count = argc - optind;
960 if (STRCMP(argv[optind], "-") == 0) {
962 } else if ((infile = fopen(argv[optind], FDREAD)) == NULL) {
963 fprintf(stderr, "Can't open file %s.\n", argv[optind]);
969 if (STRCMP(argv[optind], "-") == 0) {
971 } else if ((infile = fopen(argv[optind], FDREAD)) == NULL) {
972 fprintf(stderr, "Can't open file %s.\n", argv[optind]);
976 if (STRCMP(argv[optind], "-") == 0) {
978 } else if ((outfile = fopen(argv[optind], FDWRITE)) == NULL) {
979 fprintf(stderr, "Can't open file %s.\n", argv[optind]);
989 /* Override argments by progname. */
991 if (STRCMP(progname, DECODE_NAME) == 0)
993 if (STRCMP(progname, CAT_NAME) == 0) {
997 if (STRCMP(progname, SIGN_NAME) == 0)
1002 sevenbit_signform(infile, outfile);
1007 base64_encode(infile, outfile, text, length);
1010 quoted_printable_encode(infile, outfile, length);
1013 gzip64_encode(infile, outfile, text, length);
1020 base64_decode(infile, outfile, text);
1023 quoted_printable_decode(infile, outfile);
1026 gzip64_decode(infile, outfile, text);
1036 * Copyright (C) 1994, 1995, 1996, 1997 Mew developing team.
1037 * All rights reserved.
1039 * Redistribution and use in source and binary forms, with or without
1040 * modification, are permitted provided that the following conditions
1043 * 1. Redistributions of source code must retain the above copyright
1044 * notice, this list of conditions and the following disclaimer.
1045 * 2. Redistributions in binary form must reproduce the above copyright
1046 * notice, this list of conditions and the following disclaimer in the
1047 * documentation and/or other materials provided with the distribution.
1048 * 3. Neither the name of the team nor the names of its contributors
1049 * may be used to endorse or promote products derived from this software
1050 * without specific prior written permission.
1052 * THIS SOFTWARE IS PROVIDED BY THE TEAM AND CONTRIBUTORS ``AS IS'' AND
1053 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1054 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1055 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TEAM OR CONTRIBUTORS BE
1056 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1057 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1058 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
1059 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
1060 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
1061 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
1062 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1066 * mewencode.c ends here