diff -r bc39523cca98 -r abe1b4c57038 mail/src/main/java/com/sun/mail/imap/IMAPMessage.java --- a/mail/src/main/java/com/sun/mail/imap/IMAPMessage.java Mon Jul 02 11:50:56 2012 -0700 +++ b/mail/src/main/java/com/sun/mail/imap/IMAPMessage.java Wed Jul 25 00:49:07 2012 +0200 @@ -40,20 +40,56 @@ package com.sun.mail.imap; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; import java.util.Date; -import java.io.*; import java.util.Enumeration; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.Locale; +import java.util.Map; import java.util.Vector; -import java.util.Hashtable; -import java.util.Locale; -import javax.mail.*; -import javax.mail.internet.*; -import javax.activation.*; +import javax.activation.DataHandler; +import javax.mail.Address; +import javax.mail.FetchProfile; +import javax.mail.Flags; +import javax.mail.FolderClosedException; +import javax.mail.Header; +import javax.mail.IllegalWriteException; +import javax.mail.Message; +import javax.mail.MessageRemovedException; +import javax.mail.MessagingException; +import javax.mail.Session; +import javax.mail.UIDFolder; +import javax.mail.internet.ContentType; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.InternetHeaders; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeUtility; -import com.sun.mail.util.*; -import com.sun.mail.iap.*; -import com.sun.mail.imap.protocol.*; +import com.sun.mail.iap.CommandFailedException; +import com.sun.mail.iap.ConnectionException; +import com.sun.mail.iap.ProtocolException; +import com.sun.mail.iap.Response; +import com.sun.mail.imap.protocol.BODY; +import com.sun.mail.imap.protocol.BODYSTRUCTURE; +import com.sun.mail.imap.protocol.ENVELOPE; +import com.sun.mail.imap.protocol.FetchCommandBuilder; +import com.sun.mail.imap.protocol.FetchExtensions; +import com.sun.mail.imap.protocol.FetchResponse; +import com.sun.mail.imap.protocol.IMAPProtocol; +import com.sun.mail.imap.protocol.INTERNALDATE; +import com.sun.mail.imap.protocol.Item; +import com.sun.mail.imap.protocol.MessageSet; +import com.sun.mail.imap.protocol.RFC822DATA; +import com.sun.mail.imap.protocol.RFC822SIZE; +import com.sun.mail.imap.protocol.UID; +import com.sun.mail.util.ReadableMime; /** * This class implements an IMAPMessage object.

@@ -115,6 +151,8 @@ // This is our Envelope private static String EnvelopeCmd = "ENVELOPE INTERNALDATE RFC822.SIZE"; + private Map customItems = new HashMap(); + /** * Constructor. */ @@ -974,8 +1012,9 @@ private boolean needHeaders = false; private boolean needSize = false; private String[] hdrs = null; + private List neededBuilders; - public FetchProfileCondition(FetchProfile fp) { + public FetchProfileCondition(FetchProfile fp, List neededBuilders) { if (fp.contains(FetchProfile.Item.ENVELOPE)) needEnvelope = true; if (fp.contains(FetchProfile.Item.FLAGS)) @@ -989,6 +1028,7 @@ if (fp.contains(IMAPFolder.FetchProfileItem.SIZE)) needSize = true; hdrs = fp.getHeaderNames(); + this.neededBuilders = neededBuilders; } // The actual test. @@ -1011,43 +1051,40 @@ if (!m.isHeaderLoaded(hdrs[i])) return true; // Nope, return } + for (FetchCommandBuilder builder: neededBuilders) { + if (builder.needFetch(m)) { + return true; + } + } return false; } } - StringBuffer command = new StringBuffer(); - boolean first = true; + DelimitedStringBuilder command = new DelimitedStringBuilder(); boolean allHeaders = false; if (fp.contains(FetchProfile.Item.ENVELOPE)) { command.append(EnvelopeCmd); - first = false; } if (fp.contains(FetchProfile.Item.FLAGS)) { - command.append(first ? "FLAGS" : " FLAGS"); - first = false; + command.append("FLAGS"); } if (fp.contains(FetchProfile.Item.CONTENT_INFO)) { - command.append(first ? "BODYSTRUCTURE" : " BODYSTRUCTURE"); - first = false; + command.append("BODYSTRUCTURE"); } if (fp.contains(UIDFolder.FetchProfileItem.UID)) { - command.append(first ? "UID" : " UID"); - first = false; + command.append("UID"); } if (fp.contains(IMAPFolder.FetchProfileItem.HEADERS)) { allHeaders = true; if (folder.protocol.isREV1()) - command.append(first ? - "BODY.PEEK[HEADER]" : " BODY.PEEK[HEADER]"); + command.append("BODY.PEEK[HEADER]"); else - command.append(first ? "RFC822.HEADER" : " RFC822.HEADER"); - first = false; + command.append("RFC822.HEADER"); } if (fp.contains(IMAPFolder.FetchProfileItem.SIZE)) { - command.append(first ? "RFC822.SIZE" : " RFC822.SIZE"); - first = false; + command.append("RFC822.SIZE"); } // if we're not fetching all headers, fetch individual headers @@ -1055,13 +1092,26 @@ if (!allHeaders) { hdrs = fp.getHeaderNames(); if (hdrs.length > 0) { - if (!first) - command.append(" "); command.append(craftHeaderCmd(folder.protocol, hdrs)); } } - - Utility.Condition condition = new FetchProfileCondition(fp); + FetchExtensions ext = FetchExtensions.getInstance(); + for (FetchCommandBuilder b : ext.getCommandBuilders()) { + String contrib = b.getCommandFragment(fp); + if (contrib != null) { + command.append(contrib); + } + } + javax.mail.FetchProfile.Item[] items = fp.getItems(); + List neededBuilders = new ArrayList (); + for (FetchProfile.Item item: items) { + FetchCommandBuilder builder = ext.getCommandBuilder(item); + if (builder != null) { + neededBuilders.add(builder); + } + } + + Utility.Condition condition = new FetchProfileCondition(fp, neededBuilders); // Acquire the Folder's MessageCacheLock. synchronized(folder.messageCacheLock) { @@ -1192,6 +1242,8 @@ for (int k = 0; k < hdrs.length; k++) msg.setHeaderLoaded(hdrs[k]); } + } else { + msg.customItems.put(item.getClass().getName(), item); } } @@ -1211,6 +1263,30 @@ } // Release messageCacheLock } + + static class DelimitedStringBuilder { + StringBuilder builder = new StringBuilder(); + boolean first = true; + + public void append(String str) { + if (first) { + first = false; + } else { + builder.append(' '); + } + builder.append(str); + } + + @Override + public String toString() { + return builder.toString(); + } + } + + public Item getCustomItem(Class cls) { + return customItems.get(cls.getName()); + } + /* * Load the Envelope for this message. diff -r bc39523cca98 -r abe1b4c57038 mail/src/main/java/com/sun/mail/imap/protocol/FetchCommandBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mail/src/main/java/com/sun/mail/imap/protocol/FetchCommandBuilder.java Wed Jul 25 00:49:07 2012 +0200 @@ -0,0 +1,15 @@ +package com.sun.mail.imap.protocol; + +import javax.mail.FetchProfile; + +import com.sun.mail.imap.IMAPMessage; + +public interface FetchCommandBuilder { + + FetchProfile.Item getResponsibleFor(); + + String getCommandFragment(FetchProfile profile); + + boolean needFetch(IMAPMessage alreadyLoaded); + +} diff -r bc39523cca98 -r abe1b4c57038 mail/src/main/java/com/sun/mail/imap/protocol/FetchExtensions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mail/src/main/java/com/sun/mail/imap/protocol/FetchExtensions.java Wed Jul 25 00:49:07 2012 +0200 @@ -0,0 +1,151 @@ +package com.sun.mail.imap.protocol; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; + +import javax.mail.FetchProfile; + +import com.sun.mail.iap.ParsingException; + +public class FetchExtensions { + + private static FetchExtensions instance; + + private final static char[] RFC822DATA_HEADER = (new String(RFC822DATA.name) + ".HEADER").toCharArray(); + private final static char[] RFC822DATA_TEXT = (new String(RFC822DATA.name) + ".TEXT").toCharArray(); + + + final List itemBuilders = new ArrayList(); + final Map> firstCharLists = new HashMap>(); + final Map commandBuilders = new HashMap(); + final List commandBuilderList = new ArrayList(); + + static abstract class BaseItemBuilder implements ItemBuilder { + final char[] name; + + BaseItemBuilder(char[] nm) { + this.name = nm; + } + BaseItemBuilder(String nm) { + this.name = nm.toCharArray(); + } + + @Override + public char[] getName() { + return name; + } + + @Override + public String toString() { + return "ItemBuilder[ " + String.valueOf(name)+ ']'; + } + } + + + + protected FetchExtensions() { + itemBuilders.add(new BaseItemBuilder(BODY.name) { + @Override + public Item build(FetchResponse response) throws ParsingException { + return new BODY(response); + } + }); + itemBuilders.add(new BaseItemBuilder(ENVELOPE.name) { + @Override + public Item build(FetchResponse response) throws ParsingException { + return new ENVELOPE(response); + } + }); + itemBuilders.add(new BaseItemBuilder(FLAGS.name) { + @Override + public Item build(FetchResponse response) throws ParsingException { + return new FLAGS(response); + } + }); + itemBuilders.add(new BaseItemBuilder(INTERNALDATE.name) { + @Override + public Item build(FetchResponse response) throws ParsingException { + return new INTERNALDATE(response); + } + }); + itemBuilders.add(new BaseItemBuilder(BODYSTRUCTURE.name) { + @Override + public Item build(FetchResponse response) throws ParsingException { + return new BODYSTRUCTURE(response); + } + }); + itemBuilders.add(new BaseItemBuilder(RFC822SIZE.name) { + @Override + public Item build(FetchResponse response) throws ParsingException { + return new RFC822SIZE(response); + } + }); + itemBuilders.add(new BaseItemBuilder(RFC822DATA_HEADER) { + @Override + public Item build(FetchResponse response) throws ParsingException { + return new RFC822DATA(response); + } + }); + itemBuilders.add(new BaseItemBuilder(RFC822DATA_TEXT) { + @Override + public Item build(FetchResponse response) throws ParsingException { + return new RFC822DATA(response); + } + }); + itemBuilders.add(new BaseItemBuilder(UID.name) { + @Override + public Item build(FetchResponse response) throws ParsingException { + return new UID(response); + } + }); + ServiceLoader loader = ServiceLoader.load(ItemBuilder.class); + for (ItemBuilder additional : loader) { + itemBuilders.add(additional); + } + for (ItemBuilder b : itemBuilders) { + Character firstCharacter = Character.valueOf(b.getName()[0]); + List list = firstCharLists.get(firstCharacter); + if (list == null) { + list = new ArrayList(); + firstCharLists.put(firstCharacter, list); + } + list.add(b); + } + ServiceLoader loader2 = ServiceLoader.load(FetchCommandBuilder.class); + for (FetchCommandBuilder b : loader2) { + commandBuilders.put(b.getResponsibleFor(), b); + commandBuilderList.add(b); + } + } + + + public List getItemBuilders() { + return itemBuilders; + } + + public List getItemBuildersStartsWith(Character ch) { + List list = firstCharLists.get(ch); + return list != null ? list : Collections.emptyList(); + } + + public List getCommandBuilders() { + return commandBuilderList; + } + + public FetchCommandBuilder getCommandBuilder(FetchProfile.Item item) { + return commandBuilders.get(item); + } + + + public static synchronized FetchExtensions getInstance() { + if (instance == null) { + instance = new FetchExtensions(); + } + return instance; + } + +} diff -r bc39523cca98 -r abe1b4c57038 mail/src/main/java/com/sun/mail/imap/protocol/FetchResponse.java --- a/mail/src/main/java/com/sun/mail/imap/protocol/FetchResponse.java Mon Jul 02 11:50:56 2012 -0700 +++ b/mail/src/main/java/com/sun/mail/imap/protocol/FetchResponse.java Wed Jul 25 00:49:07 2012 +0200 @@ -42,6 +42,7 @@ import java.io.*; import java.util.*; + import com.sun.mail.util.*; import com.sun.mail.iap.*; @@ -105,84 +106,34 @@ return null; } - private final static char[] HEADER = {'.','H','E','A','D','E','R'}; - private final static char[] TEXT = {'.','T','E','X','T'}; - - private void parse() throws ParsingException { skipSpaces(); if (buffer[index] != '(') throw new ParsingException( "error in FETCH parsing, missing '(' at index " + index); + FetchExtensions itemBuilders = FetchExtensions.getInstance(); Vector v = new Vector(); - Item i = null; + Item i = null; do { index++; // skip '(', or SPACE if (index >= size) throw new ParsingException( "error in FETCH parsing, ran off end of buffer, size " + size); + i = null; - switch(buffer[index]) { - case 'E': case 'e': - if (match(ENVELOPE.name)) { - index += ENVELOPE.name.length; // skip "ENVELOPE" - i = new ENVELOPE(this); - } - break; - case 'F': case 'f': - if (match(FLAGS.name)) { - index += FLAGS.name.length; // skip "FLAGS" - i = new FLAGS((IMAPResponse)this); - } - break; - case 'I': case 'i': - if (match(INTERNALDATE.name)) { - index += INTERNALDATE.name.length; // skip "INTERNALDATE" - i = new INTERNALDATE(this); - } - break; - case 'B': case 'b': - if (match(BODY.name)) { - if (buffer[index+4] == '[') { - index += BODY.name.length; // skip "BODY" - i = new BODY(this); - } - else { - if (match(BODYSTRUCTURE.name)) - index += BODYSTRUCTURE.name.length; - // skip "BODYSTRUCTURE" - else - index += BODY.name.length; // skip "BODY" - i = new BODYSTRUCTURE(this); - } - } - break; - case 'R': case 'r': - if (match(RFC822SIZE.name)) { - index += RFC822SIZE.name.length; // skip "RFC822.SIZE" - i = new RFC822SIZE(this); - } - else { - if (match(RFC822DATA.name)) { - index += RFC822DATA.name.length; - if (match(HEADER)) - index += HEADER.length; // skip ".HEADER" - else if (match(TEXT)) - index += TEXT.length; // skip ".TEXT" - i = new RFC822DATA(this); - } - } - break; - case 'U': case 'u': - if (match(UID.name)) { - index += UID.name.length; - i = new UID(this); - } - break; - default: + byte current = buffer[index]; + Character upperCase = Character.toUpperCase((char) current); + List itemBuildersStartsWith = itemBuilders.getItemBuildersStartsWith(upperCase); + for (Iterator iter = itemBuildersStartsWith.iterator(); iter.hasNext() && i == null;) { + ItemBuilder builder = iter.next(); + if (match(builder.getName())) { + index += builder.getName().length; + i = builder.build(this); + } } + if (i != null) v.addElement(i); } while (buffer[index] != ')'); @@ -203,6 +154,6 @@ // uppercase, so convert operand to uppercase before comparing. if (Character.toUpperCase((char)buffer[j++]) != itemName[i++]) return false; - return true; + return index + len >= buffer.length || !Character.isLetter(buffer[index + len]); } } diff -r bc39523cca98 -r abe1b4c57038 mail/src/main/java/com/sun/mail/imap/protocol/ItemBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mail/src/main/java/com/sun/mail/imap/protocol/ItemBuilder.java Wed Jul 25 00:49:07 2012 +0200 @@ -0,0 +1,10 @@ +package com.sun.mail.imap.protocol; + +import com.sun.mail.iap.ParsingException; + +public interface ItemBuilder { + + char[] getName(); + + Item build(FetchResponse response) throws ParsingException; +}