| 1 21 22 27 28 package javax.mail.internet; 29 30 import javax.mail.MessagingException ; 31 import javax.activation.*; 32 import java.util.*; 33 import java.io.*; 34 import com.sun.mail.util.*; 35 36 114 115 public class MimeUtility { 116 117 private MimeUtility() { } 119 120 public static final int ALL = -1; 121 122 private static boolean decodeStrict = true; 123 private static boolean encodeEolStrict = false; 124 private static boolean foldEncodedWords = false; 125 private static boolean foldText = true; 126 127 static { 128 try { 129 String s = System.getProperty("mail.mime.decodetext.strict"); 130 decodeStrict = s == null || !s.equalsIgnoreCase("false"); 132 s = System.getProperty("mail.mime.encodeeol.strict"); 133 encodeEolStrict = s != null && s.equalsIgnoreCase("true"); 135 s = System.getProperty("mail.mime.foldencodedwords"); 136 foldEncodedWords = s != null && s.equalsIgnoreCase("true"); 138 s = System.getProperty("mail.mime.foldtext"); 139 foldText = s == null || !s.equalsIgnoreCase("false"); 141 } catch (SecurityException sex) { 142 } 144 } 145 146 147 170 public static String getEncoding(DataSource ds) { 171 ContentType cType = null; 172 InputStream is = null; 173 String encoding = null; 174 175 try { 176 cType = new ContentType (ds.getContentType()); 177 is = ds.getInputStream(); 178 } catch (Exception ex) { 179 return "base64"; } 181 182 boolean isText = cType.match("text/*"); 183 int i = checkAscii(is, ALL, !isText); 185 switch (i) { 186 case ALL_ASCII: 187 encoding = "7bit"; break; 189 case MOSTLY_ASCII: 190 encoding = "quoted-printable"; break; 192 default: 193 encoding = "base64"; break; 195 } 196 197 try { 199 is.close(); 200 } catch (IOException ioex) { } 201 202 return encoding; 203 } 204 205 218 public static String getEncoding(DataHandler dh) { 219 ContentType cType = null; 220 String encoding = null; 221 222 235 if (dh.getName() != null) 236 return getEncoding(dh.getDataSource()); 237 238 try { 239 cType = new ContentType (dh.getContentType()); 240 } catch (Exception ex) { 241 return "base64"; } 243 244 if (cType.match("text/*")) { 245 AsciiOutputStream aos = new AsciiOutputStream(false, false); 247 try { 248 dh.writeTo(aos); 249 } catch (IOException ex) { } switch (aos.getAscii()) { 251 case ALL_ASCII: 252 encoding = "7bit"; break; 254 case MOSTLY_ASCII: 255 encoding = "quoted-printable"; break; 257 default: 258 encoding = "base64"; break; 260 } 261 } else { AsciiOutputStream aos = 265 new AsciiOutputStream(true, encodeEolStrict); 266 try { 267 dh.writeTo(aos); 268 } catch (IOException ex) { } if (aos.getAscii() == ALL_ASCII) encoding = "7bit"; 271 else encoding = "base64"; 273 } 274 275 return encoding; 276 } 277 278 289 public static InputStream decode(InputStream is, String encoding) 290 throws MessagingException { 291 if (encoding.equalsIgnoreCase("base64")) 292 return new BASE64DecoderStream(is); 293 else if (encoding.equalsIgnoreCase("quoted-printable")) 294 return new QPDecoderStream(is); 295 else if (encoding.equalsIgnoreCase("uuencode") || 296 encoding.equalsIgnoreCase("x-uuencode") || 297 encoding.equalsIgnoreCase("x-uue")) 298 return new UUDecoderStream(is); 299 else if (encoding.equalsIgnoreCase("binary") || 300 encoding.equalsIgnoreCase("7bit") || 301 encoding.equalsIgnoreCase("8bit")) 302 return is; 303 else 304 throw new MessagingException ("Unknown encoding: " + encoding); 305 } 306 307 318 public static OutputStream encode(OutputStream os, String encoding) 319 throws MessagingException { 320 if (encoding == null) 321 return os; 322 else if (encoding.equalsIgnoreCase("base64")) 323 return new BASE64EncoderStream(os); 324 else if (encoding.equalsIgnoreCase("quoted-printable")) 325 return new QPEncoderStream(os); 326 else if (encoding.equalsIgnoreCase("uuencode") || 327 encoding.equalsIgnoreCase("x-uuencode") || 328 encoding.equalsIgnoreCase("x-uue")) 329 return new UUEncoderStream(os); 330 else if (encoding.equalsIgnoreCase("binary") || 331 encoding.equalsIgnoreCase("7bit") || 332 encoding.equalsIgnoreCase("8bit")) 333 return os; 334 else 335 throw new MessagingException ("Unknown encoding: " +encoding); 336 } 337 338 354 public static OutputStream encode(OutputStream os, String encoding, 355 String filename) 356 throws MessagingException { 357 if (encoding == null) 358 return os; 359 else if (encoding.equalsIgnoreCase("base64")) 360 return new BASE64EncoderStream(os); 361 else if (encoding.equalsIgnoreCase("quoted-printable")) 362 return new QPEncoderStream(os); 363 else if (encoding.equalsIgnoreCase("uuencode") || 364 encoding.equalsIgnoreCase("x-uuencode") || 365 encoding.equalsIgnoreCase("x-uue")) 366 return new UUEncoderStream(os, filename); 367 else if (encoding.equalsIgnoreCase("binary") || 368 encoding.equalsIgnoreCase("7bit") || 369 encoding.equalsIgnoreCase("8bit")) 370 return os; 371 else 372 throw new MessagingException ("Unknown encoding: " +encoding); 373 } 374 375 411 public static String encodeText(String text) 412 throws UnsupportedEncodingException { 413 return encodeText(text, null, null); 414 } 415 416 441 public static String encodeText(String text, String charset, 442 String encoding) 443 throws UnsupportedEncodingException { 444 return encodeWord(text, charset, encoding, false); 445 } 446 447 479 public static String decodeText(String etext) 480 throws UnsupportedEncodingException { 481 486 String lwsp = " \t\n\r"; 487 StringTokenizer st; 488 489 498 if (etext.indexOf("=?") == -1) 499 return etext; 500 501 503 st = new StringTokenizer(etext, lwsp, true); 504 StringBuffer sb = new StringBuffer (); StringBuffer wsb = new StringBuffer (); boolean prevWasEncoded = false; 507 508 while (st.hasMoreTokens()) { 509 char c; 510 String s = st.nextToken(); 511 if (((c = s.charAt(0)) == ' ') || (c == '\t') || 513 (c == '\r') || (c == '\n')) 514 wsb.append(c); 515 else { 516 String word; 518 try { 519 word = decodeWord(s); 520 if (!prevWasEncoded && wsb.length() > 0) { 522 sb.append(wsb); 526 } 527 prevWasEncoded = true; 528 } catch (ParseException pex) { 529 word = s; 531 if (!decodeStrict) 533 word = decodeInnerWords(word); 534 if (wsb.length() > 0) 536 sb.append(wsb); 537 prevWasEncoded = false; 538 } 539 sb.append(word); wsb.setLength(0); } 542 } 543 return sb.toString(); 544 } 545 546 567 public static String encodeWord(String word) 568 throws UnsupportedEncodingException { 569 return encodeWord(word, null, null); 570 } 571 572 594 public static String encodeWord(String word, String charset, 595 String encoding) 596 throws UnsupportedEncodingException { 597 return encodeWord(word, charset, encoding, true); 598 } 599 600 607 private static String encodeWord(String string, String charset, 608 String encoding, boolean encodingWord) 609 throws UnsupportedEncodingException { 610 611 int ascii = checkAscii(string); 614 if (ascii == ALL_ASCII) 615 return string; 616 617 String jcharset; 619 if (charset == null) { jcharset = getDefaultJavaCharset(); charset = getDefaultMIMECharset(); } else jcharset = javaCharset(charset); 624 625 if (encoding == null) { 627 if (ascii != MOSTLY_NONASCII) 628 encoding = "Q"; 629 else 630 encoding = "B"; 631 } 632 633 boolean b64; 634 if (encoding.equalsIgnoreCase("B")) 635 b64 = true; 636 else if (encoding.equalsIgnoreCase("Q")) 637 b64 = false; 638 else 639 throw new UnsupportedEncodingException( 640 "Unknown transfer encoding: " + encoding); 641 642 StringBuffer outb = new StringBuffer (); doEncode(string, b64, jcharset, 644 75 - 7 - charset.length(), "=?" + charset + "?" + encoding + "?", true, encodingWord, outb); 650 651 return outb.toString(); 652 } 653 654 private static void doEncode(String string, boolean b64, 655 String jcharset, int avail, String prefix, 656 boolean first, boolean encodingWord, StringBuffer buf) 657 throws UnsupportedEncodingException { 658 659 byte[] bytes = string.getBytes(jcharset); 662 int len; 663 if (b64) len = BEncoderStream.encodedLength(bytes); 665 else len = QEncoderStream.encodedLength(bytes, encodingWord); 667 668 int size; 669 if ((len > avail) && ((size = string.length()) > 1)) { 670 doEncode(string.substring(0, size/2), b64, jcharset, 673 avail, prefix, first, encodingWord, buf); 674 doEncode(string.substring(size/2, size), b64, jcharset, 675 avail, prefix, false, encodingWord, buf); 676 } else { 677 ByteArrayOutputStream os = new ByteArrayOutputStream(); 679 OutputStream eos; if (b64) eos = new BEncoderStream(os); 682 else eos = new QEncoderStream(os, encodingWord); 684 685 try { eos.write(bytes); 687 eos.close(); 688 } catch (IOException ioex) { } 689 690 byte[] encodedBytes = os.toByteArray(); if (!first) if (foldEncodedWords) 695 buf.append("\r\n "); else 697 buf.append(" "); 699 buf.append(prefix); 700 for (int i = 0; i < encodedBytes.length; i++) 701 buf.append((char)encodedBytes[i]); 702 buf.append("?="); } 704 } 705 706 719 public static String decodeWord(String eword) 720 throws ParseException , UnsupportedEncodingException { 721 722 if (!eword.startsWith("=?")) throw new ParseException (); 724 725 int start = 2; int pos; 727 if ((pos = eword.indexOf('?', start)) == -1) 728 throw new ParseException (); 729 String charset = javaCharset(eword.substring(start, pos)); 730 731 start = pos+1; 733 if ((pos = eword.indexOf('?', start)) == -1) 734 throw new ParseException (); 735 String encoding = eword.substring(start, pos); 736 737 start = pos+1; 739 if ((pos = eword.indexOf("?=", start)) == -1) 740 throw new ParseException (); 741 String word = eword.substring(start, pos); 742 743 try { 744 String decodedWord; 745 if (word.length() > 0) { 746 ByteArrayInputStream bis = 748 new ByteArrayInputStream(ASCIIUtility.getBytes(word)); 749 750 InputStream is; 752 if (encoding.equalsIgnoreCase("B")) 753 is = new BASE64DecoderStream(bis); 754 else if (encoding.equalsIgnoreCase("Q")) 755 is = new QDecoderStream(bis); 756 else 757 throw new UnsupportedEncodingException( 758 "unknown encoding: " + encoding); 759 760 int count = bis.available(); 766 byte[] bytes = new byte[count]; 767 count = is.read(bytes, 0, count); 769 770 decodedWord = count <= 0 ? "" : 773 new String (bytes, 0, count, charset); 774 } else { 775 decodedWord = ""; 777 } 778 if (pos + 2 < eword.length()) { 779 String rest = eword.substring(pos + 2); 781 if (!decodeStrict) 782 rest = decodeInnerWords(rest); 783 decodedWord += rest; 784 } 785 return decodedWord; 786 } catch (UnsupportedEncodingException uex) { 787 throw uex; 790 } catch (IOException ioex) { 791 throw new ParseException (); 793 } catch (IllegalArgumentException iex) { 794 801 throw new UnsupportedEncodingException(); 802 } 803 } 804 805 810 private static String decodeInnerWords(String word) 811 throws UnsupportedEncodingException { 812 int start = 0, i; 813 StringBuffer buf = new StringBuffer (); 814 while ((i = word.indexOf("=?", start)) >= 0) { 815 buf.append(word.substring(start, i)); 816 int end = word.indexOf("?=", i); 817 if (end < 0) 818 break; 819 String s = word.substring(i, end + 2); 820 try { 821 s = decodeWord(s); 822 } catch (ParseException pex) { 823 } 825 buf.append(s); 826 start = end + 2; 827 } 828 if (start == 0) 829 return word; 830 if (start < word.length()) 831 buf.append(word.substring(start)); 832 return buf.toString(); 833 } 834 835 851 public static String quote(String word, String specials) { 852 int len = word.length(); 853 854 858 boolean needQuoting = false; 859 for (int i = 0; i < len; i++) { 860 char c = word.charAt(i); 861 if (c == '"' || c == '\\' || c == '\r' || c == '\n') { 862 StringBuffer sb = new StringBuffer (len + 3); 864 sb.append('"'); 865 sb.append(word.substring(0, i)); 866 int lastc = 0; 867 for (int j = i; j < len; j++) { 868 char cc = word.charAt(j); 869 if ((cc == '"') || (cc == '\\') || 870 (cc == '\r') || (cc == '\n')) 871 if (cc == '\n' && lastc == '\r') 872 ; else 874 sb.append('\\'); sb.append(cc); 876 lastc = cc; 877 } 878 sb.append('"'); 879 return sb.toString(); 880 } else if (c < 040 || c >= 0177 || specials.indexOf(c) >= 0) 881 needQuoting = true; 883 } 884 885 if (needQuoting) { 886 StringBuffer sb = new StringBuffer (len + 2); 887 sb.append('"').append(word).append('"'); 888 return sb.toString(); 889 } else 890 return word; 891 } 892 893 |