IMAP: experimental implementation of header only FETCH, do not download full message content and send approximate RFC822.SIZE (MAPI size)

git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@1961 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
mguessan 2012-05-16 16:07:35 +00:00
parent d6092e10df
commit 08abcc0514
7 changed files with 110 additions and 40 deletions

View File

@ -40,10 +40,7 @@ import org.htmlcleaner.TagNode;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.mail.MessagingException; import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress; import javax.mail.internet.*;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimePart;
import javax.mail.util.SharedByteArrayInputStream; import javax.mail.util.SharedByteArrayInputStream;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.*; import java.io.*;
@ -1798,6 +1795,23 @@ public abstract class ExchangeSession {
return mimeMessage; return mimeMessage;
} }
public Enumeration getMatchingHeaderLines(String[] headerNames) throws MessagingException, IOException {
Enumeration result = null;
if (mimeMessage == null) {
// message not loaded, try to get headers only
InputStream headers = getMimeHeaders();
if (headers != null) {
result = new InternetHeaders(headers).getMatchingHeaderLines(headerNames);
}
}
if (result == null) {
result = getMimeMessage().getMatchingHeaderLines(headerNames);
}
return result;
}
protected abstract InputStream getMimeHeaders();
/** /**
* Get message body size. * Get message body size.
* *

View File

@ -1078,6 +1078,21 @@ public class DavExchangeSession extends ExchangeSession {
public String getPermanentId() { public String getPermanentId() {
return permanentUrl; return permanentUrl;
} }
@Override
protected InputStream getMimeHeaders() {
InputStream result = null;
try {
String messageHeaders = getItemProperty(permanentUrl, "messageheaders");
if (messageHeaders != null) {
result = new ByteArrayInputStream(messageHeaders.getBytes("UTF-8"));
}
} catch (Exception e) {
LOGGER.warn(e.getMessage());
}
return result;
}
} }
@ -1309,32 +1324,11 @@ public class DavExchangeSession extends ExchangeSession {
protected byte[] getICSFromInternetContentProperty() throws IOException, DavException, MessagingException { protected byte[] getICSFromInternetContentProperty() throws IOException, DavException, MessagingException {
byte[] result = null; byte[] result = null;
// PropFind PR_INTERNET_CONTENT // PropFind PR_INTERNET_CONTENT
DavPropertyNameSet davPropertyNameSet = new DavPropertyNameSet(); String propertyValue = getItemProperty(permanentUrl, "internetContent");
davPropertyNameSet.add(Field.getPropertyName("internetContent"));
PropFindMethod propFindMethod = new PropFindMethod(encodeAndFixUrl(permanentUrl), davPropertyNameSet, 0);
try {
try {
DavGatewayHttpClientFacade.executeHttpMethod(httpClient, propFindMethod);
} catch (UnknownHostException e) {
propFindMethod.releaseConnection();
// failover for misconfigured Exchange server, replace host name in url
restoreHostName = true;
propFindMethod = new PropFindMethod(encodeAndFixUrl(permanentUrl), davPropertyNameSet, 0);
DavGatewayHttpClientFacade.executeHttpMethod(httpClient, propFindMethod);
}
MultiStatus responses = propFindMethod.getResponseBodyAsMultiStatus();
if (responses.getResponses().length > 0) {
DavPropertySet properties = responses.getResponses()[0].getProperties(HttpStatus.SC_OK);
String propertyValue = getPropertyIfExists(properties, "internetContent");
if (propertyValue != null) { if (propertyValue != null) {
byte[] byteArray = Base64.decodeBase64(propertyValue.getBytes()); byte[] byteArray = Base64.decodeBase64(propertyValue.getBytes());
result = getICS(new ByteArrayInputStream(byteArray)); result = getICS(new ByteArrayInputStream(byteArray));
} }
}
} finally {
propFindMethod.releaseConnection();
}
return result; return result;
} }
@ -2059,6 +2053,7 @@ public class DavExchangeSession extends ExchangeSession {
* Common item properties * Common item properties
*/ */
protected static final Set<String> ITEM_PROPERTIES = new HashSet<String>(); protected static final Set<String> ITEM_PROPERTIES = new HashSet<String>();
static { static {
ITEM_PROPERTIES.add("etag"); ITEM_PROPERTIES.add("etag");
ITEM_PROPERTIES.add("displayname"); ITEM_PROPERTIES.add("displayname");
@ -2974,6 +2969,33 @@ public class DavExchangeSession extends ExchangeSession {
LOGGER.debug("Deleted to :" + destination); LOGGER.debug("Deleted to :" + destination);
} }
protected String getItemProperty(String permanentUrl, String propertyName) throws IOException, DavException, MessagingException {
String result = null;
DavPropertyNameSet davPropertyNameSet = new DavPropertyNameSet();
davPropertyNameSet.add(Field.getPropertyName(propertyName));
PropFindMethod propFindMethod = new PropFindMethod(encodeAndFixUrl(permanentUrl), davPropertyNameSet, 0);
try {
try {
DavGatewayHttpClientFacade.executeHttpMethod(httpClient, propFindMethod);
} catch (UnknownHostException e) {
propFindMethod.releaseConnection();
// failover for misconfigured Exchange server, replace host name in url
restoreHostName = true;
propFindMethod = new PropFindMethod(encodeAndFixUrl(permanentUrl), davPropertyNameSet, 0);
DavGatewayHttpClientFacade.executeHttpMethod(httpClient, propFindMethod);
}
MultiStatus responses = propFindMethod.getResponseBodyAsMultiStatus();
if (responses.getResponses().length > 0) {
DavPropertySet properties = responses.getResponses()[0].getProperties(HttpStatus.SC_OK);
result = getPropertyIfExists(properties, propertyName);
}
} finally {
propFindMethod.releaseConnection();
}
return result;
}
protected String convertDateFromExchange(String exchangeDateValue) throws DavMailException { protected String convertDateFromExchange(String exchangeDateValue) throws DavMailException {
String zuluDateValue = null; String zuluDateValue = null;
if (exchangeDateValue != null) { if (exchangeDateValue != null) {

View File

@ -143,6 +143,7 @@ public class Field {
createField(URN_SCHEMAS_HTTPMAIL, "subject"); // DistinguishedPropertySetType.InternetHeaders/Subject/String createField(URN_SCHEMAS_HTTPMAIL, "subject"); // DistinguishedPropertySetType.InternetHeaders/Subject/String
//createField("subject", 0x0037, PropertyType.String);//PR_SUBJECT //createField("subject", 0x0037, PropertyType.String);//PR_SUBJECT
createField("body", 0x1000, PropertyType.String);//PR_BODY createField("body", 0x1000, PropertyType.String);//PR_BODY
createField("messageheaders", 0x007D, PropertyType.String);// PR_TRANSPORT_MESSAGE_HEADERS
createField(URN_SCHEMAS_HTTPMAIL, "from"); createField(URN_SCHEMAS_HTTPMAIL, "from");
//createField("from", DistinguishedPropertySetType.PublicStrings, 0x001f);//urn:schemas:httpmail:from //createField("from", DistinguishedPropertySetType.PublicStrings, 0x001f);//urn:schemas:httpmail:from
createField(URN_SCHEMAS_MAILHEADER, "to"); // DistinguishedPropertySetType.InternetHeaders/To/String createField(URN_SCHEMAS_MAILHEADER, "to"); // DistinguishedPropertySetType.InternetHeaders/To/String

View File

@ -41,10 +41,7 @@ import javax.mail.Session;
import javax.mail.internet.InternetAddress; import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMessage;
import javax.mail.util.SharedByteArrayInputStream; import javax.mail.util.SharedByteArrayInputStream;
import java.io.BufferedReader; import java.io.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.SocketException; import java.net.SocketException;
import java.text.ParseException; import java.text.ParseException;
@ -368,6 +365,26 @@ public class EwsExchangeSession extends ExchangeSession {
public String getPermanentId() { public String getPermanentId() {
return itemId.id; return itemId.id;
} }
@Override
protected InputStream getMimeHeaders() {
InputStream result = null;
try {
GetItemMethod getItemMethod = new GetItemMethod(BaseShape.ID_ONLY, itemId, false);
getItemMethod.addAdditionalProperty(Field.get("messageheaders"));
executeMethod(getItemMethod);
EWSMethod.Item item = getItemMethod.getResponseItem();
String messageHeaders = item.get(Field.get("messageheaders").getResponseName());
if (messageHeaders != null) {
result = new ByteArrayInputStream(messageHeaders.getBytes("UTF-8"));
}
} catch (Exception e) {
LOGGER.warn(e.getMessage());
}
return result;
}
} }
/** /**

View File

@ -79,6 +79,8 @@ public final class Field {
FIELD_MAP.put("cc", new ExtendedFieldURI(ExtendedFieldURI.DistinguishedPropertySetType.InternetHeaders, "cc")); FIELD_MAP.put("cc", new ExtendedFieldURI(ExtendedFieldURI.DistinguishedPropertySetType.InternetHeaders, "cc"));
FIELD_MAP.put("from", new ExtendedFieldURI(ExtendedFieldURI.DistinguishedPropertySetType.InternetHeaders, "from")); FIELD_MAP.put("from", new ExtendedFieldURI(ExtendedFieldURI.DistinguishedPropertySetType.InternetHeaders, "from"));
FIELD_MAP.put("messageheaders", new ExtendedFieldURI(0x007D, ExtendedFieldURI.PropertyType.String)); // PR_TRANSPORT_MESSAGE_HEADERS
FIELD_MAP.put("contentclass", new ExtendedFieldURI(ExtendedFieldURI.DistinguishedPropertySetType.InternetHeaders, "content-class")); FIELD_MAP.put("contentclass", new ExtendedFieldURI(ExtendedFieldURI.DistinguishedPropertySetType.InternetHeaders, "content-class"));
FIELD_MAP.put("message-id", new ExtendedFieldURI(ExtendedFieldURI.DistinguishedPropertySetType.InternetHeaders, "message-id")); FIELD_MAP.put("message-id", new ExtendedFieldURI(ExtendedFieldURI.DistinguishedPropertySetType.InternetHeaders, "message-id"));

View File

@ -713,7 +713,14 @@ public class ImapConnection extends AbstractConnection {
if ("FLAGS".equals(param)) { if ("FLAGS".equals(param)) {
buffer.append(" FLAGS (").append(message.getImapFlags()).append(')'); buffer.append(" FLAGS (").append(message.getImapFlags()).append(')');
} else if ("RFC822.SIZE".equals(param)) { } else if ("RFC822.SIZE".equals(param)) {
buffer.append(" RFC822.SIZE ").append(message.getMimeMessageSize()); int size;
if (parameters.indexOf("BODY.PEEK[HEADER.FIELDS (") >= 0) {
// Header request, send approximate size
size = message.size;
} else {
size = message.getMimeMessageSize();
}
buffer.append(" RFC822.SIZE ").append(size);
} else if ("ENVELOPE".equals(param)) { } else if ("ENVELOPE".equals(param)) {
appendEnvelope(buffer, message); appendEnvelope(buffer, message);
} else if ("BODYSTRUCTURE".equals(param)) { } else if ("BODYSTRUCTURE".equals(param)) {
@ -769,11 +776,12 @@ public class ImapConnection extends AbstractConnection {
if (requestedHeaders != null) { if (requestedHeaders != null) {
// OSX Lion special flags request // OSX Lion special flags request
if (requestedHeaders.length == 1 && "content-class".equals(requestedHeaders[0]) && message.contentClass != null) { if (requestedHeaders.length == 1 && "content-class".equals(requestedHeaders[0]) && message.contentClass != null) {
baos.write("Content-class: ".getBytes("UTF-8"));
baos.write(message.contentClass.getBytes("UTF-8")); baos.write(message.contentClass.getBytes("UTF-8"));
baos.write(13); baos.write(13);
baos.write(10); baos.write(10);
} else { } else {
Enumeration headerEnumeration = message.getMimeMessage().getMatchingHeaderLines(requestedHeaders); Enumeration headerEnumeration = message.getMatchingHeaderLines(requestedHeaders);
while (headerEnumeration.hasMoreElements()) { while (headerEnumeration.hasMoreElements()) {
baos.write(((String) headerEnumeration.nextElement()).getBytes("UTF-8")); baos.write(((String) headerEnumeration.nextElement()).getBytes("UTF-8"));
baos.write(13); baos.write(13);

View File

@ -388,4 +388,10 @@ public class TestImap extends AbstractImapTestCase {
writeLine(". FETCH 1:* (FLAGS UID BODY.PEEK[HEADER.FIELDS (content-class)])"); writeLine(". FETCH 1:* (FLAGS UID BODY.PEEK[HEADER.FIELDS (content-class)])");
assertEquals(". OK FETCH completed", readFullAnswer(".")); assertEquals(". OK FETCH completed", readFullAnswer("."));
} }
public void testFetchHeadersThunderbird() throws IOException {
testSelectInbox();
writeLine(". FETCH 1:* (UID RFC822.SIZE FLAGS BODY.PEEK[HEADER.FIELDS (From To Cc Bcc Subject Date Message-ID Priority X-Priority References Newsgroups In-Reply-To Content-Type)])");
assertEquals(". OK FETCH completed", readFullAnswer("."));
}
} }