1
0
mirror of https://github.com/moparisthebest/davmail synced 2024-12-13 03:02:22 -05:00

SMTP: fix regression on bcc handling

git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@1367 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
mguessan 2010-08-19 23:20:31 +00:00
parent b5f79aafe3
commit 8e91a1df5e
6 changed files with 147 additions and 43 deletions

View File

@ -508,10 +508,10 @@ public abstract class ExchangeSession {
* @param folderPath Exchange folder path
* @param messageName message name
* @param properties message properties (flags)
* @param messageBody mail body
* @param mimeMessage MIME message
* @throws IOException when unable to create message
*/
public abstract void createMessage(String folderPath, String messageName, HashMap<String, String> properties, byte[] messageBody) throws IOException;
public abstract void createMessage(String folderPath, String messageName, HashMap<String, String> properties, MimeMessage mimeMessage) throws IOException, MessagingException;
/**
* Update given properties on message.
@ -537,7 +537,7 @@ public abstract class ExchangeSession {
* @param messageBody MIME message body
* @throws IOException on error
*/
public abstract void sendMessage(byte[] messageBody) throws IOException;
public abstract void sendMessage(byte[] messageBody) throws IOException, MessagingException;
/**
* Get raw MIME message content
@ -1018,11 +1018,11 @@ public abstract class ExchangeSession {
}
protected void convertResentHeader(MimeMessage mimeMessage, String headerName) throws MessagingException {
String[] resentHeader = mimeMessage.getHeader("Resent-"+headerName);
String[] resentHeader = mimeMessage.getHeader("Resent-" + headerName);
if (resentHeader != null) {
mimeMessage.removeHeader("Resent-"+headerName);
mimeMessage.removeHeader("Resent-" + headerName);
mimeMessage.removeHeader(headerName);
for (String value:resentHeader) {
for (String value : resentHeader) {
mimeMessage.addHeader(headerName, value);
}
}
@ -1049,24 +1049,36 @@ public abstract class ExchangeSession {
convertResentHeader(mimeMessage, "Bcc");
convertResentHeader(mimeMessage, "Message-Id");
// fix From header for Exchange 2007
Address[] fromAddresses = mimeMessage.getFrom();
if (fromAddresses != null) {
for (Address fromAddress : fromAddresses) {
if (!email.equalsIgnoreCase(((InternetAddress) fromAddress).getAddress())) {
mimeMessage.removeHeader("From");
}
}
}
// remove visible recipients from list
Set<String> visibleRecipients = new HashSet<String>();
Address[] recipients = mimeMessage.getAllRecipients();
for (Address address : recipients) {
visibleRecipients.add(((InternetAddress) address).getAddress().toLowerCase());
if (recipients != null) {
for (Address address : recipients) {
visibleRecipients.add(((InternetAddress) address).getAddress().toLowerCase());
}
}
for (String recipient : rcptToRecipients) {
if (!visibleRecipients.contains(recipient.toLowerCase())) {
mimeMessage.addRecipient(javax.mail.Message.RecipientType.BCC, new InternetAddress(recipient));
}
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
mimeMessage.writeTo(baos);
sendMessage(baos.toByteArray());
sendMessage(mimeMessage);
}
}
public abstract void sendMessage(MimeMessage mimeMessage) throws IOException, MessagingException;
/**
* Get folder object.
* Folder name can be logical names INBOX, Drafts, Trash or calendar,

View File

@ -51,6 +51,7 @@ import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimePart;
import javax.mail.util.SharedByteArrayInputStream;
import java.io.*;
import java.net.URL;
import java.text.ParseException;
@ -329,10 +330,10 @@ public class DavExchangeSession extends ExchangeSession {
// return all attributes => call gallookup
if (returningAttributes == null || returningAttributes.isEmpty()) {
return true;
// iCal search, do not call gallookup
// iCal search, do not call gallookup
} else if (returningAttributes.contains("apple-serviceslocator")) {
return false;
// search attribute is gallookup attribute, need to fetch value for isMatch
// search attribute is gallookup attribute, need to fetch value for isMatch
} else if (GALLOOKUP_ATTRIBUTES.contains(searchAttributeName)) {
return true;
}
@ -601,7 +602,7 @@ public class DavExchangeSession extends ExchangeSession {
protected String getFolderName(String url) {
if (url != null) {
if (url.endsWith("/")) {
return url.substring(url.lastIndexOf('/', url.length() - 2) + 1, url.length()-1);
return url.substring(url.lastIndexOf('/', url.length() - 2) + 1, url.length() - 1);
} else if (url.indexOf('/') > 0) {
return url.substring(url.lastIndexOf('/') + 1);
} else {
@ -1503,6 +1504,21 @@ public class DavExchangeSession extends ExchangeSession {
}
}
protected void moveMessage(String sourcePath, String targetPath) throws IOException {
MoveMethod method = new MoveMethod(URIUtil.encodePath(getFolderPath(sourcePath)),
URIUtil.encodePath(getFolderPath(targetPath)), false);
try {
int statusCode = httpClient.executeMethod(method);
if (statusCode == HttpStatus.SC_PRECONDITION_FAILED) {
throw new DavMailException("EXCEPTION_UNABLE_TO_MOVE_FOLDER");
} else if (statusCode != HttpStatus.SC_OK) {
throw DavGatewayHttpClientFacade.buildHttpException(method);
}
} finally {
method.releaseConnection();
}
}
protected String getPropertyIfExists(DavPropertySet properties, String alias) {
DavProperty property = properties.get(Field.getResponsePropertyName(alias));
if (property == null) {
@ -1716,7 +1732,7 @@ public class DavExchangeSession extends ExchangeSession {
if (responses == null || responses.length == 0) {
throw new HttpNotFoundException(itemPath + " not found");
}
LOGGER.warn("search by urlcompname failed, actual value is "+getPropertyIfExists(responses[0].getProperties(HttpStatus.SC_OK), "urlcompname"));
LOGGER.warn("search by urlcompname failed, actual value is " + getPropertyIfExists(responses[0].getProperties(HttpStatus.SC_OK), "urlcompname"));
}
}
// build item
@ -1968,11 +1984,11 @@ public class DavExchangeSession extends ExchangeSession {
* @param folderPath Exchange folder path
* @param messageName message name
* @param properties message properties (flags)
* @param messageBody mail body
* @param mimeMessage MIME message
* @throws IOException when unable to create message
*/
@Override
public void createMessage(String folderPath, String messageName, HashMap<String, String> properties, byte[] messageBody) throws IOException {
public void createMessage(String folderPath, String messageName, HashMap<String, String> properties, MimeMessage mimeMessage) throws IOException {
String messageUrl = URIUtil.encodePathQuery(getFolderPath(folderPath) + '/' + messageName);
PropPatchMethod patchMethod;
List<DavConstants> davProperties = buildProperties(properties);
@ -2002,15 +2018,42 @@ public class DavExchangeSession extends ExchangeSession {
try {
// use same encoding as client socket reader
putmethod.setRequestEntity(new ByteArrayRequestEntity(messageBody));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
mimeMessage.writeTo(baos);
baos.close();
putmethod.setRequestEntity(new ByteArrayRequestEntity(baos.toByteArray()));
int code = httpClient.executeMethod(putmethod);
if (code != HttpStatus.SC_OK && code != HttpStatus.SC_CREATED) {
throw new DavMailException("EXCEPTION_UNABLE_TO_CREATE_MESSAGE", messageUrl, code, ' ', putmethod.getStatusLine());
}
} catch (MessagingException e) {
throw new IOException(e.getMessage());
} finally {
putmethod.releaseConnection();
}
try {
// need to update bcc after put
if (mimeMessage.getHeader("Bcc") != null) {
davProperties = new ArrayList<DavConstants>();
davProperties.add(Field.createDavProperty("bcc", mimeMessage.getHeader("Bcc", ",")));
patchMethod = new PropPatchMethod(messageUrl, davProperties);
try {
// update message with blind carbon copy
int statusCode = httpClient.executeMethod(patchMethod);
if (statusCode != HttpStatus.SC_MULTI_STATUS) {
throw new DavMailException("EXCEPTION_UNABLE_TO_CREATE_MESSAGE", messageUrl, statusCode, ' ', patchMethod.getStatusLine());
}
} finally {
patchMethod.releaseConnection();
}
}
} catch (MessagingException e) {
throw new IOException(e.getMessage());
}
}
/**
@ -2051,7 +2094,28 @@ public class DavExchangeSession extends ExchangeSession {
public void sendMessage(byte[] messageBody) throws IOException {
String messageName = UUID.randomUUID().toString() + ".EML";
createMessage(SENDMSG, messageName, null, messageBody);
try {
createMessage(SENDMSG, messageName, null, new MimeMessage(null, new SharedByteArrayInputStream(messageBody)));
} catch (MessagingException e) {
throw new IOException(e.getMessage());
}
}
@Override
public void sendMessage(MimeMessage mimeMessage) throws IOException, MessagingException {
if (mimeMessage.getHeader("Bcc") != null) {
// need to create draft first
String itemName = UUID.randomUUID().toString() + ".EML";
HashMap<String, String> properties = new HashMap<String, String>();
properties.put("draft", "9");
createMessage(DRAFTS, itemName, properties, mimeMessage);
moveMessage(DRAFTS + '/' + itemName, SENDMSG);
} else {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
mimeMessage.writeTo(baos);
sendMessage(baos.toByteArray());
}
}
protected boolean isGzipEncoded(HttpMethod method) {

View File

@ -31,7 +31,10 @@ import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
@ -162,10 +165,17 @@ public class EwsExchangeSession extends ExchangeSession {
}
@Override
public void createMessage(String folderPath, String messageName, HashMap<String, String> properties, byte[] messageBody) throws IOException {
public void createMessage(String folderPath, String messageName, HashMap<String, String> properties, MimeMessage mimeMessage) throws IOException {
EWSMethod.Item item = new EWSMethod.Item();
item.type = "Message";
item.mimeContent = Base64.encodeBase64(messageBody);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
mimeMessage.writeTo(baos);
} catch (MessagingException e) {
throw new IOException(e.getMessage());
}
baos.close();
item.mimeContent = Base64.encodeBase64(baos.toByteArray());
Set<FieldUpdate> fieldUpdates = buildProperties(properties);
if (!properties.containsKey("draft")) {
@ -208,6 +218,13 @@ public class EwsExchangeSession extends ExchangeSession {
executeMethod(createItemMethod);
}
@Override
public void sendMessage(MimeMessage mimeMessage) throws IOException, MessagingException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
mimeMessage.writeTo(baos);
sendMessage(baos.toByteArray());
}
/**
* @inheritDoc
*/
@ -733,7 +750,7 @@ public class EwsExchangeSession extends ExchangeSession {
for (Map.Entry<String, String> entry : entrySet()) {
if ("photo".equals(entry.getKey())) {
list.add(Field.createFieldUpdate("haspicture", "true"));
} else if (!entry.getKey().startsWith("email")){
} else if (!entry.getKey().startsWith("email")) {
list.add(Field.createFieldUpdate(entry.getKey(), entry.getValue()));
}
}

View File

@ -39,7 +39,7 @@ public class TestExchangeSessionMessage extends AbstractExchangeSessionTestCase
messageName = UUID.randomUUID().toString()+".EML";
HashMap<String, String> properties = new HashMap<String, String>();
properties.put("draft", "0");
session.createMessage("testfolder", messageName, properties, getMimeBody(mimeMessage));
session.createMessage("testfolder", messageName, properties, mimeMessage);
}
public void testSearchMessage() throws IOException, MessagingException {
@ -103,7 +103,7 @@ public class TestExchangeSessionMessage extends AbstractExchangeSessionTestCase
messageName = "Special & accenté.EML";
HashMap<String, String> properties = new HashMap<String, String>();
properties.put("draft", "0");
session.createMessage("testfolder", messageName, properties, getMimeBody(mimeMessage));
session.createMessage("testfolder", messageName, properties, mimeMessage);
ExchangeSession.MessageList messageList = session.searchMessages("testfolder", session.isEqualTo("urlcompname", messageName));
assertNotNull(messageList);
assertEquals(1, messageList.size());
@ -116,7 +116,7 @@ public class TestExchangeSessionMessage extends AbstractExchangeSessionTestCase
messageName = "test _xF8FF_ slash.EML";
HashMap<String, String> properties = new HashMap<String, String>();
properties.put("draft", "0");
session.createMessage("testfolder", messageName, properties, getMimeBody(mimeMessage));
session.createMessage("testfolder", messageName, properties, mimeMessage);
ExchangeSession.MessageList messageList = session.searchMessages("testfolder", session.isEqualTo("urlcompname", messageName));
assertNotNull(messageList);
assertEquals(1, messageList.size());
@ -130,7 +130,7 @@ public class TestExchangeSessionMessage extends AbstractExchangeSessionTestCase
messageName = "test + plus.EML";
HashMap<String, String> properties = new HashMap<String, String>();
properties.put("draft", "0");
session.createMessage("testfolder", messageName, properties, getMimeBody(mimeMessage));
session.createMessage("testfolder", messageName, properties, mimeMessage);
ExchangeSession.MessageList messageList = session.searchMessages("testfolder", session.isEqualTo("urlcompname", messageName));
assertNotNull(messageList);
assertEquals(1, messageList.size());

View File

@ -47,7 +47,7 @@ public class TestExchangeSessionMessageFlags extends AbstractExchangeSessionTest
String messageName = UUID.randomUUID().toString()+".EML";
HashMap<String, String> properties = new HashMap<String, String>();
properties.put("draft", "9");
session.createMessage("testfolder", messageName, properties, getMimeBody(mimeMessage));
session.createMessage("testfolder", messageName, properties, mimeMessage);
ExchangeSession.MessageList messageList = session.searchMessages("testfolder");
assertNotNull(messageList);
assertEquals(1, messageList.size());
@ -59,7 +59,7 @@ public class TestExchangeSessionMessageFlags extends AbstractExchangeSessionTest
String messageName = UUID.randomUUID().toString();
HashMap<String, String> properties = new HashMap<String, String>();
properties.put("draft", "9");
session.createMessage("testfolder", messageName, properties, getMimeBody(mimeMessage));
session.createMessage("testfolder", messageName, properties, mimeMessage);
ExchangeSession.MessageList messageList = session.searchMessages("testfolder");
assertNotNull(messageList);
assertEquals(1, messageList.size());
@ -72,7 +72,7 @@ public class TestExchangeSessionMessageFlags extends AbstractExchangeSessionTest
String messageName = UUID.randomUUID().toString();
HashMap<String, String> properties = new HashMap<String, String>();
properties.put("draft", "1");
session.createMessage("testfolder", messageName, properties, getMimeBody(mimeMessage));
session.createMessage("testfolder", messageName, properties, mimeMessage);
ExchangeSession.MessageList messageList = session.searchMessages("testfolder");
assertNotNull(messageList);
assertEquals(1, messageList.size());
@ -87,7 +87,7 @@ public class TestExchangeSessionMessageFlags extends AbstractExchangeSessionTest
HashMap<String, String> properties = new HashMap<String, String>();
properties.put("draft", "8");
properties.put("bcc", "testbcc@test.local");
session.createMessage("testfolder", messageName, properties, getMimeBody(mimeMessage));
session.createMessage("testfolder", messageName, properties, mimeMessage);
ExchangeSession.MessageList messageList = session.searchMessages("testfolder");
assertNotNull(messageList);
assertEquals(1, messageList.size());
@ -102,7 +102,7 @@ public class TestExchangeSessionMessageFlags extends AbstractExchangeSessionTest
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MONTH, -1);
properties.put("datereceived", dateFormatter.format(cal.getTime()));
session.createMessage("testfolder", messageName, properties, getMimeBody(mimeMessage));
session.createMessage("testfolder", messageName, properties, mimeMessage);
ExchangeSession.MessageList messageList = session.searchMessages("testfolder");
assertNotNull(messageList);
assertEquals(1, messageList.size());

View File

@ -43,7 +43,10 @@ public class TestSmtp extends AbstractDavMailTestCase {
static BufferedOutputStream socketOutputStream;
static BufferedInputStream socketInputStream;
static final byte[] CRLF = {13, 10};
enum State {CHAR, CR, CRLF}
enum State {
CHAR, CR, CRLF
}
protected void write(String line) throws IOException {
socketOutputStream.write(line.getBytes("ASCII"));
@ -71,7 +74,7 @@ public class TestSmtp extends AbstractDavMailTestCase {
} else {
state = State.CHAR;
}
}
}
if (state == State.CHAR) {
baos.write(character);
}
@ -91,7 +94,7 @@ public class TestSmtp extends AbstractDavMailTestCase {
String banner = readLine();
assertNotNull(banner);
String credentials = (char) 0+Settings.getProperty("davmail.username")+ (char) 0 +Settings.getProperty("davmail.password");
String credentials = (char) 0 + Settings.getProperty("davmail.username") + (char) 0 + Settings.getProperty("davmail.password");
writeLine("AUTH PLAIN " + new String(new Base64().encode(credentials.getBytes())));
assertEquals("235 OK Authenticated", readLine());
}
@ -101,9 +104,17 @@ public class TestSmtp extends AbstractDavMailTestCase {
}
public void sendAndCheckMessage(MimeMessage mimeMessage) throws IOException, MessagingException, InterruptedException {
writeLine("MAIL FROM:"+session.getEmail());
sendAndCheckMessage(mimeMessage, null);
}
public void sendAndCheckMessage(MimeMessage mimeMessage, String bcc) throws IOException, MessagingException, InterruptedException {
writeLine("MAIL FROM:" + session.getEmail());
readLine();
writeLine("RCPT TO:"+Settings.getProperty("davmail.to"));
if (bcc != null) {
writeLine("RCPT TO:" + bcc);
readLine();
}
writeLine("RCPT TO:" + Settings.getProperty("davmail.to"));
readLine();
writeLine("DATA");
assertEquals("354 Start mail input; end with <CRLF>.<CRLF>", readLine());
@ -113,7 +124,7 @@ public class TestSmtp extends AbstractDavMailTestCase {
assertEquals("250 Queued mail for delivery", readLine());
// wait for asynchronous message send
ExchangeSession.MessageList messages = null;
for (int i=0;i<5;i++) {
for (int i = 0; i < 5; i++) {
messages = session.searchMessages("Sent", session.headerIsEqualTo("message-id", mimeMessage.getMessageID()));
if (messages.size() > 0) {
break;
@ -138,7 +149,7 @@ public class TestSmtp extends AbstractDavMailTestCase {
public void testSendMessage() throws IOException, MessagingException, InterruptedException {
String body = "Test message\r\n" +
"Special characters: éèçà\r\n" +
"Chinese: "+((char)0x604F)+((char)0x7D59);
"Chinese: " + ((char) 0x604F) + ((char) 0x7D59);
MimeMessage mimeMessage = new MimeMessage((Session) null);
mimeMessage.addHeader("To", Settings.getProperty("davmail.to"));
mimeMessage.setSubject("Test subject");
@ -149,9 +160,9 @@ public class TestSmtp extends AbstractDavMailTestCase {
public void testBccMessage() throws IOException, MessagingException, InterruptedException {
MimeMessage mimeMessage = new MimeMessage((Session) null);
mimeMessage.addHeader("to", Settings.getProperty("davmail.to"));
mimeMessage.setSubject("Test subject");
mimeMessage.setSubject("Test subject dav");
mimeMessage.setText("Test message");
sendAndCheckMessage(mimeMessage);
sendAndCheckMessage(mimeMessage, Settings.getProperty("davmail.bcc"));
}
public void testDotMessage() throws IOException, MessagingException, InterruptedException {
@ -176,14 +187,14 @@ public class TestSmtp extends AbstractDavMailTestCase {
public void testComplexToMessage() throws IOException, MessagingException, InterruptedException {
String body = "Test message";
MimeMessage mimeMessage = new MimeMessage((Session) null);
mimeMessage.addHeader("To", "nickname <"+Settings.getProperty("davmail.to")+ '>');
mimeMessage.addHeader("To", "nickname <" + Settings.getProperty("davmail.to") + '>');
mimeMessage.setSubject("Test subject");
mimeMessage.setText(body);
sendAndCheckMessage(mimeMessage);
}
public void testQuit() throws IOException {
writeLine("QUIT");
writeLine("QUIT");
assertEquals("221 Closing connection", readLine());
}