Source Code Cross Referenced for MimeMultipart.java in  » EJB-Server-GlassFish » mail » javax » mail » internet » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » EJB Server GlassFish » mail » javax.mail.internet 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common Development
0008:         * and Distribution License("CDDL") (collectively, the "License").  You
0009:         * may not use this file except in compliance with the License. You can obtain
0010:         * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
0011:         * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
0012:         * language governing permissions and limitations under the License.
0013:         *
0014:         * When distributing the software, include this License Header Notice in each
0015:         * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
0016:         * Sun designates this particular file as subject to the "Classpath" exception
0017:         * as provided by Sun in the GPL Version 2 section of the License file that
0018:         * accompanied this code.  If applicable, add the following below the License
0019:         * Header, with the fields enclosed by brackets [] replaced by your own
0020:         * identifying information: "Portions Copyrighted [year]
0021:         * [name of copyright owner]"
0022:         *
0023:         * Contributor(s):
0024:         *
0025:         * If you wish your version of this file to be governed by only the CDDL or
0026:         * only the GPL Version 2, indicate your decision by adding "[Contributor]
0027:         * elects to include this software in this distribution under the [CDDL or GPL
0028:         * Version 2] license."  If you don't indicate a single choice of license, a
0029:         * recipient has the option to distribute your version of this file under
0030:         * either the CDDL, the GPL Version 2 or to extend the choice of license to
0031:         * its licensees as provided above.  However, if you add GPL Version 2 code
0032:         * and therefore, elected the GPL Version 2 license, then the option applies
0033:         * only if the new code is made subject to such option by the copyright
0034:         * holder.
0035:         */
0036:
0037:        /*
0038:         * @(#)MimeMultipart.java	1.48 07/05/15
0039:         */
0040:
0041:        package javax.mail.internet;
0042:
0043:        import javax.mail.*;
0044:        import javax.activation.*;
0045:        import java.util.*;
0046:        import java.io.*;
0047:        import com.sun.mail.util.LineOutputStream;
0048:        import com.sun.mail.util.LineInputStream;
0049:        import com.sun.mail.util.ASCIIUtility;
0050:
0051:        /**
0052:         * The MimeMultipart class is an implementation of the abstract Multipart
0053:         * class that uses MIME conventions for the multipart data. <p>
0054:         *
0055:         * A MimeMultipart is obtained from a MimePart whose primary type
0056:         * is "multipart" (by invoking the part's <code>getContent()</code> method)
0057:         * or it can be created by a client as part of creating a new MimeMessage. <p>
0058:         *
0059:         * The default multipart subtype is "mixed".  The other multipart
0060:         * subtypes, such as "alternative", "related", and so on, can be
0061:         * implemented as subclasses of MimeMultipart with additional methods
0062:         * to implement the additional semantics of that type of multipart
0063:         * content. The intent is that service providers, mail JavaBean writers
0064:         * and mail clients will write many such subclasses and their Command
0065:         * Beans, and will install them into the JavaBeans Activation
0066:         * Framework, so that any JavaMail implementation and its clients can
0067:         * transparently find and use these classes. Thus, a MIME multipart
0068:         * handler is treated just like any other type handler, thereby
0069:         * decoupling the process of providing multipart handlers from the
0070:         * JavaMail API. Lacking these additional MimeMultipart subclasses,
0071:         * all subtypes of MIME multipart data appear as MimeMultipart objects. <p>
0072:         *
0073:         * An application can directly construct a MIME multipart object of any
0074:         * subtype by using the <code>MimeMultipart(String subtype)</code>
0075:         * constructor.  For example, to create a "multipart/alternative" object,
0076:         * use <code>new MimeMultipart("alternative")</code>. <p>
0077:         *
0078:         * The <code>mail.mime.multipart.ignoremissingendboundary</code>
0079:         * property may be set to <code>false</code> to cause a
0080:         * <code>MessagingException</code> to be thrown if the multipart
0081:         * data does not end with the required end boundary line.  If this
0082:         * property is set to <code>true</code> or not set, missing end
0083:         * boundaries are not considered an error and the final body part
0084:         * ends at the end of the data. <p>
0085:         *
0086:         * The <code>mail.mime.multipart.ignoremissingboundaryparameter</code>
0087:         * System property may be set to <code>false</code> to cause a
0088:         * <code>MessagingException</code> to be thrown if the Content-Type
0089:         * of the MimeMultipart does not include a <code>boundary</code> parameter.
0090:         * If this property is set to <code>true</code> or not set, the multipart
0091:         * parsing code will look for a line that looks like a bounary line and
0092:         * use that as the boundary separating the parts.
0093:         *
0094:         * @version 1.48, 07/05/15
0095:         * @author  John Mani
0096:         * @author  Bill Shannon
0097:         * @author  Max Spivak
0098:         */
0099:
0100:        public class MimeMultipart extends Multipart {
0101:
0102:            private static boolean ignoreMissingEndBoundary = true;
0103:            private static boolean ignoreMissingBoundaryParameter = true;
0104:            private static boolean bmparse = true;
0105:
0106:            static {
0107:                try {
0108:                    String s = System
0109:                            .getProperty("mail.mime.multipart.ignoremissingendboundary");
0110:                    // default to true
0111:                    ignoreMissingEndBoundary = s == null
0112:                            || !s.equalsIgnoreCase("false");
0113:                    s = System
0114:                            .getProperty("mail.mime.multipart.ignoremissingboundaryparameter");
0115:                    // default to true
0116:                    ignoreMissingBoundaryParameter = s == null
0117:                            || !s.equalsIgnoreCase("false");
0118:                    s = System.getProperty("mail.mime.multipart.bmparse");
0119:                    // default to true
0120:                    bmparse = s == null || !s.equalsIgnoreCase("false");
0121:                } catch (SecurityException sex) {
0122:                    // ignore it
0123:                }
0124:            }
0125:
0126:            /**
0127:             * The DataSource supplying our InputStream.
0128:             */
0129:            protected DataSource ds = null;
0130:
0131:            /**
0132:             * Have we parsed the data from our InputStream yet?
0133:             * Defaults to true; set to false when our constructor is
0134:             * given a DataSource with an InputStream that we need to
0135:             * parse.
0136:             */
0137:            protected boolean parsed = true;
0138:
0139:            /**
0140:             * Have we seen the final bounary line?
0141:             */
0142:            private boolean complete = true;
0143:
0144:            /**
0145:             * The MIME multipart preamble text, the text that
0146:             * occurs before the first boundary line.
0147:             */
0148:            private String preamble = null;
0149:
0150:            /**
0151:             * Default constructor. An empty MimeMultipart object
0152:             * is created. Its content type is set to "multipart/mixed".
0153:             * A unique boundary string is generated and this string is
0154:             * setup as the "boundary" parameter for the 
0155:             * <code>contentType</code> field. <p>
0156:             *
0157:             * MimeBodyParts may be added later.
0158:             */
0159:            public MimeMultipart() {
0160:                this ("mixed");
0161:            }
0162:
0163:            /**
0164:             * Construct a MimeMultipart object of the given subtype.
0165:             * A unique boundary string is generated and this string is
0166:             * setup as the "boundary" parameter for the 
0167:             * <code>contentType</code> field. <p>
0168:             *
0169:             * MimeBodyParts may be added later.
0170:             */
0171:            public MimeMultipart(String subtype) {
0172:                super ();
0173:                /*
0174:                 * Compute a boundary string.
0175:                 */
0176:                String boundary = UniqueValue.getUniqueBoundaryValue();
0177:                ContentType cType = new ContentType("multipart", subtype, null);
0178:                cType.setParameter("boundary", boundary);
0179:                contentType = cType.toString();
0180:            }
0181:
0182:            /**
0183:             * Constructs a MimeMultipart object and its bodyparts from the 
0184:             * given DataSource. <p>
0185:             *
0186:             * This constructor handles as a special case the situation where the
0187:             * given DataSource is a MultipartDataSource object.  In this case, this
0188:             * method just invokes the superclass (i.e., Multipart) constructor
0189:             * that takes a MultipartDataSource object. <p>
0190:             *
0191:             * Otherwise, the DataSource is assumed to provide a MIME multipart 
0192:             * byte stream.  The <code>parsed</code> flag is set to false.  When
0193:             * the data for the body parts are needed, the parser extracts the
0194:             * "boundary" parameter from the content type of this DataSource,
0195:             * skips the 'preamble' and reads bytes till the terminating
0196:             * boundary and creates MimeBodyParts for each part of the stream.
0197:             *
0198:             * @param	ds	DataSource, can be a MultipartDataSource
0199:             */
0200:            public MimeMultipart(DataSource ds) throws MessagingException {
0201:                super ();
0202:
0203:                if (ds instanceof  MessageAware) {
0204:                    MessageContext mc = ((MessageAware) ds).getMessageContext();
0205:                    setParent(mc.getPart());
0206:                }
0207:
0208:                if (ds instanceof  MultipartDataSource) {
0209:                    // ask super to do this for us.
0210:                    setMultipartDataSource((MultipartDataSource) ds);
0211:                    return;
0212:                }
0213:
0214:                // 'ds' was not a MultipartDataSource, we have
0215:                // to parse this ourself.
0216:                parsed = false;
0217:                this .ds = ds;
0218:                contentType = ds.getContentType();
0219:            }
0220:
0221:            /**
0222:             * Set the subtype. This method should be invoked only on a new
0223:             * MimeMultipart object created by the client. The default subtype
0224:             * of such a multipart object is "mixed". <p>
0225:             *
0226:             * @param	subtype		Subtype
0227:             */
0228:            public synchronized void setSubType(String subtype)
0229:                    throws MessagingException {
0230:                ContentType cType = new ContentType(contentType);
0231:                cType.setSubType(subtype);
0232:                contentType = cType.toString();
0233:            }
0234:
0235:            /**
0236:             * Return the number of enclosed BodyPart objects.
0237:             *
0238:             * @return		number of parts
0239:             */
0240:            public synchronized int getCount() throws MessagingException {
0241:                parse();
0242:                return super .getCount();
0243:            }
0244:
0245:            /**
0246:             * Get the specified BodyPart.  BodyParts are numbered starting at 0.
0247:             *
0248:             * @param index	the index of the desired BodyPart
0249:             * @return		the Part
0250:             * @exception       MessagingException if no such BodyPart exists
0251:             */
0252:            public synchronized BodyPart getBodyPart(int index)
0253:                    throws MessagingException {
0254:                parse();
0255:                return super .getBodyPart(index);
0256:            }
0257:
0258:            /**
0259:             * Get the MimeBodyPart referred to by the given ContentID (CID). 
0260:             * Returns null if the part is not found.
0261:             *
0262:             * @param  CID 	the ContentID of the desired part
0263:             * @return          the Part
0264:             */
0265:            public synchronized BodyPart getBodyPart(String CID)
0266:                    throws MessagingException {
0267:                parse();
0268:
0269:                int count = getCount();
0270:                for (int i = 0; i < count; i++) {
0271:                    MimeBodyPart part = (MimeBodyPart) getBodyPart(i);
0272:                    String s = part.getContentID();
0273:                    if (s != null && s.equals(CID))
0274:                        return part;
0275:                }
0276:                return null;
0277:            }
0278:
0279:            /**
0280:             * Remove the specified part from the multipart message.
0281:             * Shifts all the parts after the removed part down one.
0282:             *
0283:             * @param   part	The part to remove
0284:             * @return		true if part removed, false otherwise
0285:             * @exception	MessagingException if no such Part exists
0286:             * @exception	IllegalWriteException if the underlying
0287:             *			implementation does not support modification
0288:             *			of existing values
0289:             */
0290:            public boolean removeBodyPart(BodyPart part)
0291:                    throws MessagingException {
0292:                parse();
0293:                return super .removeBodyPart(part);
0294:            }
0295:
0296:            /**
0297:             * Remove the part at specified location (starting from 0).
0298:             * Shifts all the parts after the removed part down one.
0299:             *
0300:             * @param   index	Index of the part to remove
0301:             * @exception	MessagingException
0302:             * @exception       IndexOutOfBoundsException if the given index
0303:             *			is out of range.
0304:             * @exception	IllegalWriteException if the underlying
0305:             *			implementation does not support modification
0306:             *			of existing values
0307:             */
0308:            public void removeBodyPart(int index) throws MessagingException {
0309:                parse();
0310:                super .removeBodyPart(index);
0311:            }
0312:
0313:            /**
0314:             * Adds a Part to the multipart.  The BodyPart is appended to 
0315:             * the list of existing Parts.
0316:             *
0317:             * @param  part  The Part to be appended
0318:             * @exception       MessagingException
0319:             * @exception	IllegalWriteException if the underlying
0320:             *			implementation does not support modification
0321:             *			of existing values
0322:             */
0323:            public synchronized void addBodyPart(BodyPart part)
0324:                    throws MessagingException {
0325:                parse();
0326:                super .addBodyPart(part);
0327:            }
0328:
0329:            /**
0330:             * Adds a BodyPart at position <code>index</code>.
0331:             * If <code>index</code> is not the last one in the list,
0332:             * the subsequent parts are shifted up. If <code>index</code>
0333:             * is larger than the number of parts present, the
0334:             * BodyPart is appended to the end.
0335:             *
0336:             * @param  part  The BodyPart to be inserted
0337:             * @param  index Location where to insert the part
0338:             * @exception       MessagingException
0339:             * @exception	IllegalWriteException if the underlying
0340:             *			implementation does not support modification
0341:             *			of existing values
0342:             */
0343:            public synchronized void addBodyPart(BodyPart part, int index)
0344:                    throws MessagingException {
0345:                parse();
0346:                super .addBodyPart(part, index);
0347:            }
0348:
0349:            /**
0350:             * Return true if the final boundary line for this
0351:             * multipart was seen.  When parsing multipart content,
0352:             * this class will (by default) terminate parsing with
0353:             * no error if the end of input is reached before seeing
0354:             * the final multipart boundary line.  In such a case,
0355:             * this method will return false.  (If the System property
0356:             * "mail.mime.multipart.ignoremissingendboundary" is set to
0357:             * false, parsing such a message will instead throw a
0358:             * MessagingException.)
0359:             *
0360:             * @return	true if the final boundary line was seen
0361:             * @since		JavaMail 1.4
0362:             */
0363:            public synchronized boolean isComplete() throws MessagingException {
0364:                parse();
0365:                return complete;
0366:            }
0367:
0368:            /**
0369:             * Get the preamble text, if any, that appears before the
0370:             * first body part of this multipart.  Some protocols,
0371:             * such as IMAP, will not allow access to the preamble text.
0372:             *
0373:             * @return		the preamble text, or null if no preamble
0374:             * @since		JavaMail 1.4
0375:             */
0376:            public synchronized String getPreamble() throws MessagingException {
0377:                parse();
0378:                return preamble;
0379:            }
0380:
0381:            /**
0382:             * Set the preamble text to be included before the first
0383:             * body part.  Applications should generally not include
0384:             * any preamble text.  In some cases it may be helpful to
0385:             * include preamble text with instructions for users of
0386:             * pre-MIME software.  The preamble text should be complete
0387:             * lines, including newlines.
0388:             *
0389:             * @param	preamble	the preamble text
0390:             * @since		JavaMail 1.4
0391:             */
0392:            public synchronized void setPreamble(String preamble)
0393:                    throws MessagingException {
0394:                this .preamble = preamble;
0395:            }
0396:
0397:            /**
0398:             * Update headers. The default implementation here just
0399:             * calls the <code>updateHeaders</code> method on each of its
0400:             * children BodyParts. <p>
0401:             *
0402:             * Note that the boundary parameter is already set up when
0403:             * a new and empty MimeMultipart object is created. <p>
0404:             *
0405:             * This method is called when the <code>saveChanges</code>
0406:             * method is invoked on the Message object containing this
0407:             * Multipart. This is typically done as part of the Message
0408:             * send process, however note that a client is free to call
0409:             * it any number of times. So if the header updating process is 
0410:             * expensive for a specific MimeMultipart subclass, then it
0411:             * might itself want to track whether its internal state actually
0412:             * did change, and do the header updating only if necessary.
0413:             */
0414:            protected void updateHeaders() throws MessagingException {
0415:                for (int i = 0; i < parts.size(); i++)
0416:                    ((MimeBodyPart) parts.elementAt(i)).updateHeaders();
0417:            }
0418:
0419:            /**
0420:             * Iterates through all the parts and outputs each MIME part
0421:             * separated by a boundary.
0422:             */
0423:            public synchronized void writeTo(OutputStream os)
0424:                    throws IOException, MessagingException {
0425:                parse();
0426:
0427:                String boundary = "--"
0428:                        + (new ContentType(contentType))
0429:                                .getParameter("boundary");
0430:                LineOutputStream los = new LineOutputStream(os);
0431:
0432:                // if there's a preamble, write it out
0433:                if (preamble != null) {
0434:                    byte[] pb = ASCIIUtility.getBytes(preamble);
0435:                    los.write(pb);
0436:                    // make sure it ends with a newline
0437:                    if (pb.length > 0
0438:                            && !(pb[pb.length - 1] == '\r' || pb[pb.length - 1] == '\n')) {
0439:                        los.writeln();
0440:                    }
0441:                    // XXX - could force a blank line before start boundary
0442:                }
0443:                for (int i = 0; i < parts.size(); i++) {
0444:                    los.writeln(boundary); // put out boundary
0445:                    ((MimeBodyPart) parts.elementAt(i)).writeTo(os);
0446:                    los.writeln(); // put out empty line
0447:                }
0448:
0449:                // put out last boundary
0450:                los.writeln(boundary + "--");
0451:            }
0452:
0453:            /**
0454:             * Parse the InputStream from our DataSource, constructing the
0455:             * appropriate MimeBodyParts.  The <code>parsed</code> flag is
0456:             * set to true, and if true on entry nothing is done.  This
0457:             * method is called by all other methods that need data for
0458:             * the body parts, to make sure the data has been parsed.
0459:             *
0460:             * @since	JavaMail 1.2
0461:             */
0462:            protected synchronized void parse() throws MessagingException {
0463:                if (parsed)
0464:                    return;
0465:
0466:                if (bmparse) {
0467:                    parsebm();
0468:                    return;
0469:                }
0470:
0471:                InputStream in = null;
0472:                SharedInputStream sin = null;
0473:                long start = 0, end = 0;
0474:
0475:                try {
0476:                    in = ds.getInputStream();
0477:                    if (!(in instanceof  ByteArrayInputStream)
0478:                            && !(in instanceof  BufferedInputStream)
0479:                            && !(in instanceof  SharedInputStream))
0480:                        in = new BufferedInputStream(in);
0481:                } catch (Exception ex) {
0482:                    throw new MessagingException(
0483:                            "No inputstream from datasource", ex);
0484:                }
0485:                if (in instanceof  SharedInputStream)
0486:                    sin = (SharedInputStream) in;
0487:
0488:                ContentType cType = new ContentType(contentType);
0489:                String boundary = null;
0490:                String bp = cType.getParameter("boundary");
0491:                if (bp != null)
0492:                    boundary = "--" + bp;
0493:                else if (!ignoreMissingBoundaryParameter)
0494:                    throw new MessagingException("Missing boundary parameter");
0495:
0496:                try {
0497:                    // Skip and save the preamble
0498:                    LineInputStream lin = new LineInputStream(in);
0499:                    StringBuffer preamblesb = null;
0500:                    String line;
0501:                    String lineSeparator = null;
0502:                    while ((line = lin.readLine()) != null) {
0503:                        /*
0504:                         * Strip trailing whitespace.  Can't use trim method
0505:                         * because it's too aggressive.  Some bogus MIME
0506:                         * messages will include control characters in the
0507:                         * boundary string.
0508:                         */
0509:                        int i;
0510:                        for (i = line.length() - 1; i >= 0; i--) {
0511:                            char c = line.charAt(i);
0512:                            if (!(c == ' ' || c == '\t'))
0513:                                break;
0514:                        }
0515:                        line = line.substring(0, i + 1);
0516:                        if (boundary != null) {
0517:                            if (line.equals(boundary))
0518:                                break;
0519:                        } else {
0520:                            /*
0521:                             * Boundary hasn't been defined, does this line
0522:                             * look like a boundary?  If so, assume it is
0523:                             * the boundary and save it.
0524:                             */
0525:                            if (line.startsWith("--")) {
0526:                                boundary = line;
0527:                                break;
0528:                            }
0529:                        }
0530:
0531:                        // save the preamble after skipping blank lines
0532:                        if (line.length() > 0) {
0533:                            // if we haven't figured out what the line seprator
0534:                            // is, do it now
0535:                            if (lineSeparator == null) {
0536:                                try {
0537:                                    lineSeparator = System.getProperty(
0538:                                            "line.separator", "\n");
0539:                                } catch (SecurityException ex) {
0540:                                    lineSeparator = "\n";
0541:                                }
0542:                            }
0543:                            // accumulate the preamble
0544:                            if (preamblesb == null)
0545:                                preamblesb = new StringBuffer(line.length() + 2);
0546:                            preamblesb.append(line).append(lineSeparator);
0547:                        }
0548:                    }
0549:                    if (line == null)
0550:                        throw new MessagingException("Missing start boundary");
0551:
0552:                    if (preamblesb != null)
0553:                        preamble = preamblesb.toString();
0554:
0555:                    // save individual boundary bytes for easy comparison later
0556:                    byte[] bndbytes = ASCIIUtility.getBytes(boundary);
0557:                    int bl = bndbytes.length;
0558:
0559:                    /*
0560:                     * Read and process body parts until we see the
0561:                     * terminating boundary line (or EOF).
0562:                     */
0563:                    boolean done = false;
0564:                    getparts: while (!done) {
0565:                        InternetHeaders headers = null;
0566:                        if (sin != null) {
0567:                            start = sin.getPosition();
0568:                            // skip headers
0569:                            while ((line = lin.readLine()) != null
0570:                                    && line.length() > 0)
0571:                                ;
0572:                            if (line == null) {
0573:                                if (!ignoreMissingEndBoundary)
0574:                                    throw new MessagingException(
0575:                                            "missing multipart end boundary");
0576:                                // assume there's just a missing end boundary
0577:                                complete = false;
0578:                                break getparts;
0579:                            }
0580:                        } else {
0581:                            // collect the headers for this body part
0582:                            headers = createInternetHeaders(in);
0583:                        }
0584:
0585:                        if (!in.markSupported())
0586:                            throw new MessagingException(
0587:                                    "Stream doesn't support mark");
0588:
0589:                        ByteArrayOutputStream buf = null;
0590:                        // if we don't have a shared input stream, we copy the data
0591:                        if (sin == null)
0592:                            buf = new ByteArrayOutputStream();
0593:                        else
0594:                            end = sin.getPosition();
0595:                        int b;
0596:                        boolean bol = true; // beginning of line flag
0597:                        // the two possible end of line characters
0598:                        int eol1 = -1, eol2 = -1;
0599:
0600:                        /*
0601:                         * Read and save the content bytes in buf.
0602:                         */
0603:                        for (;;) {
0604:                            if (bol) {
0605:                                /*
0606:                                 * At the beginning of a line, check whether the
0607:                                 * next line is a boundary.
0608:                                 */
0609:                                int i;
0610:                                in.mark(bl + 4 + 1000); // bnd + "--\r\n" + lots of LWSP
0611:                                // read bytes, matching against the boundary
0612:                                for (i = 0; i < bl; i++)
0613:                                    if (in.read() != (bndbytes[i] & 0xff))
0614:                                        break;
0615:                                if (i == bl) {
0616:                                    // matched the boundary, check for last boundary
0617:                                    int b2 = in.read();
0618:                                    if (b2 == '-') {
0619:                                        if (in.read() == '-') {
0620:                                            complete = true;
0621:                                            done = true;
0622:                                            break; // ignore trailing text
0623:                                        }
0624:                                    }
0625:                                    // skip linear whitespace
0626:                                    while (b2 == ' ' || b2 == '\t')
0627:                                        b2 = in.read();
0628:                                    // check for end of line
0629:                                    if (b2 == '\n')
0630:                                        break; // got it!  break out of the loop
0631:                                    if (b2 == '\r') {
0632:                                        in.mark(1);
0633:                                        if (in.read() != '\n')
0634:                                            in.reset();
0635:                                        break; // got it!  break out of the loop
0636:                                    }
0637:                                }
0638:                                // failed to match, reset and proceed normally
0639:                                in.reset();
0640:
0641:                                // if this is not the first line, write out the
0642:                                // end of line characters from the previous line
0643:                                if (buf != null && eol1 != -1) {
0644:                                    buf.write(eol1);
0645:                                    if (eol2 != -1)
0646:                                        buf.write(eol2);
0647:                                    eol1 = eol2 = -1;
0648:                                }
0649:                            }
0650:
0651:                            // read the next byte
0652:                            if ((b = in.read()) < 0) {
0653:                                if (!ignoreMissingEndBoundary)
0654:                                    throw new MessagingException(
0655:                                            "missing multipart end boundary");
0656:                                complete = false;
0657:                                done = true;
0658:                                break;
0659:                            }
0660:
0661:                            /*
0662:                             * If we're at the end of the line, save the eol characters
0663:                             * to be written out before the beginning of the next line.
0664:                             */
0665:                            if (b == '\r' || b == '\n') {
0666:                                bol = true;
0667:                                if (sin != null)
0668:                                    end = sin.getPosition() - 1;
0669:                                eol1 = b;
0670:                                if (b == '\r') {
0671:                                    in.mark(1);
0672:                                    if ((b = in.read()) == '\n')
0673:                                        eol2 = b;
0674:                                    else
0675:                                        in.reset();
0676:                                }
0677:                            } else {
0678:                                bol = false;
0679:                                if (buf != null)
0680:                                    buf.write(b);
0681:                            }
0682:                        }
0683:
0684:                        /*
0685:                         * Create a MimeBody element to represent this body part.
0686:                         */
0687:                        MimeBodyPart part;
0688:                        if (sin != null)
0689:                            part = createMimeBodyPart(sin.newStream(start, end));
0690:                        else
0691:                            part = createMimeBodyPart(headers, buf
0692:                                    .toByteArray());
0693:                        super .addBodyPart(part);
0694:                    }
0695:                } catch (IOException ioex) {
0696:                    throw new MessagingException("IO Error", ioex);
0697:                } finally {
0698:                    try {
0699:                        in.close();
0700:                    } catch (IOException cex) {
0701:                        // ignore
0702:                    }
0703:                }
0704:
0705:                parsed = true;
0706:            }
0707:
0708:            /**
0709:             * Parse the InputStream from our DataSource, constructing the
0710:             * appropriate MimeBodyParts.  The <code>parsed</code> flag is
0711:             * set to true, and if true on entry nothing is done.  This
0712:             * method is called by all other methods that need data for
0713:             * the body parts, to make sure the data has been parsed.
0714:             *
0715:             * @since	JavaMail 1.2
0716:             */
0717:            /*
0718:             * Boyer-Moore version of parser.  Keep both versions around
0719:             * until we're sure this new one works.
0720:             */
0721:            private synchronized void parsebm() throws MessagingException {
0722:                if (parsed)
0723:                    return;
0724:
0725:                InputStream in = null;
0726:                SharedInputStream sin = null;
0727:                long start = 0, end = 0;
0728:
0729:                try {
0730:                    in = ds.getInputStream();
0731:                    if (!(in instanceof  ByteArrayInputStream)
0732:                            && !(in instanceof  BufferedInputStream)
0733:                            && !(in instanceof  SharedInputStream))
0734:                        in = new BufferedInputStream(in);
0735:                } catch (Exception ex) {
0736:                    throw new MessagingException(
0737:                            "No inputstream from datasource", ex);
0738:                }
0739:                if (in instanceof  SharedInputStream)
0740:                    sin = (SharedInputStream) in;
0741:
0742:                ContentType cType = new ContentType(contentType);
0743:                String boundary = null;
0744:                String bp = cType.getParameter("boundary");
0745:                if (bp != null)
0746:                    boundary = "--" + bp;
0747:                else if (!ignoreMissingBoundaryParameter)
0748:                    throw new MessagingException("Missing boundary parameter");
0749:
0750:                try {
0751:                    // Skip and save the preamble
0752:                    LineInputStream lin = new LineInputStream(in);
0753:                    StringBuffer preamblesb = null;
0754:                    String line;
0755:                    String lineSeparator = null;
0756:                    while ((line = lin.readLine()) != null) {
0757:                        /*
0758:                         * Strip trailing whitespace.  Can't use trim method
0759:                         * because it's too aggressive.  Some bogus MIME
0760:                         * messages will include control characters in the
0761:                         * boundary string.
0762:                         */
0763:                        int i;
0764:                        for (i = line.length() - 1; i >= 0; i--) {
0765:                            char c = line.charAt(i);
0766:                            if (!(c == ' ' || c == '\t'))
0767:                                break;
0768:                        }
0769:                        line = line.substring(0, i + 1);
0770:                        if (boundary != null) {
0771:                            if (line.equals(boundary))
0772:                                break;
0773:                        } else {
0774:                            /*
0775:                             * Boundary hasn't been defined, does this line
0776:                             * look like a boundary?  If so, assume it is
0777:                             * the boundary and save it.
0778:                             */
0779:                            if (line.startsWith("--")) {
0780:                                boundary = line;
0781:                                break;
0782:                            }
0783:                        }
0784:
0785:                        // save the preamble after skipping blank lines
0786:                        if (line.length() > 0) {
0787:                            // if we haven't figured out what the line seprator
0788:                            // is, do it now
0789:                            if (lineSeparator == null) {
0790:                                try {
0791:                                    lineSeparator = System.getProperty(
0792:                                            "line.separator", "\n");
0793:                                } catch (SecurityException ex) {
0794:                                    lineSeparator = "\n";
0795:                                }
0796:                            }
0797:                            // accumulate the preamble
0798:                            if (preamblesb == null)
0799:                                preamblesb = new StringBuffer(line.length() + 2);
0800:                            preamblesb.append(line).append(lineSeparator);
0801:                        }
0802:                    }
0803:                    if (line == null)
0804:                        throw new MessagingException("Missing start boundary");
0805:
0806:                    if (preamblesb != null)
0807:                        preamble = preamblesb.toString();
0808:
0809:                    // save individual boundary bytes for comparison later
0810:                    byte[] bndbytes = ASCIIUtility.getBytes(boundary);
0811:                    int bl = bndbytes.length;
0812:
0813:                    /*
0814:                     * Compile Boyer-Moore parsing tables.
0815:                     */
0816:
0817:                    // initialize Bad Character Shift table
0818:                    int[] bcs = new int[256];
0819:                    for (int i = 0; i < bl; i++)
0820:                        bcs[bndbytes[i]] = i + 1;
0821:
0822:                    // initialize Good Suffix Shift table
0823:                    int[] gss = new int[bl];
0824:                    NEXT: for (int i = bl; i > 0; i--) {
0825:                        int j; // the beginning index of the suffix being considered
0826:                        for (j = bl - 1; j >= i; j--) {
0827:                            // Testing for good suffix
0828:                            if (bndbytes[j] == bndbytes[j - i]) {
0829:                                // bndbytes[j..len] is a good suffix
0830:                                gss[j - 1] = i;
0831:                            } else {
0832:                                // No match. The array has already been
0833:                                // filled up with correct values before.
0834:                                continue NEXT;
0835:                            }
0836:                        }
0837:                        while (j > 0)
0838:                            gss[--j] = i;
0839:                    }
0840:                    gss[bl - 1] = 1;
0841:
0842:                    /*
0843:                     * Read and process body parts until we see the
0844:                     * terminating boundary line (or EOF).
0845:                     */
0846:                    boolean done = false;
0847:                    getparts: while (!done) {
0848:                        InternetHeaders headers = null;
0849:                        if (sin != null) {
0850:                            start = sin.getPosition();
0851:                            // skip headers
0852:                            while ((line = lin.readLine()) != null
0853:                                    && line.length() > 0)
0854:                                ;
0855:                            if (line == null) {
0856:                                if (!ignoreMissingEndBoundary)
0857:                                    throw new MessagingException(
0858:                                            "missing multipart end boundary");
0859:                                // assume there's just a missing end boundary
0860:                                complete = false;
0861:                                break getparts;
0862:                            }
0863:                        } else {
0864:                            // collect the headers for this body part
0865:                            headers = createInternetHeaders(in);
0866:                        }
0867:
0868:                        if (!in.markSupported())
0869:                            throw new MessagingException(
0870:                                    "Stream doesn't support mark");
0871:
0872:                        ByteArrayOutputStream buf = null;
0873:                        // if we don't have a shared input stream, we copy the data
0874:                        if (sin == null)
0875:                            buf = new ByteArrayOutputStream();
0876:                        else
0877:                            end = sin.getPosition();
0878:                        int b;
0879:
0880:                        /*
0881:                         * These buffers contain the bytes we're checking
0882:                         * for a match.  inbuf is the current buffer and
0883:                         * previnbuf is the previous buffer.  We need the
0884:                         * previous buffer to check that we're preceeded
0885:                         * by an EOL.
0886:                         */
0887:                        // XXX - a smarter algorithm would use a sliding window
0888:                        //	 over a larger buffer
0889:                        byte[] inbuf = new byte[bl];
0890:                        byte[] previnbuf = new byte[bl];
0891:                        int inSize = 0; // number of valid bytes in inbuf
0892:                        int prevSize = 0; // number of valid bytes in previnbuf
0893:                        int eolLen;
0894:                        boolean first = true;
0895:
0896:                        /*
0897:                         * Read and save the content bytes in buf.
0898:                         */
0899:                        for (;;) {
0900:                            in.mark(bl + 4 + 1000); // bnd + "--\r\n" + lots of LWSP
0901:                            eolLen = 0;
0902:                            inSize = readFully(in, inbuf, 0, bl);
0903:                            if (inSize < bl) {
0904:                                // hit EOF
0905:                                if (!ignoreMissingEndBoundary)
0906:                                    throw new MessagingException(
0907:                                            "missing multipart end boundary");
0908:                                if (sin != null)
0909:                                    end = sin.getPosition();
0910:                                complete = false;
0911:                                done = true;
0912:                                break;
0913:                            }
0914:                            // check whether inbuf contains a boundary string
0915:                            int i;
0916:                            for (i = bl - 1; i >= 0; i--) {
0917:                                if (inbuf[i] != bndbytes[i])
0918:                                    break;
0919:                            }
0920:                            if (i < 0) { // matched all bytes
0921:                                eolLen = 0;
0922:                                if (!first) {
0923:                                    // working backwards, find out if we were preceeded
0924:                                    // by an EOL, and if so find its length
0925:                                    b = previnbuf[prevSize - 1];
0926:                                    if (b == '\r' || b == '\n') {
0927:                                        eolLen = 1;
0928:                                        if (b == '\n' && prevSize >= 2) {
0929:                                            b = previnbuf[prevSize - 2];
0930:                                            if (b == '\r')
0931:                                                eolLen = 2;
0932:                                        }
0933:                                    }
0934:                                }
0935:                                if (first || eolLen > 0) { // yes, preceed by EOL
0936:                                    if (sin != null) {
0937:                                        // update "end", in case this really is
0938:                                        // a valid boundary
0939:                                        end = sin.getPosition() - bl - eolLen;
0940:                                    }
0941:                                    // matched the boundary, check for last boundary
0942:                                    int b2 = in.read();
0943:                                    if (b2 == '-') {
0944:                                        if (in.read() == '-') {
0945:                                            complete = true;
0946:                                            done = true;
0947:                                            break; // ignore trailing text
0948:                                        }
0949:                                    }
0950:                                    // skip linear whitespace
0951:                                    while (b2 == ' ' || b2 == '\t')
0952:                                        b2 = in.read();
0953:                                    // check for end of line
0954:                                    if (b2 == '\n')
0955:                                        break; // got it!  break out of the loop
0956:                                    if (b2 == '\r') {
0957:                                        in.mark(1);
0958:                                        if (in.read() != '\n')
0959:                                            in.reset();
0960:                                        break; // got it!  break out of the loop
0961:                                    }
0962:                                }
0963:                                i = 0;
0964:                            }
0965:
0966:                            /*
0967:                             * Get here if boundary didn't match,
0968:                             * wasn't preceeded by EOL, or wasn't
0969:                             * followed by whitespace or EOL.
0970:                             */
0971:
0972:                            // compute how many bytes we can skip
0973:                            int skip = Math.max(i + 1 - bcs[inbuf[i] & 0x7f],
0974:                                    gss[i]);
0975:                            // want to keep at least two characters
0976:                            if (skip < 2) {
0977:                                // only skipping one byte, save one byte
0978:                                // from previous buffer as well
0979:                                // first, write out bytes we're done with
0980:                                if (sin == null && prevSize > 1)
0981:                                    buf.write(previnbuf, 0, prevSize - 1);
0982:                                in.reset();
0983:                                skipFully(in, 1);
0984:                                if (prevSize >= 1) { // is there a byte to save?
0985:                                    // yes, save one from previous and one from current
0986:                                    previnbuf[0] = previnbuf[prevSize - 1];
0987:                                    previnbuf[1] = inbuf[0];
0988:                                    prevSize = 2;
0989:                                } else {
0990:                                    // no previous bytes to save, can only save current
0991:                                    previnbuf[0] = inbuf[0];
0992:                                    prevSize = 1;
0993:                                }
0994:                            } else {
0995:                                // first, write out data from previous buffer before
0996:                                // we dump it
0997:                                if (prevSize > 0 && sin == null)
0998:                                    buf.write(previnbuf, 0, prevSize);
0999:                                // all the bytes we're skipping are saved in previnbuf
1000:                                prevSize = skip;
1001:                                in.reset();
1002:                                skipFully(in, prevSize);
1003:                                // swap buffers
1004:                                byte[] tmp = inbuf;
1005:                                inbuf = previnbuf;
1006:                                previnbuf = tmp;
1007:                            }
1008:                            first = false;
1009:                        }
1010:
1011:                        /*
1012:                         * Create a MimeBody element to represent this body part.
1013:                         */
1014:                        MimeBodyPart part;
1015:                        if (sin != null) {
1016:                            part = createMimeBodyPart(sin.newStream(start, end));
1017:                        } else {
1018:                            // write out data from previous buffer, not including EOL
1019:                            if (prevSize - eolLen > 0)
1020:                                buf.write(previnbuf, 0, prevSize - eolLen);
1021:                            // if we didn't find a trailing boundary,
1022:                            // the current buffer has data we need too
1023:                            if (!complete && inSize > 0)
1024:                                buf.write(inbuf, 0, inSize);
1025:                            part = createMimeBodyPart(headers, buf
1026:                                    .toByteArray());
1027:                        }
1028:                        super .addBodyPart(part);
1029:                    }
1030:                } catch (IOException ioex) {
1031:                    throw new MessagingException("IO Error", ioex);
1032:                } finally {
1033:                    try {
1034:                        in.close();
1035:                    } catch (IOException cex) {
1036:                        // ignore
1037:                    }
1038:                }
1039:
1040:                parsed = true;
1041:            }
1042:
1043:            /**
1044:             * Read data from the input stream to fill the buffer starting
1045:             * at the specified offset with the specified number of bytes.
1046:             * If len is zero, return zero.  If at EOF, return -1.  Otherwise,
1047:             * return the number of bytes read.  Call the read method on the
1048:             * input stream as many times as necessary to read len bytes.
1049:             *
1050:             * @param	in	InputStream to read from
1051:             * @param	buf	buffer to read into
1052:             * @param	off	offset in the buffer for first byte
1053:             * @param	len	number of bytes to read
1054:             * @return		-1 on EOF, otherwise number of bytes read
1055:             * @exception	IOException	on I/O errors
1056:             */
1057:            private static int readFully(InputStream in, byte[] buf, int off,
1058:                    int len) throws IOException {
1059:                if (len == 0)
1060:                    return 0;
1061:                int total = 0;
1062:                while (len > 0) {
1063:                    int bsize = in.read(buf, off, len);
1064:                    if (bsize <= 0) // should never be zero
1065:                        break;
1066:                    off += bsize;
1067:                    total += bsize;
1068:                    len -= bsize;
1069:                }
1070:                return total > 0 ? total : -1;
1071:            }
1072:
1073:            /**
1074:             * Skip the specified number of bytes, repeatedly calling
1075:             * the skip method as necessary.
1076:             */
1077:            private void skipFully(InputStream in, long offset)
1078:                    throws IOException {
1079:                while (offset > 0) {
1080:                    long cur = in.skip(offset);
1081:                    if (cur <= 0)
1082:                        throw new EOFException("can't skip");
1083:                    offset -= cur;
1084:                }
1085:            }
1086:
1087:            /**
1088:             * Create and return an InternetHeaders object that loads the
1089:             * headers from the given InputStream.  Subclasses can override
1090:             * this method to return a subclass of InternetHeaders, if
1091:             * necessary.  This implementation simply constructs and returns
1092:             * an InternetHeaders object.
1093:             *
1094:             * @param	is	the InputStream to read the headers from
1095:             * @exception  	MessagingException
1096:             * @since		JavaMail 1.2
1097:             */
1098:            protected InternetHeaders createInternetHeaders(InputStream is)
1099:                    throws MessagingException {
1100:                return new InternetHeaders(is);
1101:            }
1102:
1103:            /**
1104:             * Create and return a MimeBodyPart object to represent a
1105:             * body part parsed from the InputStream.  Subclasses can override
1106:             * this method to return a subclass of MimeBodyPart, if
1107:             * necessary.  This implementation simply constructs and returns
1108:             * a MimeBodyPart object.
1109:             *
1110:             * @param	headers		the headers for the body part
1111:             * @param	content		the content of the body part
1112:             * @exception  		MessagingException
1113:             * @since			JavaMail 1.2
1114:             */
1115:            protected MimeBodyPart createMimeBodyPart(InternetHeaders headers,
1116:                    byte[] content) throws MessagingException {
1117:                return new MimeBodyPart(headers, content);
1118:            }
1119:
1120:            /**
1121:             * Create and return a MimeBodyPart object to represent a
1122:             * body part parsed from the InputStream.  Subclasses can override
1123:             * this method to return a subclass of MimeBodyPart, if
1124:             * necessary.  This implementation simply constructs and returns
1125:             * a MimeBodyPart object.
1126:             *
1127:             * @param	is		InputStream containing the body part
1128:             * @exception  		MessagingException
1129:             * @since			JavaMail 1.2
1130:             */
1131:            protected MimeBodyPart createMimeBodyPart(InputStream is)
1132:                    throws MessagingException {
1133:                return new MimeBodyPart(is);
1134:            }
1135:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.