commits@javamail.java.net

[javamail~mercurial:289] Allow the SASL authorization ID to be null, for mechanisms or servers

From: <shannon_at_kenai.com>
Date: Fri, 25 Jun 2010 07:20:02 +0000

Project: javamail
Repository: mercurial
Revision: 289
Author: shannon
Date: 2010-06-21 17:20:15 UTC
Link:

Log Message:
------------
Header violates RFC 2822 for multiple calls of addRecipient(s) - bug 6928566
Protect against NPE.
Cache POP3 content using java.lang.ref.SoftReference,
set mail.pop3.keepmessagecontent to true to disable.
Document the mail.imap.auth.ntlm.disable property.
Document that expunge(Message[]) depends on UIDPLUS.
Add POP3 PIPELINING support and significantly reduce memory usage.
Fix typo in javadocs for Folder.getPermanentFlags and fix NPE in IMAP.
Add support for IMAP SORT extension (RFC 5256) to IMAPFolder.
Fix reference to JavaMail spec document. Relative reference needs to be
different than in javax/mail/package.html.
Include SortTerm in javadocs.
Add demo classes to handle non-MIME messages generated by Outlook.
Change to new Oracle email address. Sigh...
Also clear flags when invalidating message.
Handle untagged responses between IDLE command and continuation request.
Be sure to close stream - found by FindBugs.
Need to export more packages.
Fix bug in handling of non-ASCII boundaries in multipart messages.
Fix deadlock when using IMAP fetch and IDLE.
Add support for mail.smtp.auth.<mechanism>.disable properties.
Fix javadoc link error.
Make it possible to subclass IMAPFolder, e.g., to add support for new IMAP cmds.
Correct RFC reference for PLAIN authentication.
Fix bug with namespace handling introduced by previous change.
Publish the parent-distrib module too, since others depend on it.
Allow the SASL authorization ID to be null, for mechanisms or servers
that don't support an authorization ID.


Revisions:
----------
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289


Modified Paths:
---------------
doc/release/CHANGES.txt
mail/src/main/java/javax/mail/internet/MimeMessage.java
mail/src/main/java/com/sun/mail/pop3/POP3Message.java
mail/src/main/java/com/sun/mail/pop3/POP3Store.java
mail/src/main/java/com/sun/mail/pop3/package.html
mail/src/main/java/com/sun/mail/imap/package.html
mail/src/main/java/com/sun/mail/imap/IMAPFolder.java
mail/src/main/java/com/sun/mail/pop3/Protocol.java
mail/src/main/java/javax/mail/Folder.java
mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java
mail/src/main/java/overview.html
javadoc/pom.xml
assembly.xml
doc/release/README.txt
pom.xml
doc/release/NOTES.txt
doc/release/NTLMNOTES.txt
mail/src/main/java/com/sun/mail/imap/IMAPMessage.java
dsn/src/main/java/com/sun/mail/dsn/text_rfc822headers.java
mail/pom.xml
mail/src/main/java/javax/mail/internet/MimeMultipart.java
mail/src/main/java/com/sun/mail/smtp/SMTPTransport.java
mail/src/main/java/com/sun/mail/smtp/package.html
mail/src/main/java/com/sun/mail/imap/SortTerm.java
mail/src/main/java/com/sun/mail/imap/DefaultFolder.java
mail/src/main/java/com/sun/mail/imap/IMAPStore.java
mail/src/main/java/com/sun/mail/imap/protocol/SearchSequence.java
doc/release/COMPAT.txt


Added Paths:
------------
mail/src/test/java/javax/mail/internet/AddAddressHeaderTest.java
mail/src/main/java/com/sun/mail/imap/SortTerm.java
outlook/pom.xml
outlook/src/main/java/MSBodyPart.java
outlook/src/main/java/MSMessage.java
outlook/src/main/java/MSMultipartDataSource.java
outlook/src/main/java/README.txt
mail/src/test/java/com/sun/mail/imap/IMAPHandler.java
mail/src/test/java/com/sun/mail/imap/IMAPIdleUntaggedResponseTest.java
mail/src/test/java/com/sun/mail/imap/IMAPServer.java
mail/src/test/java/javax/mail/internet/NonAsciiBoundaryTest.java


Diffs:
------
diff -r 2201d882950b -r 0295e020772c doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Fri Feb 19 16:32:14 2010 -0800
+++ b/doc/release/CHANGES.txt Mon Feb 22 12:13:26 2010 -0800
@@ -22,6 +22,7 @@
 6778568 lower memory usage of POP3 parsing by buffering to disk
 6905730 MimeMessage.parse() is very slow on malformed message content
 6910675 IMAP provider can lose track of message sequence numbers
+6928566 Header violates RFC 2822 for multiple calls of addRecipient(s)
 G 11069 update the mail.jar manifest to include DynamicImport-Package
 <no id> add mail.mime.windowsfilenames System property to handle IE6 breakage
 <no id> properly disable TOP if POP3 CAPA response doesn't include it

