home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / metamail / contrib / mms / mmsencode.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-29  |  16.0 KB  |  825 lines

  1. /*////////////////////////////////////////////////////////////////////////
  2. Copyright (c) 1992 Electrotechnical Laboratry (ETL)
  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 ETL 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 ETL.
  11. ETL 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. Content-Type: program/C; charset=US-ASCII
  16. Program:      mmsencode.c (encoder)
  17. Author:       Yutaka Sato <ysato@etl.go.jp>
  18.  
  19. History:
  20.         92-05-15 extracted from mmsclient.c
  21.         92-05-16 added MIME header encoder/decoder for ISO-2022-JP
  22.     92-09-30 added switch to ASCII at the end of splitted encoded-text
  23. ///////////////////////////////////////////////////////////////////////*/
  24.  
  25. #include <stdio.h>
  26. #include "str_stdio.h"
  27. FILE *str_fopen();
  28. char *index(),*getenv();
  29. #define MAX_LNSIZE        512
  30.  
  31. /*//////////////////////////////////////////////////////////////////////*/
  32.  
  33. MMS_E_head_ENCODER(ac,av,in,out){
  34. /* test
  35.     char ins[100000],outs[100000];
  36.     int size;
  37.  
  38.     size = fread(ins,1,sizeof(ins),in);
  39.     ins[size] = 0;
  40.     MIME_strHeaderEncode(ins,outs,sizeof(outs));
  41.     printf("%s\n",outs);
  42. */
  43.     MIME_headerEncode(in,out);
  44. }
  45. MMS_E_head_DECODER(ac,av,in,out){
  46. /* test
  47.     char ins[100000],outs[100000];
  48.     int size;
  49.  
  50.     size = fread(ins,1,sizeof(ins),in);
  51.     ins[size] = 0;
  52.     MIME_strHeaderDecode(ins,outs,sizeof(outs));
  53.     printf("%s\n",outs);
  54. */
  55.     MIME_headerDecode(in,out,1);
  56. }
  57. MMS_E_decodeBASE16(ac,av,in,out){
  58.     MMS_decodeBASE16(in,out);
  59. }
  60. MMS_E_encodeBASE16(ac,av,in,out){
  61.     MMS_encodeBASE16(in,out);
  62. }
  63. int (*MMS_E_HEAD_ENCODER)() = MMS_E_head_ENCODER;
  64. int (*MMS_E_HEAD_DECODER)() = MMS_E_head_DECODER;
  65.  
  66. int (*MMS_E_DECODEBASE16)() = MMS_E_decodeBASE16;
  67. int (*MMS_E_ENCODEBASE16)() = MMS_E_encodeBASE16;
  68.  
  69. /*//////////////////////////////////////////////////////////////////////*/
  70. #define MAXCOL            71
  71. #define SWCODE_LENG        4 /*length(encoded(charset sw ESC seq))*/
  72. #define MIN_ENCODEDLEN        2 /* minimum length of encoded text */
  73.  
  74. #define ENCODE_BEGIN        "=?"
  75. #define CHARSET_DONE        '?'
  76. #define ENCODING_DONE        '?'
  77. #define ENCODE_DONE        "?="
  78.  
  79. #define NL            '\n'
  80. #define CR            '\r'
  81. #define TAB            '\t'
  82. #define SPACE            ' '
  83. #define ESC            033
  84. #define NLNL            (NL<<8|NL)
  85.  
  86. #define GOTO1BCODE        '('
  87. #define GOTO2BCODE        '$'
  88. #define GOTO_ASCII_SEQ        "\033(B"
  89.  
  90. char US_ASCII[]        =    "US-ASCII";
  91. char ISO_2022_JP[]    =    "ISO-2022-JP";
  92.  
  93. #define ENCODE_NONE         0
  94. #define ENCODE_BASE64        "B"
  95. #define    ENCODE_QP        "Q"
  96.  
  97. typedef struct {
  98.     int    local;
  99.     char    codesw;
  100.     char   *charset;
  101.     char   *encoding;
  102. } CodeSwitch;
  103.  
  104. static
  105. CodeSwitch Codes1[16] = {
  106.     {1,    'B',    US_ASCII,    ENCODE_NONE    },
  107.     {1,    'J',    US_ASCII,    ENCODE_NONE    },
  108.     0
  109. };
  110.  
  111. static
  112. CodeSwitch Codes2[16] = {
  113.     {1,    '@',    ISO_2022_JP,    ENCODE_BASE64    },
  114.     {1,    'B',    ISO_2022_JP,    ENCODE_BASE64    },
  115.     0
  116. };
  117. MMS_localCharset(charset)
  118.     char *charset;
  119. {    int csi;
  120.     char *cs;
  121.  
  122.     for(csi = 0; cs = Codes1[csi].charset; csi++)
  123.         if( strcasecmp(cs,charset) == 0 )
  124.             return Codes1[csi].local;
  125.  
  126.     for(csi = 0; cs = Codes2[csi].charset; csi++)
  127.         if( strcasecmp(cs,charset) == 0 )
  128.             return Codes2[csi].local;
  129.     return 0;
  130. }
  131.  
  132.  
  133. typedef struct {
  134.     FILE    *in_file;
  135.     char    *in_charset;
  136.     char    *in_encoding;
  137.     int     in_codesw_seq[4];
  138.     int     in_prevch;
  139.  
  140.     FILE    *out_file;
  141.     char    *out_prevcharset;
  142.     char     out_codesw_seq[4];
  143.     int     out_column;
  144. } INOUT;
  145.  
  146. static
  147. INOUT_init(io,in,out)
  148.     INOUT *io;
  149.     FILE *in,*out;
  150. {
  151.     io->in_file = in;
  152.     io->in_charset = US_ASCII;
  153.     io->in_encoding = ENCODE_NONE;
  154.     io->in_codesw_seq[0] = 0;
  155.     io->in_prevch = EOF;
  156.  
  157.     io->out_file = out;
  158.     io->out_prevcharset = US_ASCII;
  159.     io->out_codesw_seq[0] = 0;
  160.     io->out_column = 0;
  161. }
  162.  
  163.  
  164. static
  165. NLfgetc(in)
  166.     FILE *in;
  167. {    int ch;
  168.  
  169.     ch = fgetc(in);
  170.     if( ch == CR ){
  171.         ch = fgetc(in);
  172.         if( ch != NL ){
  173.             if( ch != EOF )
  174.                 ungetc(ch,in);
  175.             ch = CR;
  176.         }
  177.     }
  178.     return ch;
  179. }
  180.  
  181.  
  182. static
  183. EN_FGETC(io)
  184.     INOUT *io;
  185. {    int ch;
  186.     CodeSwitch *csw;
  187.     int ci;
  188.     char *charset;
  189.     char swseq[4],*sw;
  190.     FILE *infile = io->in_file;
  191.  
  192. GET1:
  193.     ch = NLfgetc(infile);
  194. GOT1:
  195.     if( ch != ESC )
  196.         goto exit;
  197.  
  198.     /* got ESC character */
  199.     if( (ch = fgetc(infile)) == EOF )
  200.         goto exit;
  201.  
  202.     if( io->in_prevch == NL )
  203.         if( ch == TAB || ch == SPACE )
  204.             goto GET1;
  205.  
  206.     sw = swseq;
  207.     *sw++ = ESC;
  208.     *sw++ = ch;
  209.  
  210.     switch( ch ){
  211.         default:    goto exit;
  212.         case GOTO1BCODE: csw = Codes1; break;
  213.         case GOTO2BCODE: csw = Codes2; break;
  214.     }
  215.     if( (ch = fgetc(infile)) == EOF )
  216.         goto exit;
  217.  
  218.     *sw++ = ch;
  219.     *sw++ = 0;
  220.  
  221.     for( ci = 0; charset = csw[ci].charset; ci++ )
  222.         if( ch == csw[ci].codesw ){
  223.             io->in_charset = charset;
  224.             io->in_encoding = csw[ci].encoding;
  225.             strcpy(io->in_codesw_seq,swseq);
  226.         }
  227.  
  228.     ch = NLfgetc(infile);
  229.     if( ch == ESC )
  230.         goto GOT1;
  231. exit:
  232.     io->in_prevch = ch;
  233.     return ch;
  234. }
  235.  
  236. static
  237. ew_overhead(charset,encoding)
  238.     char *charset,*encoding;
  239. {    char overhead[128];
  240.  
  241.     sprintf(overhead,"=?%s?%s??= ",charset,encoding);
  242.     return strlen(overhead);
  243. }
  244.  
  245. static EN_FPUTC(ch,io,charset,encoding)
  246.     INOUT *io;
  247.     char *charset,*encoding;
  248. {
  249.     if( charset != io->out_prevcharset ){
  250.         if( io->out_prevcharset != US_ASCII ){
  251.             int len;
  252.             len = fprintf(io->out_file,
  253.                 (ch==NL?"%s":"%s "), ENCODE_DONE);
  254.             io->out_column += len;
  255.         }
  256.         if( charset != US_ASCII ){
  257.             int reqlen,remlen,len;
  258.  
  259.             reqlen = ew_overhead(charset,encoding);
  260.             remlen = MAXCOL - (io->out_column + reqlen);
  261.  
  262.             if( (remlen-SWCODE_LENG) < MIN_ENCODEDLEN ){
  263.                 fprintf(io->out_file,"%c%c",NL,TAB);
  264.                 io->out_column = 1;
  265.             }
  266.             len = fprintf(io->out_file,"=?%s?%s?",
  267.                 charset,encoding);
  268.             io->out_column += len;
  269.         }
  270.         io->out_prevcharset = charset;
  271.     }
  272.  
  273.     if( ch != EOF ){
  274.         if( ch == NL )
  275.             io->out_column = 0;
  276.         else{
  277. /*
  278. SHOULD SPLIT AT WHITE CHARACTER BUT ...
  279.             if( !encoding )
  280.             if( MAXCOL < io->out_column ){
  281.                 fputs("\n\t",io->out_file);
  282.                 io->out_column = 1;
  283.             }
  284. */
  285.             io->out_column++;
  286.         }
  287.         fputc(ch,io->out_file);
  288.     }
  289. }
  290.  
  291. MIME_headerEncode0(in,out)
  292.     FILE *in,*out;
  293. {    char *ip,*op;
  294.     INOUT iob,*io = &iob;
  295.     int ch,prev_ch;
  296.  
  297.     INOUT_init(io,in,out);
  298.     prev_ch = 0;
  299.  
  300.     for(;;){
  301.         ch = EN_FGETC(io);
  302.         if( io->in_charset == US_ASCII ){
  303.             if( ch == EOF )
  304.                 break;
  305.             if( ch == NL && prev_ch == NL )
  306.                 break;
  307.             EN_FPUTC(ch,io,US_ASCII,ENCODE_NONE);
  308.             prev_ch = ch;
  309.             continue;
  310.         }
  311.         ungetc(ch,io->in_file);
  312.  
  313.         for(;;){
  314.             ch = encode_word(io);
  315.             if( io->in_charset == US_ASCII )
  316.                 break;
  317.         }
  318.         if( ch == EOF )
  319.             break;
  320.         ungetc(ch,io->in_file);
  321.     }
  322.     if( ch == EOF )
  323.         EN_FPUTC(ch,io,US_ASCII,ENCODE_NONE);
  324.     return ch;
  325. }
  326. MIME_headerEncode(in,out)
  327.     FILE *in,*out;
  328. {    int ch;
  329.  
  330.     ch = MIME_headerEncode0(in,out);
  331.     if( ch != EOF ){
  332.         fputc(NL,out);
  333.         while( (ch = NLfgetc(in)) != EOF )
  334.             fputc(ch,out);
  335.     }
  336. }
  337.  
  338. static
  339. encode_one(encoding,ins,ilen,outs,osize)
  340.     char *encoding,*ins,*outs;
  341. {    int len;
  342.  
  343.     if( strcasecmp(encoding,ENCODE_QP) == 0 )
  344.         len = str_toqp(ins,ilen,outs,osize);
  345.     else
  346.     if( strcasecmp(encoding,ENCODE_BASE64) == 0 )
  347.         len = str_to64(ins,ilen,outs,osize);
  348.     else{
  349.         strncpy(outs,ins,ilen);
  350.         len = ilen;
  351.     }
  352.     outs[len] = 0;
  353.     return len;
  354. }
  355.  
  356. static
  357. encode_word(io)
  358.     INOUT *io;
  359. {    char *charset;
  360.     char *encoding;
  361.     char ins[0x200],outs[0x200];
  362.     int inx,outx;
  363.     int nchar,reqlen,remlen,outlen;
  364.     char ch,encoded_ch;
  365.  
  366.     charset = io->in_charset;
  367.     encoding = io->in_encoding;
  368.     sprintf(ins,"%s",io->in_codesw_seq);
  369.     inx = strlen(ins);
  370.     outlen = encode_one(encoding,ins,inx,outs,sizeof(outs));
  371.  
  372.     reqlen = ew_overhead(charset,encoding);
  373.     remlen = MAXCOL - (io->out_column + reqlen);
  374.  
  375.     if( (remlen-outlen) < MIN_ENCODEDLEN ){
  376.         EN_FPUTC(NL,io,US_ASCII,ENCODE_NONE);
  377.         EN_FPUTC(TAB,io,US_ASCII,ENCODE_NONE);
  378.         remlen = MAXCOL - (io->out_column + reqlen);
  379.     }
  380.  
  381.     for(nchar = 0; ;nchar++){
  382.         outlen = encode_one(encoding,ins,inx,outs,sizeof(outs));
  383.         if( (remlen <= outlen) && ((nchar%2)==0)){
  384.             strcpy(&ins[inx],GOTO_ASCII_SEQ); /* (1) */
  385.             inx += strlen(&ins[inx]);
  386.             break;
  387.         }
  388.         ch = EN_FGETC(io);
  389.         if( ch == EOF ){
  390.             strcpy(&ins[inx],GOTO_ASCII_SEQ); /* (2) */
  391.             inx += strlen(&ins[inx]);
  392.             break;
  393.         }
  394.         if( io->in_charset != charset ){
  395.             strcpy(&ins[inx],io->in_codesw_seq);
  396.             inx += strlen(&ins[inx]);
  397.             break;
  398.         }
  399.         ins[inx++] = ch;
  400.         ins[inx] = 0;
  401.     }
  402.     outlen = encode_one(encoding,ins,inx,outs,sizeof(outs));
  403.     for(outx = 0; outx < outlen; outx++){
  404.         encoded_ch = outs[outx];
  405.         if( encoded_ch == NL )
  406.             continue;
  407.         EN_FPUTC(encoded_ch,io,charset,encoding);
  408.     }
  409.     if( remlen <= outlen ){    /* this encoded-word was splitted */
  410.         EN_FPUTC(NL,io,US_ASCII,ENCODE_NONE);
  411.         EN_FPUTC(TAB,io,US_ASCII,ENCODE_NONE);
  412.     }
  413.     return ch;
  414. }
  415. /* it's desireble ? to insert NL before an encoded-word which length is
  416.  * shorter than MAXCOL, when it will be splitted otherwise. */
  417. /* (1),(2): Terminate every encoded-texts with the switch to US_ASCII */
  418.  
  419. static
  420. decode_word(io)
  421.     INOUT *io;
  422. {    char reads[256],charset[128],encoding[128],itext[256],dtext[256];
  423.     int ilen,dch,dsize,len,pad;
  424.     int eow;
  425.  
  426.     *charset = *encoding = *itext = 0;
  427.     eow = scan_encoded_word(io->in_file,reads,charset,encoding,itext);
  428.  
  429.     if( eow == NL || eow == EOF ){
  430.         fprintf(io->out_file,"=?%s",reads);
  431.         if(eow != EOF)
  432.         fprintf(io->out_file,"%c",eow);
  433.         return eow;
  434.     }
  435.  
  436.     if( !MMS_localCharset(charset) ){
  437.         fprintf(io->out_file,"=?%s?%s?%s?=",charset,encoding,itext);
  438.         if( eow )
  439.             fprintf(io->out_file,"%c",eow);
  440.         return 0;
  441.     }
  442.  
  443.     ilen = strlen(itext);
  444.     dsize = sizeof(dtext);
  445.     if( strcasecmp(encoding,ENCODE_QP) == 0 )
  446.         len = str_fromqp(itext,ilen,dtext,dsize);
  447.     else
  448.     if( strcasecmp(encoding,ENCODE_BASE64) == 0 )
  449.         len = str_from64(itext,ilen,dtext,dsize);
  450.     else{
  451.         strcpy(dtext,itext);
  452.         len = ilen;
  453.     }
  454.  
  455.     if( 0 < len ){
  456.         FILE *Dout;
  457.         INOUT tinb,*tin = &tinb;
  458.         char *charset1;
  459.  
  460.         Dout = str_fopen(dtext,len);
  461.         INOUT_init(tin,Dout,NULL);
  462.         charset1 = US_ASCII;
  463.  
  464.         while((dch = EN_FGETC(tin)) != EOF ){
  465.             if( tin->in_charset != charset1 ){
  466.                 set_outcodesw_seq(io,tin->in_codesw_seq);
  467.                 charset1 = tin->in_charset;
  468.             }
  469.             DE_FPUTC(dch,io);
  470.         }
  471.         str_fclose(Dout);
  472.         if( charset1 != US_ASCII )
  473.             if( tin->in_charset == US_ASCII )
  474.                 set_outcodesw_seq(io,tin->in_codesw_seq);
  475.             else    set_outcodesw_seq(io,GOTO_ASCII_SEQ);
  476.     }
  477.     return 0;
  478. }
  479.  
  480. static
  481. DE_FPUTC(ch,io)
  482.     INOUT *io;
  483. {    char *seq;
  484.  
  485.     seq = io->out_codesw_seq;
  486.     if( ch == EOF ){
  487.         /* FLUSH PENDING CODE SWITCH SEQUENCE IF EXISTS */
  488.         if( seq[0] )
  489.             fputs(seq,io->out_file);
  490.     }else{
  491.         if( seq[0] ){
  492.             fputs(seq,io->out_file);
  493.             seq[0] = 0;
  494.         }
  495.         fputc(ch,io->out_file);
  496.     }
  497. }
  498. set_outcodesw_seq(io,seq)
  499.     INOUT *io;
  500.     char *seq;
  501. {
  502.     strcpy(io->out_codesw_seq,seq);
  503. }
  504.  
  505. static
  506. DE_FGETC(in,unfold)
  507.     FILE *in;
  508. {    int ch;
  509.  
  510.     ch = NLfgetc(in);
  511. GOT1:
  512.     if( ch == NL ){
  513.         ch = NLfgetc(in);
  514.         if( ch == NL ){
  515.             ch = NLNL;
  516.             goto EXIT;
  517.         }
  518.         if(unfold){
  519.             if( ch == TAB || ch == SPACE ){
  520.                 do{    ch = NLfgetc(in);
  521.                 }while( ch == TAB || ch == SPACE );
  522.                 goto GOT1;
  523.             }
  524.         }
  525.         ungetc(ch,in);
  526.         ch = NL;
  527.     }
  528. EXIT:
  529.     return ch;
  530. }
  531. MIME_headerDecode(in,out,bodytoo)
  532.     FILE *in,*out;
  533. {    int ch,next_ch;
  534.     int unfold = 0;
  535.     INOUT iob,*io = &iob;
  536.  
  537.     INOUT_init(io,in,out);
  538.  
  539.     for(;;){
  540.         ch = DE_FGETC(in,unfold);
  541.         if( ch == EOF )
  542.             break;
  543.         if( ch == NL )
  544.             unfold = 0;
  545.  
  546.         if( ch == ENCODE_BEGIN[0] ){
  547.             ch = NLfgetc(in);
  548.             if( ch == EOF )
  549.                 break;
  550.             if( ch == ENCODE_BEGIN[1] ){
  551.                 if( decode_word(io) == EOF )
  552.                     break;
  553.                 unfold = 1;
  554.             }else{
  555.                 DE_FPUTC(ENCODE_BEGIN[0],io);
  556.                 ungetc(ch,in);
  557.             }
  558.         }else{
  559.             if( ch == NLNL ){
  560.                 DE_FPUTC(NL,io);
  561.                 DE_FPUTC(NL,io);
  562.                 break;
  563.             }
  564.             DE_FPUTC(ch,io);
  565.         }
  566.     }
  567.     if( ch != EOF && bodytoo )
  568.         while( (ch = NLfgetc(in)) != EOF )
  569.             DE_FPUTC(ch,io);
  570.     DE_FPUTC(EOF,io);
  571. }
  572.  
  573. MIME_strHeaderDecode(ins,outs,osize)
  574.     char *ins,*outs;
  575. {    FILE *In,*Out;
  576.     int oi;
  577.  
  578.     In = str_fopen(ins,strlen(ins));
  579.     Out = str_fopen(outs,osize);
  580.     MIME_headerDecode(In,Out,1);
  581.     fflush(Out);
  582.     for(oi = 0; outs[oi]; oi++)
  583.         if((outs[oi] & 0xFF) == 0xFF)
  584.             strcpy(&outs[oi],&outs[oi+1]);
  585.     str_fclose(In);
  586.     str_fclose(Out);
  587. }
  588. MIME_strHeaderEncode(ins,outs,osize)
  589.     char *ins,*outs;
  590. {    FILE *In,*Out;
  591.  
  592.     In = str_fopen(ins,strlen(ins));
  593.     Out = str_fopen(outs,osize);
  594.     MIME_headerEncode(In,Out);
  595.     fflush(Out);
  596.     str_fclose(In);
  597.     str_fclose(Out);
  598. }
  599.  
  600. is_MIME_header(fp)
  601.     FILE *fp;
  602. {    char line[256];
  603.     int off;
  604.  
  605.     off = ftell(fp);
  606.     while( fgets(line,sizeof(line),fp) != NULL ){
  607.         if( *line == NL )
  608.             break;
  609.         if( *line == CR && line[1] == NL )
  610.             break;
  611.  
  612.         if( strstr(line,ENCODE_BEGIN) ){
  613.             fseek(fp,off,0);
  614.             return 1;
  615.         }
  616.     }
  617.     fseek(fp,off,0);
  618.     return 0;
  619. }
  620.  
  621. FILE *
  622. MIME_tmpHeaderDecode(fp,bodytoo)
  623.     FILE *fp;
  624. {    FILE *tfp;
  625.  
  626.     if( fp == NULL )
  627.         return NULL;
  628.  
  629.     if( fseek(fp,0,1) == 0 ){
  630.         if( !is_MIME_header(fp) )
  631.             return NULL;
  632.     }
  633.  
  634.     tfp = tmpfile();
  635.     MIME_headerDecode(fp,tfp,bodytoo);
  636.     fflush(tfp);
  637.     fseek(tfp,0,0);
  638.     return tfp;
  639. }
  640. FILE *
  641. MIME_tmpHeaderEncode(fp,savFILE)
  642.     FILE *fp,savFILE;
  643. {    FILE *tin,*tfp;
  644.     char line[256];
  645.     int ch;
  646.  
  647.     if( fp == NULL )
  648.         return;
  649.     tin = tmpfile();
  650.     while( fgets(line,sizeof(line),fp) != NULL ){
  651.         fputs(line,tin);
  652.         if(strcmp(line,".\n")==0 || strcmp(line,".\r\n")==0)
  653.             break;
  654.     }
  655.     fflush(tin);
  656.     fseek(tin,0,0);
  657.  
  658.     tfp = tmpfile();
  659.     ch = MIME_headerEncode0(tin,tfp);
  660.     if( ch == NL ){
  661.         fputs("\r\n",tfp);
  662.         while( fgets(line,sizeof(line),tin) != NULL )
  663.             fputs(line,tfp);
  664.     }
  665.     fputs(".\r\n",tfp);
  666.     fflush(tfp);
  667.     fseek(tfp,0,0);
  668.  
  669.     fclose(tin);
  670.     return tfp;
  671. }
  672.  
  673. static
  674. scan_encoded_word(in,reads,charset,encoding,text)
  675.     FILE *in;
  676.     char *reads,*charset,*encoding,*text;
  677. {    int i,cs;
  678.  
  679.     for(i = 0; ;i++){
  680.         cs = NLfgetc(in);
  681.         *reads++ = cs;
  682.         if(cs==NL || cs==EOF) goto error;
  683.         if(cs==CHARSET_DONE) break;
  684.         charset[i] = cs;
  685.         charset[i+1] = 0;
  686.     }
  687.     for(i = 0; ;i++){
  688.         cs = NLfgetc(in);
  689.         *reads++ = cs;
  690.         if(cs==NL || cs==EOF) goto error;
  691.         if(cs==ENCODING_DONE) break;
  692.         encoding[i] = cs;
  693.         encoding[i+1] = 0;
  694.     }
  695.     for(i = 0; i < 80; i++ ){
  696.         cs = NLfgetc(in);
  697.         *reads++ = cs;
  698.         if(cs==NL || cs==EOF) goto error;
  699.         if(cs == ENCODE_DONE[0]){
  700.             cs = NLfgetc(in);
  701.             *reads++ = cs;
  702.             if(cs==NL || cs==EOF) goto error;
  703.             if( cs == ENCODE_DONE[1] ){
  704.                 cs = NLfgetc(in);
  705.                 if(cs == SPACE || cs == TAB || cs == EOF)
  706.                     break;
  707.                 else    ungetc(cs,in);
  708.                 text[i] = 0;
  709.                 break;
  710.             }
  711.             ungetc(cs,in);
  712.             cs = ENCODE_DONE[0];
  713.         }
  714.         text[i] = cs;
  715.         text[i+1] = 0;
  716.     }
  717.     return 0;
  718. error:
  719.     *reads = 0;
  720.     return cs;
  721. }
  722.  
  723.  
  724. /*//////////////////////////////////////////////////////////////////////*/
  725. MMS_decodeStrColumns(str)
  726.     char *str;
  727. {    INOUT iob,*io = &iob;
  728.     FILE *sfp;
  729.     int len;
  730.  
  731.     sfp = str_fopen(str,strlen(str));
  732.     INOUT_init(io,sfp,NULL);
  733.  
  734.     len = 0;
  735.     while( EN_FGETC(io) != EOF )
  736.         len++;
  737.  
  738.     str_fclose(sfp);
  739.     return len;
  740. }
  741.  
  742. /*//////////////////////////////////////////////////////////////////////*/
  743. MMS_encodeBASE16(ifp,ofp)
  744.     register FILE *ifp,*ofp;
  745. {    char ibuf[32],obuf[64+2];
  746.     register char *op;
  747.     register int bytes,rc,ci,ch;
  748.  
  749.     bytes = 0;
  750.     while( 0 < (rc = fread(ibuf,1,sizeof(ibuf),ifp)) ){
  751.         op = obuf;
  752.         for( ci = 0; ci < rc; ci++ ){
  753.             ch = ibuf[ci];
  754.             *op++ = 'A' + (0xF & (ch>>4));
  755.             *op++ = 'A' + (0xF &  ch    );
  756.             bytes++;
  757.         }
  758.         *op++ = '\n';
  759.         fwrite(obuf,rc*2+1,1,ofp);
  760.     }
  761.     fwrite(".\n",2,1,ofp);
  762.     return bytes;
  763. }
  764.  
  765. MMS_decodeBASE16(ifp,ofp)
  766.     register FILE *ifp,*ofp;
  767. {    char ibuf[64+2],obuf[32];
  768.     register char *op;
  769.     register int bytes,ci,c1,c2;
  770.  
  771.     bytes = 0;
  772.     while( fgets(ibuf,sizeof(ibuf),ifp) != NULL ){
  773.         if( ibuf[0] == '.' && ibuf[1] == '\n' )
  774.             break;
  775.         op = obuf;
  776.         for( ci = 0; c1 = ibuf[ci]; ci += 2 ){
  777.             if( c1 < 'A' || 'Z' < c1 )
  778.                 break;
  779.             c1 -= 'A';
  780.             c2 = ibuf[ci+1] - 'A';
  781.             *op++ = c1 << 4 | c2;
  782.             bytes++;
  783.         }
  784.         fwrite(obuf,ci/2,1,ofp);
  785.     }
  786.     fflush(ofp);
  787.     return bytes;
  788. }
  789.  
  790. /*//////////////////////////////////////////////////////////////////////*/
  791.  
  792. MIME_Decode(in,out,encode)
  793.     FILE *in,*out;
  794.     char *encode;
  795. {
  796.     if( strcasecmp(encode,"base64") == 0 )
  797.         from64(in,out,NULL,0);
  798.     else
  799.     if( strcasecmp(encode,"quoted-printable") == 0 )
  800.         fromqp(in,out,NULL,0);
  801.     else{
  802.         fprintf(out,"unknown encoding: %s\n",encode);
  803.     }
  804.     fflush(out);
  805. }
  806.  
  807. /*//////////////////////////////////////////////////////////////////////*/
  808.  
  809. #include <ctype.h>
  810.  
  811. MMS_touppers(str) char *str; {
  812.     char *cp;
  813.  
  814.     for( cp = str; *cp; cp++ )
  815.         if( islower(*cp) )
  816.             *cp = toupper(*cp);
  817. }
  818. MMS_tolowers(str) char *str; {
  819.     char *cp;
  820.  
  821.     for( cp = str; *cp; cp++ )
  822.         if( isupper(*cp) )
  823.             *cp = tolower(*cp);
  824. }
  825.