@@ -384,16 +384,17 @@ public class MailHandler extends Handler {
384384 * prepared to deal with unexpected null values since the
385385 * WebappClassLoader.clearReferencesThreadLocals() and
386386 * InnocuousThread.eraseThreadLocals() can remove thread local values.
387- * The MUTEX has 4 states:
387+ * The MUTEX has 5 states:
388388 * 1. A null value meaning default state of not publishing.
389389 * 2. MUTEX_PUBLISH on first entry of a push or publish.
390390 * 3. The index of the first filter to accept a log record.
391391 * 4. MUTEX_REPORT when cycle of records is detected.
392+ * 5. MUTEXT_LINKAGE when a linkage error is reported.
392393 */
393394 private static final ThreadLocal <Integer > MUTEX = new ThreadLocal <Integer >();
394395 /**
395396 * The marker object used to report a publishing state.
396- * This must be less than the body filter index.
397+ * This must be less than the body filter index (-1) .
397398 */
398399 private static final Integer MUTEX_PUBLISH = -2 ;
399400 /**
@@ -1632,6 +1633,39 @@ final String contentTypeOf(String head) {
16321633 return null ; //text/plain
16331634 }
16341635
1636+ /**
1637+ * Determines the mimeType of a formatter by the class name. This method
1638+ * avoids calling getHead and getTail of content formatters during verify
1639+ * because they might trigger side effects or excessive work. The name
1640+ * formatters and subject are usually safe to call.
1641+ * Package-private for unit testing.
1642+ *
1643+ * @param f the formatter or null.
1644+ * @return return the mime type or text/plain.
1645+ * @since JavaMail 1.5.6
1646+ */
1647+ final String contentTypeOf (final Formatter f ) {
1648+ if (f != null ) {
1649+ for (Class <?> k = f .getClass (); k != Formatter .class ;
1650+ k = k .getSuperclass ()) {
1651+ String name = k .getName ().toLowerCase (Locale .ENGLISH );
1652+ for (int idx = name .indexOf ('$' ) + 1 ;
1653+ (idx = name .indexOf ("ml" , idx )) > -1 ; idx += 2 ) {
1654+ if (idx > 0 ) {
1655+ if (name .charAt (idx - 1 ) == 'x' ) {
1656+ return "application/xml" ;
1657+ }
1658+ if (idx > 1 && name .charAt (idx - 2 ) == 'h'
1659+ && name .charAt (idx - 1 ) == 't' ) {
1660+ return "text/html" ;
1661+ }
1662+ }
1663+ }
1664+ }
1665+ }
1666+ return "text/plain" ;
1667+ }
1668+
16351669 /**
16361670 * Determines if the given throwable is a no content exception. It is
16371671 * assumed Transport.sendMessage will call Message.writeTo so we need to
@@ -1677,12 +1711,14 @@ final boolean isMissingContent(Message msg, Throwable t) {
16771711 */
16781712 @ SuppressWarnings ("UseSpecificCatch" )
16791713 private void reportError (Message msg , Exception ex , int code ) {
1680- try { //Use direct call so we do not prefix raw email.
1681- errorManager .error (toRawString (msg ), ex , code );
1682- } catch (final RuntimeException re ) {
1683- reportError (toMsgString (re ), ex , code );
1684- } catch (final Exception e ) {
1685- reportError (toMsgString (e ), ex , code );
1714+ try {
1715+ try { //Use direct call so we do not prefix raw email.
1716+ errorManager .error (toRawString (msg ), ex , code );
1717+ } catch (final RuntimeException re ) {
1718+ reportError (toMsgString (re ), ex , code );
1719+ } catch (final Exception e ) {
1720+ reportError (toMsgString (e ), ex , code );
1721+ }
16861722 } catch (final LinkageError GLASSFISH_21258 ) {
16871723 reportLinkageError (GLASSFISH_21258 , code );
16881724 }
@@ -1798,7 +1834,7 @@ private String contentWithEncoding(String type, String encoding) {
17981834 * Sets the capacity for this handler. This method is kept private
17991835 * because we would have to define a public policy for when the size is
18001836 * greater than the capacity.
1801- * I.E . do nothing, flush now, truncate now, push now and resize.
1837+ * E.G . do nothing, flush now, truncate now, push now and resize.
18021838 * @param newCapacity the max number of records.
18031839 * @throws SecurityException if a security manager exists and the
18041840 * caller does not have <tt>LoggingPermission("control")</tt>.
@@ -2998,9 +3034,19 @@ private void verifySettings0(Session session, String verify) {
29983034 }
29993035
30003036 //Perform all of the copy actions first.
3037+ String [] atn ;
30013038 synchronized (this ) { //Create the subject.
30023039 appendSubject (abort , head (subjectFormatter ));
30033040 appendSubject (abort , tail (subjectFormatter , "" ));
3041+ atn = new String [attachmentNames .length ];
3042+ for (int i = 0 ; i < atn .length ; ++i ) {
3043+ atn [i ] = head (attachmentNames [i ]);
3044+ if (atn [i ].length () == 0 ) {
3045+ atn [i ] = tail (attachmentNames [i ], "" );
3046+ } else {
3047+ atn [i ] = atn [i ].concat (tail (attachmentNames [i ], "" ));
3048+ }
3049+ }
30043050 }
30053051
30063052 setIncompleteCopy (abort ); //Original body part is never added.
@@ -3151,13 +3197,29 @@ private void verifySettings0(Session session, String verify) {
31513197 try { //Verify that the DataHandler can be loaded.
31523198 Object ccl = getAndSetContextClassLoader (MAILHANDLER_LOADER );
31533199 try {
3154- final MimeMultipart multipart = new MimeMultipart ();
3155- final MimeBodyPart body = new MimeBodyPart ();
3156- body .setDisposition (Part .INLINE );
3200+ MimeMultipart multipart = new MimeMultipart ();
3201+ MimeBodyPart [] ambp = new MimeBodyPart [atn .length ];
3202+ final MimeBodyPart body ;
3203+ final String bodyContentType ;
3204+ synchronized (this ) {
3205+ bodyContentType = contentTypeOf (getFormatter ());
3206+ body = createBodyPart ();
3207+ for (int i = 0 ; i < atn .length ; ++i ) {
3208+ ambp [i ] = createBodyPart (i );
3209+ ambp [i ].setFileName (atn [i ]);
3210+ //Convert names to mime type.
3211+ atn [i ] = getContentType (atn [i ]);
3212+ }
3213+ }
3214+
31573215 body .setDescription (verify );
3158- setAcceptLang (body );
3159- setContent (body , "" , "text/plain" );
3216+ setContent (body , "" , bodyContentType );
31603217 multipart .addBodyPart (body );
3218+ for (int i = 0 ; i < ambp .length ; ++i ) {
3219+ ambp [i ].setDescription (verify );
3220+ setContent (ambp [i ], "" , atn [i ]);
3221+ }
3222+
31613223 abort .setContent (multipart );
31623224 abort .saveChanges ();
31633225 abort .writeTo (new ByteArrayOutputStream (MIN_HEADER_SIZE ));
@@ -3220,6 +3282,8 @@ private void verifySettings0(Session session, String verify) {
32203282 * @param host the host or null.
32213283 * @return the address.
32223284 * @throws IOException if the host name is not valid.
3285+ * @throws SecurityException if security manager is present and doesn't
3286+ * allow access to check connect permission.
32233287 * @since JavaMail 1.5.0
32243288 */
32253289 private static InetAddress verifyHost (String host ) throws IOException {
0 commit comments