diff -r 2201d882950b -r 0295e020772c mail/src/main/java/javax/mail/internet/MimeMessage.java
--- a/mail/src/main/java/javax/mail/internet/MimeMessage.java Fri Feb 19 16:32:14 2010 -0800
+++ b/mail/src/main/java/javax/mail/internet/MimeMessage.java Mon Feb 22 12:13:26 2010 -0800
@@ -414,16 +414,7 @@
      * @exception MessagingException
      */
     public void addFrom(Address[] addresses) throws MessagingException {
- Address[] a = getAddressHeader("From");
- Address[] anew;
- if (a == null || a.length == 0)
- anew = addresses;
- else {
- anew = new Address[a.length + addresses.length];
- System.arraycopy(a, 0, anew, 0, a.length);
- System.arraycopy(addresses, 0, anew, a.length, addresses.length);
- }
- setHeader("From", InternetAddress.toString(anew));
+ addAddressHeader("From", addresses);
     }
 
     /**
@@ -711,10 +702,21 @@
 
     private void addAddressHeader(String name, Address[] addresses)
                         throws MessagingException {
- String s = InternetAddress.toString(addresses);
+ if (addresses.length == 0)
+ return;
+ Address[] a = getAddressHeader(name);
+ Address[] anew;
+ if (a == null || a.length == 0)
+ anew = addresses;
+ else {
+ anew = new Address[a.length + addresses.length];
+ System.arraycopy(a, 0, anew, 0, a.length);
+ System.arraycopy(addresses, 0, anew, a.length, addresses.length);
+ }
+ String s = InternetAddress.toString(anew);
         if (s == null)
             return;
- addHeader(name, s);
+ setHeader(name, s);
     }
 
     /**

diff -r 2201d882950b -r 0295e020772c mail/src/test/java/javax/mail/internet/AddAddressHeaderTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mail/src/test/java/javax/mail/internet/AddAddressHeaderTest.java Mon Feb 22 12:13:26 2010 -0800
@@ -0,0 +1,101 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can obtain
+ * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
+ * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
+ * Sun designates this particular file as subject to the "Classpath" exception
+ * as provided by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the License
+ * Header, with the fields enclosed by brackets [] replaced by your own
+ * identifying information: "Portions Copyrighted [year]
+ * [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.mail.internet;
+
+import java.util.Properties;
+
+import javax.mail.Session;
+import javax.mail.MessagingException;
+import javax.mail.Message;
+import javax.mail.internet.MimeMessage;
+
+import org.junit.*;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test that "add" methods for address headers result in only a single
+ * address header, per RFC 2822.
+ */
+public class AddAddressHeaderTest {
+
+ private static Session s = Session.getInstance(new Properties());
+ private static InternetAddress[] setList = new InternetAddress[1];
+ private static InternetAddress[] addList = new InternetAddress[1];
+
+ static {
+ try {
+ setList[0] = new InternetAddress("me_at_example.com");
+ addList[0] = new InternetAddress("you_at_example.com");
+ } catch (MessagingException ex) {
+ }
+ }
+
+ @Test
+ public void testFrom() throws Exception {
+ MimeMessage m = new MimeMessage(s);
+ m.setFrom(setList[0]);
+ m.addFrom(addList);
+ m.saveChanges();
+ String[] h = m.getHeader("From");
+ assertEquals(1, h.length);
+ }
+
+ @Test
+ public void testTo() throws Exception {
+ testRecipients(Message.RecipientType.TO);
+ }
+
+ @Test
+ public void testCc() throws Exception {
+ testRecipients(Message.RecipientType.CC);
+ }
+
+ @Test
+ public void testBcc() throws Exception {
+ testRecipients(Message.RecipientType.BCC);
+ }
+
+ private void testRecipients(Message.RecipientType type) throws Exception {
+ MimeMessage m = new MimeMessage(s);
+ m.setRecipients(type, setList);
+ m.addRecipients(type, addList);
+ m.saveChanges();
+ // XXX - depends on RecipientType.toString
+ String[] h = m.getHeader(type.toString());
+ assertEquals(1, h.length);
+ }
+}


