/** * Encodes header as quoted-printable * * Encode a string according to RFC 1522 for use in headers if it * contains 8-bit characters or anything that looks like it should * be encoded. */ function encodeHeader($string) { global $default_charset, $languages, $squirrelmail_language; if (isset($languages[$squirrelmail_language]['XTRA_CODE']) && function_exists($languages[$squirrelmail_language]['XTRA_CODE'])) { return $languages[$squirrelmail_language]['XTRA_CODE']('encodeheader', $string); } // Use B encoding for multibyte charsets $mb_charsets = array('utf-8', 'big5', 'gb2313', 'euc-kr'); if (in_array($default_charset, $mb_charsets) && in_array($default_charset, sq_mb_list_encodings()) && sq_is8bit($string)) { return encodeHeaderBase64($string, $default_charset); } elseif (in_array($default_charset, $mb_charsets) && sq_is8bit($string) && !in_array($default_charset, sq_mb_list_encodings())) { // Add E_USER_NOTICE error here (can cause 'Cannot add header information' warning in compose.php) // trigger_error('encodeHeader: Multibyte character set unsupported by mbstring extension.',E_USER_NOTICE); } // Encode only if the string contains 8-bit characters or =? $j = strlen($string); $max_l = 75 - strlen($default_charset) - 7; $aRet = array(); $ret = ''; $iEncStart = $enc_init = false; $cur_l = $iOffset = 0; for ($i = 0; $i < $j; ++$i) { switch ($string[$i]) { case '=': case '<': case '>': case ',': case '?': case '_': if ($iEncStart === false) { $iEncStart = $i; } $cur_l += 3; if ($cur_l > $max_l - 2) { /* if there is an stringpart that doesn't need encoding, add it */ $aRet[] = substr($string, $iOffset, $iEncStart - $iOffset); $aRet[] = "=?{$default_charset}?Q?{$ret}?="; $iOffset = $i; $cur_l = 0; $ret = ''; $iEncStart = false; } else { $ret .= sprintf("=%02X", ord($string[$i])); } break; case '(': case ')': if ($iEncStart !== false) { $aRet[] = substr($string, $iOffset, $iEncStart - $iOffset); $aRet[] = "=?{$default_charset}?Q?{$ret}?="; $iOffset = $i; $cur_l = 0; $ret = ''; $iEncStart = false; } break; case ' ': if ($iEncStart !== false) { $cur_l++; if ($cur_l > $max_l) { $aRet[] = substr($string, $iOffset, $iEncStart - $iOffset); $aRet[] = "=?{$default_charset}?Q?{$ret}?="; $iOffset = $i; $cur_l = 0; $ret = ''; $iEncStart = false; } else { $ret .= '_'; } } break; default: $k = ord($string[$i]); if ($k > 126) { if ($iEncStart === false) { // do not start encoding in the middle of a string, also take the rest of the word. $sLeadString = substr($string, 0, $i); $aLeadString = explode(' ', $sLeadString); $sToBeEncoded = array_pop($aLeadString); $iEncStart = $i - strlen($sToBeEncoded); $ret .= $sToBeEncoded; $cur_l += strlen($sToBeEncoded); } $cur_l += 3; /* first we add the encoded string that reached it's max size */ if ($cur_l > $max_l - 2) { $aRet[] = substr($string, $iOffset, $iEncStart - $iOffset); $aRet[] = "=?{$default_charset}?Q?{$ret}?= "; /* the next part is also encoded => separate by space */ $cur_l = 3; $ret = ''; $iOffset = $i; $iEncStart = $i; } $enc_init = true; $ret .= sprintf("=%02X", $k); } else { if ($iEncStart !== false) { $cur_l++; if ($cur_l > $max_l) { $aRet[] = substr($string, $iOffset, $iEncStart - $iOffset); $aRet[] = "=?{$default_charset}?Q?{$ret}?="; $iEncStart = false; $iOffset = $i; $cur_l = 0; $ret = ''; } else { $ret .= $string[$i]; } } } break; } } if ($enc_init) { if ($iEncStart !== false) { $aRet[] = substr($string, $iOffset, $iEncStart - $iOffset); $aRet[] = "=?{$default_charset}?Q?{$ret}?="; } else { $aRet[] = substr($string, $iOffset); } $string = implode('', $aRet); } return $string; }
/** * Japanese charset extra function */ function japanese_charset_xtra() { $ret = func_get_arg(1); /* default return value */ if (function_exists('mb_detect_encoding')) { switch (func_get_arg(0)) { /* action */ case 'decode': $detect_encoding = @mb_detect_encoding($ret); if ($detect_encoding == 'JIS' || $detect_encoding == 'EUC-JP' || $detect_encoding == 'SJIS' || $detect_encoding == 'UTF-8') { $ret = mb_convert_kana(mb_convert_encoding($ret, 'EUC-JP', 'AUTO'), "KV"); } break; case 'encode': $detect_encoding = @mb_detect_encoding($ret); if ($detect_encoding == 'JIS' || $detect_encoding == 'EUC-JP' || $detect_encoding == 'SJIS' || $detect_encoding == 'UTF-8') { $ret = mb_convert_encoding(mb_convert_kana($ret, "KV"), 'JIS', 'AUTO'); } break; case 'strimwidth': $width = func_get_arg(2); $ret = mb_strimwidth($ret, 0, $width, '...'); break; case 'encodeheader': /** * First argument ($ret) contains header string. * SquirrelMail ja_JP translation uses euc-jp as internal encoding. * euc-jp stores Japanese letters in 0xA1-0xFE block (source: * JIS X 0208 unicode.org mapping. see euc_jp.php in extra decoding * library). Standard SquirrelMail 8bit test should detect if text * is in euc or in ascii. */ if (sq_is8bit($ret)) { /** * Minimize dependency on mb_mime_encodeheader(). PHP 4.4.1 bug * and maybe other bugs. * * Convert text from euc-jp (internal encoding) to iso-2022-jp * (commonly used Japanese encoding) with mbstring functions. * * Use SquirrelMail internal B encoding function. 'encodeheader' * XTRA_CODE is executed in encodeHeader() function, so * functions/mime.php (encodeHeaderBase64) and functions/strings.php * (sq_is8bit) are already loaded. */ $ret = encodeHeaderBase64(mb_convert_encoding($ret, 'ISO-2022-JP', 'EUC-JP'), 'iso-2022-jp'); } /** * if text is in ascii, we leave it unchanged. If some ASCII * chars must be encoded, add code here in else statement. */ break; case 'decodeheader': $ret = str_replace("\t", "", $ret); if (eregi('=\\?([^?]+)\\?(q|b)\\?([^?]+)\\?=', $ret)) { $ret = @mb_decode_mimeheader($ret); } $ret = @mb_convert_encoding($ret, 'EUC-JP', 'AUTO'); break; case 'downloadfilename': $useragent = func_get_arg(2); if (strstr($useragent, 'Windows') !== false || strstr($useragent, 'Mac_') !== false) { $ret = mb_convert_encoding($ret, 'SJIS', 'AUTO'); } else { $ret = mb_convert_encoding($ret, 'EUC-JP', 'AUTO'); } break; case 'wordwrap': $no_begin = "!%),.:;?]}¡ñ¡ë¡" . "Ç¡É¢ó¡ì¡í¡î¡¢¡£¡¹" . "¡Ó¡Õ¡×¡Ù¡Û¡Í¤¡¤£¤" . "¥¤§¤©¤Ã¤ã¤å¤ç¤î¡«" . "¡¬¡µ¡¶¥¡¥£¥¥¥§¥©¥" . "Ã¥ã¥å¥ç¥î¥õ¥ö¡¦¡¼" . "¡³¡´¡ª¡ó¡Ë¡¤¡¥¡§¡" . "¨¡©¡Ï¡Ñ"; $no_end = "\\\$([{¡ò\\¡Æ¡È¡Ò¡" . "Ô¡Ö¡Ø¡Ú¡Ì¡ð¡Ê¡Î¡Ð¡ï"; $wrap = func_get_arg(2); if (strlen($ret) >= $wrap && substr($ret, 0, 1) != '>' && strpos($ret, 'http://') === FALSE && strpos($ret, 'https://') === FALSE && strpos($ret, 'ftp://') === FALSE) { $ret = mb_convert_kana($ret, "KV"); $line_new = ''; $ptr = 0; while ($ptr < strlen($ret) - 1) { $l = mb_strcut($ret, $ptr, $wrap); $ptr += strlen($l); $tmp = $l; $l = mb_strcut($ret, $ptr, 2); while (strlen($l) != 0 && mb_strpos($no_begin, $l) !== FALSE) { $tmp .= $l; $ptr += strlen($l); $l = mb_strcut($ret, $ptr, 1); } $line_new .= $tmp; if ($ptr < strlen($ret) - 1) { $line_new .= "\n"; } } $ret = $line_new; } break; case 'utf7-imap_encode': $ret = mb_convert_encoding($ret, 'UTF7-IMAP', 'EUC-JP'); break; case 'utf7-imap_decode': $ret = mb_convert_encoding($ret, 'EUC-JP', 'UTF7-IMAP'); break; } } return $ret; }