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