diff -r 0295e020772c -r 79f5c4cc0e6d mail/src/main/java/javax/mail/internet/MimeMessage.java
--- a/mail/src/main/java/javax/mail/internet/MimeMessage.java Mon Feb 22 12:13:26 2010 -0800
+++ b/mail/src/main/java/javax/mail/internet/MimeMessage.java Mon Feb 22 15:45:15 2010 -0800
@@ -702,7 +702,7 @@
 
     private void addAddressHeader(String name, Address[] addresses)
                         throws MessagingException {
- if (addresses.length == 0)
+ if (addresses == null || addresses.length == 0)
             return;
         Address[] a = getAddressHeader(name);
         Address[] anew;


diff -r 79f5c4cc0e6d -r 6fc762a92ca1 doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Mon Feb 22 15:45:15 2010 -0800
+++ b/doc/release/CHANGES.txt Mon Mar 01 15:34:39 2010 -0800
@@ -38,6 +38,8 @@
 <no id> add support for SASL authentication to SMTP provider
 <no id> add SMTPSenderFailedException to indicate problems with sender address
 <no id> ignore encoding for composite content when writing message
+<no id> cache POP3 content using java.lang.ref.SoftReference,
+ set mail.pop3.keepmessagecontent to true to disable
 
 
                   CHANGES IN THE 1.4.3 RELEASE

diff -r 79f5c4cc0e6d -r 6fc762a92ca1 mail/src/main/java/com/sun/mail/pop3/POP3Message.java
--- a/mail/src/main/java/com/sun/mail/pop3/POP3Message.java Mon Feb 22 15:45:15 2010 -0800
+++ b/mail/src/main/java/com/sun/mail/pop3/POP3Message.java Mon Mar 01 15:34:39 2010 -0800
@@ -38,6 +38,7 @@
 
 import java.io.*;
 import java.util.Enumeration;
+import java.lang.ref.SoftReference;
 import javax.mail.*;
 import javax.mail.internet.*;
 import javax.mail.event.*;
@@ -64,6 +65,9 @@
     private int msgSize = -1;
     String uid = UNKNOWN; // controlled by folder lock
 
+ // contentData itself is never null
+ private SoftReference contentData = new SoftReference(null);
+
     public POP3Message(Folder folder, int msgno)
                         throws MessagingException {
         super(folder, msgno);
@@ -99,8 +103,6 @@
     public int getSize() throws MessagingException {
         try {
             synchronized (this) {
- if (msgSize >= 0)
- return msgSize;
                 if (msgSize < 0) {
                     /*
                      * Use LIST to determine the entire message
@@ -108,13 +110,12 @@
                      * (which may involve loading the headers,
                      * which may load the content as a side effect).
                      * If the content is loaded as a side effect of
- * loading the headers, get the size directly.
+ * loading the headers, it will set the size.
                      */
                     if (headers == null)
                         loadHeaders();
- if (contentStream != null)
- msgSize = contentStream.available();
- else
+
+ if (msgSize < 0)
                         msgSize = folder.getProtocol().list(msgnum) - hdrSize;
                 }
                 return msgSize;
@@ -134,9 +135,11 @@
      * @see #contentStream
      */
     protected InputStream getContentStream() throws MessagingException {
+ InputStream cstream = null;
         try {
         synchronized(this) {
- if (contentStream == null) {
+ cstream = (InputStream)contentData.get();
+ if (cstream == null) {
                 InputStream rawcontent = null;
                 TempFile cache = folder.getFileCache();
                 if (cache != null) {
@@ -214,9 +217,19 @@
                     hdrSize =
                         (int)((SharedInputStream)rawcontent).getPosition();
                 }
- contentStream =
+ cstream =
                     ((SharedInputStream)rawcontent).newStream(hdrSize, -1);
+ msgSize = cstream.available();
                 rawcontent = null; // help GC
+
+ /*
+ * Keep a hard reference to the content if we're using a file
+ * cache or if the "mail.pop3.keepmessagecontent" prop is set.
+ */
+ if (cache != null ||
+ ((POP3Store)(folder.getStore())).keepMessageContent)
+ contentStream = cstream;
+ contentData = new SoftReference(cstream);
             }
         }
         } catch (EOFException eex) {
@@ -225,7 +238,7 @@
         } catch (IOException ex) {
             throw new MessagingException("error fetching POP3 content", ex);
         }
- return super.getContentStream();
+ return cstream;
     }
 
     /**
@@ -238,14 +251,16 @@
      */
     public synchronized void invalidate(boolean invalidateHeaders) {
         content = null;
- if (contentStream != null) {
+ InputStream cstream = (InputStream)contentData.get();
+ if (cstream != null) {
             // note that if the content is in the file cache, it will be lost
             // and fetched from the server if it's needed again
             try {
- contentStream.close();
+ cstream.close();
             } catch (IOException ex) {
                 // ignore it
             }
+ contentData = new SoftReference(null);
             contentStream = null;
         }
         msgSize = -1;

diff -r 79f5c4cc0e6d -r 6fc762a92ca1 mail/src/main/java/com/sun/mail/pop3/POP3Store.java
--- a/mail/src/main/java/com/sun/mail/pop3/POP3Store.java Mon Feb 22 15:45:15 2010 -0800
+++ b/mail/src/main/java/com/sun/mail/pop3/POP3Store.java Mon Mar 01 15:34:39 2010 -0800
@@ -85,6 +85,7 @@
     volatile boolean cacheWriteTo = false;
     volatile boolean useFileCache = false;
     volatile File fileCacheDir = null;
+ volatile boolean keepMessageContent = false;
 
     public POP3Store(Session session, URLName url) {
         this(session, url, "pop3", false);
@@ -119,6 +120,7 @@
             out.println("DEBUG POP3: mail." + name + ".filecache.dir: " + dir);
         if (dir != null)
             fileCacheDir = new File(dir);
+ keepMessageContent = getBoolProp("keepmessagecontent");
 
         // mail.pop3.starttls.enable enables use of STLS command
         useStartTLS = getBoolProp("starttls.enable");

diff -r 79f5c4cc0e6d -r 6fc762a92ca1 mail/src/main/java/com/sun/mail/pop3/package.html
--- a/mail/src/main/java/com/sun/mail/pop3/package.html Mon Feb 22 15:45:15 2010 -0800
+++ b/mail/src/main/java/com/sun/mail/pop3/package.html Mon Mar 01 15:34:39 2010 -0800
@@ -489,6 +489,24 @@
 </TD>
 </TR>
 
+<TR>
+<TD>mail.pop3.keepmessagecontent</TD>
+<TD>boolean</TD>
+<TD>
+The content of a message is cached when it is first fetched.
+Normally this cache uses a {_at_link java.lang.ref.SoftReference SoftReference}
+to refer to the cached content. This allows the cached content to be purged
+if memory is low, in which case the content will be fetched again if it's
+needed.
+If this property is set to true, a hard reference to the cached content
+will be kept, preventing the memory from being reused until the folder
+is closed or the cached content is explicitly invalidated (using the
+{_at_link com.sun.mail.pop3.POP3Message#invalidate invalidate} method).
+(This was the behavior in previous versions of JavaMail.)
+Defaults to false.
+</TD>
+</TR>
+
 </TABLE>
 <P>
 In general, applications should not need to use the classes in this


diff -r 6fc762a92ca1 -r 6d27e3a3d83b mail/src/main/java/com/sun/mail/imap/package.html
--- a/mail/src/main/java/com/sun/mail/imap/package.html Mon Mar 01 15:34:39 2010 -0800
+++ b/mail/src/main/java/com/sun/mail/imap/package.html Tue Mar 02 10:13:34 2010 -0800
@@ -217,6 +217,13 @@
 </TR>
 
 <TR>
+<TD>mail.imap.auth.ntlm.disable</TD>
+<TD>boolean</TD>
+<TD>If true, prevents use of the <code>AUTHENTICATE NTLM</code> command.
+Default is false.</TD>
+</TR>
+
+<TR>
 <TD>mail.imap.proxyauth.user</TD>
 <TD>String</TD>
 <TD>If the server supports the PROXYAUTH extension, this property
@@ -332,29 +339,6 @@
 </TD>
 </TR>
 
-<!--
-<TR>
-<TD>mail.imap.auth.ntlm.unicode</TD>
-<TD>boolean</TD>
-<TD>
-Set this to "true" if the username or password may use
-Unicode UTF-8 encoded characters. Default is "true".
-Currently has no effect.
-</TD>
-</TR>
-
-<TR>
-<TD>mail.imap.auth.ntlm.lmcompat</TD>
-<TD>int</TD>
-<TD>
-Sets the LM compatibility level, as described here:
-<A HREF="http://curl.haxx.se/rfc/ntlm.html#ntlmVersion2" TARGET="_top">
-http://curl.haxx.se/rfc/ntlm.html#ntlmVersion2</A>
-Defaults to "3". Currently not used.
-</TD>
-</TR>
--->
-
 <TR>
 <TD>mail.imap.socketFactory</TD>
 <TD>SocketFactory</TD>


diff -r 6d27e3a3d83b -r 668af76305fd mail/src/main/java/com/sun/mail/imap/IMAPFolder.java
--- a/mail/src/main/java/com/sun/mail/imap/IMAPFolder.java Tue Mar 02 10:13:34 2010 -0800
+++ b/mail/src/main/java/com/sun/mail/imap/IMAPFolder.java Fri Mar 05 15:28:53 2010 -0800
@@ -1572,6 +1572,9 @@
 
     /**
      * Expunge the indicated messages, which must have been marked as DELETED.
+ *
+ * Depends on the UIDPLUS extension -
+ * <A HREF="http://www.ietf.org/rfc/rfc2359.txt">RFC 2359</A>.
      */
     public synchronized Message[] expunge(Message[] msgs)
                                 throws MessagingException {


diff -r 668af76305fd -r 7b9ef4c947c9 doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Fri Mar 05 15:28:53 2010 -0800
+++ b/doc/release/CHANGES.txt Fri Mar 05 15:29:55 2010 -0800
@@ -40,6 +40,8 @@
 <no id> ignore encoding for composite content when writing message
 <no id> cache POP3 content using java.lang.ref.SoftReference,
         set mail.pop3.keepmessagecontent to true to disable
+<no id> add POP3 PIPELINING support
+<no id> reduce POP3 memory usage, especially if server supports pipelining
 
 
                   CHANGES IN THE 1.4.3 RELEASE

diff -r 668af76305fd -r 7b9ef4c947c9 mail/src/main/java/com/sun/mail/pop3/Protocol.java
--- a/mail/src/main/java/com/sun/mail/pop3/Protocol.java Fri Mar 05 15:28:53 2010 -0800
+++ b/mail/src/main/java/com/sun/mail/pop3/Protocol.java Fri Mar 05 15:29:55 2010 -0800
@@ -40,6 +40,7 @@
 import java.net.*;
 import java.io.*;
 import java.security.*;
+import javax.net.ssl.SSLSocket;
 
 import com.sun.mail.util.LineInputStream;
 import com.sun.mail.util.SocketFetcher;
@@ -67,12 +68,16 @@
     private String prefix; // protocol name prefix, for props
     private DataInputStream input; // input buf
     private PrintWriter output; // output buf
- private static final int POP3_PORT = 110; // standard POP3 port
- private static final String CRLF = "\r\n";
     private boolean debug = false;
     private PrintStream out;
     private String apopChallenge = null;
     private Map capabilities = null;
+ private boolean pipelining;
+
+ private static final int POP3_PORT = 110; // standard POP3 port
+ private static final String CRLF = "\r\n";
+ // sometimes the returned size isn't quite big enough
+ private static final int SLOP = 128;
 
     /**
      * Open a connection to the POP3 server.
@@ -86,10 +91,8 @@
         this.props = props;
         this.prefix = prefix;
         Response r;
- boolean enableAPOP = PropUtil.getBooleanProperty(props,
- prefix + ".apop.enable", false);
- boolean disableCapa = PropUtil.getBooleanProperty(props,
- prefix + ".disablecapa", false);
+ boolean enableAPOP = getBoolProp(props, prefix + ".apop.enable");
+ boolean disableCapa = getBoolProp(props, prefix + ".disablecapa");
         try {
             if (port == -1)
                 port = POP3_PORT;
@@ -127,6 +130,23 @@
         // if server supports RFC 2449, set capabilities
         if (!disableCapa)
             setCapabilities(capa());
+
+ pipelining = hasCapability("PIPELINING") ||
+ PropUtil.getBooleanProperty(props, prefix + ".pipelining", false);
+ if (pipelining && debug)
+ out.println("DEBUG POP3: PIPELINING enabled");
+ }
+
+ /**
+ * Get the value of a boolean property.
+ * Print out the value if debug is set.
+ */
+ private final synchronized boolean getBoolProp(Properties props,
+ String prop) {
+ boolean val = PropUtil.getBooleanProperty(props, prop, false);
+ if (debug)
+ out.println("DEBUG POP3: " + prop + ": " + val);
+ return val;
     }
 
     private void initStreams() throws IOException {
@@ -194,11 +214,29 @@
     synchronized String login(String user, String password)
                                         throws IOException {
         Response r;
+ // only pipeline password if connection is secure
+ boolean batch = pipelining && socket instanceof SSLSocket;
         String dpw = null;
         if (apopChallenge != null)
             dpw = getDigest(password);
         if (apopChallenge != null && dpw != null) {
             r = simpleCommand("APOP " + user + " " + dpw);
+ } else if (batch) {
+ String cmd = "USER " + user;
+ batchCommandStart(cmd);
+ issueCommand(cmd);
+ cmd = "PASS " + password;
+ batchCommandContinue(cmd);
+ issueCommand(cmd);
+ r = readResponse();
+ if (!r.ok) {
+ String err = r.data != null ? r.data : "USER command failed";
+ r = readResponse();
+ batchCommandEnd();
+ return err;
+ }
+ r = readResponse();
+ batchCommandEnd();
         } else {
             r = simpleCommand("USER " + user);
             if (!r.ok)
@@ -338,7 +376,85 @@
      * us to share the array.
      */
     synchronized InputStream retr(int msg, int size) throws IOException {
- Response r = multilineCommand("RETR " + msg, size);
+ Response r;
+ String cmd;
+ boolean batch = size == 0 && pipelining;
+ if (batch) {
+ cmd = "LIST " + msg;
+ batchCommandStart(cmd);
+ issueCommand(cmd);
+ cmd = "RETR " + msg;
+ batchCommandContinue(cmd);
+ issueCommand(cmd);
+ r = readResponse();
+ if (r.ok && r.data != null) {
+ // parse the LIST response to get the message size
+ try {
+ StringTokenizer st = new StringTokenizer(r.data);
+ st.nextToken(); // skip message number
+ size = Integer.parseInt(st.nextToken());
+ // don't allow ridiculous sizes
+ if (size > 1024*1024*1024 || size < 0)
+ size = 0;
+ else {
+ if (debug)
+ out.println(
+ "DEBUG POP3: pipeline message size " + size);
+ size += SLOP;
+ }
+ } catch (Exception e) {
+ }
+ }
+ r = readResponse();
+ if (r.ok)
+ r.bytes = readMultilineResponse(size + SLOP);
+ batchCommandEnd();
+ } else {
+ cmd = "RETR " + msg;
+ multilineCommandStart(cmd);
+ issueCommand(cmd);
+ r = readResponse();
+ if (!r.ok) {
+ multilineCommandEnd();
+ return null;
+ }
+
+ /*
+ * Many servers return a response to the RETR command of the form:
+ * +OK 832 octets
+ * If we don't have a size guess already, try to parse the response
+ * for data in that format and use it if found. It's only a guess,
+ * but it might be a good guess.
+ */
+ if (size <= 0 && r.data != null) {
+ try {
+ StringTokenizer st = new StringTokenizer(r.data);
+ String s = st.nextToken();
+ String octets = st.nextToken();
+ if (octets != null && octets.equals("octets")) {
+ size = Integer.parseInt(s);
+ // don't allow ridiculous sizes
+ if (size > 1024*1024*1024 || size < 0)
+ size = 0;
+ else {
+ if (debug)
+ out.println(
+ "DEBUG POP3: guessing message size: " +
+ size);
+ size += SLOP;
+ }
+ }
+ } catch (Exception e) {
+ }
+ }
+ r.bytes = readMultilineResponse(size);
+ multilineCommandEnd();
+ }
+ if (r.ok) {
+ if (debug && size > 0)
+ out.println(
+ "DEBUG POP3: got message size " + r.bytes.available());
+ }
         return r.bytes;
     }
 
@@ -347,7 +463,10 @@
      * specified OutputStream. Return true on success.
      */
     synchronized boolean retr(int msg, OutputStream os) throws IOException {
- Response r = simpleCommand("RETR " + msg);
+ String cmd = "RETR " + msg;
+ multilineCommandStart(cmd);
+ issueCommand(cmd);
+ Response r = readResponse();
         if (!r.ok) {
             multilineCommandEnd();
             return false;
@@ -529,18 +648,34 @@
      */
     private Response simpleCommand(String cmd) throws IOException {
         simpleCommandStart(cmd);
+ issueCommand(cmd);
+ Response r = readResponse();
+ simpleCommandEnd();
+ return r;
+ }
+
+ /**
+ * Send the specified command.
+ */
+ private void issueCommand(String cmd) throws IOException {
         if (socket == null)
             throw new IOException("Folder is closed"); // XXX
 
+ if (cmd != null) {
+ if (debug)
+ out.println("C: " + cmd);
+ cmd += CRLF;
+ output.print(cmd); // do it in one write
+ output.flush();
+ }
+ }
+
+ /**
+ * Read the response to a command.
+ */
+ private Response readResponse() throws IOException {
         String line = null;
         try {
- if (cmd != null) {
- if (debug)
- out.println("C: " + cmd);
- cmd += CRLF;
- output.print(cmd); // do it in one write
- output.flush();
- }
             line = input.readLine(); // XXX - readLine is deprecated
         } catch (InterruptedIOException iioex) {
             /*
@@ -573,7 +708,6 @@
         int i;
         if ((i = line.indexOf(' ')) >= 0)
             r.data = line.substring(i + 1);
- simpleCommandEnd();
         return r;
     }
 
@@ -583,12 +717,24 @@
      */
     private Response multilineCommand(String cmd, int size) throws IOException {
         multilineCommandStart(cmd);
- Response r = simpleCommand(cmd);
+ issueCommand(cmd);
+ Response r = readResponse();
         if (!r.ok) {
             multilineCommandEnd();
- return (r);
+ return r;
         }
+ r.bytes = readMultilineResponse(size);
+ multilineCommandEnd();
+ return r;
+ }
 
+ /**
+ * Read the response to a multiline command after the command response.
+ * The size parameter indicates the expected size of the response;
+ * the actual size can be different. Returns an InputStream to the
+ * response bytes.
+ */
+ private InputStream readMultilineResponse(int size) throws IOException {
         SharedByteArrayOutputStream buf = new SharedByteArrayOutputStream(size);
         int b, lastb = '\n';
         try {
@@ -614,7 +760,7 @@
             }
         } catch (InterruptedIOException iioex) {
             /*
- * As above in simpleCommand, close the socket to recover.
+ * As above in readResponse, close the socket to recover.
              */
             try {
                 socket.close();
@@ -623,9 +769,7 @@
         }
         if (b < 0)
             throw new EOFException("EOF on socket");
- r.bytes = buf.toStream();
- multilineCommandEnd();
- return r;
+ return buf.toStream();
     }
 
     /*
@@ -635,6 +779,9 @@
     private void simpleCommandEnd() { }
     private void multilineCommandStart(String command) { }
     private void multilineCommandEnd() { }
+ private void batchCommandStart(String command) { }
+ private void batchCommandContinue(String command) { }
+ private void batchCommandEnd() { }
 }
 
 /**

diff -r 668af76305fd -r 7b9ef4c947c9 mail/src/main/java/com/sun/mail/pop3/package.html
--- a/mail/src/main/java/com/sun/mail/pop3/package.html Fri Mar 05 15:28:53 2010 -0800
+++ b/mail/src/main/java/com/sun/mail/pop3/package.html Fri Mar 05 15:29:55 2010 -0800
@@ -151,6 +151,31 @@
 forgotten and fetched from the server if it's needed again, and stored again
 in the file cache.
 <P>
+The POP3 CAPA command (defined by
+<A HREF="http://www.ietf.org/rfc/rfc2449.txt" TARGET="_top">RFC 2449</A>)
+will be used to determine the capabilities supported by the server.
+Some servers don't implement the CAPA command, and some servers don't
+return correct information, so various properties are available to
+disable use of certain POP3 commands, including CAPA.
+<P>
+If the server advertises the PIPELINING capability (defined by
+<A HREF="http://www.ietf.org/rfc/rfc2449.txt" TARGET="_top">RFC 2449</A>),
+or the <CODE>mail.pop3.pipelining</CODE> property is set, the POP3
+provider will send some commands in batches, which can significantly
+improve performance and memory use.
+Some servers that don't support the CAPA command or don't advertise
+PIPELINING may still support pipelining; experimentation may be required.
+<P>
+If pipelining is supported and the connection is using
+SSL, the USER and PASS commands will be sent as a batch.
+(If SSL is not being used, the PASS command isn't sent
+until the user is verified to avoid exposing the password
+if the user name is bad.)
+<P>
+If pipelining is supported, when fetching a message with the RETR command,
+the LIST command will be sent as well, and the result will be used to size
+the I/O buffer, greatly reducing memory usage when fetching messages.
+<P>
 The POP3 protocol provider supports the following properties,
 which may be set in the JavaMail <code>Session</code> object.
 The properties are always set as strings; the Type column describes


diff -r 7b9ef4c947c9 -r 576bc3f46e81 mail/src/main/java/com/sun/mail/imap/IMAPFolder.java
--- a/mail/src/main/java/com/sun/mail/imap/IMAPFolder.java Fri Mar 05 15:29:55 2010 -0800
+++ b/mail/src/main/java/com/sun/mail/imap/IMAPFolder.java Thu Mar 18 13:53:55 2010 -0700
@@ -1177,6 +1177,8 @@
      * Return the permanent flags supported by the server.
      */
     public synchronized Flags getPermanentFlags() {
+ if (permanentFlags == null)
+ return null;
         return (Flags)(permanentFlags.clone());
     }
 

diff -r 7b9ef4c947c9 -r 576bc3f46e81 mail/src/main/java/javax/mail/Folder.java
--- a/mail/src/main/java/javax/mail/Folder.java Fri Mar 05 15:29:55 2010 -0800
+++ b/mail/src/main/java/javax/mail/Folder.java Thu Mar 18 13:53:55 2010 -0700
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 1997-2010 Sun Microsystems, Inc. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
  * General Public License Version 2 only ("GPL") or the Common Development
@@ -643,7 +643,7 @@
      * Get the permanent flags supported by this Folder. Returns a Flags
      * object that contains all the flags supported. <p>
      *
- * The special flag <code>Flags.USER </code> indicates that this Folder
+ * The special flag <code>Flags.Flag.USER </code> indicates that this Folder
      * supports arbitrary user-defined flags. <p>
      *
      * The supported permanent flags for a folder may not be available


diff -r 576bc3f46e81 -r 9ecda98ff0d4 doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Thu Mar 18 13:53:55 2010 -0700
+++ b/doc/release/CHANGES.txt Tue Apr 06 13:39:03 2010 -0700
@@ -42,6 +42,7 @@
         set mail.pop3.keepmessagecontent to true to disable
 <no id> add POP3 PIPELINING support
 <no id> reduce POP3 memory usage, especially if server supports pipelining
+<no id> add support for IMAP SORT extension (RFC 5256) to IMAPFolder
 
 
                   CHANGES IN THE 1.4.3 RELEASE

diff -r 576bc3f46e81 -r 9ecda98ff0d4 mail/src/main/java/com/sun/mail/imap/IMAPFolder.java
--- a/mail/src/main/java/com/sun/mail/imap/IMAPFolder.java Thu Mar 18 13:53:55 2010 -0700
+++ b/mail/src/main/java/com/sun/mail/imap/IMAPFolder.java Tue Apr 06 13:39:03 2010 -0700
@@ -1719,6 +1719,58 @@
         }
     }
 
+ /**
+ * Sort the messages in the folder according to the sort criteria.
+ * The messages are returned in the sorted order, but the order of
+ * the messages in the folder is not changed.
+ *
+ * @since JavaMail 1.4.4
+ */
+ public synchronized Message[] getSortedMessages(SortTerm[] term)
+ throws MessagingException {
+ return getSortedMessages(term, null);
+ }
+
+ /**
+ * Sort the messages in the folder according to the sort criteria.
+ * The messages are returned in the sorted order, but the order of
+ * the messages in the folder is not changed. Only messages matching
+ * the search criteria are considered.
+ *
+ * @since JavaMail 1.4.4
+ */
+ public synchronized Message[] getSortedMessages(SortTerm[] term,
+ SearchTerm sterm) throws MessagingException {
+ checkOpened();
+
+ try {
+ Message[] matchMsgs = null;
+
+ synchronized(messageCacheLock) {
+ int[] matches = getProtocol().sort(term, sterm);
+ if (matches != null) {
+ matchMsgs = new IMAPMessage[matches.length];
+ // Map seq-numbers into actual Messages.
+ for (int i = 0; i < matches.length; i++)
+ matchMsgs[i] = getMessageBySeqNumber(matches[i]);
+ }
+ }
+ return matchMsgs;
+
+ } catch (CommandFailedException cfx) {
+ // unsupported charset or search criterion
+ throw new MessagingException(cfx.getMessage(), cfx);
+ } catch (SearchException sex) {
+ // too complex for IMAP
+ throw new MessagingException(sex.getMessage(), sex);
+ } catch (ConnectionException cex) {
+ throw new FolderClosedException(this, cex.getMessage());
+ } catch (ProtocolException pex) {
+ // bug in our IMAP layer ?
+ throw new MessagingException(pex.getMessage(), pex);
+ }
+ }
+
     /*
      * Override Folder method to keep track of whether we have any
      * message count listeners. Normally we won't have any, so we

diff -r 576bc3f46e81 -r 9ecda98ff0d4 mail/src/main/java/com/sun/mail/imap/SortTerm.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mail/src/main/java/com/sun/mail/imap/SortTerm.java Tue Apr 06 13:39:03 2010 -0700
@@ -0,0 +1,99 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2010 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can obtain
+ * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
+ * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
+ * Sun designates this particular file as subject to the "Classpath" exception
+ * as provided by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the License
+ * Header, with the fields enclosed by brackets [] replaced by your own
+ * identifying information: "Portions Copyrighted [year]
+ * [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package com.sun.mail.imap;
+
+/**
+ * A particular sort criteria, as defined by
+ * <A HREF="http://www.ietf.org/rfc/rfc5256.txt">RFC 5256</A>.
+ * Sort criteria are used with the {_at_link IMAPFolder#sort sort} method.
+ * Multiple sort criteria are specified in an array with the order in
+ * the array specifying the order in which the sort criteria are applied.
+ *
+ * @since JavaMail 1.4.4
+ */
+public final class SortTerm {
+ /**
+ * Sort by message arrival date and time.
+ */
+ public static final SortTerm ARRIVAL = new SortTerm("ARRIVAL");
+
+ /**
+ * Sort by email address of first Cc recipient.
+ */
+ public static final SortTerm CC = new SortTerm("CC");
+
+ /**
+ * Sort by sent date and time.
+ */
+ public static final SortTerm DATE = new SortTerm("DATE");
+
+ /**
+ * Sort by first From email address.
+ */
+ public static final SortTerm FROM = new SortTerm("FROM");
+
+ /**
+ * Reverse the sort order of the following item.
+ */
+ public static final SortTerm REVERSE = new SortTerm("REVERSE");
+
+ /**
+ * Sort by the message size.
+ */
+ public static final SortTerm SIZE = new SortTerm("SIZE");
+
+ /**
+ * Sort by the base subject text. Note that the "base subject"
+ * is defined by RFC 5256 and doesn't include items such as "Re:"
+ * in the subject header.
+ */
+ public static final SortTerm SUBJECT = new SortTerm("SUBJECT");
+
+ /**
+ * Sort by email address of first To recipient.
+ */
+ public static final SortTerm TO = new SortTerm("TO");
+
+ private String term;
+ private SortTerm(String term) {
+ this.term = term;
+ }
+
+ public String toString() {
+ return term;
+ }
+}

diff -r 576bc3f46e81 -r 9ecda98ff0d4 mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java
--- a/mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java Thu Mar 18 13:53:55 2010 -0700
+++ b/mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java Tue Apr 06 13:39:03 2010 -0700
@@ -52,6 +52,7 @@
 import com.sun.mail.imap.ACL;
 import com.sun.mail.imap.Rights;
 import com.sun.mail.imap.AppendUID;
+import com.sun.mail.imap.SortTerm;
 
 /**
  * This class extends the iap.Protocol object and implements IMAP
@@ -267,6 +268,15 @@
      * returns false.
      */
     public boolean hasCapability(String c) {
+ if (c.endsWith("*")) {
+ c = c.substring(0, c.length() - 1).toUpperCase(Locale.ENGLISH);
+ Iterator it = capabilities.keySet().iterator();
+ while (it.hasNext()) {
+ if (((String)it.next()).startsWith(c))
+ return true;
+ }
+ return false;
+ }
         return capabilities.containsKey(c.toUpperCase(Locale.ENGLISH));
     }
 
@@ -1570,7 +1580,8 @@
         return search("ALL", term);
     }
 
- /* Apply the given SearchTerm on the specified sequence.
+ /*
+ * Apply the given SearchTerm on the specified sequence.
      * Returns array of matching sequence numbers. Note that an empty
      * array is returned for no matches.
      */
@@ -1676,6 +1687,78 @@
     }
 
     /**
+ * Sort messages in the folder according to the specified sort criteria.
+ * If the search term is not null, limit the sort to only the messages
+ * that match the search term.
+ * Returns an array of sorted sequence numbers. An empty array
+ * is returned if no matches are found.
+ *
+ * @param term sort criteria
+ * @param sterm SearchTerm
+ * @return array of matching sequence numbers.
+ *
+ * @see "RFC 5256"
+ * @since JavaMail 1.4.4
+ */
+ public int[] sort(SortTerm[] term, SearchTerm sterm)
+ throws ProtocolException, SearchException {
+ if (!hasCapability("SORT*"))
+ throw new BadCommandException("SORT not supported");
+
+ if (term == null || term.length == 0)
+ throw new BadCommandException("Must have at least one sort term");
+
+ Argument args = new Argument();
+ Argument sargs = new Argument();
+ for (int i = 0; i < term.length; i++)
+ sargs.writeAtom(term[i].toString());
+ args.writeArgument(sargs); // sort criteria
+
+ args.writeAtom("UTF-8"); // charset specification
+ if (sterm != null) {
+ try {
+ args.append(SearchSequence.generateSequence(sterm, "UTF-8"));
+ } catch (IOException ioex) {
+ // should never happen
+ throw new SearchException(ioex.toString());
+ }
+ } else
+ args.writeAtom("ALL");
+
+ Response[] r = command("SORT", args);
+ Response response = r[r.length-1];
+ int[] matches = null;
+
+ // Grab all SORT responses
+ if (response.isOK()) { // command succesful
+ Vector v = new Vector();
+ int num;
+ for (int i = 0, len = r.length; i < len; i++) {
+ if (!(r[i] instanceof IMAPResponse))
+ continue;
+
+ IMAPResponse ir = (IMAPResponse)r[i];
+ if (ir.keyEquals("SORT")) {
+ while ((num = ir.readNumber()) != -1)
+ v.addElement(new Integer(num));
+ r[i] = null;
+ }
+ }
+
+ // Copy the vector into 'matches'
+ int vsize = v.size();
+ matches = new int[vsize];
+ for (int i = 0; i < vsize; i++)
+ matches[i] = ((Integer)v.elementAt(i)).intValue();
+ }
+
+ // dispatch remaining untagged responses
+ notifyResponseHandlers(r);
+ handleResult(response);
+ return matches;
+ }
+
+ /**
      * NAMESPACE Command.
      *
      * @see "RFC2342"


diff -r 9ecda98ff0d4 -r cefd72fcf049 mail/src/main/java/overview.html
--- a/mail/src/main/java/overview.html Tue Apr 06 13:39:03 2010 -0700
+++ b/mail/src/main/java/overview.html Wed Apr 07 17:27:50 2010 -0700
@@ -52,7 +52,7 @@
 The JavaMail API includes the <code>javax.mail</code> package and subpackages.
 <P>
 For an overview of the JavaMail API, read the JavaMail specification
-<A HREF="../../../JavaMail-1.4.pdf" TARGET="_top">
+<A HREF="../JavaMail-1.4.pdf" TARGET="_top">
 included in the download bundle</A> or
 <A HREF="http://java.sun.com/products/javamail/JavaMail-1.4.pdf" TARGET="_top">
 available on the JavaMail web site</A>.


diff -r cefd72fcf049 -r ad69e3e3d40a javadoc/pom.xml
--- a/javadoc/pom.xml Wed Apr 07 17:27:50 2010 -0700
+++ b/javadoc/pom.xml Wed Apr 07 23:51:32 2010 -0700
@@ -83,6 +83,7 @@
                         com/sun/mail/imap/ACL.java,
                         com/sun/mail/imap/Rights.java,
                         com/sun/mail/imap/Quota.java,
+ com/sun/mail/imap/SortTerm.java,
                         com/sun/mail/pop3/POP3Store.java,
                         com/sun/mail/pop3/POP3SSLStore.java,
                         com/sun/mail/pop3/POP3Folder.java,


diff -r ad69e3e3d40a -r 3fb9d94b00dc assembly.xml
--- a/assembly.xml Wed Apr 07 23:51:32 2010 -0700
+++ b/assembly.xml Wed Apr 07 23:53:33 2010 -0700
@@ -2,7 +2,7 @@
 <!--
     DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 
- Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
+ Copyright 1997-2010 Sun Microsystems, Inc. All rights reserved.
 
     The contents of this file are subject to the terms of either the GNU
     General Public License Version 2 only ("GPL") or the Common Development
@@ -193,6 +193,21 @@
             </sources>
         </moduleSet>
 
+ <moduleSet>
+ <includes>
+ <include>com.sun.mail:outlook</include>
+ </includes>
+ <sources>
+ <includeModuleDirectory>false</includeModuleDirectory>
+ <fileSets>
+ <fileSet>
+ <directory>src/main/java</directory>
+ <outputDirectory>demo/outlook</outputDirectory>
+ </fileSet>
+ </fileSets>
+ </sources>
+ </moduleSet>
+
     </moduleSets>
 
     <!-- include docs, specs, and javadocs -->

diff -r ad69e3e3d40a -r 3fb9d94b00dc doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Wed Apr 07 23:51:32 2010 -0700
+++ b/doc/release/CHANGES.txt Wed Apr 07 23:53:33 2010 -0700
@@ -43,6 +43,7 @@
 <no id> add POP3 PIPELINING support
 <no id> reduce POP3 memory usage, especially if server supports pipelining
 <no id> add support for IMAP SORT extension (RFC 5256) to IMAPFolder
+<no id> add demo classes to support non-MIME messages from Outlook
 
 
                   CHANGES IN THE 1.4.3 RELEASE

diff -r ad69e3e3d40a -r 3fb9d94b00dc doc/release/README.txt
--- a/doc/release/README.txt Wed Apr 07 23:51:32 2010 -0700
+++ b/doc/release/README.txt Wed Apr 07 23:53:33 2010 -0700
@@ -130,6 +130,8 @@
                         README file that describes the JavaMailServlet
     demo/logging/ source files for demo program showing use of the
                         com.sun.mail.util.logging.MailHandler class
+ demo/outlook/ source files for demo classes showing how to handle
+ old non-MIME messages generated by Outlook
 
 
 Requirements

diff -r ad69e3e3d40a -r 3fb9d94b00dc outlook/pom.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/outlook/pom.xml Wed Apr 07 23:53:33 2010 -0700
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!--
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright 1997-2010 Sun Microsystems, Inc. All rights reserved.
+
+ The contents of this file are subject to the terms of either the GNU
+ General Public License Version 2 only ("GPL") or the Common Development
+ and Distribution License("CDDL") (collectively, the "License"). You
+ may not use this file except in compliance with the License. You can obtain
+ a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
+ or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
+ language governing permissions and limitations under the License.
+
+ When distributing the software, include this License Header Notice in each
+ file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
+ Sun designates this particular file as subject to the "Classpath" exception
+ as provided by Sun in the GPL Version 2 section of the License file that
+ accompanied this code. If applicable, add the following below the License
+ Header, with the fields enclosed by brackets [] replaced by your own
+ identifying information: "Portions Copyrighted [year]
+ [name of copyright owner]"
+
+ Contributor(s):
+
+ If you wish your version of this file to be governed by only the CDDL or
+ only the GPL Version 2, indicate your decision by adding "[Contributor]
+ elects to include this software in this distribution under the [CDDL or GPL
+ Version 2] license." If you don't indicate a single choice of license, a
+ recipient has the option to distribute your version of this file under
+ either the CDDL, the GPL Version 2 or to extend the choice of license to
+ its licensees as provided above. However, if you add GPL Version 2 code
+ and therefore, elected the GPL Version 2 license, then the option applies
+ only if the new code is made subject to such option by the copyright
+ holder.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+ http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>com.sun.mail</groupId>
+ <artifactId>all</artifactId>
+ <version>1.4.4-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.sun.mail</groupId>
+ <artifactId>outlook</artifactId>
+ <packaging>jar</packaging>
+ <name>JavaMail API demo Outlook message support</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>javax.mail</groupId>
+ <artifactId>mail</artifactId>
+ </dependency>
+ </dependencies>
+</project>

diff -r ad69e3e3d40a -r 3fb9d94b00dc outlook/src/main/java/MSBodyPart.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/outlook/src/main/java/MSBodyPart.java Wed Apr 07 23:53:33 2010 -0700
@@ -0,0 +1,122 @@
+/*
+ * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Sun Microsystems nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.io.*;
+import javax.activation.*;
+import javax.mail.*;
+import javax.mail.internet.*;
+
+/**
+ * A special MimeBodyPart used with MSMessage.
+ *
+ * @author John Mani
+ * @author Bill Shannon
+ */
+public class MSBodyPart extends MimeBodyPart {
+ private int start;
+ private int end;
+ private String type = UNKNOWN;
+ private String disposition;
+ private String encoding;
+ private String filename = UNKNOWN;
+
+ private static final String UNKNOWN = "UNKNOWN";
+
+ public MSBodyPart(byte[] content, int start, int end,
+ String disposition, String encoding) {
+ this.content = content;
+ this.start = start;
+ this.end = end;
+ this.disposition = disposition;
+ this.encoding = encoding;
+ }
+
+ public String getContentType() throws MessagingException {
+ // try to figure this out from the filename extension
+ if (type == UNKNOWN)
+ processBegin();
+ return type;
+ }
+
+ public String getEncoding() throws MessagingException {
+ return encoding;
+ }
+
+ public String getDisposition() throws MessagingException {
+ return disposition;
+ }
+
+ public String getFileName() throws MessagingException {
+ // get filename from the "begin" line
+ if (filename == UNKNOWN)
+ processBegin();
+ return filename;
+ }
+
+ protected InputStream getContentStream() {
+ return new ByteArrayInputStream(content, start, end - start);
+ }
+
+ /**
+ * Process the "begin" line to extract the filename,
+ * and from it determine the Content-Type.
+ */
+ private void processBegin() {
+ InputStream in = getContentStream();
+ try {
+ BufferedReader r = new BufferedReader(new InputStreamReader(in));
+ String begin = r.readLine();
+ // format is "begin 666 filename.txt"
+ if (begin.regionMatches(true, 0, "begin ", 0, 6)) {
+ int i = begin.indexOf(' ', 6);
+ if (i > 0) {
+ filename = begin.substring(i + 1);
+ FileTypeMap map = FileTypeMap.getDefaultFileTypeMap();
+ type = map.getContentType(filename);
+ if (type == null)
+ type = "application/octet-stream";
+ }
+ }
+ } catch (IOException ex) {
+ // ignore
+ } finally {
+ try {
+ in.close();
+ } catch (IOException ex) {
+ // ignore it
+ }
+ if (filename == UNKNOWN)
+ filename = null;
+ if (type == UNKNOWN || type == null)
+ type = "text/plain";
+ }
+ }
+}

diff -r ad69e3e3d40a -r 3fb9d94b00dc outlook/src/main/java/MSMessage.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/outlook/src/main/java/MSMessage.java Wed Apr 07 23:53:33 2010 -0700
@@ -0,0 +1,234 @@
+/*
+ * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Sun Microsystems nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.io.*;
+import javax.mail.*;
+import javax.mail.internet.*;
+import javax.activation.*;
+
+/**
+ * This class models a UUEncoded Message sent from MS Outlook etc. <p>
+ *
+ * The message structure looks like this :=
+ * [text body] [uuencoded attachment]*
+ * <p>
+ * i.e., an optional text/plain main-body, followed by zero or more
+ * UUENCODE-ed attachments.
+ *
+ * @author John Mani
+ * @author Bill Shannon
+ * @see javax.mail.internet.MimeMessage
+ */
+
+public class MSMessage extends MimeMessage {
+ private String type;
+
+ /**
+ * Constructor that converts a MimeMessage object into a MSMessage.
+ *
+ * @exception MessagingException if the given MimeMessage
+ * is not a non-MIME MS message, or if an
+ * IOException occurs when accessing the given
+ * MimeMessage object
+ */
+ public MSMessage(Session session, MimeMessage msg)
+ throws MessagingException {
+ super(session);
+
+ if (!isMSMessage(msg)) // sanity check
+ throw new MessagingException("Not an MS message");
+
+ class FastByteArrayOutputStream extends ByteArrayOutputStream {
+ ByteArrayInputStream toByteArrayInputStream() {
+ return new ByteArrayInputStream(buf, 0, count);
+ }
+ }
+
+ // extract the bytes of the given message
+ // ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ FastByteArrayOutputStream bos = new FastByteArrayOutputStream();
+ try {
+ msg.writeTo(bos);
+ } catch (IOEx
[truncated due to length]