home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libi18n / mime2fun.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  39.1 KB  |  1,473 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /*    mime2fun.c    */
  19. /*  Function related to MIME-2 support    */
  20.  
  21. #include "intlpriv.h"
  22. #include "prefapi.h"
  23.  
  24. /*
  25.     "The character set names may be up to 40 characters taken from the
  26.     printable characters of US-ASCII.  However, no distinction is made
  27.     between use of upper and lower case letters." [RFC 1700]
  28. */
  29. typedef struct {
  30.     int16    csid_key;
  31.     int16    csid_target;
  32. } cs_csid_map_t;
  33.  
  34.  
  35.     /* Maps a window encoding to the MIME encoding used for posting
  36.      * news and internet email.  String is for the MIME charset string.
  37.  
  38.         Currently, this table is only used for HEADER ENCODING!!!!
  39.         It is not used for HEADER decoding!!!!
  40.         It is not used for Body Decoding or Encoding!!!!
  41.         NOTE: We need to change this  from win_csid base to doc_csid base
  42.     
  43.      */
  44.  
  45. PRIVATE cs_csid_map_t    cs_mime_csidmap_tbl[] = {
  46.             {CS_ASCII,        CS_ASCII    },
  47.             
  48.             {CS_LATIN1,        CS_LATIN1    },
  49.             
  50.             {CS_JIS,        CS_JIS        },
  51.             {CS_SJIS,        CS_JIS        },
  52.             {CS_EUCJP,        CS_JIS,        },
  53.             
  54.             {CS_KSC_8BIT,    CS_KSC_8BIT    },
  55.                 
  56.             {CS_GB_8BIT,    CS_GB_8BIT    },
  57.             
  58.             {CS_BIG5,        CS_BIG5        },
  59.             {CS_CNS_8BIT,    CS_BIG5        },
  60.             
  61.             {CS_MAC_ROMAN,    CS_LATIN1    },
  62.             
  63.             {CS_LATIN2,        CS_LATIN2    },
  64.             {CS_MAC_CE,        CS_LATIN2    },
  65.             {CS_CP_1250,    CS_LATIN2    },
  66.  
  67.             {CS_8859_5,            CS_KOI8_R    },
  68.             {CS_KOI8_R,            CS_KOI8_R    },
  69.             {CS_MAC_CYRILLIC,    CS_KOI8_R    },
  70.             {CS_CP_1251,        CS_KOI8_R    },
  71.             
  72.             {CS_8859_7,        CS_8859_7    },
  73.             {CS_CP_1253,        CS_8859_7    },
  74.             {CS_MAC_GREEK,    CS_8859_7    },
  75.  
  76.             {CS_8859_9,        CS_8859_9    },
  77.             {CS_MAC_TURKISH,CS_8859_9    },
  78.             
  79.             {CS_UTF8,        CS_UTF8        },
  80.             {CS_UTF7,        CS_UTF7        },
  81.             {CS_UCS2,        CS_UTF7        },
  82.             {CS_UCS2_SWAP,    CS_UTF7        },
  83.             {0,                0,            }
  84. };
  85.  
  86. #define MAXLINELEN 72
  87. #define IS_MAIL_SEPARATOR(p) ((*(p) == ',' || *(p) == ' ' || *(p) == '\"' || *(p) == ':' || \
  88.   *(p) == '(' || *(p) == ')' || *(p) == '\\' || (unsigned char)*p < 0x20))
  89.  
  90. /*
  91.     Prototype for Private Function
  92. */
  93. PRIVATE void    intlmime_init_csidmap();
  94. PRIVATE XP_Bool    intlmime_only_ascii_str(const char *s);
  95. PRIVATE char *    intlmime_encode_mail_address(int wincsid, const char *src, CCCDataObject obj, 
  96.                                             int maxLineLen);
  97. PRIVATE char *    intlmime_encode_next8bitword(int wincsid, char *src);
  98. PRIVATE int16    intlmime_get_outgoing_mime_csid(int16);
  99. PRIVATE int16    intlmime_map_csid(cs_csid_map_t *csmimep, int16    csid_key);
  100.  
  101. /*    we should consider replace this base64 decodeing and encoding function with a better one */
  102. PRIVATE int        intlmime_decode_base64 (const char *in, char *out);
  103. PRIVATE char *    intlmime_decode_qp(char *in);
  104. PRIVATE int        intlmime_encode_base64 (const char *in, char *out);
  105. PRIVATE char *    intlmime_decode_base64_buf(char *subject);
  106. PRIVATE char *    intlmime_encode_base64_buf(char *subject, size_t size);
  107. PRIVATE char *    intlmime_encode_qp_buf(char *subject);
  108.  
  109.  
  110. PRIVATE XP_Bool intlmime_is_hz(const char *header);
  111. PRIVATE XP_Bool intlmime_is_mime_part2_header(const char *header);
  112. PRIVATE XP_Bool intlmime_is_iso_2022_xxx(const char *, int16 );
  113. PRIVATE    char *    intl_decode_mime_part2_str(const char *, int , XP_Bool );
  114. PRIVATE    char *    intl_DecodeMimePartIIStr(const char *, int16 , XP_Bool );
  115. PRIVATE char *    intl_EncodeMimePartIIStr(char *subject, int16 wincsid, XP_Bool bUseMime, int maxLineLen);
  116.  
  117.  
  118. #if 0
  119. /* Prototype of callback routine invoked by prefapi when the pref value changes 
  120.  * Win16 build fails if this is declared as static.
  121.  */
  122. MODULE_PRIVATE
  123. int PR_CALLBACK intlmime_get_mail_strictly_mime(const char * newpref, void * data);
  124. #endif
  125.  
  126. /*    We probably should change these into private instead of PUBLIC */
  127. PUBLIC char *DecodeBase64Buffer(char *subject);
  128. PUBLIC char *EncodeBase64Buffer(char *subject, size_t size);
  129.  
  130.  
  131. /* 4.0: Made Encode & Decode public for use by libpref; added size param.
  132.  */
  133. PUBLIC char *EncodeBase64Buffer(char *subject, size_t size)
  134. {
  135.     /* This function should be obsolete */
  136.     /* We should not make this public in libi18n */
  137.     /* We should use the new Base64 Encoder wrote by jwz in libmime */
  138.     return intlmime_encode_base64_buf(subject, size);
  139. }
  140.  
  141. PUBLIC char *DecodeBase64Buffer(char *subject)
  142. {
  143.     /* This function should be obsolete */
  144.     /* We should not make this public in libi18n */
  145.     /* We should use the new Base64 Decoder wrote by jwz in libmime */
  146.     return intlmime_decode_base64_buf(subject);
  147. }
  148.  
  149. #if defined(MOZ_MAIL_COMPOSE) || defined(MOZ_MAIL_NEWS)
  150.  
  151. /*
  152.     Implementation 
  153. */
  154. /*
  155.     INTL_DefaultMailCharSetID,
  156. */
  157. PUBLIC int16 INTL_DefaultMailCharSetID(int16 csid)
  158. {
  159.     int16 retcsid;
  160.      csid &= ~CS_AUTO;
  161.  
  162.     intlmime_init_csidmap();
  163.     retcsid = intlmime_map_csid(cs_mime_csidmap_tbl, csid);
  164.  
  165.     if(retcsid == CS_KSC_8BIT)
  166.         retcsid = CS_2022_KR;
  167.     return retcsid;
  168. }
  169.  
  170. PUBLIC int16 INTL_DefaultNewsCharSetID(int16 csid)
  171. {
  172.  
  173.     if (csid == 0)
  174.         csid = INTL_DefaultDocCharSetID(0);
  175.     csid &= ~CS_AUTO;
  176.     intlmime_init_csidmap();
  177.     return intlmime_map_csid(cs_mime_csidmap_tbl, csid);
  178. }
  179.  
  180. PUBLIC
  181. char *INTL_DecodeMimePartIIStr(const char *header, int16 wincsid, XP_Bool dontConvert)
  182. {
  183.     return intl_DecodeMimePartIIStr(header, wincsid, dontConvert);
  184. }
  185. PUBLIC
  186. char *INTL_EncodeMimePartIIStr(char *subject, int16 wincsid, XP_Bool bUseMime)
  187. {
  188.     return intl_EncodeMimePartIIStr(subject, wincsid, bUseMime, MAXLINELEN);
  189. }
  190. #endif /* MOZ_MAIL_COMPOSE || MOZ_MAIL_NEWS */
  191.  
  192. #ifdef MOZ_MAIL_NEWS
  193. /*  This is a routine used to re-encode subject lines for use in the summary file.
  194.     The reason why we specify a different length here is because we are not encoding
  195.     the string for use in a mail message, but rather want to stuff as much content
  196.     into the subject string as possible. */
  197. PUBLIC
  198. char *INTL_EncodeMimePartIIStr_VarLen(char *subject, int16 wincsid, XP_Bool bUseMime, int encodedWordSize)
  199. {
  200.     return intl_EncodeMimePartIIStr(subject, wincsid, bUseMime, encodedWordSize);
  201. }
  202. #endif /* MOZ_MAIL_NEWS */
  203.  
  204.  
  205. #if defined(MOZ_MAIL_COMPOSE) || defined(MOZ_MAIL_NEWS)
  206. /*    some utility function used by this file */
  207. PRIVATE XP_Bool intlmime_only_ascii_str(const char *s)
  208. {
  209.     for(; *s; s++)
  210.         if(*s & 0x80)
  211.             return FALSE;
  212.     return TRUE;
  213. }
  214. #endif /* MOZ_MAIL_COMPOSE || MOZ_MAIL_NEWS */
  215.  
  216. #ifdef MOZ_MAIL_NEWS
  217. PRIVATE void intlmime_update_csidmap(int16 csid_key, int16 csid_target)
  218. {
  219.     cs_csid_map_t * mapp;
  220.     
  221.     for(mapp = cs_mime_csidmap_tbl ; 
  222.         mapp->csid_key != 0 ; 
  223.         mapp++) 
  224.         {
  225.         if (mapp->csid_key == csid_key) 
  226.             mapp->csid_target = csid_target;
  227.         }
  228. }
  229.  
  230. #if 0
  231. /* callback routine invoked by prefapi when the pref value changes */
  232. MODULE_PRIVATE
  233. int PR_CALLBACK intlmime_get_mail_strictly_mime(const char * newpref, void * data)
  234. {
  235.     XP_Bool    mail_strictly_mime = FALSE;
  236.  
  237.     if (PREF_NOERROR == PREF_GetBoolPref("mail.strictly_mime", &mail_strictly_mime))
  238.     {
  239.         intlmime_update_csidmap(CS_UTF8, mail_strictly_mime ? CS_UTF7 : CS_UTF8);
  240.         intlmime_update_csidmap(CS_UCS2, mail_strictly_mime ? CS_UTF7 : CS_UTF8);
  241.         intlmime_update_csidmap(CS_UCS2_SWAP, mail_strictly_mime ? CS_UTF7 : CS_UTF8);
  242.     }
  243.     
  244.     return PREF_NOERROR;
  245. }
  246. #endif
  247. #endif /* MOZ_MAIL_NEWS */
  248.  
  249. #if defined(MOZ_MAIL_COMPOSE) || defined(MOZ_MAIL_NEWS)
  250. PRIVATE void
  251. intlmime_init_csidmap()
  252. {
  253.     static XP_Bool initialized = FALSE;
  254.  
  255.     if(initialized)
  256.         return;
  257.  
  258. #if 0 /* UTF-8 is sent as UTF-8 regardless of the pref setting. */
  259.         {
  260.       XP_Bool    mail_strictly_mime;
  261.       /* modify csidmap for UTF-8 if the pref is not strictly mime */
  262.       if (PREF_NOERROR == PREF_GetBoolPref("mail.strictly_mime", &mail_strictly_mime))
  263.         {
  264.         intlmime_update_csidmap(CS_UTF8, mail_strictly_mime ? CS_UTF7 : CS_UTF8);
  265.         intlmime_update_csidmap(CS_UCS2, mail_strictly_mime ? CS_UTF7 : CS_UTF8);
  266.         intlmime_update_csidmap(CS_UCS2_SWAP, mail_strictly_mime ? CS_UTF7 : CS_UTF8);
  267.         /* to detect pref change */
  268.         PREF_RegisterCallback("mail.strictly_mime", intlmime_get_mail_strictly_mime, NULL);
  269.       }
  270.         }
  271. #endif
  272.         
  273.     /* Speical Hack for Cyrllic */
  274.     /* We need to know wheater we should send KOI8-R or ISO-8859-5 */
  275.  
  276.     {
  277.         cs_csid_map_t * mapp;
  278.         static const char* pref_mailcharset_cyrillic = "intl.mailcharset.cyrillic";
  279.         char *mailcharset_cyrillic = NULL;
  280.         int16 mailcsid_cyrillic = CS_UNKNOWN;
  281.  
  282.         if( PREF_NOERROR == PREF_CopyCharPref(pref_mailcharset_cyrillic, 
  283.                                 &mailcharset_cyrillic))
  284.         {
  285.             mailcsid_cyrillic = INTL_CharSetNameToID(mailcharset_cyrillic);
  286.             XP_FREE(mailcharset_cyrillic);
  287.  
  288.             if(CS_UNKNOWN != mailcsid_cyrillic)
  289.             {
  290.                 for(mapp = cs_mime_csidmap_tbl ; 
  291.                     mapp->csid_key != 0 ; 
  292.                     mapp++) 
  293.                 {
  294.                     if (
  295.                         (mapp->csid_key == CS_KOI8_R) ||  
  296.                         (mapp->csid_key == CS_8859_5) ||
  297.                         (mapp->csid_key == CS_MAC_CYRILLIC) || 
  298.                         (mapp->csid_key == CS_CP_1251) 
  299.                        ) 
  300.                     {
  301.                         mapp->csid_target = mailcsid_cyrillic;
  302.                     }
  303.                 }
  304.             }
  305.         }
  306.     }
  307.  
  308.     initialized = TRUE;
  309. }
  310.  
  311. PRIVATE int16
  312. intlmime_map_csid(cs_csid_map_t *mapp, int16    csid_key)
  313. {
  314.     for( ; mapp->csid_key != 0 ; mapp++) 
  315.     {
  316.         if (csid_key == mapp->csid_key) 
  317.             return(mapp->csid_target);
  318.     }
  319.     return(csid_key);            /* causes no conversion */
  320. }
  321.  
  322. PRIVATE int16
  323. intlmime_get_outgoing_mime_csid(int16    win_csid)
  324. {
  325.      win_csid &= ~CS_AUTO;
  326.     intlmime_init_csidmap();
  327.     return intlmime_map_csid(cs_mime_csidmap_tbl, win_csid);
  328. }
  329.  
  330. PRIVATE char *intlmime_decode_qp(char *in)
  331. {
  332.     int i = 0, length;
  333.     char token[3];
  334.     char *out, *dest = 0;
  335.  
  336.     out = dest = (char *)XP_ALLOC(strlen(in)+1);
  337.     if (dest == NULL)
  338.         return NULL;
  339.     memset(out, 0, strlen(in)+1);
  340.     length = strlen(in);
  341.       while (length > 0 || i != 0)
  342.     {
  343.           while (i < 3 && length > 0)
  344.         {
  345.               token [i++] = *in;
  346.               in++;
  347.               length--;
  348.         }
  349.  
  350.           if (i < 3)
  351.         {
  352.           /* Didn't get enough for a complete token.
  353.              If it might be a token, unread it.
  354.              Otherwise, just dump it.
  355.              */
  356.             strncpy (out, token, i);
  357.               break;
  358.         }
  359.           i = 0;
  360.  
  361.           if (token [0] == '=')
  362.         {
  363.               unsigned char c = 0;
  364.               if (token[1] >= '0' && token[1] <= '9')
  365.                 c = token[1] - '0';
  366.               else if (token[1] >= 'A' && token[1] <= 'F')
  367.                 c = token[1] - ('A' - 10);
  368.               else if (token[1] >= 'a' && token[1] <= 'f')
  369.                 c = token[1] - ('a' - 10);
  370.               else if (token[1] == CR || token[1] == LF)
  371.             {
  372.                   /* =\n means ignore the newline. */
  373.                   if (token[1] == CR && token[2] == LF)
  374.                     ;        /* swallow all three chars */
  375.                   else
  376.                 {
  377.                       in--;    /* put the third char back */
  378.                       length++;
  379.                 }
  380.                   continue;
  381.             }
  382.               else
  383.             {
  384.                   /* = followed by something other than hex or newline -
  385.                  pass it through unaltered, I guess.  (But, if
  386.                  this bogus token happened to occur over a buffer
  387.                  boundary, we can't do this, since we don't have
  388.                  space for it.  Oh well.  Forget it.)  */
  389.                   if (in > out) *out++ = token[0];
  390.                   if (in > out) *out++ = token[1];
  391.                   if (in > out) *out++ = token[2];
  392.                   continue;
  393.             }
  394.  
  395.               /* Second hex digit */
  396.               c = (c << 4);
  397.               if (token[2] >= '0' && token[2] <= '9')
  398.                 c += token[2] - '0';
  399.               else if (token[2] >= 'A' && token[2] <= 'F')
  400.                 c += token[2] - ('A' - 10);
  401.               else if (token[2] >= 'a' && token[2] <= 'f')
  402.                 c += token[2] - ('a' - 10);
  403.               else
  404.             {
  405.                   /* We got =xy where "x" was hex and "y" was not, so
  406.                  treat that as a literal "=", x, and y.  (But, if
  407.                  this bogus token happened to occur over a buffer
  408.                  boundary, we can't do this, since we don't have
  409.                  space for it.  Oh well.  Forget it.) */
  410.                   if (in > out) *out++ = token[0];
  411.                   if (in > out) *out++ = token[1];
  412.                   if (in > out) *out++ = token[2];
  413.                   continue;
  414.             }
  415.  
  416.               *out++ = (char) c;
  417.         }
  418.           else
  419.         {
  420.               *out++ = token [0];
  421.  
  422.               token[0] = token[1];
  423.               token[1] = token[2];
  424.               i = 2;
  425.         }
  426.     }
  427.     /* take care of special underscore case */
  428.     for (out = dest; *out; out++)
  429.         if (*out == '_')     *out = ' ';
  430.     return dest;
  431. }
  432.  
  433. #endif  /* MOZ_MAIL_COMPOSE || MOZ_MAIL_NEWS */
  434.  
  435. PRIVATE int intlmime_decode_base64 (const char *in, char *out)
  436. {
  437.   /* reads 4, writes 3. */
  438.   int j;
  439.   unsigned long num = 0;
  440.  
  441.   for (j = 0; j < 4; j++)
  442.     {
  443.       unsigned char c;
  444.       if (in[j] >= 'A' && in[j] <= 'Z')         c = in[j] - 'A';
  445.       else if (in[j] >= 'a' && in[j] <= 'z') c = in[j] - ('a' - 26);
  446.       else if (in[j] >= '0' && in[j] <= '9') c = in[j] - ('0' - 52);
  447.       else if (in[j] == '+')                 c = 62;
  448.       else if (in[j] == '/')                 c = 63;
  449.       else if (in[j] == '=')                 c = 0;
  450.       else
  451.       {
  452.         /*    abort ();    */
  453.         strcpy(out, in);    /* I hate abort */
  454.         return 0;
  455.       }
  456.       num = (num << 6) | c;
  457.     }
  458.  
  459.   *out++ = (unsigned char) (num >> 16);
  460.   *out++ = (unsigned char) ((num >> 8) & 0xFF);
  461.   *out++ = (unsigned char) (num & 0xFF);
  462.   return 1;
  463. }
  464.  
  465. PRIVATE char *intlmime_decode_base64_buf(char *subject)
  466. {
  467.     char *output = 0;
  468.     char *pSrc, *pDest ;
  469.     int i ;
  470.  
  471.     StrAllocCopy(output, subject); /* Assume converted text are always less than source text */
  472.  
  473.     pSrc = subject;
  474.     pDest = output ;
  475.     for (i = strlen(subject); i > 3; i -= 4)
  476.     {
  477.         if (intlmime_decode_base64(pSrc, pDest) == 0)
  478.         {
  479.             pSrc += 4;
  480.             pDest += 4;
  481.         }
  482.         else
  483.         {
  484.             pSrc += 4;
  485.             pDest += 3;
  486.         }
  487.     }
  488.     
  489.     *pDest = '\0';
  490.     return output;
  491. }
  492.  
  493. #if defined(MOZ_MAIL_COMPOSE) || defined(MOZ_MAIL_NEWS)
  494.  
  495. PRIVATE char *intlmime_convert_but_no_decode(const char *header, int16 mailcsid, int16 wincsid)
  496. {
  497.     char* tmpbuf = NULL, *convbuf = NULL;
  498.     CCCDataObject    obj;
  499.     CCCFunc cvtfunc;
  500.     /* Copy buf to tmpbuf, this guarantee the convresion won't overwrite the origional buffer and  */
  501.     /* It will always return something it any conversion occcur */
  502.     StrAllocCopy(tmpbuf, header);
  503.     
  504.     if(tmpbuf == NULL)
  505.         return NULL;
  506.     
  507.     obj = INTL_CreateCharCodeConverter();
  508.     if (obj == NULL)
  509.         return NULL;
  510.     INTL_GetCharCodeConverter(mailcsid, wincsid, obj);
  511.     convbuf = NULL;
  512.     cvtfunc = INTL_GetCCCCvtfunc(obj);
  513.     if (cvtfunc)
  514.         convbuf = (char*)cvtfunc(obj, (unsigned char*)tmpbuf, (int32)XP_STRLEN((char*)tmpbuf));
  515.     XP_FREE(obj);
  516.     
  517.     /*    if the conversion which use the origional buffer 
  518.         them we return the tmpbuf */
  519.     if(convbuf == NULL)    
  520.         return tmpbuf;
  521.  
  522.     /*  if the conversion return a different buffer, we free the
  523.         origional one and return the one return from conversion */
  524.     if(convbuf != tmpbuf)
  525.         XP_FREE(tmpbuf);
  526.     return convbuf;
  527. }
  528. /* 
  529.     intlmime_is_hz: it is CS_HZ 
  530. */
  531. PRIVATE XP_Bool intlmime_is_hz(const char *header)
  532. {
  533.     return (XP_STRSTR(header, "~{") ? TRUE : FALSE);
  534. }
  535. /* 
  536.     intlmime_is_iso_2022_xxx: it is statefule encoding with esc 
  537. */
  538. PRIVATE XP_Bool intlmime_is_iso_2022_xxx(const char *header, int16 mailcsid)
  539. {
  540.     return (((mailcsid & STATEFUL) && (XP_STRCHR(header, '\033'))) ? TRUE : FALSE);
  541. }
  542. /* 
  543.     intlmime_is_mime_part2_header: 
  544. */
  545. PRIVATE XP_Bool intlmime_is_mime_part2_header(const char *header)
  546. {
  547.     return ((
  548.               XP_STRSTR(header, "=?") &&
  549.              ( 
  550.               XP_STRSTR(header, "?q?")  ||
  551.               XP_STRSTR(header, "?Q?")  ||
  552.               XP_STRSTR(header, "?b?")  ||
  553.               XP_STRSTR(header, "?B?")  
  554.              )
  555.             ) ? TRUE : FALSE );    
  556. }
  557.  
  558. extern char *strip_continuations(char *original);
  559.  
  560. PRIVATE
  561. char *intl_decode_mime_part2_str(const char *header, int wincsid, XP_Bool dontConvert)
  562. {
  563.     char *work_buf = NULL;
  564.     char *output_p = NULL;
  565.     char *retbuff = NULL;
  566.     char *p, *q, *decoded_text;
  567.     char *begin; /* tracking pointer for where we are in the work buffer */
  568.     int16     csid = 0;
  569.     int  ret = 0;
  570.  
  571.  
  572.     StrAllocCopy(work_buf, header);  /* temporary buffer */
  573.     StrAllocCopy(retbuff, header);
  574.  
  575.     if (work_buf == NULL || retbuff == NULL)
  576.         return NULL;
  577.  
  578.     output_p = retbuff;
  579.     begin = work_buf;
  580.  
  581.     while (*begin != '\0')
  582.     {        
  583.         char * output_text;
  584.  
  585.         /*        GetCharset();        */
  586.         p = strstr(begin, "=?");
  587.         if (p == NULL)
  588.             break;                /* exit the loop because the rest are not encoded */
  589.         *p = '\0';
  590.         /* skip strings don't need conversion */
  591.         strncpy(output_p, begin, p - begin);
  592.         output_p += p - begin;
  593.  
  594.         p += 2;
  595.         begin = p;
  596.  
  597.         q = strchr(p, '?');  /* Get charset info */
  598.         if (q == NULL)
  599.             break;                /* exit the loop because there are no charset info */
  600.         *q++ = '\0';
  601.         csid = INTL_CharSetNameToID(p);
  602.         if (csid == CS_UNKNOWN)
  603.         {
  604.             /*
  605.              * @@@ may want to use context's default doc_csid in the future
  606.              */
  607.             break;                /* exit the loop because we don't know the charset */
  608.         }
  609.  
  610.         if (*(q+1) == '?' &&
  611.             (*q == 'Q' || *q == 'q' || *q == 'B' || *q == 'b'))
  612.         {            
  613.             p = strstr(q+2, "?=");
  614.             if(p != NULL)
  615.                 *p = '\0';
  616.             if(*q == 'Q' || *q == 'q')
  617.                 decoded_text = intlmime_decode_qp(q+2);
  618.             else
  619.                 decoded_text = intlmime_decode_base64_buf(q+2);
  620.         }
  621.         else 
  622.             break;                /* exit the loop because we don't know the encoding method */
  623.  
  624.         begin = (p != NULL) ? p + 2 : (q + strlen(q));
  625.  
  626.         if (decoded_text == NULL) 
  627.             break;                /* exit the loop because we have problem to decode */
  628.  
  629.         ret = 1;
  630.         if ((! dontConvert) && (csid != wincsid))
  631.             output_text = (char *)intlmime_convert_but_no_decode(decoded_text, csid, (int16)wincsid);
  632.         else
  633.             output_text = (char *)decoded_text;
  634.  
  635.         XP_ASSERT(output_text != NULL);
  636.         XP_STRCPY(output_p, (char *)output_text);
  637.         output_p += strlen(output_text);
  638.  
  639.         if (output_text != decoded_text)
  640.             XP_FREE(output_text);
  641.         XP_FREE(decoded_text);
  642.     }
  643.     XP_STRCPY(output_p, (char *)begin);    /* put the tail back  */
  644.  
  645.     if (work_buf)
  646.         XP_FREE(work_buf);
  647.  
  648.     if (ret)
  649.     {
  650.         return retbuff;
  651.     }
  652.     else
  653.     {
  654.         XP_FREE(retbuff);
  655.         return NULL;  /* null means no conversion */
  656.     }
  657. }
  658.  
  659. /* PRIVATE */
  660. /* char* intl_strip_crlftab(char* str) */
  661. /* { */
  662. /*     char* out, *in; */
  663. /*     if(str) { */
  664. /*         for(out = in = str; *in != NULL; in++) */
  665. /*             if((*in != CR) && (*in != LF) && (*in != TAB)) */
  666. /*                 *out++ = *in; */
  667. /*         *out = NULL; */
  668. /*     } */
  669. /*     return str; */
  670. /* } */
  671.  
  672.  
  673. /* 
  674.  IntlDecodeMimePartIIStr
  675.   This functions converts mail charset to Window charset for subject
  676.     Syntax:   =?MimeCharset?[B|Q]?text?=
  677.         MimeCharset = ISO-2022-JP
  678.                       ISO-8859-1
  679.                       ISO-8859-?
  680.                       ....
  681.         ?B? :  Base64 Encoding          (used for multibyte encoding)
  682.         ?Q? :  Quote Printable Encoding (used for single byte encoding)
  683.  
  684.       eg. for Japanese mail, it looks like
  685.          =?ISO-2022-JP?B?   ........   ?=
  686. */
  687. /* IMPORTANT NOTE: */
  688. /* Return NULL in this interface only mean ther are no conversion */
  689. /* It does not mean the conversion is store in the origional buffer */
  690. /* and the length is not change. This is differ from other conversion routine */
  691.  
  692.  
  693. PRIVATE
  694. char *intl_DecodeMimePartIIStr(const char *header, int16 wincsid, XP_Bool dontConvert)
  695. {
  696.     int16 mailcsid = INTL_DefaultMailCharSetID(wincsid);
  697.     XP_Bool no8bitdata = TRUE;
  698.  
  699.     if (header == 0 || *header == '\0')
  700.         return NULL;
  701.     if (wincsid == 0) /* Use global if undefined */
  702.         wincsid = INTL_DefaultWinCharSetID(0);
  703.  
  704.     no8bitdata = intlmime_only_ascii_str(header);
  705.  
  706.     /*    Start Special Case Handling        */
  707.     if(! dontConvert) 
  708.     {
  709.         /* Need to do conversion in here if necessary */
  710.         if(! no8bitdata)
  711.         {
  712.             /*    Special Case 1: 8 Bit */
  713.             /* then we assume it is not mime part 2  encoding, we convert from the internet encoding to wincsid */
  714.             if(wincsid == CS_UTF8)
  715.                 return strip_continuations(intlmime_convert_but_no_decode(header, CS_UTF8, (int16)wincsid));
  716.             else
  717.                 return strip_continuations(intlmime_convert_but_no_decode(header, mailcsid, (int16)wincsid));
  718.         }
  719.         else
  720.         {
  721.             /* 7bit- It could be MIME Part 2 Header */
  722.             if ((wincsid == CS_GB_8BIT) && (intlmime_is_hz(header)) )
  723.             {  
  724.                 /*    Special Case 2: HZ */
  725.                 /*    for subject list pane, if it's GB, we only do HZ conversion */
  726.                 return strip_continuations(intlmime_convert_but_no_decode(header, CS_GB_8BIT, CS_GB_8BIT));
  727.             }
  728.             else if((wincsid == CS_UTF8) && 
  729.                     (! intlmime_is_mime_part2_header(header)))
  730.             {    
  731.                 /*    Special Case 3: UTF8, no mime2 */
  732.                 return strip_continuations(intlmime_convert_but_no_decode(header, CS_UTF8, CS_UTF8));
  733.             } 
  734.             else if(intlmime_is_iso_2022_xxx(header, mailcsid) && 
  735.                     (! intlmime_is_mime_part2_header(header)))
  736.             {
  737.                 return strip_continuations(intlmime_convert_but_no_decode(header, mailcsid, wincsid));
  738.             }
  739.         }
  740.     }
  741.     /* Handle only Mime Part 2 after this point */
  742.     return strip_continuations(intl_decode_mime_part2_str(header, wincsid, dontConvert));
  743. }
  744. #endif /* MOZ_MAIL_COMPOSE || MOZ_MAIL_NEWS */
  745.  
  746.  
  747.  
  748. PRIVATE char basis_64[] =
  749.    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  750.  
  751. PRIVATE int intlmime_encode_base64 (const char *in, char *out)
  752. {
  753.     unsigned char c1, c2, c3;
  754.     c1 = in[0];
  755.     c2 = in[1];
  756.     c3 = in[2];
  757.  
  758.     *out++ = basis_64[c1>>2];
  759.     *out++ = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
  760.  
  761.     *out++ = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
  762.     *out++ = basis_64[c3 & 0x3F];
  763.     return 1;
  764. }
  765.  
  766. PRIVATE char *intlmime_encode_base64_buf(char *subject, size_t size)
  767. {
  768.     char *output = 0;
  769.     char *pSrc, *pDest ;
  770.     int i ;
  771.  
  772.     output = (char *)XP_ALLOC(size * 4 / 3 + 4);
  773.     if (output == NULL)
  774.         return NULL;
  775.  
  776.     pSrc = subject;
  777.     pDest = output ;
  778.     for (i = size; i >= 3; i -= 3)
  779.     {
  780.         if (intlmime_encode_base64(pSrc, pDest) == 0) /* error */
  781.         {
  782.             pSrc += 3;
  783.             pDest += 3;
  784.         }
  785.         else
  786.         {
  787.             pSrc += 3;
  788.             pDest += 4;
  789.         }
  790.     }
  791.     /* in case (i % 3 ) == 1 or 2 */
  792.     if(i > 0)
  793.     {
  794.         char in[3];
  795.         int j;
  796.         in[0] = in[1] = in[2] ='\0';
  797.         for(j=0;j<i;j++)
  798.             in[j] = *pSrc++;
  799.         intlmime_encode_base64(in, pDest);
  800.         for(j=i+1;j<4;j++)
  801.             pDest[j] = '=';
  802.         pDest += 4;
  803.     }
  804.     *pDest = '\0';
  805.     return output;
  806. }
  807.  
  808. #if defined(MOZ_MAIL_COMPOSE) || defined(MOZ_MAIL_NEWS)
  809. PRIVATE char *intlmime_encode_qp_buf(char *subject)
  810. {
  811.     char *output = 0;
  812.     unsigned char *p, *pDest ;
  813.     int i, n, len ;
  814.  
  815.     if (subject == NULL || *subject == '\0')
  816.         return NULL;
  817.     len = strlen(subject);
  818.     output = XP_ALLOC(len * 3 + 1);
  819.     if (output == NULL)
  820.         return NULL;
  821.  
  822.     p = (unsigned char*)subject;
  823.     pDest = (unsigned char*)output ;
  824.  
  825.     for (i = 0; i < len; i++)
  826.     {
  827.         /* XP_IS_ALPHA(*p) || XP_IS_DIGIT(*p)) */
  828.         if ((*p < 0x80) &&
  829.             (((*p >= 'a') && (*p <= 'z')) ||
  830.              ((*p >= 'A') && (*p <= 'Z')) ||
  831.              ((*p >= '0') && (*p <= '9')))
  832.            )
  833.             *pDest = *p;
  834.         else
  835.         {
  836.             *pDest++ = '=';
  837.             n = (*p & 0xF0) >> 4; /* high byte */
  838.             if (n < 10)
  839.                 *pDest = '0' + n;
  840.             else
  841.                 *pDest = 'A' + n - 10;
  842.             pDest ++ ;
  843.  
  844.             n = *p & 0x0F;            /* low byte */
  845.             if (n < 10)
  846.                 *pDest = '0' + n;
  847.             else
  848.                 *pDest = 'A' + n - 10;
  849.         }
  850.  
  851.         p ++;
  852.         pDest ++;
  853.     }
  854.  
  855.     *pDest = '\0';
  856.     return output;
  857. }
  858.  
  859. PRIVATE char *intlmime_encode_next8bitword(int wincsid, char *src)
  860. {
  861.     char *p;
  862.     XP_Bool non_ascii = FALSE;
  863.     if (src == NULL)
  864.         return NULL;
  865.     p = src;
  866.     while (*p == ' ')
  867.         p ++ ;
  868.     while ( *p )
  869.     {
  870.         if ((unsigned char) *p > 0x7F)
  871.             non_ascii = TRUE;
  872.         if ( IS_MAIL_SEPARATOR(p) )
  873.         {
  874.             break;
  875.         }
  876.         p = INTL_NextChar(wincsid, p);
  877.     }
  878.  
  879.     if (non_ascii)
  880.         return p;
  881.     else
  882.         return NULL;
  883. }
  884.  
  885. /*
  886. lock then length of input buffer, so the return value is less than iThreshold bytes
  887. */
  888. PRIVATE int ResetLen( int iThreshold, const char* buffer, int16 wincsid )
  889. {
  890.     const char *begin, *end, *tmp;
  891.  
  892.     tmp = begin = end = buffer;
  893.     XP_ASSERT( iThreshold > 1 );
  894.     XP_ASSERT( buffer != NULL );
  895.     while( ( end - begin ) <= iThreshold ){
  896.         tmp = end;
  897.         if (!(*end))
  898.             break;
  899.         end = INTL_NextChar( wincsid, (char*)end );
  900.     }
  901.  
  902.     XP_ASSERT( tmp > begin );
  903.     return tmp - begin;
  904. }
  905.  
  906. PRIVATE char * intlmime_encode_mail_address(int wincsid, const char *src, CCCDataObject obj,
  907.                                             int maxLineLen)
  908. {
  909.     char *begin, *end;
  910.     char *retbuf = NULL, *srcbuf = NULL;
  911.     char sep = '\0';
  912.     char *sep_p = NULL;
  913.     char *name;
  914.     int  retbufsize;
  915.     int line_len = 0;
  916.     int srclen;
  917.     int default_iThreshold;
  918.     int iThreshold;        /* how many bytes we can convert from the src */
  919.     int iEffectLen;        /* the maximum length we can convert from the src */
  920.     XP_Bool bChop = FALSE;
  921.     XP_Bool is_being_used_in_email_summary_file = (maxLineLen > 120);
  922.     CCCFunc cvtfunc = NULL;
  923.  
  924.     if (obj)
  925.         cvtfunc = INTL_GetCCCCvtfunc(obj);
  926.  
  927.     if (src == NULL || *src == '\0')
  928.         return NULL;
  929.     /* make a copy, so don't need touch original buffer */
  930.     StrAllocCopy(srcbuf, src);
  931.     if (srcbuf == NULL)
  932.         return NULL;
  933.     begin = srcbuf;
  934.     
  935.     name = (char *)INTL_CsidToCharsetNamePt(intlmime_get_outgoing_mime_csid ((int16)wincsid));
  936.     default_iThreshold = iEffectLen = ( maxLineLen - XP_STRLEN( name ) - 7 ) * 3 / 4;
  937.     iThreshold = default_iThreshold;
  938.  
  939.  
  940.     /* allocate enough buffer for conversion, this way it can avoid
  941.        do another memory allocation which is expensive
  942.      */
  943.        
  944.     retbufsize = XP_STRLEN(srcbuf) * 3 + MAX_CSNAME + 8;
  945.     retbuf =  XP_ALLOC(retbufsize);
  946.     if (retbuf == NULL)  /* Give up if not enough memory */
  947.     {
  948.         XP_FREE(srcbuf);
  949.         return NULL;
  950.     }
  951.  
  952.     *retbuf = '\0';
  953.  
  954.     srclen = XP_STRLEN(srcbuf);
  955.     while (begin < (srcbuf + srclen))
  956.     {    /* get block of data between commas */
  957.         char *p, *q;
  958.         char *buf1, *buf2;
  959.         int len, newsize, convlen, retbuflen;
  960.         XP_Bool non_ascii;
  961.  
  962.         retbuflen = XP_STRLEN(retbuf);
  963.         end = NULL;
  964.         if (is_being_used_in_email_summary_file) {
  965.         } else {
  966.         /* scan for separator, conversion happens on 8bit
  967.            word between separators
  968.          */
  969.         if (IS_MAIL_SEPARATOR(begin))
  970.         {   /*  skip white spaces and separator */
  971.             q = begin;
  972.             while (    IS_MAIL_SEPARATOR(q) )
  973.                 q ++ ;
  974.             sep = *(q - 1);
  975.             sep_p = (q - 1);
  976.             *(q - 1) = '\0';
  977.             end = q - 1;
  978.         }
  979.         else
  980.         {
  981.             sep = '\0';
  982.             /* scan for next separator */
  983.             non_ascii = FALSE;
  984.             for (q = begin; *q;)
  985.             {
  986.                 if ((unsigned char) *q > 0x7F)
  987.                     non_ascii = TRUE;
  988.                 if ( IS_MAIL_SEPARATOR(q) )
  989.                 {
  990.                     if ((*q == ' ') && (non_ascii == TRUE))
  991.                     {
  992.                         while ((p = intlmime_encode_next8bitword(wincsid, q)) != NULL)
  993.                         {
  994.                             if (p == NULL)
  995.                                 break;
  996.                             q = p;
  997.                             if (*p != ' ')
  998.                                 break;
  999.                         }
  1000.                     }
  1001.                     sep = *q;
  1002.                     sep_p = q;
  1003.                     *q = '\0';
  1004.                     end = q;
  1005.                     break;
  1006.                 }
  1007.                 q = INTL_NextChar(wincsid, q);
  1008.             }
  1009.         }
  1010.         }
  1011.  
  1012.         /* get the to_be_converted_buffer's len */
  1013.         len = XP_STRLEN(begin);
  1014.  
  1015.         if ( !intlmime_only_ascii_str(begin) )
  1016.         {
  1017.             if (obj && cvtfunc)
  1018.             {
  1019.                 /*
  1020.                        the 30 lenght is calculated as follows (I think)
  1021.                     total:             30 = 7 + 11 + 8 + 4
  1022.                     --------------------------------------
  1023.                     Mime Part II tags: 7  = "=?...?B?...?="
  1024.                     Charset name:      11 = "iso-2022-jp"
  1025.                     JIS excape seq.    8  = "<ESC>$B" + "<ESC>(B" * 4/3
  1026.                     space for one char 4  = 2 * 4/3 rounded up to nearest 4
  1027.                     Brian Stell 10/97
  1028.                 */
  1029.                 if( ( maxLineLen - line_len < 30 ) || bChop ){
  1030.                     /* chop first, then continue */
  1031.                     buf1 = retbuf + retbuflen; 
  1032.                       *buf1++ = CR;    *buf1++ = LF;    *buf1++ = '\t';
  1033.                     line_len = 0;
  1034.                     retbuflen += 3;
  1035.                     *buf1 = '\0';
  1036.                     bChop = FALSE;
  1037.                     iThreshold = default_iThreshold;
  1038.                 }
  1039.                 /*    iEffectLen - the max byte-string length of JIS ( converted form S-JIS )
  1040.                     name - such as "iso-2022-jp", the encoding name, MUST be shorter than 23 bytes
  1041.                     7    - is the "=?:?:?="    */
  1042.                 iEffectLen = ( maxLineLen - line_len - XP_STRLEN( name ) - 7 ) * 3 / 4;
  1043.                 while( TRUE ){
  1044.                     int iBufLen;    /* converted buffer's length, not BASE64 */
  1045.                     if( len > iThreshold )
  1046.                         len = ResetLen( iThreshold, begin, (int16)wincsid );
  1047.  
  1048.                     buf1 = (char *) cvtfunc(obj, (unsigned char *)begin, len);
  1049.                     iBufLen = XP_STRLEN( buf1 );
  1050.                     XP_ASSERT( iBufLen > 0 );
  1051.  
  1052.                     /* recal iThreshold each time based on last experience */
  1053.                     iThreshold = len * iEffectLen / iBufLen;
  1054.                     if( iBufLen > iEffectLen ){
  1055.                         /* the converted buffer is too large, we have to
  1056.                             1. free the buffer;
  1057.                             2. redo again based on the new iThreshold
  1058.                         */
  1059.                         bChop = TRUE;        /* append CRLFTAB */
  1060.                         if (buf1 && (buf1 != begin)){
  1061.                             XP_FREE(buf1);
  1062.                             buf1 = NULL;
  1063.                         }
  1064.                     } else {
  1065.                         end = begin + len - 1;
  1066.                         break;
  1067.                     }
  1068.                 }
  1069.                 if (bChop && (NULL!=sep_p)) {
  1070.                     *sep_p = sep;    /* we are length limited so we do not need this */
  1071.                     sep = '\0';        /* artifical terminator. So, restore the original character */
  1072.                     sep_p = NULL;
  1073.                 }
  1074.  
  1075.                 if (!buf1)
  1076.                 {
  1077.                     XP_FREE(srcbuf);
  1078.                     XP_FREE(retbuf);
  1079.                     return NULL;
  1080.                 }
  1081.             }
  1082.             else
  1083.             {
  1084.                 buf1 = XP_ALLOC(len + 1);
  1085.                 if (!buf1)
  1086.                 {
  1087.                     XP_FREE(srcbuf);
  1088.                     XP_FREE(retbuf);
  1089.                     return NULL;
  1090.                 }
  1091.                 XP_MEMCPY(buf1, begin, len);
  1092.                 *(buf1 + len) = '\0';
  1093.             }
  1094.  
  1095.             if (wincsid & MULTIBYTE)
  1096.             {
  1097.                 /* converts to Base64 Encoding */
  1098.                 buf2 = (char *)intlmime_encode_base64_buf(buf1, strlen(buf1));
  1099.             }
  1100.             else
  1101.             {
  1102.                 /* Converts to Quote Printable Encoding */
  1103.                 buf2 = (char *)intlmime_encode_qp_buf(buf1);
  1104.             }
  1105.  
  1106.  
  1107.             if (buf1 && (buf1 != begin))
  1108.                 XP_FREE(buf1);
  1109.  
  1110.             if (buf2 == NULL) /* QUIT if memory allocation failed */
  1111.             {
  1112.                 XP_FREE(srcbuf);
  1113.                 XP_FREE(retbuf);
  1114.                 return NULL;
  1115.             }
  1116.  
  1117.             /* realloc memory for retbuff if necessary, 
  1118.                7: =?...?B?..?=, 3: CR LF TAB */
  1119.             convlen = XP_STRLEN(buf2) + XP_STRLEN(name) + 7;
  1120.             newsize = convlen + retbuflen + 3 + 2;  /* 2:SEP '\0', 3:CRLFTAB */
  1121.  
  1122.             if (newsize > retbufsize)
  1123.             {
  1124.                 char *tempbuf;
  1125.                 tempbuf = XP_REALLOC(retbuf, newsize);
  1126.                 if (tempbuf == NULL)  /* QUIT, if not enough memory left */
  1127.                 {
  1128.                     XP_FREE(buf2);
  1129.                     XP_FREE(srcbuf);
  1130.                     XP_FREE(retbuf);
  1131.                     return NULL;
  1132.                 }
  1133.                 retbuf = tempbuf;
  1134.                 retbufsize = newsize;
  1135.             }
  1136.             /* buf1 points to end of current retbuf */
  1137.             buf1 = retbuf + retbuflen; 
  1138.  
  1139.             if ((line_len > 10) && 
  1140.                 ((line_len + convlen) > maxLineLen))
  1141.             {
  1142.                   *buf1++ = CR;
  1143.                   *buf1++ = LF;
  1144.                   *buf1++ = '\t';
  1145.                 line_len = 0;
  1146.                 iThreshold = default_iThreshold;
  1147.             }
  1148.             *buf1 = '\0';
  1149.  
  1150.             /* Add encoding tag for base62 and QP */
  1151.             XP_STRCAT(buf1, "=?");
  1152.             XP_STRCAT(buf1, name );
  1153.             if(wincsid & MULTIBYTE)
  1154.                 XP_STRCAT(buf1, "?B?");
  1155.             else
  1156.                 XP_STRCAT(buf1, "?Q?");
  1157.             XP_STRCAT(buf1, buf2);
  1158.             XP_STRCAT(buf1, "?=");
  1159.  
  1160.             line_len += convlen + 1;  /* 1: SEP */
  1161.  
  1162.             XP_FREE(buf2);    /* free base64 buffer */
  1163.         }
  1164.         else  /* if no 8bit data in the block */
  1165.         {
  1166.             newsize = retbuflen + len + 2 + 3; /* 2: ',''\0', 3: CRLFTAB */
  1167.             if (newsize > retbufsize)
  1168.             {
  1169.                 char *tempbuf;
  1170.                 tempbuf = XP_REALLOC(retbuf, newsize);
  1171.                 if (tempbuf == NULL)
  1172.                 {
  1173.                     XP_FREE(srcbuf);
  1174.                     XP_FREE(retbuf);
  1175.                     return NULL;
  1176.                 }
  1177.                 retbuf = tempbuf;
  1178.                 retbufsize = newsize;
  1179.             }
  1180.             buf1 = retbuf + retbuflen;
  1181.  
  1182.             if ((line_len > 10) && 
  1183.                 ((line_len + len) > maxLineLen))
  1184.             {
  1185.                   *buf1++ = CR;
  1186.                   *buf1++ = LF;
  1187.                   *buf1++ = '\t';
  1188.                 line_len = 0;
  1189.                 iThreshold = default_iThreshold;
  1190.             }
  1191.             /* copy buffer from begin to buf1 stripping CRLFTAB */
  1192.             for (p = begin; *p; p++)
  1193.             {
  1194.                 if (*p == CR || *p == LF || *p == TAB)
  1195.                     len --;
  1196.                 else
  1197.                     *buf1++ = *p;
  1198.             }
  1199.             *buf1 = '\0';
  1200.             line_len += len + 1;  /* 1: SEP */
  1201.         }
  1202.  
  1203.         buf1 = buf1 + XP_STRLEN(buf1);
  1204.         if (sep == CR || sep == LF || sep == TAB) /* strip CR,LF,TAB */
  1205.             *buf1 = '\0';
  1206.         else
  1207.         {
  1208.             *buf1 = sep;
  1209.             *(buf1+1) = '\0';
  1210.         }
  1211.  
  1212.         if (end == NULL)
  1213.             break;
  1214.         begin = end + 1;
  1215.     }
  1216.     if (srcbuf)
  1217.         XP_FREE(srcbuf);
  1218.     return retbuf;
  1219. }
  1220.  
  1221. /*
  1222.     Latin1, latin2:
  1223.        Source --> Quote Printable --> Encoding Info
  1224.     Japanese:
  1225.        EUC,JIS,SJIS --> JIS --> Base64 --> Encoding Info
  1226.     Others:
  1227.        No conversion  
  1228.     flag:   0:   8bit on
  1229.             1:   mime_use_quoted_printable_p
  1230.     return:  NULL  if no conversion occured
  1231.  
  1232. */
  1233.  
  1234. PRIVATE
  1235. char *intl_EncodeMimePartIIStr(char *subject, int16 wincsid, XP_Bool bUseMime, int maxLineLen)
  1236. {
  1237.     int iSrcLen;
  1238.     unsigned char *buf  = NULL;    /* Initial to NULL */
  1239.     int16 mail_csid;
  1240.        CCCDataObject    obj = NULL;
  1241.     char  *name;
  1242.     CCCFunc cvtfunc = NULL;
  1243.  
  1244.     if (subject == NULL || *subject == '\0')
  1245.         return NULL;
  1246.  
  1247.     iSrcLen = XP_STRLEN(subject);
  1248.     if (wincsid == 0)
  1249.         wincsid = INTL_DefaultWinCharSetID(0) ;
  1250.  
  1251.     mail_csid = intlmime_get_outgoing_mime_csid ((int16)wincsid);
  1252.     name = (char *)INTL_CsidToCharsetNamePt(mail_csid);
  1253.     
  1254.     /* check to see if subject are all ascii or not */
  1255.     if(intlmime_only_ascii_str(subject))
  1256.         return NULL;
  1257.         
  1258.     if (mail_csid != wincsid)
  1259.     {
  1260.            obj = INTL_CreateCharCodeConverter();
  1261.         if (obj == NULL)
  1262.             return 0;
  1263.         /* setup converter from wincsid --> mail_csid */
  1264.         INTL_GetCharCodeConverter((int16)wincsid, mail_csid, obj) ;
  1265.         cvtfunc = INTL_GetCCCCvtfunc(obj);
  1266.     }
  1267.     /* Erik said in the case of STATEFUL mail encoding, we should FORCE it to use */
  1268.     /* MIME Part2 to get ride of ESC in To: and CC: field, which may introduce more trouble */
  1269.     if((bUseMime) || (mail_csid & STATEFUL))/* call intlmime_encode_mail_address */
  1270.     {
  1271.         buf = (unsigned char *)intlmime_encode_mail_address(wincsid, subject, obj, maxLineLen);
  1272.         if(buf == (unsigned char*)subject)    /* no encoding, set return value to NULL */
  1273.             buf =  NULL;
  1274.     }
  1275.     else
  1276.     {    /* 8bit, just do conversion if necessary */
  1277.         /* In this case, since the conversion routine may reuse the origional buffer */
  1278.         /* We better allocate one first- We don't want to reuse the origional buffer */
  1279.         
  1280.         if ((mail_csid != wincsid) && (cvtfunc))
  1281.         {
  1282.             char* newbuf = NULL;
  1283.             /* Copy buf to newbuf */
  1284.             StrAllocCopy(newbuf, subject);
  1285.             if(newbuf != NULL)
  1286.             {
  1287.                 buf = (unsigned char *)cvtfunc(obj, (unsigned char*)newbuf, iSrcLen);
  1288.                 if(buf != (unsigned char*)newbuf)
  1289.                     XP_FREE(newbuf);
  1290.             }
  1291.         }
  1292.     }
  1293.     if (obj)   
  1294.         XP_FREE(obj);
  1295.     return (char*)buf;
  1296.     
  1297.     /* IMPORTANT NOTE: */
  1298.     /* Return NULL in this interface only mean ther are no conversion */
  1299.     /* It does not mean the conversion is store in the origional buffer */
  1300.     /* and the length is not change. This is differ from other conversion routine */
  1301. }
  1302. #endif /* MOZ_MAIL_COMPOSE || MOZ_MAIL_NEWS */
  1303.  
  1304. #ifdef MOZ_MAIL_NEWS
  1305. #if 0
  1306. PUBLIC XP_Bool INTL_FindMimePartIIStr(int16 csid, XP_Bool searchcasesensitive, const char *mimepart2str,const char *s2)
  1307. {
  1308.     XP_Bool onlyAscii;
  1309.     char *ret = NULL;
  1310.     char *s1 = (char*)mimepart2str;
  1311.     char *conv;
  1312.     if((s2 == NULL) || (*s2 == '\0'))    /* if search for NULL string, return TRUE */
  1313.         return TRUE;
  1314.     if((s1 == NULL) || (*s1 == '\0'))    /* if string is NULL, return FALSE */
  1315.         return FALSE;
  1316.     
  1317.     conv= IntlDecodeMimePartIIStr(mimepart2str, csid, FALSE);
  1318.     if(conv)
  1319.         s1 = conv;
  1320.     onlyAscii = intlmime_only_ascii_str(s1) && intlmime_only_ascii_str(s2);
  1321.     if(onlyAscii)    /* for performance reason, let's call the ANSI C routine for ascii only case */
  1322.     {
  1323.         if(searchcasesensitive)
  1324.             ret= strstr( s1, s2);
  1325.         else
  1326.             ret= strcasestr(s1, s2);
  1327.     }
  1328.     else
  1329.     {
  1330.         if(searchcasesensitive)
  1331.             ret= INTL_Strstr(csid, s1, s2);
  1332.         else
  1333.             ret= INTL_Strcasestr(csid, s1, s2);
  1334.     }
  1335.     if(conv != mimepart2str)
  1336.         XP_FREE(conv);
  1337.     return (ret != NULL);        /* return TRUE if it find something */
  1338. }
  1339. #endif
  1340. /* 
  1341.     NNTP XPAT I18N Support
  1342.         INTL_FormatNNTPXPATInNonRFC1522Format and INTL_FormatNNTPXPATInRFC1522Format 
  1343.         return the a new string to the caller 
  1344.         that could be send to NNTP server for Mail Header Search (use XPAT)
  1345.         The caller must free the return string.        
  1346. */
  1347.  
  1348. /* This function use the same buffer it pass in, it strip the leading and trialling ISO-2022 ESC */
  1349. PRIVATE void intl_strip_leading_and_trial_iso_2022_esc (char* iso_2022_str);
  1350. PRIVATE char *intl_xpat_escape ( char *str);
  1351.  
  1352. #define ISO_2022_I_CODE(c)    ((0x20 <= (c)) && ((c) <= 0x2F))
  1353. #define ISO_2022_F_CODE(c)    ((0x30 <= (c)) && ((c) <= 0x7E))
  1354.  
  1355. PRIVATE void intl_strip_leading_and_trial_iso_2022_esc(char* iso_2022_str)
  1356. {
  1357.     char* inp = iso_2022_str;
  1358.     char* outp = iso_2022_str;
  1359.     char* lastescp = NULL;
  1360.     
  1361.     /* strip leading Escape */
  1362.     if(ESC == *inp)    
  1363.     {
  1364.         for(inp++ ;((*inp) && (ISO_2022_I_CODE(*inp))); /* void */)
  1365.             inp++;    /* Skip I Code */
  1366.         if(ISO_2022_F_CODE(*inp))    /* Skip F Code */
  1367.             inp++;
  1368.     }
  1369.         
  1370.     for( ; (0 != *inp); inp++, outp++)    /* copy data including esc */
  1371.     {
  1372.         *outp = *inp;
  1373.         if(ESC == *outp)    /* remember the last position of esc */
  1374.             lastescp = outp;    
  1375.     }
  1376.     *outp = '\0';    /* NULL terminate */
  1377.     
  1378.     /* strip trialling Escape if necessary */
  1379.     if(lastescp)
  1380.     {        
  1381.         char* esc_p;    
  1382.         for(esc_p = lastescp + 1; ((*esc_p) && (ISO_2022_I_CODE(*esc_p))); /* void */ )
  1383.             esc_p++;    /* Skip I Code */
  1384.             
  1385.         if(ISO_2022_F_CODE(*esc_p))    /* Skip F Code */
  1386.             esc_p++;
  1387.             
  1388.         if('\0' == *esc_p)    /* if it point to our NULL terminate, it is the trialling esp, we take it out */
  1389.         {                    /* otherwise, it is the esc in the middle, ignore it */
  1390.             *lastescp = '\0';
  1391.         }
  1392.     }
  1393. }
  1394. #define BETWEEN_A_Z(c)    (('A' <= (c)) && ((c) <= 'Z'))
  1395. #define BETWEEN_a_z(c)    (('a' <= (c)) && ((c) <= 'z'))
  1396. #define BETWEEN_0_9(c)    (('0' <= (c)) && ((c) <= '9'))
  1397. /* 
  1398.     Escape Everything except 0-9 A-Z a-z 
  1399.    "Common NNTP Extensions" and wildmat(3) does not state clearly what NEED TO BE Escape.
  1400.    I look like the * ? [ \ need to be escape , 
  1401.    But by trial and error I also find out ^ and $ need to be escape. 
  1402.    That's why I just do this ESCAPE MORE THAN WE NEEDED untill we figure out what relly NEED TO BE Escaped    
  1403. */
  1404. #define XPAT_NEED_ESCAPE(c)        (! (BETWEEN_A_Z(c) || BETWEEN_a_z(c) || BETWEEN_0_9(c))) 
  1405. PRIVATE char *intl_xpat_escape( char *str)
  1406. {
  1407.     char *result = NULL;
  1408.     /* max escaped length is one extra characters for every character in the str. */
  1409.     char *scratchBuf = (char*) XP_ALLOC (2*XP_STRLEN(str) + 1);
  1410.     if(scratchBuf)
  1411.     {
  1412.         char *scratchPtr = scratchBuf;
  1413.         char ch;
  1414.         while ('\0' != (ch = *str++))
  1415.         {
  1416.             if (XPAT_NEED_ESCAPE(ch))
  1417.                 *scratchPtr++ = '\\';
  1418.             *scratchPtr++ = ch;
  1419.         }
  1420.         *scratchPtr = '\0';
  1421.         result = XP_STRDUP (scratchBuf); /* realloc down to smaller size */
  1422.         XP_FREE (scratchBuf);
  1423.     }
  1424.     return result;
  1425. }
  1426.  
  1427.  
  1428. /*
  1429.     INTL_FormatNNTPXPATInNonRFC1522Format
  1430.     1. Convert the data from wincsid to newscsid
  1431.     2. Strip Out leading Esc Sequence and trialing Esc Sequence
  1432.     3. Always return memory unless memory is not enough. Never have side effect on the pass-in buffer
  1433. */
  1434.  
  1435. PUBLIC unsigned char* INTL_FormatNNTPXPATInNonRFC1522Format(int16 wincsid, unsigned char* searchString)
  1436. {
  1437.     char* temp = NULL;
  1438.     char* conv = NULL;
  1439.     char* xpat_escape = NULL;
  1440.     StrAllocCopy(temp, (char*) searchString);
  1441.     XP_ASSERT(temp);    /* Should only come here if Memory Not Enough */
  1442.     if(NULL == temp)
  1443.         return NULL;
  1444.         
  1445.     /* Convert text from wincsid to newscsid */
  1446.     if(NULL != (conv = (char*)INTL_ConvertLineWithoutAutoDetect(wincsid, INTL_DefaultNewsCharSetID(wincsid), (unsigned char*)temp, XP_STRLEN((char*)temp))))
  1447.         XP_FREE(temp);    /* If the conversion do use the same buffer, free the origional one */
  1448.     else 
  1449.         conv = temp;
  1450.     intl_strip_leading_and_trial_iso_2022_esc(conv);
  1451.     
  1452.     /* Do XPAT escape */
  1453.     xpat_escape = intl_xpat_escape(conv);
  1454.     if(NULL != conv)
  1455.         XP_FREE(conv);
  1456.     return (unsigned char*) xpat_escape;
  1457. }
  1458.  
  1459. #if 0
  1460.  
  1461. PUBLIC unsigned char* INTL_FormatNNTPXPATInRFC1522Format(int16 wincsid, unsigned char* searchString)
  1462. {
  1463.     /* Temp Implementation untill we really support it : Just make a duplication. */
  1464.     char* result = NULL;
  1465.     StrAllocCopy(result, (char*) searchString);
  1466.     XP_ASSERT(result);    /* Should only come here if Memory Not Enough */
  1467.     return (unsigned char*) result;
  1468. }
  1469.  
  1470. #endif
  1471.  
  1472. #endif  /* MOZ_MAIL_NEWS */
  1473.