Prepare custom IMAP folder/message implementation

This commit is contained in:
M66B 2022-03-23 22:17:11 +01:00
parent 4905d2ff0e
commit 632a82a870
3 changed files with 246 additions and 0 deletions

View File

@ -279,6 +279,9 @@ public class EmailService implements AutoCloseable {
properties.put("mail." + protocol + ".peek", "true");
properties.put("mail." + protocol + ".appendbuffersize", Integer.toString(APPEND_BUFFER_SIZE));
if (!"gimaps".equals(protocol) && BuildConfig.DEBUG)
properties.put("mail." + protocol + ".folder.class", IMAPFolderEX.class.getName());
} else if ("smtp".equals(protocol) || "smtps".equals(protocol)) {
// https://javaee.github.io/javamail/docs/api/com/sun/mail/smtp/package-summary.html#properties
properties.put("mail.smtps.starttls.enable", "false");

View File

@ -0,0 +1,167 @@
package eu.faircode.email;
/*
This file is part of FairEmail.
FairEmail is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
FairEmail is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
Copyright 2018-2022 by Marcel Bokhorst (M66B)
*/
import com.sun.mail.iap.Argument;
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.IMAPFolder;
import com.sun.mail.imap.IMAPMessage;
import com.sun.mail.imap.IMAPStore;
import com.sun.mail.imap.Utility;
import com.sun.mail.imap.protocol.IMAPProtocol;
import com.sun.mail.imap.protocol.ListInfo;
import com.sun.mail.imap.protocol.MessageSet;
import com.sun.mail.imap.protocol.UIDSet;
import javax.mail.FetchProfile;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.FolderClosedException;
import javax.mail.FolderNotFoundException;
import javax.mail.Message;
import javax.mail.MessageRemovedException;
import javax.mail.MessagingException;
import javax.mail.UIDFolder;
public class IMAPFolderEX extends IMAPFolder {
public IMAPFolderEX(String fullName, char separator, IMAPStore store, Boolean isNamespace) {
super(fullName, separator, store, isNamespace);
}
public IMAPFolderEX(ListInfo li, IMAPStore store) {
super(li, store);
}
@Override
public synchronized void setFlags(Message[] msgs, Flags flag, boolean value) throws MessagingException {
checkOpened();
// checkFlags(flag);
if (msgs.length == 0)
return;
synchronized (messageCacheLock) {
try {
IMAPProtocol p = getProtocol();
if (p.hasCapability("X-UIDONLY") ||
(p.hasCapability("UIDPLUS") &&
Boolean.parseBoolean(System.getProperty("fairemail.uid_command")))) {
// Verizon
FetchProfile fp = new FetchProfile();
fp.add(UIDFolder.FetchProfileItem.UID);
fetch(msgs, fp);
UIDSet[] uids = Utility.toUIDSet(msgs);
if (uids == null)
return;
Response[] r = p.command("UID STORE " + UIDSet.toString(uids) +
" " + (value ? '+' : '-') + "FLAGS " + p.createFlagList(new Flags(flag)), null);
p.notifyResponseHandlers(r);
p.handleResult(r[r.length - 1]);
return;
}
MessageSet[] ms = Utility.toMessageSetSorted(msgs, null);
if (ms == null)
throw new MessageRemovedException("Messages have been removed");
p.storeFlags(ms, flag, value);
} catch (ConnectionException cex) {
throw new FolderClosedException(this, cex.getMessage());
} catch (ProtocolException pex) {
throw new MessagingException(pex.getMessage(), pex);
}
}
}
@Override
public synchronized void copyMessages(Message[] msgs, Folder folder) throws MessagingException {
copyMessages(msgs, folder, false);
}
public synchronized void moveMessages(Message[] msgs, Folder folder) throws MessagingException {
copyMessages(msgs, folder, true);
}
private synchronized void copyMessages(Message[] msgs, Folder folder, boolean move) throws MessagingException {
checkOpened();
if (msgs.length == 0)
return;
if (folder.getStore() == store) {
synchronized (messageCacheLock) {
try {
IMAPProtocol p = getProtocol();
if (p.hasCapability("X-UIDONLY") ||
(p.hasCapability("UIDPLUS") &&
Boolean.parseBoolean(System.getProperty("fairemail.uid_command")))) {
// Verizon
FetchProfile fp = new FetchProfile();
fp.add(UIDFolder.FetchProfileItem.UID);
fetch(msgs, fp);
UIDSet[] uids = Utility.toUIDSet(msgs);
if (uids == null)
return;
Argument args = new Argument();
args.writeAtom(UIDSet.toString(uids));
p.writeMailboxName(args, folder.getFullName());
Response[] r = p.command(move ? "UID MOVE" : "UID COPY", args);
p.notifyResponseHandlers(r);
p.handleResult(r[r.length - 1]);
return;
}
MessageSet[] ms = Utility.toMessageSet(msgs, null);
if (ms == null)
throw new MessageRemovedException("Messages have been removed");
if (move)
p.move(ms, folder.getFullName());
else
p.copy(ms, folder.getFullName());
} catch (CommandFailedException cfx) {
if (cfx.getMessage() != null &&
cfx.getMessage().contains("TRYCREATE"))
throw new FolderNotFoundException(folder,
folder.getFullName() + " does not exist");
else
throw new MessagingException(cfx.getMessage(), cfx);
} catch (ConnectionException cex) {
throw new FolderClosedException(this, cex.getMessage());
} catch (ProtocolException pex) {
throw new MessagingException(pex.getMessage(), pex);
}
}
} else {
if (move)
throw new MessagingException("Move between stores not supported");
else
super.copyMessages(msgs, folder);
}
}
@Override
public IMAPMessage newIMAPMessage(int msgnum) {
return new IMAPMessageEx(this, msgnum);
}
}

View File

@ -0,0 +1,76 @@
package eu.faircode.email;
/*
This file is part of FairEmail.
FairEmail is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
FairEmail is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
Copyright 2018-2022 by Marcel Bokhorst (M66B)
*/
import com.sun.mail.iap.ConnectionException;
import com.sun.mail.iap.ProtocolException;
import com.sun.mail.iap.Response;
import com.sun.mail.imap.IMAPFolder;
import com.sun.mail.imap.IMAPMessage;
import com.sun.mail.imap.protocol.IMAPProtocol;
import com.sun.mail.imap.protocol.UID;
import javax.mail.Flags;
import javax.mail.FolderClosedException;
import javax.mail.MessagingException;
import javax.mail.Session;
public class IMAPMessageEx extends IMAPMessage {
protected IMAPMessageEx(IMAPFolder folder, int msgnum) {
super(folder, msgnum);
}
protected IMAPMessageEx(Session session) {
super(session);
}
@Override
public synchronized void setFlags(Flags flag, boolean set) throws MessagingException {
synchronized (getMessageCacheLock()) {
try {
IMAPProtocol p = getProtocol();
checkExpunged(); // Insure that this message is not expunged
if (p.hasCapability("X-UIDONLY") ||
"imap.mail.yahoo.co.jp".equals(p.getInetAddress().getHostName()) ||
(p.hasCapability("UIDPLUS") &&
Boolean.parseBoolean(System.getProperty("fairemail.uid_command")))) {
// Verizon
// Yahoo: NO [CANNOT] STORE It's not possible to perform specified operation
long uid = getUID();
if (uid < 0) {
UID u = p.fetchUID(getSequenceNumber());
if (u != null)
uid = u.uid;
}
Response[] r = p.command("UID STORE " + uid +
" " + (set ? '+' : '-') + "FLAGS " + p.createFlagList(new Flags(flag)), null);
p.notifyResponseHandlers(r);
p.handleResult(r[r.length - 1]);
return;
}
p.storeFlags(getSequenceNumber(), flag, set);
} catch (ConnectionException cex) {
throw new FolderClosedException(folder, cex.getMessage());
} catch (ProtocolException pex) {
throw new MessagingException(pex.getMessage(), pex);
}
}
}
}