dtcm: Resolve CID 87408
[oweals/cde.git] / cde / programs / dtcm / dtcm / RFCMIME.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 static char sccsid[] = "$TOG: RFCMIME.c /main/11 1999/06/30 12:08:55 mgreess $";
24 /*
25  *   COMPONENT_NAME: desktop
26  *
27  *   FUNCTIONS: CvtStr
28  *              DtXlateOpToStdLocale
29  *              DtXlateStdToOpLocale
30  *              _converter_
31  *              base64size
32  *              crlf
33  *              getCharSet
34  *              getEncodingType
35  *              mbisspace
36  *              md5PlainText
37  *              rfc1522cpy
38  *              targetTagName
39  *              writeBase64
40  *              writeContentHeaders
41  *              writeQPrint
42  *
43  *   ORIGINS: 119
44  *
45  *   OBJECT CODE ONLY SOURCE MATERIALS
46  */
47
48 #include <stdio.h>
49 #include <errno.h>
50 #include <unistd.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <md5.h>
54 #define _ILS_MACROS
55 #include <ctype.h>
56 #include <assert.h>
57 #include <RFCMIME.h>
58
59 /* Iconv not defined for linux.  Use the EUSCompat stubs instead. */
60 #if !defined(linux)
61 #  include <iconv.h>
62 #endif
63 #include <EUSCompat.h>
64 #include <locale.h>
65 #include <LocaleXlate.h>
66
67 #ifdef ICONV_INBUF_CONST
68 # define ICONV_INBUF_TYPE       const char **
69 #else
70 # define ICONV_INBUF_TYPE       char **
71 #endif
72
73 #define WORKSIZE 1024*10        
74 /*
75  * The following escape sequence is defined as "To ASCII".
76  * But is it correct regardless of ISO-2022-XX ???
77  */
78 #define ToASCII_NUM 3
79 static char ToASCII[ToASCII_NUM] = { 0x1b, 0x28, 0x42 };
80
81 /*
82  * _i18nwork1[] is used to convert the passed string with CD iconv.
83  * in _converter_().
84  *
85  */
86 static void           *_i18nwork1 = NULL;
87 static unsigned long  _i18nsize1 = 0;
88 static int            shouldAlloc1 = ~0;
89
90 /*
91  * _i18nwork2[] is used to convert the passed string with CD iconv.
92  * in CvtStr().
93  *
94  */
95 static void           *_i18nwork2 = NULL;
96 static unsigned long  _i18nsize2 = 0;
97 static int            shouldAlloc2 = ~0;
98
99 /*
100  * Forward declarations
101  */
102 extern void writeBase64(char * buf, const char * bp, const unsigned long len);
103
104 static const char *DfltStdCharset = "us-ascii";
105 static const char *DfltStdLang = "C";
106
107 static void crlf(char *buf)
108 {
109         strcat(buf,"\n");
110 }
111
112 /******************************************************************************
113  * Function:    int DtXlateOpToStdLocale (char *operation, char *opLocale,
114  *                         char **ret_stdLocale, char **ret_stdLang, char **ret_stdSet)
115  *
116  * Parameters:
117  *              operation       Operation associated with the locale value
118  *              opLocale        An operation-specific locale string
119  *              ret_locale      Returns the std locale
120  *                              Caller must free this string.
121  *              ret_stdLang        Returns the std language & territory string.
122  *                              Caller must free this string.
123  *              ret_stdSet         Returns the std code set string.
124  *                              Caller must free this string.
125  *
126  * Return Value:
127  *
128  * Purpose:  Gets the standard locale given an operation and its locale
129  *
130  *****************************************************************************/
131 void
132 DtXlateOpToStdLocale (
133      char       *operation,
134      char       *opLocale,
135      char       **ret_stdLocale,
136      char       **ret_stdLang,
137      char       **ret_stdSet)
138 {
139      _DtXlateDb MyDb = NULL;
140      char MyPlatform[_DtPLATFORM_MAX_LEN + 1];
141      int        ExecVer;
142      int        CompVer;        
143
144      if (_DtLcxOpenAllDbs(&MyDb) == 0 &&
145          _DtXlateGetXlateEnv(MyDb,MyPlatform,&ExecVer,&CompVer) != 0)
146      {
147           _DtLcxCloseDb(&MyDb);
148           MyDb = NULL;
149      }
150
151
152     if (MyDb != NULL)   
153         {
154         (void) _DtLcxXlateOpToStd(MyDb, MyPlatform, ExecVer,
155                                 operation,opLocale,
156                                 ret_stdLocale, ret_stdLang, ret_stdSet, NULL);
157         }
158
159     /* if failed, give default values */
160     if (ret_stdLocale != NULL && *ret_stdLocale == NULL)
161     {
162         *ret_stdLocale = (char *)malloc(strlen(DfltStdLang)+strlen(DfltStdCharset)+3);
163         sprintf(*ret_stdLocale,"%s.%s",DfltStdLang,DfltStdCharset);
164     }
165     if (ret_stdLang != NULL && *ret_stdLang == NULL)
166         *ret_stdLang = (char *)strdup(DfltStdLang);
167     if (ret_stdSet != NULL && *ret_stdSet == NULL)
168         *ret_stdSet = (char *)strdup(DfltStdCharset);
169 }
170
171 /******************************************************************************
172  * Function:    int DtXlateStdToOpLocale ( char *operation, char *stdLocale,
173  *                                      char *stdLang, char *stdCodeSet,
174  *                                      char *dflt_opLocale, char **ret_opLocale)
175  *
176  * Parameters:
177  *    operation         operation whose locale value will be retrieved
178  *    stdLocale         standard locale value
179  *    stdLang           standard Lang/Territory Value
180  *    stdCodeSet        standard CodeSet Value
181  *    dflt_opLocale     operation-specific locale-value
182  *                      This is the default value used in error case
183  *    ret_opLocale      operation-specific locale-value placed here
184  *                      Caller must free this string.
185  *
186  * Return Value:
187  *
188  * Purpose: Gets an operation-specific locale string given the standard string
189  *
190  *****************************************************************************/
191 void
192 DtXlateStdToOpLocale (
193      char       *operation,
194      char       *stdLocale,
195      char       *stdLang,
196      char       *stdCodeSet,
197      char       *dflt_opLocale,
198      char       **ret_opLocale)
199 {
200      _DtXlateDb MyDb = NULL;
201      char MyPlatform[_DtPLATFORM_MAX_LEN + 1];
202      int        ExecVer;
203      int        CompVer;
204
205      if (_DtLcxOpenAllDbs(&MyDb) == 0 &&
206          _DtXlateGetXlateEnv(MyDb,MyPlatform,&ExecVer,&CompVer) != 0)
207      {
208           _DtLcxCloseDb(&MyDb);
209           MyDb = NULL;
210      }
211
212
213     if (MyDb != NULL)
214     {
215         (void) _DtLcxXlateStdToOp(MyDb, MyPlatform, ExecVer,
216                         operation, stdLocale, stdLang, stdCodeSet, NULL,
217                         ret_opLocale);
218     }
219
220     /* if translation fails, use a default value */
221     if (ret_opLocale && *ret_opLocale == NULL)
222     {
223        if (dflt_opLocale) *ret_opLocale = (char *)strdup(dflt_opLocale);
224        else if (stdLocale) *ret_opLocale = (char *)strdup(stdLocale);
225     }
226 }
227 char *
228 targetTagName()
229 {
230    char *ret_locale = NULL;
231    char *ret_lang = NULL;
232    char *ret_codeset = NULL;
233    char *ret_target = NULL;
234
235    DtXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
236           setlocale(LC_CTYPE, NULL),
237           &ret_locale,
238           &ret_lang,
239           &ret_codeset);
240    DtXlateStdToOpLocale(DtLCX_OPER_INTERCHANGE_CODESET,
241           NULL,
242           NULL,
243           ret_codeset,
244           NULL,
245           &ret_target);
246    DtXlateStdToOpLocale(DtLCX_OPER_MIME,
247           NULL,
248           NULL,
249           ret_target,
250           NULL,
251           &ret_codeset);
252
253    return ret_codeset;
254 }
255
256 void
257 getCharSet(char * charset)
258 {
259         char *mimeCS = NULL;
260
261      mimeCS = targetTagName();
262
263     if (mimeCS) {
264        strcpy(charset, mimeCS);
265     } else {
266            strcpy(charset, "us-ascii");   /* default MIME codeset */
267     }
268 }
269
270
271 void
272 md5PlainText(const char * bp, const unsigned long len, unsigned char * digest)
273 {
274     /* We need to compute the md5 signature based on a message that has
275     // the CRLF line terminator. Most of our buffers don't so we will need
276     // to scan the body and do some magic. The approach will be to sum
277     // one line at a time. If the buffer doesn't have CRLF we will do that
278     // independently.
279     */
280
281     MD5_CTX context;
282     unsigned char * local_crlf = (unsigned char *)"\r\n";
283     const char * last = bp;
284     const char * cur;
285
286     MD5Init(&context);
287     for (cur = bp; cur < (bp + len); cur++) {
288         if (*cur == '\n') {
289             if (cur == bp || *(cur - 1) == '\r') {
290                 MD5Update(&context, (unsigned char *)last,
291                           cur - last + 1);
292             }
293             else {
294                 MD5Update(&context, (unsigned char *)last,
295                           cur - last);
296                 MD5Update(&context, local_crlf, 2);
297             }
298             last = cur + 1;
299         }
300     }
301
302     if (bp[len - 1] != '\n') {
303         /* Need to sum the trailing fraction with a CRLF. */
304         MD5Update(&context, (unsigned char *)last,
305                   cur - last);
306         MD5Update(&context, local_crlf, 2);
307     }
308
309     MD5Final(digest, &context);
310 }
311
312
313 static void _converter_( iconv_t CD,
314                         void *from, unsigned long from_len,
315                         void **to,  unsigned long *to_len )
316 {
317     char          *InBuf;
318     size_t        InBytesLeft;
319     char          *OutBuf = NULL;
320     size_t        OutBytesLeft = 0;
321     size_t        _OutBytesLeft = 0;
322     size_t        iconv_ret;
323     size_t        converted_num = 0;
324
325
326     *to = NULL;
327     *to_len = 0;
328
329     if ( shouldAlloc1 ) {
330         /* Obtain work area */
331         _i18nwork1 = (size_t *)malloc( WORKSIZE );
332         if ( !_i18nwork1 ) {
333             _i18nwork1 = NULL;
334             return;
335         }
336         _i18nsize1 = WORKSIZE; 
337         shouldAlloc1 = 0;
338     }
339
340     InBuf        = (char *)from;
341     InBytesLeft  = from_len;
342     OutBytesLeft = _i18nsize1;
343     OutBuf = (char *)_i18nwork1;
344
345     /*
346      * Need to place iconv state to the initial one by
347      * setting inbuf to NULL of iconv().
348      */
349     iconv( CD, (ICONV_INBUF_TYPE)NULL, 0, NULL, 0 );
350     while( 1 ) {
351         /*
352          * InBuf
353          *  v
354          * +----------------------------+
355          * | |                        | |
356          * +----------------------------+
357          *  <-------------------------->
358          *          InBytesLeft
359          *
360          *             |
361          *             | iconv()
362          *             V
363          * (_i18nwork1)
364          * OutBuf
365          *  v
366          * +----------------------------+
367          * | |                        | |
368          * +----------------------------+
369          *  <-------------------------->
370          *          InBytesLeft
371          */
372
373         iconv_ret = iconv( CD, (ICONV_INBUF_TYPE)&InBuf, &InBytesLeft,
374                                &OutBuf, &OutBytesLeft );
375         if ( iconv_ret == 0 ) {
376             /* iconv done
377              *                             InBuf
378              *                               v
379              * +----------------------------+
380              * |XXXXXXXXXXXXXXXXXXXXXXXXXXXX|
381              * +----------------------------+
382              *                               
383              *                               InBytesLeft=0
384              *
385              * (_i18nwork1)
386              *  |               OutBuf
387              *  V                 v
388              * +----------------------------+
389              * |XXXXXXXXXXXXXXXXX| |      | |
390              * +----------------------------+
391              *  <---------------> <-------->
392              *   converted_num    OutBytesLeft
393              */
394             converted_num = (unsigned long)((char *)OutBuf-(char *)_i18nwork1);
395             *to = (void *)_i18nwork1;
396             *to_len = (unsigned long)converted_num;
397             break;
398         } else {
399             if ( errno == E2BIG ) {
400                 /* Overflow. still data is left.
401                  *               InBuf
402                  *                 v
403                  * +----------------------------+
404                  * |XXXXXXXXXXXXXX| |         | |
405                  * +----------------------------+
406                  *                 <----------->
407                  *                  InBytesLeft
408                  *
409                  * (_i18nwork1)
410                  *  |                         OutBuf
411                  *  V                          v
412                  * +----------------------------+
413                  * |XXXXXXXXXXXXXXXXXXXXXXXXXXX |
414                  * +----------------------------+
415                  *  <-------------------------> 
416                  *          converted_num      OutBytesLeft=?
417                  */
418                 void *_p;
419
420                 /* Check how many converted already.
421                 */
422                 converted_num =
423                         (unsigned long)((char *)OutBuf - (char *)_i18nwork1);
424                 _i18nsize1 += WORKSIZE;
425                 _p = realloc( _i18nwork1, _i18nsize1 );
426                 if ( !_p ) {
427                     *to = NULL;
428                     *to_len = 0;
429                     free( _i18nwork1 );
430                     _i18nwork1 = NULL;
431                     _i18nsize1 = 0;
432                     shouldAlloc1 = ~0;
433                     break;
434                 } else {
435                     _i18nwork1 = _p;
436                     OutBuf = (char *)((char*)_i18nwork1 + converted_num);
437                     OutBytesLeft += WORKSIZE;
438                 }  
439             } else {
440                 *to = NULL;
441                 *to_len = 0;
442                 break;
443             }
444         }
445     }
446 }
447
448
449 int
450 CvtStr( char *charSet, void *from, unsigned long from_len,
451                  void **to, unsigned long *to_len, Direction dir )
452 {
453     char        *ret_locale = NULL;
454     char        *ret_lang = NULL;
455     char        *ret_codeset = NULL;
456     char        *from_codeset = NULL;
457     char        *to_codeset = NULL;
458     char        *CuStdCodeSet = NULL;
459     char        *InterChCodeSet = NULL;
460     char        *StdCodeSet = NULL;
461     iconv_t     CD;
462     int         isASCII=~0;
463     int         isStopASCII = ~0;
464     unsigned long converted_num = 0;
465
466 /* Get CuStdCodeSet */
467     DtXlateOpToStdLocale( DtLCX_OPER_SETLOCALE,
468                           setlocale( LC_CTYPE, NULL ),
469                           &ret_locale,
470                           &ret_lang,
471                           &CuStdCodeSet );
472
473 /*
474  * If charSet is NULL, it means the passed string's charset in *from is
475  * unknown by dtmail. In this case, this converter assumes that 
476  * when dir = CURRENT_TO_INTERNET,
477  *     *from's encoding is the current locale's one.
478  * when dir = INTERNET_TO_CURRENT,
479  *     *from's encoding is the current locale's Internet Message's one.
480  *
481  * Example.
482  *   dtmail is running under ja_JP locale.
483  *    dir : CURRENT_TO_INTERNET
484  *         *from = IBM-eucJP
485  *         *to   = ISO-2022-JP
486  *    dir : INTERNET_TO_CURRENT
487  *         *from = ISO-2022-JP
488  *         *to   = IBM-eucJP
489  */
490 /*
491  * ISO-2022-JP can be converted to either EUC-JP or IBM-932 practically.
492  * But the current AIX.lcx says 
493  *       StdCodeSet      InterchangeCodeset
494  *         EUC-JP   <-->   ISO-2022-JP
495  *         IBM-932  --->   ISO-2022-JP
496  *         HP-SJIS  --->   ISO-2022-JP
497  *         HP-KANA8 --->   ISO-2022-JP
498  * therefore DtXlateOpToStdLocale() can convert ISO-2022-JP to EUC-JP only.
499  * To fix this, we hard-code'ed this situation with the CDE Standard Name
500  *
501  * ???? Is it correct ???
502  */
503     if ( dir == INTERNET_TO_CURRENT ) {
504         /*
505          * As for from_codeset
506          */
507         if ( ( charSet == NULL ) || ( *charSet == '\0' ) ) {
508             /* Convert CuStdCodeSet to StdInterChangeCodeSet */
509             DtXlateStdToOpLocale( DtLCX_OPER_INTERCHANGE_CODESET,
510                                 NULL,
511                                 NULL,
512                                 CuStdCodeSet,
513                                 NULL,
514                                 &InterChCodeSet );
515         } else {
516             /* Convert charSet to StdInterChangeCodeSet */
517             ret_locale = ret_lang = ret_codeset = NULL;
518             DtXlateOpToStdLocale( DtLCX_OPER_MIME,
519                                 charSet,
520                                 &ret_locale,
521                                 &ret_lang,
522                                 &InterChCodeSet );
523         }
524
525         /* Convert StdInterChangeCodeSet to OpIVONC3 codeset */
526         DtXlateStdToOpLocale( DtLCX_OPER_ICONV3,
527                                 NULL,
528                                 NULL,
529                                 InterChCodeSet,
530                                 NULL,
531                                 &from_codeset );
532         /*
533          * As for to_codeset
534          */
535         if ( ( charSet == NULL ) || ( *charSet == '\0' ) ) {
536             /* Convert CuStdCodeSet to OpIVONC3 codeset */
537             DtXlateStdToOpLocale( DtLCX_OPER_ICONV3,
538                                 NULL,
539                                 NULL,
540                                 CuStdCodeSet,
541                                 NULL,
542                                 &to_codeset );
543         } else {
544 #ifdef _AIX
545             if ( (!strncasecmp(InterChCodeSet,"ISO-2022-JP",11) &&
546                   !strncasecmp(CuStdCodeSet,"IBM-932",7)        ) ||
547                  (!strncasecmp(InterChCodeSet,"ISO-2022-JP",11) &&
548                   !strncasecmp(CuStdCodeSet,"EUC-JP",6)         )    ) {
549                 ret_codeset = CuStdCodeSet;
550             } else 
551 #endif /* _AIX */
552             {
553                 /* Convert InterChCodeSet to StdCodeSet */
554                 ret_locale = ret_lang = ret_codeset = NULL;
555                 DtXlateOpToStdLocale( DtLCX_OPER_INTERCHANGE_CODESET,
556                                 InterChCodeSet,
557                                 &ret_locale,
558                                 &ret_lang,
559                                 &ret_codeset );
560             }
561             DtXlateStdToOpLocale( DtLCX_OPER_ICONV3,
562                                 NULL,
563                                 NULL,
564                                 ret_codeset,
565                                 NULL,
566                                 &to_codeset );
567         }
568     } else { /* dir == CURRENT_TO_INTERNET */
569         /*
570          * As for from_codeset
571          */
572         if ( ( charSet == NULL ) || ( *charSet == '\0' ) ) {
573             /* Convert CuStdCodeSet to OpICONV3 codeset */
574             DtXlateStdToOpLocale( DtLCX_OPER_ICONV3,
575                                 NULL,
576                                 NULL,
577                                 CuStdCodeSet,
578                                 NULL,
579                                 &from_codeset );
580         } else {
581             /* Convert charSet to StdInterChangeCodeSet */
582             ret_locale = ret_lang = ret_codeset = NULL;
583             DtXlateOpToStdLocale( DtLCX_OPER_MIME,
584                                 charSet,
585                                 &ret_locale,
586                                 &ret_lang,
587                                 &ret_codeset );
588             /* Convert StdInterChangeCodeSet to OpIVONC3 codeset */
589             DtXlateStdToOpLocale( DtLCX_OPER_ICONV3,
590                                 NULL,
591                                 NULL,
592                                 ret_codeset,
593                                 NULL,
594                                 &from_codeset );
595         }
596         /*
597          * As for to_codeset
598          */
599         if ( ( charSet == NULL ) || ( *charSet == '\0' ) ) {
600             /* Convert CuStdCodeSet to StdInterChangeCodeSet */
601             DtXlateStdToOpLocale( DtLCX_OPER_INTERCHANGE_CODESET,
602                                 NULL,
603                                 NULL,
604                                 CuStdCodeSet,
605                                 NULL,
606                                 &InterChCodeSet );
607         } else {
608             /* Convert charSet to StdInterChangeCodeSet */
609             ret_locale = ret_lang = ret_codeset = NULL;
610             DtXlateOpToStdLocale( DtLCX_OPER_MIME,
611                                 charSet,
612                                 &ret_locale,
613                                 &ret_lang,
614                                 &InterChCodeSet );
615         }
616
617         /* Convert StdInterChangeCodeSet to OpIVONC3 codeset */
618         DtXlateStdToOpLocale( DtLCX_OPER_ICONV3,
619                                 NULL,
620                                 NULL,
621                                 InterChCodeSet,
622                                 NULL,
623                                 &to_codeset );
624     }
625
626     *to = NULL;
627     *to_len = 0;
628
629     if ( shouldAlloc2 ) {
630         /* Obtain work area */
631         _i18nwork2 = (size_t *)malloc( WORKSIZE );
632         if ( !_i18nwork2 ) {
633             _i18nwork2 = NULL;
634             return( isASCII );
635         }
636         _i18nsize2 = WORKSIZE; 
637         shouldAlloc2 = 0;
638     }
639
640     if (NULL == to_codeset || NULL == from_codeset)
641       return( isASCII );
642
643     if ( ( CD = iconv_open( to_codeset, from_codeset ) ) != (iconv_t)-1 ) {
644         /*
645          * According to several RFCs( 822, 1468, 1557, ..... )
646          * the escape sequence to switch to ASCII is needed just before
647          * '\n'. IBM-eucJP/IBM-932 <--> fold 7 does while the other doesn't.
648          * Therefore CvtStr() does take care of this here.
649          */
650         if ( dir == INTERNET_TO_CURRENT ) {
651             _converter_( CD, from, from_len, to, to_len );
652         } else {
653             void *new_from = from;
654             unsigned long new_from_len = from_len;
655             unsigned long _passed = 0;
656             size_t clen;
657             void *_tmp = NULL;
658             unsigned long _tmp_len = 0;
659
660             while ( _passed < from_len ) {
661                 /*
662                  * Find \n or \0
663                  */
664                 for ( ; _passed < from_len; _passed += clen ) {
665                     clen = mblen(&(((char *)from)[_passed]), MB_CUR_MAX);
666                     if ( clen < 0 )
667                         break;
668
669                     if ( ( clen > 1 ) || !isascii( ((char*)from)[_passed] ) ){
670                         /* Here, maybe MB or non-ASCII */
671                         isASCII = 0;
672                         isStopASCII = 0;
673                     } else {
674                         if ( ( ((char*)from)[_passed] != '\n' ) &&
675                              ( ((char*)from)[_passed] != '\0' )    ) {
676                             isStopASCII = ~0;
677                         }
678                     }
679
680                     if ( ((char*)from)[_passed] == '\n' ||
681                          ((char*)from)[_passed] == '\0'    )
682                         break;
683                 }
684                 new_from_len = &(((char *)from)[_passed])-(char *)new_from;
685                 if ( ( _passed < from_len ) && ( clen == 1 ) &&
686                      ( ((char*)from)[_passed] == '\n' ) ) {
687                     new_from_len++;
688                 }
689
690                 /*
691                  * new_from                 from[_passed]
692                  *  V                        V
693                  * +------------------------+--+------.................+
694                  * | |                      |\n| |                     |
695                  * +------------------------+--+------.................+
696                  *  <-------------------------> $
697                  *     new_from_len             next new_from
698                  *  <------------------------------------------------->
699                  *  $                 from_len
700                  * from 
701                  */
702
703                 /*
704                  *      ********** DO 1 LINE CONVERSION **********
705                  */
706                 _tmp = NULL; _tmp_len = 0;
707                 _converter_( CD, new_from, new_from_len, &_tmp, &_tmp_len );
708
709                 if ( ( _tmp == NULL ) && ( _tmp_len == 0 ) ) {
710                     /* Conversion fail */
711                     *to = NULL;
712                     *to_len = 0;
713                     break;
714                 }
715
716                 /*
717                  * _i18nwork2                 _tmp
718                  *  V                           V
719                  * +-----------------------+   +-------------+  
720                  * |XXXXXXXX               | + |             |
721                  * +-----------------------+   +-------------+  
722                  *  <------>
723                  *  converted_num
724                  *  <--------------------->     <----------->
725                  *   _18nsize2                    _tmp_len
726                  */
727                 /* Append _tmp to target */
728                 if ( converted_num + _tmp_len > _i18nsize2 ) {
729                     /* Need much memory..... */
730                     void *_i18n = NULL;
731
732                     _i18nsize2 += WORKSIZE;
733                     _i18n = realloc( _i18nwork2, _i18nsize2  ); 
734                     if ( !_i18n ) {
735                         *to = NULL;
736                         *to_len = 0;
737                         _i18nwork2 = NULL;
738                         _i18nsize2 = 0;
739                         shouldAlloc2 = ~0;
740                         break;
741                     } else {
742                         _i18nwork2 = _i18n;
743                     }
744                 }
745
746                 /*
747                  * _i18nwork2  _tmp
748                  *  V          v
749                  * +---------------------------+  
750                  * |XXXXXXXXXXX(COPIED)XX      |
751                  * +---------------------------+  
752                  *  <---------><-------->
753                  *  (old)conv.  _tmp_len
754                  *  <------------------->
755                  *  (new)converted_num
756                  *  <--------------------------> 
757                  *        _i18nsize2
758                  */
759                 strncpy( (char *)_i18nwork2 + converted_num,
760                                 (char *)_tmp, _tmp_len );
761                 converted_num += _tmp_len;
762
763                 *to = (void *)_i18nwork2;
764                 *to_len = converted_num;
765                 new_from =  &(((char *)from)[_passed]) + 1;
766                 _passed++;
767
768                 /*
769                  * According to RFC1468, if the line is ended with non-ASCII
770                  * char, but not not switch to ASCII before the end of line,
771                  * we must switch to ASCII just before the end of the line.
772                  *
773                  * _i18nwork2                     ToASCII
774                  *  V                           ??? V
775                  * +---------------------------+   +------+
776                  * |XXXXXXXXXXXXXXXXXXXXX      | + |1b2842|
777                  * +---------------------------+   +------+
778                  *  <------------------->           <---->
779                  *  converted_num                   ToASCII_NUM
780                  *  <------------------------->
781                  *        _i18nsize2
782                  *                ========
783                  *                1b 28 42 ??
784                  *
785                  */
786                 if ( !isStopASCII ) {
787                     if ( (((char *)_i18nwork2)[converted_num-1] == '\n') ||
788                          (((char *)_i18nwork2)[converted_num-1] == '\0')    ) {
789
790                         char _p = ((char *)_i18nwork2)[converted_num-1];
791
792                         if (!((converted_num >=3+1 ) &&
793                          !memcmp((void *)((char *)_i18nwork2+converted_num-3-1),
794                                 ToASCII, ToASCII_NUM ))                      ){
795                             /* if not ToASCII there, then */
796                             /* Append ToASCII */
797
798                             if ( converted_num + ToASCII_NUM > _i18nsize2 ) {
799                                 /* Need much memory..... */
800                                 void *_i18n = NULL;
801
802                                 _i18nsize2 += WORKSIZE;
803                                 _i18n=realloc(_i18nwork2,_i18nsize2); 
804                                 if ( !_i18n ) {
805                                     *to = NULL;
806                                     *to_len = 0;
807                                     shouldAlloc2 = ~0;
808                                     break;
809                                 } else {
810                                     _i18nwork2 = _i18n;
811                                 }
812                             }
813                             strncpy( (char *)_i18nwork2+converted_num-1,
814                                         ToASCII, ToASCII_NUM );
815                             converted_num += ToASCII_NUM;
816                             ((char *)_i18nwork2)[converted_num-1] = _p;
817                             *to = _i18nwork2;
818                             *to_len = converted_num;
819                             isStopASCII = ~0;
820                         }
821                     } else {
822                         if (!((converted_num >=3 ) &&
823                          !memcmp((void *)((char *)_i18nwork2+converted_num-3),
824                                 ToASCII, ToASCII_NUM ))                      ){
825                             /*
826                             // if not ToASCII there, then
827                             // Append ToASCII
828                             */
829                             if ( converted_num + ToASCII_NUM > _i18nsize2 ) {
830                                 void *_i18n = NULL;
831
832                                 _i18nsize2 += WORKSIZE;
833                                 _i18n=realloc(_i18nwork2,_i18nsize2); 
834                                 if ( !_i18n ) {
835                                     *to = NULL;
836                                     *to_len = 0;
837                                     shouldAlloc2 = ~0;
838                                     break;
839                                 } else {
840                                     _i18nwork2 = _i18n;
841                                 }
842                             }
843                             strncpy( (char *)_i18nwork2+converted_num,
844                                         ToASCII, ToASCII_NUM );
845                             converted_num += ToASCII_NUM;
846                             *to = _i18nwork2;
847                             *to_len = converted_num;
848                             isStopASCII = ~0;
849                         }
850                     }
851                 }
852             }
853             /*
854              * Again........
855              */
856             if( ( *to != NULL ) && ( *to_len != 0 ) ) {
857                 if ( !isStopASCII ) {
858                     if ( (((char *)_i18nwork2)[converted_num-1] == '\n') ||
859                          (((char *)_i18nwork2)[converted_num-1] == '\0')    ) {
860
861                         char _p = ((char *)_i18nwork2)[converted_num-1];
862
863                         if (!((converted_num >=3+1 ) &&
864                          !memcmp((void *)((char *)_i18nwork2+converted_num-3-1),
865                                 ToASCII, ToASCII_NUM ))                      ){
866                             /* if not ToASCII there, then
867                             // Append ToASCII
868                             */
869
870                             if ( converted_num + ToASCII_NUM > _i18nsize2 ) {
871                                 void *_i18n = NULL;
872
873                                 _i18nsize2 += WORKSIZE;
874                                 _i18n=realloc(_i18nwork2,_i18nsize2); 
875                                 if ( !_i18n ) {
876                                     *to = NULL;
877                                     *to_len = 0;
878                                     shouldAlloc2 = ~0;
879                                 } else {
880                                     _i18nwork2 = _i18n;
881                                 }
882                             }
883                             strncpy( (char *)_i18nwork2+converted_num-1,
884                                         ToASCII, ToASCII_NUM );
885                             converted_num += ToASCII_NUM;
886                             ((char *)_i18nwork2)[converted_num-1] = _p;
887                             *to = _i18nwork2;
888                             *to_len = converted_num;
889                             isStopASCII = ~0;
890                         }
891                     } else {
892                         if (!((converted_num >=3 ) &&
893                          !memcmp((void *)((char *)_i18nwork2+converted_num-3),
894                                 ToASCII, ToASCII_NUM ))                      ){
895                             /* if not ToASCII there, then
896                             // Append ToASCII
897                             */
898
899                             if ( converted_num + ToASCII_NUM > _i18nsize2 ) {
900                                 void *_i18n = NULL;
901
902                                 _i18nsize2 += WORKSIZE;
903                                 _i18n=realloc(_i18nwork2,_i18nsize2); 
904                                 if ( !_i18n ) {
905                                     *to = NULL;
906                                     *to_len = 0;
907                                     shouldAlloc2 = ~0;
908                                 } else {
909                                     _i18nwork2 = _i18n;
910                                 }
911                             }
912                             strncpy( (char *)_i18nwork2+converted_num,
913                                         ToASCII, ToASCII_NUM );
914                             converted_num += ToASCII_NUM;
915                             *to = _i18nwork2;
916                             *to_len = converted_num;
917                             isStopASCII = ~0;
918                         }
919                     }
920                 }
921             }
922             /*
923              * If InterChCodeSet is either ISO-2022-JP/ISO-2022-KR/ISO-2022-TW
924              * ISO-2022-CN, strip MSB here since iconv'ed UDC has MSB set to 1
925              */
926             if ( !strncasecmp( InterChCodeSet, "ISO-2022-JP", 11 ) ||
927                  !strncasecmp( InterChCodeSet, "ISO-2022-KR", 11 ) ||
928                  !strncasecmp( InterChCodeSet, "ISO-2022-TW", 11 ) ||
929                  !strncasecmp( InterChCodeSet, "ISO-2022-CN", 11 )   ) {
930                 int _i;
931
932                 for ( _i = 0; _i < *to_len; _i++ ) {
933                         ((unsigned char *)(*to))[_i] &= (unsigned char)0x7f;
934                 }
935             }
936         }
937         iconv_close( CD );
938     }
939     return( isASCII );
940 }
941 unsigned int
942 base64size(const unsigned long len)
943 {
944     int b_len = len + (len / 3);
945     b_len += (b_len / 72 * 2) + 4;
946
947     return(b_len);
948 }
949
950 getEncodingType(const char * body,
951                          const unsigned int len,
952                          boolean_t strict_mime)
953 {
954     /*
955     // Our goal here is to produce the most readable, safe encoding.
956     // We have a couple of parameters that will guide our
957     // choices:
958     //
959     // 1) RFC822 allows lines to be a minimum of 1000 characters,
960     //    but MIME encourages mailers to keep lines to <76 characters
961     //    and use quoted-printable if necessary to achieve this.
962     //
963     // 2) The base64 encoding will grow the body size by 33%, and
964     //    also render it unreadable by humans. We don't want to use
965     //    it unless really necessary.
966     //
967     // Given the above 2 rules, we want to scan the body part and
968     // select an encoding. The 3 choices will be decided by:
969     //
970     // 1) If the text is 7 bit clean, and all lines are <76 chars,
971     //    then no encoding will be applied.
972     //
973     //
974     // 2) If the text is not 7 bit clean, or there are lines >76 chars,
975     //    and the quoted-printable size is less than the base64 size,
976     //    then quoted-printable will be done.
977     //
978     // 3) If 1 & 2 are not true, then base64 will be applied.
979     //
980     // If "strict_mime" is false we will only encode if the message
981     // is not 7 bit clean.
982     */
983
984
985     int base64_growth = base64size(len) - len;
986     int qprint_growth = 0;
987     boolean_t eight_bit = B_FALSE;
988     boolean_t base64 = B_FALSE;
989     boolean_t encode = B_FALSE;
990     Encoding    enc;
991
992     const char * last_nl = body;
993     const char * cur;
994
995     if (body == NULL || len == 0) {
996         return(MIME_7BIT);
997     }
998     if (strncmp(body, "From ", 5) == 0) {
999         qprint_growth += 2;
1000     }
1001
1002     for (cur = body; cur < (body + len); cur++) {
1003         if (*cur != (*cur & 0x7f)) {
1004             eight_bit = B_TRUE;
1005             encode = B_TRUE;
1006             qprint_growth += 2;
1007         } else if (*cur == '=' || *cur == 0) {
1008             /*
1009             // These characters don't force encoding, but will be
1010             // encoded if we end up encoding.
1011             qprint_growth += 2;
1012             */
1013         }
1014
1015         if (*cur == '\n') {
1016             if ((cur - last_nl) > 76) {
1017                 encode = B_TRUE;
1018                 qprint_growth += 2;
1019             }
1020
1021
1022             if ((cur != body && (*(cur - 1) == ' ' || *(cur - 1) == '\t'))) {
1023                 encode = B_TRUE;
1024                 qprint_growth += 2;
1025             }
1026
1027             if ((cur + 6) < (body + len) &&
1028                                         strncmp((cur + 1), "From ", 5) == 0) {
1029                 encode = B_TRUE;
1030                 qprint_growth += 2;
1031             }
1032
1033             last_nl = cur + 1;
1034         }
1035
1036         if (encode && (qprint_growth > base64_growth)) {
1037             base64 = B_TRUE;
1038             break;
1039         }
1040     }
1041
1042     /* Deal with buffers that dont end with a new line. */
1043
1044     if ((cur - last_nl) > 76) {
1045         encode = B_TRUE;
1046         qprint_growth += 2;
1047     }
1048
1049     enc = MIME_7BIT;
1050
1051     if (!strict_mime && !eight_bit) {
1052         /* If strict_mime is off we only encode if we have 8 bit data */
1053         enc = MIME_7BIT;
1054     } else if (encode) {
1055         /* strict_mime is TRUE and we have reason to encode. */
1056         if (base64) {
1057                 enc = MIME_BASE64;
1058         } else {
1059                 enc = MIME_QPRINT;
1060         }
1061     }
1062
1063     return(enc);
1064 }
1065
1066 void
1067 writeContentHeaders(char * hdr_buf,
1068                              const char * type,
1069                              const Encoding enc,
1070                              const char * digest,
1071                              int isAllASCII)
1072 {
1073     char default_charset[64];
1074
1075     strcat(hdr_buf,"Content-Type: ");
1076     strcat(hdr_buf,type);
1077
1078     if (isAllASCII)
1079         strcpy(default_charset,"US-ASCII");
1080     else
1081         getCharSet(default_charset);
1082
1083     strcat(hdr_buf,"; charset=");
1084
1085     strcat(hdr_buf,default_charset);
1086
1087     crlf(hdr_buf);
1088
1089     strcat(hdr_buf,"Content-Transfer-Encoding: ");
1090
1091     switch (enc) {
1092       case MIME_7BIT:
1093         strcat(hdr_buf,"7bit\n");
1094         break;
1095
1096       case MIME_8BIT:
1097       default: /* Assume the worst. */
1098         strcat(hdr_buf,"8bit\n");
1099         break;
1100       case MIME_QPRINT:
1101         strcat(hdr_buf,"quoted-printable\n");
1102         break;
1103
1104       case MIME_BASE64:
1105         strcat(hdr_buf,"base64\n");
1106         break;
1107     }
1108
1109     strcat(hdr_buf,"Content-MD5: ");
1110     writeBase64(hdr_buf, digest, 16);
1111 }
1112 /*
1113 //
1114 // Base64 Alphabet (65-character subset of US-ASCII as per RFC1521)
1115 //
1116 */
1117
1118 static const char base64_chars[] =
1119 {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1120  'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a',
1121  'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
1122  'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
1123  '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
1124 };
1125
1126 void
1127 writeBase64(char * buf, const char * bp, const unsigned long len)
1128 {
1129
1130     /* The length has to be a multiple of 3. We will need to pad
1131     // any extra. Let's just work on the main body and save the
1132     // fractional stuff for the end.
1133     */
1134     unsigned long main_len = len - (len % 3);
1135     const unsigned char * ubp = (const unsigned char *)bp;
1136
1137     char line[80];
1138
1139     unsigned int enc_char;
1140
1141     int lf = 0;
1142
1143     int block;
1144
1145     if (bp == NULL || len == 0) {
1146         crlf(buf);
1147         return;
1148     }
1149
1150     for (block = 0; block < main_len; block += 3) {
1151         enc_char = (ubp[block] >> 2) & 0x3f;
1152         line[lf++] = base64_chars[enc_char];
1153
1154         enc_char = ((ubp[block] & 0x3) << 4) | ((ubp[block+1] >> 4) & 0xf);
1155         line[lf++] = base64_chars[enc_char];
1156
1157         enc_char = ((ubp[block + 1] & 0xf) << 2) | ((ubp[block + 2] >> 6) & 0x3);
1158         line[lf++] = base64_chars[enc_char];
1159
1160         enc_char = ubp[block + 2] & 0x3f;
1161         line[lf++] = base64_chars[enc_char];
1162
1163         if (lf == 72) {
1164             strncat(buf,line,lf);
1165             crlf(buf);
1166             lf = 0;
1167         }
1168     }
1169
1170     if (lf > 0) {
1171         strncat(buf, line,lf);
1172     }
1173
1174     if (((lf + 4) % 72) == 0) {
1175         crlf(buf);
1176     }
1177
1178     switch(len % 3) {
1179       case 1:
1180         enc_char = (ubp[block] >> 2) & 0x3f ;
1181         strncat(buf, &base64_chars[enc_char], 1);
1182
1183         enc_char = ((ubp[block] & 0x3) << 4);
1184         strncat(buf, &base64_chars[enc_char], 1);
1185
1186         strncat(buf,"==", 2);
1187         break;
1188
1189       case 2:
1190         enc_char = (ubp[block] >> 2) & 0x3f;
1191         strncat(buf,&base64_chars[enc_char], 1);
1192
1193         enc_char = ((ubp[block] & 0x3) << 4) | ((ubp[block+1] >> 4) & 0xf);
1194         strncat(buf,&base64_chars[enc_char], 1);
1195
1196         enc_char = ((ubp[block + 1] & 0xf) << 2);
1197         strncat(buf,&base64_chars[enc_char], 1);
1198
1199         strncat(buf,"=", 1);
1200     }
1201
1202 /*    crlf(buf); */
1203 }
1204 void
1205 writeQPrint(char *buf, const char * bp, const unsigned long bp_len,
1206                         int is_Special )
1207 {
1208     int last_nl = 0;
1209     int off = 0;
1210     char line_buf[80];
1211     const char * start;
1212     const char * cur;
1213     const char * white;
1214     const char * nw;
1215     int line_len;
1216     const char *cp_w;
1217     char prev;
1218     char tmpbuf[20];
1219
1220     if (bp == NULL || bp_len == 0) {
1221         crlf(buf);
1222         return;
1223     }
1224
1225
1226     /*
1227     // A line buffer for improving formatting performance. Note that
1228     // QP requires all lines to be < 72 characters plus CRLF. So, a
1229     // fixed size 80 character buffer is safe.
1230     */
1231
1232     /* There are probably more elegant ways to deal with a message that
1233     // begins with "From ", but we will simply due it this more simplistic
1234     // way.
1235     */
1236     if (strncmp(bp, "From ", 5) == 0) {
1237         memcpy(&line_buf[off], "=46", 3);
1238         start = bp + 1;
1239         off += 3;
1240     }
1241     else {
1242         start = bp;
1243     }
1244
1245     /* This loop will apply the encodings, following the rules identified
1246     // in RFC1521 (though not necessarily in the order presented.
1247     */
1248     for (cur = start; cur < (bp + bp_len); cur++) {
1249
1250         /* Rule #5: Part 1! We will try to break at white space
1251         // if possible, but it may not be possible. In any case,
1252         // we want to force the lines to be less than 76 characters.
1253         */
1254         if (off > 72) {
1255             line_buf[off++] = '=';
1256             strncat(buf,line_buf, off);
1257             crlf(buf);
1258             last_nl = 0;
1259             off = 0;
1260         }
1261
1262         /* Rule #1: Any octet, except those indicating a line break
1263         // according to the newline convention mabe represented by
1264         // an = followed by a two digit hexadecimal representation
1265         // of the octet's value. We will represent any non-7bit
1266         // data this way, but let the rest slide. We do wrap "="
1267         // just to be safe.
1268         */
1269         if (*cur != (*cur & 0x7f) || *cur == '=') {
1270             char tmp[20];
1271             sprintf(tmp, "=%02X", (int)(unsigned char)*cur);
1272             memcpy(&line_buf[off], tmp, 3);
1273             off += 3;
1274             continue;
1275         }
1276         if ( is_Special ){
1277         /*
1278          * Under ISO-2022-XX codeset, several escape sequence may be in
1279          * From, Subject field. To pass them, writeQPrint() also accept
1280          * such kind of character.
1281          */
1282             if ( *cur == (char)0x1b ) {
1283                 /* Only 0x1b ????? */
1284                 char tmp[3];
1285                 sprintf(tmp, "=%02X", (int)(unsigned char)*cur);
1286                 memcpy(&line_buf[off], tmp, 3);
1287                 off += 3;
1288                 continue;
1289             }
1290         }
1291
1292         /* Rule #2: Octets with decimal values of 33 through 60
1293         // inclusive and 62 through 126, inclusive, MAY be represented
1294         // as the ASCII characters which correspond to those octets.
1295         */
1296         if ((*cur >= 33 && *cur <= 60) ||
1297             (*cur >= 62 && *cur <= 126)) {
1298             line_buf[off++] = *cur;
1299             continue;
1300         }
1301
1302         /* Rule #5: The q-p encoding REQUIRES that encoded lines be
1303         // no more than 76 characters long. If longer, an equal sign
1304         // as the last character n the line indicates a soft line break.
1305         //
1306         // This is tricky if you want to leave it reasonably readable
1307         // (why else do this?). We only want to break on white space.
1308         // At each white gap, we need to count forward to the next
1309         // white gap and see if we exceed the 76 character limit.
1310         // We will cheat a few characters to allow us some room
1311         // for arithmetic.
1312         */
1313         if (*cur == ' ' || *cur == '\t') {
1314             /* Find the end of this clump of white space.
1315             */
1316             for (nw = cur;
1317                  nw < (bp + bp_len) && *nw && *nw != '\n'; nw++) {
1318                 if (!isspace(*nw)) {
1319                     break;
1320                 }
1321             }
1322
1323             /* Find the end of the next non-white region.
1324             */
1325             for (white = nw;
1326                  white < (bp + bp_len) && *white && !isspace(*white);
1327                  white++) {
1328                 continue;
1329             }
1330
1331             line_len = (off - last_nl) + (white - cur);
1332             if (line_len > 72) {
1333                 /* Need a soft line break. Lets put it after the
1334                 // current clump of white space. We will break
1335                 // at 72 characters, even if we arent at the end
1336                 // of the white space. This prevents buffer overruns.
1337                 */
1338                 for (cp_w = cur; cp_w < nw; cp_w++) {
1339                     line_buf[off++] = *cp_w;
1340                     if (off > 72) {
1341                         line_buf[off++] = '=';
1342                         strncat(buf,line_buf, off);
1343                         crlf(buf);
1344                         off = 0;
1345                         last_nl = 0;
1346                     }
1347                 }
1348
1349                 /* There is an edge case that we may have written the last
1350                 // white space character in the for loop above. This will
1351                 // prevent us from spitting an extra continuation line.
1352                 */
1353                 if (off) {
1354                     line_buf[off++] = '=';
1355                     strncat(buf,line_buf, off);
1356                     crlf(buf);
1357                     last_nl = 0;
1358                     off = 0;
1359                 }
1360
1361                 /* If we created a "From " at the front we need to wrap
1362                 // it to protect from parsers.
1363                 */
1364                 if ((nw + 5) < (bp + bp_len) && strncmp(nw, "From ", 5) == 0) {
1365                     memcpy(&line_buf[off], "=46", 3);
1366                     off += 3;
1367                     cur = nw + 1;
1368                 }
1369                 else {
1370                     cur = nw - 1;
1371                 }
1372             }
1373             else {
1374                 line_buf[off++] = *cur;
1375             }
1376
1377             continue;
1378         }
1379
1380         /* Rule 3: Octets with values of 9 and 32 MAY be represented
1381         // as ASCII TAB and SPACE but MUST NOT be represented at the
1382         // end of an encoded line. We solve this be encoding the last
1383         // white space before a new line (except a new line) using
1384         // Rule #1.
1385         */
1386         if (*cur == '\n') {
1387             if (cur == start) {
1388                 crlf(buf);
1389             }
1390             else {
1391                 last_nl = off + 1;
1392                 
1393                 prev = *(cur - 1);
1394                 if ((prev == ' ' || prev == '\t') && prev != '\n') {
1395                     off = off ? off - 1 : off;
1396                     
1397                     sprintf(tmpbuf, "=%02X", *(cur - 1));
1398                     memcpy(&line_buf[off], tmpbuf, 3);
1399                     off += 3;
1400                 }
1401
1402                 strncat(buf,line_buf, off);
1403                 last_nl = 0;
1404                 off = 0;
1405
1406                 if (*(cur - 1) == '\r') {
1407                     strncat(buf,cur, 1);
1408                 }
1409 /*
1410                 else {
1411                     crlf(buf);
1412                 }
1413 */
1414             }
1415             /* We need to munge a line that starts with "From " to it
1416             // protect from parsers. The simplest way is to encode the
1417             // "F" using rule #1.
1418             */
1419             if ((cur + 5) < (bp + bp_len) && strncmp((cur + 1), "From ", 5) == 0) {
1420                 memcpy(&line_buf[off], "=46", 3);
1421                 off += 3;
1422                 cur += 1;
1423             }
1424             continue;
1425         }
1426     }
1427
1428     if (off > 0) {
1429         strncat(buf,line_buf, off);
1430     }
1431 /*
1432     if (*(cur - 1) != '\n') {
1433         crlf(buf);
1434     }
1435 */
1436 }
1437
1438
1439 static int
1440 mbisspace(int c)
1441 {
1442     return((c & 0x7f) == c && isspace(c));
1443 }
1444
1445 void
1446 rfc1522cpy(char * buf, const char * value)
1447 {
1448     const char * cur;
1449     const char * scan_c;
1450     boolean_t eight_bit = B_FALSE;
1451     char charset[64];
1452     char *ret_locale = NULL;
1453     char *ret_lang = NULL;
1454     char *ret_codeset = NULL;
1455     char  tmp[1024];
1456     char *NewBuf = NULL;
1457     unsigned long _len = 0;
1458     /*
1459     // We are going to encode 8 bit data, one word at a time. This may
1460     // not be the best possible algorithm, but it will get the correct
1461     // information in the header.
1462     */
1463     for (cur = value; *cur; cur++) {
1464         if (mbisspace(*cur)) {
1465             strncat(buf,cur, 1);
1466             continue;
1467         }
1468
1469         for (scan_c = cur; *scan_c && !mbisspace(*scan_c); scan_c++) {
1470             if (*scan_c != (*scan_c & 0x7f)) {
1471                 eight_bit = B_TRUE;
1472             }
1473         }
1474
1475         if (eight_bit == B_FALSE) {
1476             /* Simple! Copy the chars to the output. */
1477             strncat(buf,cur,scan_c - cur);
1478             cur = scan_c - 1;
1479         }
1480         else {
1481
1482             getCharSet( charset );
1483             /* Convert default_charset to InterchangeCodeset name. */
1484             DtXlateOpToStdLocale( DtLCX_OPER_MIME,
1485                                 charset,
1486                                 &ret_locale,
1487                                 &ret_lang,
1488                                 &ret_codeset );
1489
1490             /* We have a word here. It has 8 bit data, so we will put
1491             // it out as RFC1522 chunk.
1492             */
1493
1494             if ( !strncasecmp( ret_codeset, "ISO-2022-KR", 11 ) ) {
1495             /*
1496              * According to RFC1557, in the Header Field, we don't use
1497              * ISO-2022-KR encoding char.
1498              */
1499                 char *_tmp1_;
1500                 char *_tmp2_;
1501                 ret_locale = ret_lang = _tmp1_ = NULL;
1502                 DtXlateOpToStdLocale( DtLCX_OPER_INTERCHANGE_CODESET,
1503                                         ret_codeset,
1504                                         &ret_locale,
1505                                         &ret_lang,
1506                                         &_tmp1_ );
1507                 _tmp2_ = NULL;
1508                 DtXlateStdToOpLocale( DtLCX_OPER_MIME,
1509                                 NULL,
1510                                 NULL,
1511                                 _tmp1_,
1512                                 NULL,
1513                                 &_tmp2_ );
1514                 strncat(buf,"=?", 2);
1515                 strncat(buf,_tmp2_, strlen(_tmp2_));
1516                 strncat(buf,"?q?", 3);
1517             } else if ( !strncasecmp( ret_codeset, "ISO-2022-JP", 11 ) ) {
1518             /*
1519              * According to RFC1468, in the Header Field, we should use
1520              * B-encoding
1521              */
1522                 strncat(buf,"=?", 2);
1523                 strncat(buf,charset, strlen(charset));
1524                 strncat(buf,"?b?", 3);
1525             } else {
1526                 strncat(buf,"=?", 2);
1527                 strncat(buf,charset, strlen(charset));
1528                 strncat(buf,"?q?", 3);
1529             }
1530
1531             /*
1532              * According to RFC1557, in the Header Field, we don't use
1533              * ISO-2022-KR encoding char. Also in us-ascci, we don't have to
1534              * call converter.
1535              */
1536             memset(tmp, '\0', 1024);
1537             if (!( !strncasecmp( ret_codeset, "ISO-2022-KR", 11 ) ||
1538                    !strncasecmp( charset, "us-ascii", 8 ) )          )
1539                 (void)CvtStr( (char *)NULL, (void *)cur, scan_c - cur,
1540                                 (void **)&NewBuf, &_len, CURRENT_TO_INTERNET );
1541             if ( ( NewBuf != NULL ) && ( _len != 0 ) ) {
1542                 /*
1543                  * if ret_codeset == ISO-2022-KR, we don't come here.
1544                  */
1545                 /*
1546                  * According to RFC1468, we should use B-encoding.
1547                  */
1548                 if ( !strncasecmp( ret_codeset, "ISO-2022-JP", 11 ) ) {
1549                     writeBase64( tmp, NewBuf, _len );
1550                 } else {
1551                     writeQPrint( tmp, NewBuf, _len, 
1552                            (!strncasecmp( ret_codeset, "ISO-2022-TW", 11 ) ||
1553                             !strncasecmp( ret_codeset, "ISO-2022-CN", 11 )   ));
1554                 }
1555             } else
1556                 writeQPrint( tmp, cur, scan_c - cur, 0 );
1557
1558             strncat(buf,tmp,strlen(tmp));
1559             strcat(buf,"?=");
1560             cur = scan_c - 1;
1561         }
1562     }
1563
1564     crlf(buf);
1565 }