mirror of
https://github.com/moparisthebest/davmail
synced 2025-01-07 11:48:02 -05:00
IMAP: implement store by id and ENVELOPE
git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@801 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
parent
24d7399555
commit
1d3cd69a7e
@ -287,7 +287,7 @@ public class ExchangeSession {
|
|||||||
if (path.startsWith("/")) {
|
if (path.startsWith("/")) {
|
||||||
// path is absolute, replace method path
|
// path is absolute, replace method path
|
||||||
uri.setPath(path);
|
uri.setPath(path);
|
||||||
} else if (path.startsWith("http://") || path.startsWith("https://")){
|
} else if (path.startsWith("http://") || path.startsWith("https://")) {
|
||||||
return path;
|
return path;
|
||||||
} else {
|
} else {
|
||||||
// relative path, build new path
|
// relative path, build new path
|
||||||
@ -1100,8 +1100,8 @@ public class ExchangeSession {
|
|||||||
/**
|
/**
|
||||||
* Create Exchange folder with given folder class.
|
* Create Exchange folder with given folder class.
|
||||||
*
|
*
|
||||||
* @param folderName logical folder name
|
* @param folderName logical folder name
|
||||||
* @param folderClass folder class
|
* @param folderClass folder class
|
||||||
* @throws IOException on error
|
* @throws IOException on error
|
||||||
*/
|
*/
|
||||||
public void createFolder(String folderName, String folderClass) throws IOException {
|
public void createFolder(String folderName, String folderClass) throws IOException {
|
||||||
@ -1350,6 +1350,11 @@ public class ExchangeSession {
|
|||||||
*/
|
*/
|
||||||
public boolean forwarded;
|
public boolean forwarded;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message content parsed in a MIME message.
|
||||||
|
*/
|
||||||
|
protected MimeMessage mimeMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IMAP uid , unique in folder (x0e230003)
|
* IMAP uid , unique in folder (x0e230003)
|
||||||
*
|
*
|
||||||
@ -1453,6 +1458,15 @@ public class ExchangeSession {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MimeMessage getMimeMessage() throws IOException, MessagingException {
|
||||||
|
if (mimeMessage == null) {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
write(baos);
|
||||||
|
mimeMessage = new MimeMessage(null, new ByteArrayInputStream(baos.toByteArray()));
|
||||||
|
}
|
||||||
|
return mimeMessage;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete message.
|
* Delete message.
|
||||||
*
|
*
|
||||||
|
@ -30,11 +30,9 @@ import davmail.exchange.ExchangeSessionFactory;
|
|||||||
import davmail.ui.tray.DavGatewayTray;
|
import davmail.ui.tray.DavGatewayTray;
|
||||||
import org.apache.commons.httpclient.HttpException;
|
import org.apache.commons.httpclient.HttpException;
|
||||||
|
|
||||||
import javax.mail.internet.MimeMessage;
|
import javax.mail.internet.*;
|
||||||
import javax.mail.internet.MimeMultipart;
|
|
||||||
import javax.mail.internet.MimeBodyPart;
|
|
||||||
import javax.mail.internet.MimePart;
|
|
||||||
import javax.mail.MessagingException;
|
import javax.mail.MessagingException;
|
||||||
|
import javax.mail.Address;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
@ -278,13 +276,7 @@ public class ImapConnection extends AbstractConnection {
|
|||||||
UIDRangeIterator uidRangeIterator = new UIDRangeIterator(tokens.nextToken());
|
UIDRangeIterator uidRangeIterator = new UIDRangeIterator(tokens.nextToken());
|
||||||
String action = tokens.nextToken();
|
String action = tokens.nextToken();
|
||||||
String flags = tokens.nextToken();
|
String flags = tokens.nextToken();
|
||||||
while (uidRangeIterator.hasNext()) {
|
handleStore(commandId, uidRangeIterator, action, flags);
|
||||||
DavGatewayTray.switchIcon();
|
|
||||||
ExchangeSession.Message message = uidRangeIterator.next();
|
|
||||||
updateFlags(message, action, flags);
|
|
||||||
sendClient("* " + (uidRangeIterator.currentIndex) + " FETCH (UID " + message.getImapUid() + " FLAGS (" + (message.getImapFlags()) + "))");
|
|
||||||
}
|
|
||||||
sendClient(commandId + " OK STORE completed");
|
|
||||||
} else if ("copy".equalsIgnoreCase(subcommand)) {
|
} else if ("copy".equalsIgnoreCase(subcommand)) {
|
||||||
try {
|
try {
|
||||||
UIDRangeIterator uidRangeIterator = new UIDRangeIterator(tokens.nextToken());
|
UIDRangeIterator uidRangeIterator = new UIDRangeIterator(tokens.nextToken());
|
||||||
@ -333,6 +325,11 @@ public class ImapConnection extends AbstractConnection {
|
|||||||
sendClient(commandId + " OK FETCH completed");
|
sendClient(commandId + " OK FETCH completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if ("store".equalsIgnoreCase(command)) {
|
||||||
|
RangeIterator rangeIterator = new RangeIterator(tokens.nextToken());
|
||||||
|
String action = tokens.nextToken();
|
||||||
|
String flags = tokens.nextToken();
|
||||||
|
handleStore(commandId, rangeIterator, action, flags);
|
||||||
|
|
||||||
} else if ("append".equalsIgnoreCase(command)) {
|
} else if ("append".equalsIgnoreCase(command)) {
|
||||||
String folderName = BASE64MailboxDecoder.decode(tokens.nextToken());
|
String folderName = BASE64MailboxDecoder.decode(tokens.nextToken());
|
||||||
@ -506,6 +503,8 @@ public class ImapConnection extends AbstractConnection {
|
|||||||
String param = paramTokens.nextToken();
|
String param = paramTokens.nextToken();
|
||||||
if ("FLAGS".equals(param)) {
|
if ("FLAGS".equals(param)) {
|
||||||
buffer.append(" FLAGS (").append(message.getImapFlags()).append(')');
|
buffer.append(" FLAGS (").append(message.getImapFlags()).append(')');
|
||||||
|
} else if ("ENVELOPE".equals(param)) {
|
||||||
|
appendEnvelope(buffer, message);
|
||||||
} else if ("BODYSTRUCTURE".equals(param)) {
|
} else if ("BODYSTRUCTURE".equals(param)) {
|
||||||
if (parameters.indexOf("BODY.") >= 0) {
|
if (parameters.indexOf("BODY.") >= 0) {
|
||||||
// Apple Mail: send structure with body, need exact RFC822.SIZE
|
// Apple Mail: send structure with body, need exact RFC822.SIZE
|
||||||
@ -596,6 +595,17 @@ public class ImapConnection extends AbstractConnection {
|
|||||||
sendClient(buffer.toString());
|
sendClient(buffer.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void handleStore(String commandId, AbstractRangeIterator rangeIterator, String action, String flags) throws IOException {
|
||||||
|
while (rangeIterator.hasNext()) {
|
||||||
|
DavGatewayTray.switchIcon();
|
||||||
|
ExchangeSession.Message message = rangeIterator.next();
|
||||||
|
updateFlags(message, action, flags);
|
||||||
|
sendClient("* " + (rangeIterator.getCurrentIndex()) + " FETCH (UID " + message.getImapUid() + " FLAGS (" + (message.getImapFlags()) + "))");
|
||||||
|
}
|
||||||
|
sendClient(commandId + " OK STORE completed");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected List<Long> handleSearch(IMAPTokenizer tokens) throws IOException {
|
protected List<Long> handleSearch(IMAPTokenizer tokens) throws IOException {
|
||||||
List<Long> uidList = new ArrayList<Long>();
|
List<Long> uidList = new ArrayList<Long>();
|
||||||
SearchConditions conditions = new SearchConditions();
|
SearchConditions conditions = new SearchConditions();
|
||||||
@ -642,13 +652,88 @@ public class ImapConnection extends AbstractConnection {
|
|||||||
return uidList;
|
return uidList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void appendEnvelope(StringBuilder buffer, ExchangeSession.Message message) throws IOException {
|
||||||
|
buffer.append(" ENVELOPE (");
|
||||||
|
|
||||||
|
try {
|
||||||
|
MimeMessage mimeMessage = message.getMimeMessage();
|
||||||
|
// Fake envelope for date, subject, from, sender, reply-to, to, cc, bcc,in-reply-to, message-id
|
||||||
|
appendEnvelopeHeader(buffer, mimeMessage.getHeader("Date"));
|
||||||
|
appendEnvelopeHeader(buffer, mimeMessage.getHeader("Subject"));
|
||||||
|
appendMailEnvelopeHeader(buffer, mimeMessage.getHeader("From", ","));
|
||||||
|
appendMailEnvelopeHeader(buffer, mimeMessage.getHeader("Sender", ","));
|
||||||
|
appendMailEnvelopeHeader(buffer, mimeMessage.getHeader("Reply-To", ","));
|
||||||
|
appendMailEnvelopeHeader(buffer, mimeMessage.getHeader("CC", ","));
|
||||||
|
appendMailEnvelopeHeader(buffer, mimeMessage.getHeader("BCC", ","));
|
||||||
|
appendMailEnvelopeHeader(buffer, mimeMessage.getHeader("In-Reply-To", ","));
|
||||||
|
appendEnvelopeHeader(buffer, mimeMessage.getHeader("Messagee-Id"));
|
||||||
|
|
||||||
|
} catch (MessagingException me) {
|
||||||
|
DavGatewayTray.warn(me);
|
||||||
|
// send fake envelope
|
||||||
|
buffer.append(" nil nil nil nil nil nil nil nil nil nil");
|
||||||
|
}
|
||||||
|
buffer.append(')');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void appendEnvelopeHeader(StringBuilder buffer, String[] value) {
|
||||||
|
buffer.append(' ');
|
||||||
|
if (value != null && value.length > 0) {
|
||||||
|
try {
|
||||||
|
buffer.append('"');
|
||||||
|
// TODO: replace with MimeUtility.unfold
|
||||||
|
buffer.append(MimeUtility.decodeText(value[0]).replaceAll("\r\n", ""));
|
||||||
|
buffer.append('"');
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
DavGatewayTray.warn(e);
|
||||||
|
buffer.append("nil");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buffer.append("nil");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void appendMailEnvelopeHeader(StringBuilder buffer, String value) {
|
||||||
|
buffer.append(' ');
|
||||||
|
if (value != null) {
|
||||||
|
try {
|
||||||
|
InternetAddress[] addresses = InternetAddress.parseHeader(value, false);
|
||||||
|
buffer.append('(');
|
||||||
|
for (InternetAddress address : addresses) {
|
||||||
|
buffer.append('(');
|
||||||
|
String personal = address.getPersonal();
|
||||||
|
if (personal != null) {
|
||||||
|
buffer.append('"').append(personal).append('"');
|
||||||
|
} else {
|
||||||
|
buffer.append("nil");
|
||||||
|
}
|
||||||
|
buffer.append(" nil ");
|
||||||
|
String mail = address.getAddress();
|
||||||
|
int atIndex = mail.indexOf('@');
|
||||||
|
if (atIndex >= 0) {
|
||||||
|
buffer.append('"').append(mail.substring(0, atIndex)).append('"');
|
||||||
|
buffer.append(' ');
|
||||||
|
buffer.append('"').append(mail.substring(atIndex + 1)).append('"');
|
||||||
|
} else {
|
||||||
|
buffer.append("nil nil");
|
||||||
|
}
|
||||||
|
buffer.append(')');
|
||||||
|
}
|
||||||
|
buffer.append(')');
|
||||||
|
} catch (AddressException e) {
|
||||||
|
DavGatewayTray.warn(e);
|
||||||
|
buffer.append("nil");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buffer.append("nil");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void appendBodyStructure(StringBuilder buffer, ExchangeSession.Message message) throws IOException {
|
protected void appendBodyStructure(StringBuilder buffer, ExchangeSession.Message message) throws IOException {
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
message.write(baos);
|
|
||||||
|
|
||||||
buffer.append(" BODYSTRUCTURE ");
|
buffer.append(" BODYSTRUCTURE ");
|
||||||
try {
|
try {
|
||||||
MimeMessage mimeMessage = new MimeMessage(null, new ByteArrayInputStream(baos.toByteArray()));
|
MimeMessage mimeMessage = message.getMimeMessage();
|
||||||
Object mimeBody = mimeMessage.getContent();
|
Object mimeBody = mimeMessage.getContent();
|
||||||
if (mimeBody instanceof MimeMultipart) {
|
if (mimeBody instanceof MimeMultipart) {
|
||||||
buffer.append('(');
|
buffer.append('(');
|
||||||
@ -674,16 +759,12 @@ public class ImapConnection extends AbstractConnection {
|
|||||||
}
|
}
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
DavGatewayTray.warn(e);
|
DavGatewayTray.warn(e);
|
||||||
// dump message in log
|
|
||||||
DavGatewayTray.debug(new BundleMessage("LOG_MESSAGE", new String(baos.toByteArray())));
|
|
||||||
// failover: send default bodystructure
|
// failover: send default bodystructure
|
||||||
buffer.append("(\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\") NIL NIL NIL ").append(baos.size()).append(" NIL)");
|
buffer.append("(\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\") NIL NIL NIL NIL NIL)");
|
||||||
} catch (MessagingException me) {
|
} catch (MessagingException me) {
|
||||||
DavGatewayTray.warn(me);
|
DavGatewayTray.warn(me);
|
||||||
// dump message in log
|
|
||||||
DavGatewayTray.debug(new BundleMessage("LOG_MESSAGE", new String(baos.toByteArray())));
|
|
||||||
// failover: send default bodystructure
|
// failover: send default bodystructure
|
||||||
buffer.append("(\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\") NIL NIL NIL ").append(baos.size()).append(" NIL)");
|
buffer.append("(\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\") NIL NIL NIL NIL NIL)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1138,9 +1219,16 @@ public class ImapConnection extends AbstractConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class UIDRangeIterator implements Iterator<ExchangeSession.Message> {
|
protected abstract class AbstractRangeIterator implements Iterator<ExchangeSession.Message> {
|
||||||
final String[] ranges;
|
|
||||||
int currentIndex;
|
int currentIndex;
|
||||||
|
|
||||||
|
protected int getCurrentIndex() {
|
||||||
|
return currentIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class UIDRangeIterator extends AbstractRangeIterator {
|
||||||
|
final String[] ranges;
|
||||||
int currentRangeIndex;
|
int currentRangeIndex;
|
||||||
long startUid;
|
long startUid;
|
||||||
long endUid;
|
long endUid;
|
||||||
@ -1219,9 +1307,8 @@ public class ImapConnection extends AbstractConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class RangeIterator implements Iterator<ExchangeSession.Message> {
|
protected class RangeIterator extends AbstractRangeIterator {
|
||||||
final String[] ranges;
|
final String[] ranges;
|
||||||
int currentIndex;
|
|
||||||
int currentRangeIndex;
|
int currentRangeIndex;
|
||||||
long startUid;
|
long startUid;
|
||||||
long endUid;
|
long endUid;
|
||||||
|
Loading…
Reference in New Issue
Block a user