Changeset 3837 in subversion
- Timestamp:
- Jul 29, 2010 2:50:19 AM (3 years ago)
- Location:
- trunk/roundcubemail/program/lib/Mail
- Files:
-
- 2 edited
-
mime.php (modified) (4 diffs)
-
mimePart.php (modified) (10 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/roundcubemail/program/lib/Mail/mime.php
r3648 r3837 843 843 if (isset($this->_headers['From'])) { 844 844 // Bug #11381: Illegal characters in domain ID 845 if (preg_match( "|(@[0-9a-zA-Z\-\.]+)|", $this->_headers['From'], $matches)) {845 if (preg_match('#(@[0-9a-zA-Z\-\.]+)#', $this->_headers['From'], $matches)) { 846 846 $domainID = $matches[1]; 847 847 } else { 848 $domainID = "@localhost";848 $domainID = '@localhost'; 849 849 } 850 850 foreach ($this->_html_images as $i => $img) { 851 $cid = $this->_html_images[$i]['cid']; 851 $cid = $this->_html_images[$i]['cid']; 852 852 if (!preg_match('#'.preg_quote($domainID).'$#', $cid)) { 853 853 $this->_html_images[$i]['cid'] = $cid . $domainID; … … 996 996 return $ret; 997 997 } 998 998 999 999 // Use saved boundary 1000 1000 if (!empty($this->_build_params['boundary'])) { … … 1156 1156 if (preg_match('/^multipart\//i', $type)) { 1157 1157 if (empty($this->_build_params['boundary'])) { 1158 $this->_build_params['boundary'] = '=_' . md5(rand() . microtime()); 1158 $this->_build_params['boundary'] = '=_' . md5(rand() . microtime()); 1159 1159 } 1160 1160 … … 1189 1189 { 1190 1190 $this->_headers['From'] = $email; 1191 } 1192 1193 /** 1194 * Add an email to the To header 1195 * (multiple calls to this method are allowed) 1196 * 1197 * @param string $email The email direction to add 1198 * 1199 * @return void 1200 * @access public 1201 */ 1202 function addTo($email) 1203 { 1204 if (isset($this->_headers['To'])) { 1205 $this->_headers['To'] .= ", $email"; 1206 } else { 1207 $this->_headers['To'] = $email; 1208 } 1191 1209 } 1192 1210 -
trunk/roundcubemail/program/lib/Mail/mimePart.php
r3402 r3837 216 216 } 217 217 218 // Default content-type 219 if (empty($c_type['type'])) { 220 $c_type['type'] = 'text/plain'; 221 } 222 218 223 // Content-Type 219 if ( isset($c_type['type'])) {224 if (!empty($c_type['type'])) { 220 225 $headers['Content-Type'] = $c_type['type']; 221 if (isset($c_type['name'])) { 226 if (!empty($c_type['charset'])) { 227 $charset = "charset={$c_type['charset']}"; 228 // place charset parameter in the same line, if possible 229 if ((strlen($headers['Content-Type']) + strlen($charset) + 16) <= 76) { 230 $headers['Content-Type'] .= '; '; 231 } else { 232 $headers['Content-Type'] .= ';' . $this->_eol . ' '; 233 } 234 $headers['Content-Type'] .= $charset; 235 } 236 if (!empty($c_type['name'])) { 222 237 $headers['Content-Type'] .= ';' . $this->_eol; 223 238 $headers['Content-Type'] .= $this->_buildHeaderParam( 224 'name', $c_type['name'], 225 isset($c_type['charset']) ? $c_type['charset'] : 'US-ASCII', 239 'name', $c_type['name'], 240 isset($c_type['charset']) ? $c_type['charset'] : 'US-ASCII', 226 241 isset($c_type['language']) ? $c_type['language'] : null, 227 242 isset($params['name_encoding']) ? $params['name_encoding'] : null 228 243 ); 229 244 } 230 if (isset($c_type['charset'])) {231 $headers['Content-Type']232 .= ';' . $this->_eol . " charset={$c_type['charset']}";233 }234 245 } 235 246 236 247 // Content-Disposition 237 if ( isset($c_disp['disp'])) {248 if (!empty($c_disp['disp'])) { 238 249 $headers['Content-Disposition'] = $c_disp['disp']; 239 if ( isset($c_disp['filename'])) {250 if (!empty($c_disp['filename'])) { 240 251 $headers['Content-Disposition'] .= ';' . $this->_eol; 241 252 $headers['Content-Disposition'] .= $this->_buildHeaderParam( 242 'filename', $c_disp['filename'], 243 isset($c_disp['charset']) ? $c_disp['charset'] : 'US-ASCII', 253 'filename', $c_disp['filename'], 254 isset($c_disp['charset']) ? $c_disp['charset'] : 'US-ASCII', 244 255 isset($c_disp['language']) ? $c_disp['language'] : null, 245 256 isset($params['filename_encoding']) ? $params['filename_encoding'] : null … … 255 266 $this->_eol 256 267 ); 257 }258 259 // Default content-type260 if (!isset($headers['Content-Type'])) {261 $headers['Content-Type'] = 'text/plain';262 268 } 263 269 … … 961 967 function encodeHeaderValue($value, $charset, $encoding, $prefix_len=0, $eol="\r\n") 962 968 { 963 if ($encoding == 'base64') { 969 // #17311: Use multibyte aware method (requires mbstring extension) 970 if ($result = Mail_mimePart::encodeMB($value, $charset, $encoding, $prefix_len, $eol)) { 971 return $result; 972 } 973 974 // Generate the header using the specified params and dynamicly 975 // determine the maximum length of such strings. 976 // 75 is the value specified in the RFC. 977 $encoding = $encoding == 'base64' ? 'B' : 'Q'; 978 $prefix = '=?' . $charset . '?' . $encoding .'?'; 979 $suffix = '?='; 980 $maxLength = 75 - strlen($prefix . $suffix); 981 $maxLength1stLine = $maxLength - $prefix_len; 982 983 if ($encoding == 'B') { 964 984 // Base64 encode the entire string 965 985 $value = base64_encode($value); 966 986 967 // Generate the header using the specified params and dynamicly 968 // determine the maximum length of such strings. 969 // 75 is the value specified in the RFC. 970 $prefix = '=?' . $charset . '?B?'; 971 $suffix = '?='; 972 $maxLength = 75 - strlen($prefix . $suffix) - 2; 973 $maxLength1stLine = $maxLength - $prefix_len; 974 975 // We can cut base4 every 4 characters, so the real max 987 // We can cut base64 every 4 characters, so the real max 976 988 // we can get must be rounded down. 977 989 $maxLength = $maxLength - ($maxLength % 4); … … 979 991 980 992 $cutpoint = $maxLength1stLine; 981 $value_out = $value;982 993 $output = ''; 983 while ($value_out) { 994 995 while ($value) { 984 996 // Split translated string at every $maxLength 985 $part = substr($value _out, 0, $cutpoint);986 $value _out = substr($value_out, $cutpoint);997 $part = substr($value, 0, $cutpoint); 998 $value = substr($value, $cutpoint); 987 999 $cutpoint = $maxLength; 988 1000 // RFC 2047 specifies that any split header should 989 // be seperated by a CRLF SPACE. 1001 // be seperated by a CRLF SPACE. 990 1002 if ($output) { 991 1003 $output .= $eol . ' '; … … 998 1010 $value = Mail_mimePart::encodeQP($value); 999 1011 1000 // Generate the header using the specified params and dynamicly1001 // determine the maximum length of such strings.1002 // 75 is the value specified in the RFC.1003 $prefix = '=?' . $charset . '?Q?';1004 $suffix = '?=';1005 $maxLength = 75 - strlen($prefix . $suffix) - 3;1006 $maxLength1stLine = $maxLength - $prefix_len;1007 $maxLength = $maxLength - 1;1008 1009 1012 // This regexp will break QP-encoded text at every $maxLength 1010 1013 // but will not break any encoded letters. … … 1012 1015 $reg2nd = "|(.{0,$maxLength}[^\=][^\=])|"; 1013 1016 1014 $value_out = $value; 1015 $realMax = $maxLength1stLine + strlen($prefix . $suffix); 1016 if (strlen($value_out) >= $realMax) { 1017 if (strlen($value) > $maxLength1stLine) { 1017 1018 // Begin with the regexp for the first line. 1018 1019 $reg = $reg1st; 1019 1020 $output = ''; 1020 while ($value _out) {1021 while ($value) { 1021 1022 // Split translated string at every $maxLength 1022 1023 // But make sure not to break any translated chars. 1023 $found = preg_match($reg, $value _out, $matches);1024 $found = preg_match($reg, $value, $matches); 1024 1025 1025 1026 // After this first line, we need to use a different … … 1033 1034 $part = $matches[0]; 1034 1035 $len = strlen($matches[0]); 1035 $value _out = substr($value_out, $len);1036 $value = substr($value, $len); 1036 1037 } else { 1037 $part = $value _out;1038 $value _out = "";1038 $part = $value; 1039 $value = ''; 1039 1040 } 1040 1041 1041 // RFC 2047 specifies that any split header should 1042 // RFC 2047 specifies that any split header should 1042 1043 // be seperated by a CRLF SPACE 1043 1044 if ($output) { … … 1046 1047 $output .= $prefix . $part . $suffix; 1047 1048 } 1048 $value _out= $output;1049 $value = $output; 1049 1050 } else { 1050 $value_out = $prefix . $value_out . $suffix; 1051 } 1052 $value = $value_out; 1051 $value = $prefix . $value . $suffix; 1052 } 1053 1053 } 1054 1054 … … 1068 1068 { 1069 1069 // Bug #17226 RFC 2047 restricts some characters 1070 // if the word is inside a phrase, permit chars are only:1070 // if the word is inside a phrase, permitted chars are only: 1071 1071 // ASCII letters, decimal digits, "!", "*", "+", "-", "/", "=", and "_" 1072 1072 … … 1081 1081 1082 1082 /** 1083 * Encodes the given string using base64 or quoted-printable. 1084 * This method makes sure that encoded-word represents an integral 1085 * number of characters as per RFC2047. 1086 * 1087 * @param string $str String to encode 1088 * @param string $charset Character set name 1089 * @param string $encoding Encoding name (base64 or quoted-printable) 1090 * @param int $prefix_len Prefix length. Default: 0 1091 * @param string $eol End-of-line sequence. Default: "\r\n" 1092 * 1093 * @return string Encoded string 1094 * @access public 1095 * @since 1.8.0 1096 */ 1097 function encodeMB($str, $charset, $encoding, $prefix_len=0, $eol="\r\n") 1098 { 1099 if (!function_exists('mb_substr') || !function_exists('mb_strlen')) { 1100 return; 1101 } 1102 1103 $encoding = $encoding == 'base64' ? 'B' : 'Q'; 1104 // 75 is the value specified in the RFC 1105 $prefix = '=?' . $charset . '?'.$encoding.'?'; 1106 $suffix = '?='; 1107 $maxLength = 75 - strlen($prefix . $suffix); 1108 1109 // A multi-octet character may not be split across adjacent encoded-words 1110 // So, we'll loop over each character 1111 // mb_stlen() with wrong charset will generate a warning here and return null 1112 $length = mb_strlen($str, $charset); 1113 $result = ''; 1114 $line_length = $prefix_len; 1115 1116 if ($encoding == 'B') { 1117 // base64 1118 $start = 0; 1119 $prev = ''; 1120 1121 for ($i=1; $i<=$length; $i++) { 1122 // See #17311 1123 $chunk = mb_substr($str, $start, $i-$start, $charset); 1124 $chunk = base64_encode($chunk); 1125 $chunk_len = strlen($chunk); 1126 1127 if ($line_length + $chunk_len == $maxLength || $i == $length) { 1128 if ($result) { 1129 $result .= "\n"; 1130 } 1131 $result .= $chunk; 1132 $line_length = 0; 1133 $start = $i; 1134 } else if ($line_length + $chunk_len > $maxLength) { 1135 if ($result) { 1136 $result .= "\n"; 1137 } 1138 if ($prev) { 1139 $result .= $prev; 1140 } 1141 $line_length = 0; 1142 $start = $i - 1; 1143 } else { 1144 $prev = $chunk; 1145 } 1146 } 1147 } else { 1148 // quoted-printable 1149 // see encodeQP() 1150 $regexp = '/([\x22-\x29\x2C\x2E\x3A-\x40\x5B-\x60\x7B-\x7E\x80-\xFF])/'; 1151 1152 for ($i=0; $i<=$length; $i++) { 1153 $char = mb_substr($str, $i, 1, $charset); 1154 // RFC recommends underline (instead of =20) in place of the space 1155 // that's one of the reasons why we're not using iconv_mime_encode() 1156 if ($char == ' ') { 1157 $char = '_'; 1158 $char_len = 1; 1159 } else { 1160 $char = preg_replace_callback( 1161 $regexp, array('Mail_mimePart', '_qpReplaceCallback'), $char 1162 ); 1163 $char_len = strlen($char); 1164 } 1165 1166 if ($line_length + $char_len > $maxLength) { 1167 if ($result) { 1168 $result .= "\n"; 1169 } 1170 $line_length = 0; 1171 } 1172 1173 $result .= $char; 1174 $line_length += $char_len; 1175 } 1176 } 1177 1178 if ($result) { 1179 $result = $prefix 1180 .str_replace("\n", $suffix.$eol.' '.$prefix, $result).$suffix; 1181 } 1182 1183 return $result; 1184 } 1185 1186 /** 1083 1187 * Callback function to replace extended characters (\x80-xFF) with their 1084 1188 * ASCII values (RFC2047: quoted-printable)
Note: See TracChangeset
for help on using the changeset viewer.
