1 21 22 27 28 package javax.mail.internet; 29 30 import javax.mail.*; 31 import javax.activation.*; 32 import java.util.*; 33 import java.io.*; 34 import com.sun.mail.util.LineOutputStream; 35 import com.sun.mail.util.LineInputStream; 36 import com.sun.mail.util.ASCIIUtility; 37 38 86 87 public class MimeMultipart extends Multipart { 88 89 private static boolean ignoreMissingEndBoundary = true; 90 private static boolean ignoreMissingBoundaryParameter = true; 91 private static boolean bmparse = true; 92 93 static { 94 try { 95 String s = System.getProperty( 96 "mail.mime.multipart.ignoremissingendboundary"); 97 ignoreMissingEndBoundary = 99 s == null || !s.equalsIgnoreCase("false"); 100 s = System.getProperty( 101 "mail.mime.multipart.ignoremissingboundaryparameter"); 102 ignoreMissingBoundaryParameter = 104 s == null || !s.equalsIgnoreCase("false"); 105 s = System.getProperty( 106 "mail.mime.multipart.bmparse"); 107 bmparse = s == null || !s.equalsIgnoreCase("false"); 109 } catch (SecurityException sex) { 110 } 112 } 113 114 117 protected DataSource ds = null; 118 119 125 protected boolean parsed = true; 126 127 130 private boolean complete = true; 131 132 136 private String preamble = null; 137 138 147 public MimeMultipart() { 148 this("mixed"); 149 } 150 151 159 public MimeMultipart(String subtype) { 160 super(); 161 164 String boundary = UniqueValue.getUniqueBoundaryValue(); 165 ContentType cType = new ContentType ("multipart", subtype, null); 166 cType.setParameter("boundary", boundary); 167 contentType = cType.toString(); 168 } 169 170 188 public MimeMultipart(DataSource ds) throws MessagingException { 189 super(); 190 191 if (ds instanceof MessageAware) { 192 MessageContext mc = ((MessageAware)ds).getMessageContext(); 193 setParent(mc.getPart()); 194 } 195 196 if (ds instanceof MultipartDataSource) { 197 setMultipartDataSource((MultipartDataSource)ds); 199 return; 200 } 201 202 parsed = false; 205 this.ds = ds; 206 contentType = ds.getContentType(); 207 } 208 209 216 public synchronized void setSubType(String subtype) 217 throws MessagingException { 218 ContentType cType = new ContentType (contentType); 219 cType.setSubType(subtype); 220 contentType = cType.toString(); 221 } 222 223 228 public synchronized int getCount() throws MessagingException { 229 parse(); 230 return super.getCount(); 231 } 232 233 240 public synchronized BodyPart getBodyPart(int index) 241 throws MessagingException { 242 parse(); 243 return super.getBodyPart(index); 244 } 245 246 253 public synchronized BodyPart getBodyPart(String CID) 254 throws MessagingException { 255 parse(); 256 257 int count = getCount(); 258 for (int i = 0; i < count; i++) { 259 MimeBodyPart part = (MimeBodyPart )getBodyPart(i); 260 String s = part.getContentID(); 261 if (s != null && s.equals(CID)) 262 return part; 263 } 264 return null; 265 } 266 267 281 public boolean isComplete() throws MessagingException { 282 parse(); 283 return complete; 284 } 285 286 294 public String getPreamble() throws MessagingException { 295 parse(); 296 return preamble; 297 } 298 299 310 public void setPreamble(String preamble) throws MessagingException { 311 this.preamble = preamble; 312 } 313 314 331 protected void updateHeaders() throws MessagingException { 332 for (int i = 0; i < parts.size(); i++) 333 ((MimeBodyPart )parts.elementAt(i)).updateHeaders(); 334 } 335 336 340 public void writeTo(OutputStream os) 341 throws IOException, MessagingException { 342 parse(); 343 344 String boundary = "--" + 345 (new ContentType (contentType)).getParameter("boundary"); 346 LineOutputStream los = new LineOutputStream(os); 347 348 if (preamble != null) { 350 byte[] pb = ASCIIUtility.getBytes(preamble); 351 los.write(pb); 352 if (pb.length > 0 && 354 !(pb[pb.length-1] == '\r' || pb[pb.length-1] == '\n')) { 355 los.writeln(); 356 } 357 } 359 for (int i = 0; i < parts.size(); i++) { 360 los.writeln(boundary); ((MimeBodyPart )parts.elementAt(i)).writeTo(os); 362 los.writeln(); } 364 365 los.writeln(boundary + "--"); 367 } 368 369 378 protected synchronized void parse() throws MessagingException { 379 if (parsed) 380 return; 381 382 if (bmparse) { 383 parsebm(); 384 return; 385 } 386 387 InputStream in = null; 388 SharedInputStream sin = null; 389 long start = 0, end = 0; 390 391 try { 392 in = ds.getInputStream(); 393 if (!(in instanceof ByteArrayInputStream) && 394 !(in instanceof BufferedInputStream) && 395 !(in instanceof SharedInputStream )) 396 in = new BufferedInputStream(in); 397 } catch (Exception ex) { 398 throw new MessagingException("No inputstream from datasource"); 399 } 400 if (in instanceof SharedInputStream ) 401 sin = (SharedInputStream )in; 402 403 ContentType cType = new ContentType (contentType); 404 String boundary = null; 405 String bp = cType.getParameter("boundary"); 406 if (bp != null) 407 boundary = "--" + bp; 408 else if (!ignoreMissingBoundaryParameter) 409 throw new MessagingException("Missing boundary parameter"); 410 411 try { 412 LineInputStream lin = new LineInputStream(in); 414 String line; 415 String lineSeparator = null; 416 while ((line = lin.readLine()) != null) { 417 423 int i; 424 for (i = line.length() - 1; i >= 0; i--) { 425 char c = line.charAt(i); 426 if (!(c == ' ' || c == '\t')) 427 break; 428 } 429 line = line.substring(0, i + 1); 430 if (boundary != null) { 431 if (line.equals(boundary)) 432 break; 433 } else { 434 439 if (line.startsWith("--")) { 440 boundary = line; 441 break; 442 } 443 } 444 445 if (line.length() > 0) { 447 if (lineSeparator == null) { 450 try { 451 lineSeparator = 452 System.getProperty("line.separator", "\n"); 453 } catch (SecurityException ex) { 454 lineSeparator = "\n"; 455 } 456 } 457 if (preamble == null) 459 preamble = line + lineSeparator; 460 else 461 preamble += line + lineSeparator; 462 } 463 } 464 if (line == null) 465 throw new MessagingException("Missing start boundary"); 466 467 byte[] bndbytes = ASCIIUtility.getBytes(boundary); 469 int bl = bndbytes.length; 470 471 475 boolean done = false; 476 getparts: 477 while (!done) { 478 InternetHeaders headers = null; 479 if (sin != null) { 480 start = sin.getPosition(); 481 while ((line = lin.readLine()) != null && line.length() > 0) 483 ; 484 if (line == null) { 485 if (!ignoreMissingEndBoundary) 486 throw new MessagingException( 487 "missing multipart end boundary"); 488 complete = false; 490 break getparts; 491 } 492 } else { 493 headers = createInternetHeaders(in); 495 } 496 497 if (!in.markSupported()) 498 throw new MessagingException("Stream doesn't support mark"); 499 500 ByteArrayOutputStream buf = null; 501 if (sin == null) 503 buf = new ByteArrayOutputStream(); 504 else 505 end = sin.getPosition(); 506 int b; 507 boolean bol = true; int eol1 = -1, eol2 = -1; 510 511 514 for (;;) { 515 if (bol) { 516 520 int i; 521 in.mark(bl + 4 + 1000); for (i = 0; i < bl; i++) 524 if (in.read() != (bndbytes[i] & 0xff)) 525 break; 526 if (i == bl) { 527 int b2 = in.read(); 529 if (b2 == '-') { 530 if (in.read() == '-') { 531 complete = true; 532 done = true; 533 break; } 535 } 536 while (b2 == ' ' || b2 == '\t') 538 b2 = in.read(); 539 if (b2 == '\n') 541 break; if (b2 == '\r') { 543 in.mark(1); 544 if (in.read() != '\n') 545 in.reset(); 546 break; } 548 } 549 in.reset(); 551 552 if (buf != null && eol1 != -1) { 555 buf.write(eol1); 556 if (eol2 != -1) 557 buf.write(eol2); 558 eol1 = eol2 = -1; 559 } 560 } 561 562 if ((b = in.read()) < 0) { 564 if (!ignoreMissingEndBoundary) 565 throw new MessagingException( 566 "missing multipart end boundary"); 567 complete = false; 568 done = true; 569 break; 570 } 571 572 576 if (b == '\r' || b == '\n') { 577 bol = true; 578 if (sin != null) 579 end = sin.getPosition() - 1; 580 eol1 = b; 581 if (b == '\r') { 582 in.mark(1); 583 if ((b = in.read()) == '\n') 584 eol2 = b; 585 else 586 in.reset(); 587 } 588 } else { 589 bol = false; 590 if (buf != null) 591 buf.write(b); 592 } 593 } 594 595 598 MimeBodyPart part; 599 if (sin != null) 600 part = createMimeBodyPart(sin.newStream(start, end)); 601 else 602 part = createMimeBodyPart(headers, buf.toByteArray()); 603 addBodyPart(part); 604 } 605 } catch (IOException ioex) { 606 throw new MessagingException("IO Error", ioex); 607 } finally { 608 try { 609 in.close(); 610 } catch (IOException cex) { 611 } 613 } 614 615 parsed = true; 616 } 617 618 627 631 private synchronized void parsebm() throws MessagingException { 632 if (parsed) 633 return; 634 635 InputStream in = null; 636 SharedInputStream sin = null; 637 long start = 0, end = 0; 638 639 try { 640 in = ds.getInputStream(); 641 if (!(in instanceof ByteArrayInputStream) && 642 !(in instanceof BufferedInputStream) && 643 !(in instanceof SharedInputStream )) 644 in = new BufferedInputStream(in); 645 } catch (Exception ex) { 646 throw new MessagingException("No inputstream from datasource"); 647 } 648 if (in instanceof SharedInputStream ) 649 sin = (SharedInputStream )in; 650 651 ContentType cType = new ContentType (contentType); 652 String boundary = null; 653 String bp = cType.getParameter("boundary"); 654 if (bp != null) 655 boundary = "--" + bp; 656 else if (!ignoreMissingBoundaryParameter) 657 throw new MessagingException("Missing boundary parameter"); 658 659 try { 660 LineInputStream lin = new LineInputStream(in); 662 String line; 663 String lineSeparator = null; 664 while ((line = lin.readLine()) != null) { 665 671 int i; 672 for (i = line.length() - 1; i >= 0; i--) { 673 char c = line.charAt(i); 674 if (!(c == ' ' || c == '\t')) 675 break; 676 } 677 line = line.substring(0, i + 1); 678 if (boundary != null) { 679 if (line.equals(boundary)) 680 break; 681 } else { 682 687 if (line.startsWith("--")) { 688 boundary = line; 689 break; 690 } 691 } 692 693 if (line.length() > 0) { 695 if (lineSeparator == null) { 698 try { 699 lineSeparator = 700 System.getProperty("line.separator", "\n"); 701 } catch (SecurityException ex) { 702 lineSeparator = "\n"; 703 } 704 } 705 if (preamble == null) 707 preamble = line + lineSeparator; 708 else 709 preamble += line + lineSeparator; 710 } 711 } 712 if (line == null) 713 throw new MessagingException("Missing start boundary"); 714 715 byte[] bndbytes = ASCIIUtility.getBytes(boundary); 717 int bl = bndbytes.length; 718 719 722 723 int[] bcs = new int[256]; 725 for (int i = 0; i < bl; i++) 726 bcs[bndbytes[i]] = i + 1; 727 728 int[] gss = new int[bl]; 730 NEXT: 731 for (int i = bl; i > 0; i--) { 732 int j; for (j = bl - 1; j >= i; j--) { 734 if (bndbytes[j] == bndbytes[j - i]) { 736 gss[j - 1] = i; 738 } else { 739 continue NEXT; 742 } 743 } 744 while (j > 0) 745 gss[--j] = i; 746 } 747 gss[bl - 1] = 1; 748 749 753 boolean done = false; 754 getparts: 755 while (!done) { 756 InternetHeaders headers = null; 757 if (sin != null) { 758 start = sin.getPosition(); 759 while ((line = lin.readLine()) != null && line.length() > 0) 761 ; 762 if (line == null) { 763 if (!ignoreMissingEndBoundary) 764 throw new MessagingException( 765 "missing multipart end boundary"); 766 complete = false; 768 break getparts; 769 } 770 } else { 771 headers = createInternetHeaders(in); 773 } 774 775 if (!in.markSupported()) 776 throw new MessagingException("Stream doesn't support mark"); 777 778 ByteArrayOutputStream buf = null; 779 if (sin == null) 781 buf = new ByteArrayOutputStream(); 782 else 783 end = sin.getPosition(); 784 int b; 785 786 793 byte[] inbuf = new byte[bl]; 796 byte[] previnbuf = new byte[bl]; 797 int inSize = 0; int prevSize = 0; int eolLen; 800 boolean first = true; 801 802 805 for (;;) { 806 in.mark(bl + 4 + 1000); eolLen = 0; 808 inSize = in.read(inbuf, 0, bl); 809 if (inSize < bl) { 810 if (!ignoreMissingEndBoundary) 812 throw new MessagingException( 813 "missing multipart end boundary"); 814 if (sin != null) 815 end = sin.getPosition(); 816 complete = false; 817 done = true; 818 break; 819 } 820 int i; 822 for (i = bl - 1; i >= 0; i--) { 823 if (inbuf[i] != bndbytes[i]) 824 break; 825 } 826 if (i < 0) { eolLen = 0; 828 if (!first) { 829 b = previnbuf[prevSize - 1]; 832 if (b == '\r' || b == '\n') { 833 eolLen = 1; 834 if (b == '\n' && prevSize >= 2) { 835 b = previnbuf[prevSize - 2]; 836 if (b == '\r') 837 eolLen = 2; 838 } 839 } 840 } 841 if (first || eolLen > 0) { if (sin != null) { 843 end = sin.getPosition() - bl - eolLen; 846 } 847 int b2 = in.read(); 849 if (b2 == '-') { 850 if (in.read() == '-') { 851 complete = true; 852 done = true; 853 break; } 855 } 856 while (b2 == ' ' || b2 == '\t') 858 b2 = in.read(); 859 if (b2 == '\n') 861 break; if (b2 == '\r') { 863 in.mark(1); 864 if (in.read() != '\n') 865 in.reset(); 866 break; } 868 } 869 i = 0; 870 } 871 872 877 878 int skip = Math.max(i + 1 - bcs[inbuf[i] & 0x7f], gss[i]); 880 if (skip < 2) { 882 if (sin == null && prevSize > 1) 886 buf.write(previnbuf, 0, prevSize - 1); 887 in.reset(); 888 in.skip(1); 889 if (prevSize >= 1) { previnbuf[0] = previnbuf[prevSize - 1]; 892 previnbuf[1] = inbuf[0]; 893 prevSize = 2; 894 } else { 895 previnbuf[0] = inbuf[0]; 897 prevSize = 1; 898 } 899 } else { 900 if (prevSize > 0 && sin == null) 903 buf.write(previnbuf, 0, prevSize); 904 prevSize = skip; 906 in.reset(); 907 in.skip(prevSize); 908 byte[] tmp = inbuf; 910 inbuf = previnbuf; 911 previnbuf = tmp; 912 } 913 first = false; 914 } 915 916 919 MimeBodyPart part; 920 if (sin != null) { 921 part = createMimeBodyPart(sin.newStream(start, end)); 922 } else { 923 if (prevSize - eolLen > 0) 925 buf.write(previnbuf, 0, prevSize - eolLen); 926 if (!complete && inSize > 0) 929 buf.write(inbuf, 0, inSize); 930 part = createMimeBodyPart(headers, buf.toByteArray()); 931 } 932 addBodyPart(part); 933 } 934 } catch (IOException ioex) { 935 throw new MessagingException("IO Error", ioex); 936 } finally { 937 try { 938 in.close(); 939 } catch (IOException cex) { 940 } 942 } 943 944 parsed = true; 945 } 946 947 958 protected InternetHeaders createInternetHeaders(InputStream is) 959 throws MessagingException { 960 return new InternetHeaders (is); 961 } 962 963 975 protected MimeBodyPart createMimeBodyPart(InternetHeaders headers, 976 byte[] content) throws MessagingException { 977 return new MimeBodyPart (headers, content); 978 } 979 980 991 protected MimeBodyPart createMimeBodyPart(InputStream is) 992 throws MessagingException { 993 return new MimeBodyPart (is); 994 } 995 } 996
| Popular Tags
|