|
|
|
diff -rupN /home/marcel/JavaMail/mail/src/main/java/com/sun/mail/handlers/handler_base.java ./app/src/main/java/com/sun/mail/handlers/handler_base.java
|
|
|
|
--- /home/marcel/JavaMail/mail/src/main/java/com/sun/mail/handlers/handler_base.java 2020-08-14 11:44:05.401359065 +0200
|
|
|
|
+++ ./app/src/main/java/com/sun/mail/handlers/handler_base.java 2020-08-26 15:38:37.903384284 +0200
|
|
|
|
@@ -17,7 +17,6 @@
|
|
|
|
package com.sun.mail.handlers;
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
-import java.awt.datatransfer.DataFlavor;
|
|
|
|
import javax.activation.*;
|
|
|
|
|
|
|
|
/**
|
|
|
|
@@ -52,14 +51,8 @@ public abstract class handler_base imple
|
|
|
|
*
|
|
|
|
* @return The DataFlavors
|
|
|
|
*/
|
|
|
|
- @Override
|
|
|
|
- public DataFlavor[] getTransferDataFlavors() {
|
|
|
|
- ActivationDataFlavor[] adf = getDataFlavors();
|
|
|
|
- if (adf.length == 1) // the common case
|
|
|
|
- return new DataFlavor[] { adf[0] };
|
|
|
|
- DataFlavor[] df = new DataFlavor[adf.length];
|
|
|
|
- System.arraycopy(adf, 0, df, 0, adf.length);
|
|
|
|
- return df;
|
|
|
|
+ public ActivationDataFlavor[] getTransferDataFlavors() {
|
|
|
|
+ return getDataFlavors().clone();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
@@ -70,8 +63,7 @@ public abstract class handler_base imple
|
|
|
|
* @return the object
|
|
|
|
* @exception IOException for errors reading the data
|
|
|
|
*/
|
|
|
|
- @Override
|
|
|
|
- public Object getTransferData(DataFlavor df, DataSource ds)
|
|
|
|
+ public Object getTransferData(ActivationDataFlavor df, DataSource ds)
|
|
|
|
throws IOException {
|
|
|
|
ActivationDataFlavor[] adf = getDataFlavors();
|
|
|
|
for (int i = 0; i < adf.length; i++) {
|
|
|
|
diff -rupN /home/marcel/JavaMail/mail/src/main/java/com/sun/mail/iap/Protocol.java ./app/src/main/java/com/sun/mail/iap/Protocol.java
|
|
|
|
--- /home/marcel/JavaMail/mail/src/main/java/com/sun/mail/iap/Protocol.java 2020-04-03 09:00:49.201313282 +0200
|
|
|
|
+++ ./app/src/main/java/com/sun/mail/iap/Protocol.java 2020-08-28 08:09:12.005962733 +0200
|
|
|
|
@@ -347,6 +347,15 @@ public class Protocol {
|
|
|
|
* @return array of Response objects returned by the server
|
|
|
|
*/
|
|
|
|
public synchronized Response[] command(String command, Argument args) {
|
|
|
|
+ if (socket == null)
|
|
|
|
+ return new Response[]{Response.byeResponse(new SocketException("disconnected"))};
|
|
|
|
+ if ("LOGOUT".equals(command))
|
|
|
|
+ try {
|
|
|
|
+ socket.setSoTimeout(10 * 1000);
|
|
|
|
+ } catch (SocketException ex) {
|
|
|
|
+ eu.faircode.email.Log.e(ex);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
commandStart(command);
|
|
|
|
List<Response> v = new ArrayList<>();
|
|
|
|
boolean done = false;
|
|
|
|
diff -rupN /home/marcel/JavaMail/mail/src/main/java/com/sun/mail/imap/IMAPFolder.java ./app/src/main/java/com/sun/mail/imap/IMAPFolder.java
|
|
|
|
--- /home/marcel/JavaMail/mail/src/main/java/com/sun/mail/imap/IMAPFolder.java 2020-08-14 11:44:05.403359065 +0200
|
|
|
|
+++ ./app/src/main/java/com/sun/mail/imap/IMAPFolder.java 2020-08-27 09:24:28.051446453 +0200
|
|
|
|
@@ -1659,6 +1659,28 @@ public class IMAPFolder extends Folder i
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
+ public synchronized int getCachedCount() {
|
|
|
|
+ synchronized (messageCacheLock) {
|
|
|
|
+ if (messageCache == null)
|
|
|
|
+ return -1;
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ int count = 0;
|
|
|
|
+ int size = messageCache.size();
|
|
|
|
+ for (int i = 1; i <= size; i++) {
|
|
|
|
+ Message message = messageCache.getMessage(i);
|
|
|
|
+ if (message != null && !message.isExpunged())
|
|
|
|
+ count++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return count;
|
|
|
|
+ } catch (Throwable ex) {
|
|
|
|
+ eu.faircode.email.Log.e(ex);
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
/**
|
|
|
|
* Get the new message count.
|
|
|
|
*/
|
|
|
|
@@ -2608,6 +2630,20 @@ public class IMAPFolder extends Folder i
|
|
|
|
throw new FolderClosedException(this, cex.getMessage());
|
|
|
|
} catch (ProtocolException pex) {
|
|
|
|
throw new MessagingException(pex.getMessage(), pex);
|
|
|
|
+ } catch (ArrayIndexOutOfBoundsException ex) {
|
|
|
|
+ eu.faircode.email.Log.w(ex);
|
|
|
|
+ /*
|
|
|
|
+ java.lang.ArrayIndexOutOfBoundsException: message number (0) out of bounds (110)
|
|
|
|
+ at com.sun.mail.imap.MessageCache.getMessage(SourceFile:116)
|
|
|
|
+ at com.sun.mail.imap.MessageCache.getMessageBySeqnum(SourceFile:148)
|
|
|
|
+ at com.sun.mail.imap.IMAPFolder.getMessageBySeqNumber(SourceFile:3999)
|
|
|
|
+ at com.sun.mail.imap.IMAPFolder.processFetchResponse(SourceFile:3604)
|
|
|
|
+ at com.sun.mail.imap.IMAPFolder.handleResponse(SourceFile:3586)
|
|
|
|
+ at com.sun.mail.iap.Protocol.notifyResponseHandlers(SourceFile:245)
|
|
|
|
+ at com.sun.mail.imap.protocol.IMAPProtocol.fetchSequenceNumber(SourceFile:2057)
|
|
|
|
+ at com.sun.mail.imap.IMAPFolder.getMessageByUID(SourceFile:2598)
|
|
|
|
+ */
|
|
|
|
+ return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return m;
|
|
|
|
@@ -3963,7 +3999,8 @@ public class IMAPFolder extends Folder i
|
|
|
|
protocol.noop();
|
|
|
|
}
|
|
|
|
|
|
|
|
- if (keepStoreAlive && ((IMAPStore)store).hasSeparateStoreConnection()) {
|
|
|
|
+ if (keepStoreAlive && ((IMAPStore)store).hasSeparateStoreConnection() &&
|
|
|
|
+ !((IMAPStore)store).isStoreConnectionInUse()) {
|
|
|
|
IMAPProtocol p = null;
|
|
|
|
try {
|
|
|
|
p = ((IMAPStore)store).getFolderStoreProtocol();
|
|
|
|
diff -rupN /home/marcel/JavaMail/mail/src/main/java/com/sun/mail/imap/IMAPMessage.java ./app/src/main/java/com/sun/mail/imap/IMAPMessage.java
|
|
|
|
--- /home/marcel/JavaMail/mail/src/main/java/com/sun/mail/imap/IMAPMessage.java 2020-08-14 11:44:05.403359065 +0200
|
|
|
|
+++ ./app/src/main/java/com/sun/mail/imap/IMAPMessage.java 2020-08-26 15:38:37.906384284 +0200
|
|
|
|
@@ -1697,4 +1697,28 @@ public class IMAPMessage extends MimeMes
|
|
|
|
Session _getSession() {
|
|
|
|
return session;
|
|
|
|
}
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean isExpunged() {
|
|
|
|
+ if (super.isExpunged())
|
|
|
|
+ return true;
|
|
|
|
+
|
|
|
|
+ // Workaround expunged messages without deleted flag
|
|
|
|
+ if (envelope != null &&
|
|
|
|
+ envelope.date == null &&
|
|
|
|
+ envelope.subject == null &&
|
|
|
|
+ envelope.from == null &&
|
|
|
|
+ envelope.sender == null &&
|
|
|
|
+ envelope.replyTo == null &&
|
|
|
|
+ envelope.to == null &&
|
|
|
|
+ envelope.cc == null &&
|
|
|
|
+ envelope.inReplyTo == null &&
|
|
|
|
+ envelope.messageId == null &&
|
|
|
|
+ headersLoaded && loadedHeaders.size() == 0) {
|
|
|
|
+ eu.faircode.email.Log.w("Expunged workaround host=" + ((IMAPStore) folder.getStore()).host);
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
}
|
|
|
|
diff -rupN /home/marcel/JavaMail/mail/src/main/java/com/sun/mail/imap/IMAPStore.java ./app/src/main/java/com/sun/mail/imap/IMAPStore.java
|
|
|
|
--- /home/marcel/JavaMail/mail/src/main/java/com/sun/mail/imap/IMAPStore.java 2020-08-14 11:44:05.404359065 +0200
|
|
|
|
+++ ./app/src/main/java/com/sun/mail/imap/IMAPStore.java 2020-08-26 15:38:37.907384284 +0200
|
|
|
|
@@ -887,18 +887,26 @@ public class IMAPStore extends Store
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
- if (m.equals("PLAIN"))
|
|
|
|
- p.authplain(authzid, user, password);
|
|
|
|
- else if (m.equals("LOGIN"))
|
|
|
|
- p.authlogin(user, password);
|
|
|
|
- else if (m.equals("NTLM"))
|
|
|
|
- p.authntlm(authzid, user, password);
|
|
|
|
- else if (m.equals("XOAUTH2"))
|
|
|
|
- p.authoauth2(user, password);
|
|
|
|
- else {
|
|
|
|
- logger.log(Level.FINE, "no authenticator for mechanism {0}", m);
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
+ try {
|
|
|
|
+ if (m.equals("PLAIN"))
|
|
|
|
+ p.authplain(authzid, user, password);
|
|
|
|
+ else if (m.equals("LOGIN"))
|
|
|
|
+ p.authlogin(user, password);
|
|
|
|
+ else if (m.equals("NTLM"))
|
|
|
|
+ p.authntlm(authzid, user, password);
|
|
|
|
+ else if (m.equals("XOAUTH2"))
|
|
|
|
+ p.authoauth2(user, password);
|
|
|
|
+ else {
|
|
|
|
+ logger.log(Level.FINE, "no authenticator for mechanism {0}", m);
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ } catch (ProtocolException ex) {
|
|
|
|
+ if (m.equals("PLAIN") || m.equals("LOGIN")) {
|
|
|
|
+ eu.faircode.email.Log.i("Falling back to classic LOGIN");
|
|
|
|
+ p.authclassic(user, password);
|
|
|
|
+ } else
|
|
|
|
+ throw ex;
|
|
|
|
+ }
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
@@ -1014,6 +1022,8 @@ public class IMAPStore extends Store
|
|
|
|
p.disconnect();
|
|
|
|
} catch (Exception ex2) { }
|
|
|
|
p = null;
|
|
|
|
+ eu.faircode.email.Log.e(new MessagingException("IMAP connection failure", ex1));
|
|
|
|
+ throw new MessagingException("connection failure", ex1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p == null)
|
|
|
|
@@ -1175,7 +1185,11 @@ public class IMAPStore extends Store
|
|
|
|
// someone else is using the connection, give up
|
|
|
|
// and wait until they're done
|
|
|
|
p = null;
|
|
|
|
- pool.wait();
|
|
|
|
+ pool.wait(pool.clientTimeoutInterval);
|
|
|
|
+ if (pool.storeConnectionInUse) {
|
|
|
|
+ eu.faircode.email.Log.e("getStoreProtocol timeout");
|
|
|
|
+ throw new InterruptedException("getStoreProtocol timeout");
|
|
|
|
+ }
|
|
|
|
} catch (InterruptedException ex) {
|
|
|
|
// restore the interrupted state, which callers might
|
|
|
|
// depend on
|
|
|
|
@@ -1250,7 +1264,11 @@ public class IMAPStore extends Store
|
|
|
|
return pool.separateStoreConnection;
|
|
|
|
}
|
|
|
|
|
|
|
|
- /**
|
|
|
|
+ boolean isStoreConnectionInUse() {
|
|
|
|
+ return pool.storeConnectionInUse;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
* Return the connection pool logger.
|
|
|
|
*/
|
|
|
|
MailLogger getConnectionPoolLogger() {
|
|
|
|
@@ -1529,6 +1547,30 @@ public class IMAPStore extends Store
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
+ public synchronized String getCapability(String capability)
|
|
|
|
+ throws MessagingException {
|
|
|
|
+ IMAPProtocol p = null;
|
|
|
|
+ try {
|
|
|
|
+ p = getStoreProtocol();
|
|
|
|
+ Map<String, String> caps = p.getCapabilities();
|
|
|
|
+ if (caps != null)
|
|
|
|
+ for (String cap : caps.values()) {
|
|
|
|
+ int eq = (cap == null ? -1 : cap.indexOf('='));
|
|
|
|
+ if (eq > 0) {
|
|
|
|
+ String key = cap.substring(0, eq);
|
|
|
|
+ String value = cap.substring(eq + 1);
|
|
|
|
+ if (capability.equals(key))
|
|
|
|
+ return value;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return null;
|
|
|
|
+ } catch (ProtocolException pex) {
|
|
|
|
+ throw new MessagingException(pex.getMessage(), pex);
|
|
|
|
+ } finally {
|
|
|
|
+ releaseStoreProtocol(p);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
/**
|
|
|
|
* Set the user name to be used with the PROXYAUTH command.
|
|
|
|
* The PROXYAUTH user name can also be set using the
|
|
|
|
@@ -2035,7 +2077,11 @@ public class IMAPStore extends Store
|
|
|
|
// without aborting it ourselves
|
|
|
|
try {
|
|
|
|
// give up lock and wait to be not idle
|
|
|
|
- pool.wait();
|
|
|
|
+ pool.wait(pool.clientTimeoutInterval);
|
|
|
|
+ if (pool.idleState != ConnectionPool.RUNNING) {
|
|
|
|
+ eu.faircode.email.Log.e("idle timeout");
|
|
|
|
+ throw new InterruptedException("idle timeout");
|
|
|
|
+ }
|
|
|
|
} catch (InterruptedException ex) {
|
|
|
|
// restore the interrupted state, which callers might
|
|
|
|
// depend on
|
|
|
|
@@ -2128,7 +2174,11 @@ public class IMAPStore extends Store
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
// give up lock and wait to be not idle
|
|
|
|
- pool.wait();
|
|
|
|
+ pool.wait(pool.clientTimeoutInterval);
|
|
|
|
+ if (pool.idleState != ConnectionPool.RUNNING) {
|
|
|
|
+ eu.faircode.email.Log.e("waitIfIdle timeout");
|
|
|
|
+ throw new InterruptedException("waitIfIdle timeout");
|
|
|
|
+ }
|
|
|
|
} catch (InterruptedException ex) {
|
|
|
|
// If someone is trying to interrupt us we can't keep going
|
|
|
|
// around the loop waiting for IDLE to complete, but we can't
|
|
|
|
diff -rupN /home/marcel/JavaMail/mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java ./app/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java
|
|
|
|
--- /home/marcel/JavaMail/mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java 2020-08-14 11:44:05.406359065 +0200
|
|
|
|
+++ ./app/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java 2020-08-28 17:41:28.427621762 +0200
|
|
|
|
@@ -462,6 +462,9 @@ public class IMAPProtocol extends Protoc
|
|
|
|
*/
|
|
|
|
public void logout() throws ProtocolException {
|
|
|
|
try {
|
|
|
|
+ if (!authenticated)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
Response[] r = command("LOGOUT", null);
|
|
|
|
|
|
|
|
authenticated = false;
|
|
|
|
@@ -627,6 +630,59 @@ public class IMAPProtocol extends Protoc
|
|
|
|
authenticated = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ public synchronized void authclassic(String u, String p)
|
|
|
|
+ throws ProtocolException {
|
|
|
|
+ List<Response> v = new ArrayList<>();
|
|
|
|
+ String tag = null;
|
|
|
|
+ Response r = null;
|
|
|
|
+ boolean done = false;
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+
|
|
|
|
+ if (noauthdebug && isTracing()) {
|
|
|
|
+ logger.fine("LOGIN command trace suppressed");
|
|
|
|
+ suspendTracing();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ Argument arg = new Argument();
|
|
|
|
+ arg.writeNString(u);
|
|
|
|
+ arg.writeNString(p);
|
|
|
|
+ tag = writeCommand("LOGIN", arg);
|
|
|
|
+ } catch (Exception ex) {
|
|
|
|
+ r = Response.byeResponse(ex);
|
|
|
|
+ done = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ while (!done) {
|
|
|
|
+ try {
|
|
|
|
+ r = readResponse();
|
|
|
|
+ if (r.isTagged() && r.getTag().equals(tag))
|
|
|
|
+ done = true;
|
|
|
|
+ else if (r.isBYE()) // outta here
|
|
|
|
+ done = true;
|
|
|
|
+ } catch (Exception ioex) {
|
|
|
|
+ r = Response.byeResponse(ioex);
|
|
|
|
+ done = true;
|
|
|
|
+ }
|
|
|
|
+ v.add(r);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ } finally {
|
|
|
|
+ resumeTracing();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Response[] responses = v.toArray(new Response[v.size()]);
|
|
|
|
+
|
|
|
|
+ handleCapabilityResponse(responses);
|
|
|
|
+ notifyResponseHandlers(responses);
|
|
|
|
+
|
|
|
|
+ if (noauthdebug && isTracing())
|
|
|
|
+ logger.fine("LOGIN command result: " + r);
|
|
|
|
+ handleLoginResult(r);
|
|
|
|
+ setCapabilities(r);
|
|
|
|
+ authenticated = true;
|
|
|
|
+ }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The AUTHENTICATE command with AUTH=PLAIN authentication scheme.
|
|
|
|
--- /home/marcel/JavaMail/mail/src/main/java/javax/mail/EventQueue.java 2020-08-14 11:44:05.413359065 +0200
|
|
|
|
+++ app/src/main/java/javax/mail/EventQueue.java 2020-09-21 11:04:19.648547947 +0200
|
|
|
|
@@ -154,6 +154,19 @@ class EventQueue implements Runnable {
|
|
|
|
}
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
// just die
|
|
|
|
+ } catch (Error ex) {
|
|
|
|
+ /*
|
|
|
|
+ java.lang.Error: java.lang.InterruptedException
|
|
|
|
+ at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1173)
|
|
|
|
+ at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
|
|
|
|
+ at java.lang.Thread.run(Thread.java:919)
|
|
|
|
+ Caused by: java.lang.InterruptedException
|
|
|
|
+ at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1248)
|
|
|
|
+ at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:344)
|
|
|
|
+ at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:439)
|
|
|
|
+ at javax.mail.EventQueue.run(SourceFile:140)
|
|
|
|
+ at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
|
|
|
|
+ */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
diff --git a/app/src/main/java/com/sun/mail/imap/IMAPStore.java b/app/src/main/java/com/sun/mail/imap/IMAPStore.java
|
|
|
|
index 087e5a6f5..5fa720f3d 100644
|
|
|
|
--- a/app/src/main/java/com/sun/mail/imap/IMAPStore.java
|
|
|
|
+++ b/app/src/main/java/com/sun/mail/imap/IMAPStore.java
|
|
|
|
@@ -1571,6 +1571,19 @@ public class IMAPStore extends Store
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
+ public synchronized Map<String, String> getCapabilities()
|
|
|
|
+ throws MessagingException {
|
|
|
|
+ IMAPProtocol p = null;
|
|
|
|
+ try {
|
|
|
|
+ p = getStoreProtocol();
|
|
|
|
+ return p.getCapabilities();
|
|
|
|
+ } catch (ProtocolException pex) {
|
|
|
|
+ throw new MessagingException(pex.getMessage(), pex);
|
|
|
|
+ } finally {
|
|
|
|
+ releaseStoreProtocol(p);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
/**
|
|
|
|
* Set the user name to be used with the PROXYAUTH command.
|
|
|
|
* The PROXYAUTH user name can also be set using the
|