Added POP3 quick check

pull/200/head
M66B 3 years ago
parent 7186d57c46
commit 2b746c0a5e

File diff suppressed because it is too large Load Diff

@ -2299,255 +2299,277 @@ class Core {
? imessages.length ? imessages.length
: Math.min(imessages.length, account.max_messages)); : Math.min(imessages.length, account.max_messages));
boolean sync = true;
if (imessages.length > 0 && folder.last_sync_count != null &&
imessages.length == folder.last_sync_count) {
// Check if last message known as new messages indicator
MessageHelper helper = new MessageHelper((MimeMessage) imessages[imessages.length - 1], context);
String msgid = helper.getMessageID();
if (msgid != null) {
int count = db.message().countMessageByMsgId(folder.id, msgid);
if (count == 1) {
Log.i(account.name + " POP having last msgid=" + msgid);
sync = false;
}
}
}
EntityLog.log(context, account.name + " POP" + EntityLog.log(context, account.name + " POP" +
" device=" + ids.size() + " device=" + ids.size() +
" server=" + imessages.length + " server=" + imessages.length +
" max=" + max + "/" + account.max_messages + " max=" + max + "/" + account.max_messages +
" last=" + folder.last_sync_count +
" sync=" + sync +
" uidl=" + hasUidl); " uidl=" + hasUidl);
// Index IDs folder.last_sync_count = imessages.length;
Map<String, String> uidlMsgId = new HashMap<>(); db.folder().setFolderLastSyncCount(folder.id, folder.last_sync_count);
for (TupleUidl id : ids) {
if (id.uidl != null && id.msgid != null)
uidlMsgId.put(id.uidl, id.msgid);
}
// Fetch UIDLs if (sync) {
if (hasUidl) { // Index IDs
FetchProfile ifetch = new FetchProfile(); Map<String, String> uidlMsgId = new HashMap<>();
ifetch.add(UIDFolder.FetchProfileItem.UID); // This will fetch all UIDs for (TupleUidl id : ids) {
ifolder.fetch(imessages, ifetch); if (id.uidl != null && id.msgid != null)
} uidlMsgId.put(id.uidl, id.msgid);
}
if (!account.leave_on_device) { // Fetch UIDLs
if (hasUidl) { if (hasUidl) {
Map<String, TupleUidl> known = new HashMap<>(); FetchProfile ifetch = new FetchProfile();
for (TupleUidl id : ids) ifetch.add(UIDFolder.FetchProfileItem.UID); // This will fetch all UIDs
if (id.uidl != null) ifolder.fetch(imessages, ifetch);
known.put(id.uidl, id); }
for (Message imessage : imessages) {
String uidl = ifolder.getUID(imessage);
if (TextUtils.isEmpty(uidl))
known.clear(); // better safe than sorry
else
known.remove(uidl);
}
for (TupleUidl uidl : known.values()) { if (!account.leave_on_device) {
EntityLog.log(context, account.name + " POP purging uidl=" + uidl.uidl); if (hasUidl) {
db.message().deleteMessage(uidl.id); Map<String, TupleUidl> known = new HashMap<>();
} for (TupleUidl id : ids)
} else { if (id.uidl != null)
Map<String, TupleUidl> known = new HashMap<>(); known.put(id.uidl, id);
for (TupleUidl id : ids)
if (id.msgid != null) for (Message imessage : imessages) {
known.put(id.msgid, id); String uidl = ifolder.getUID(imessage);
if (TextUtils.isEmpty(uidl))
known.clear(); // better safe than sorry
else
known.remove(uidl);
}
for (int i = imessages.length - max; i < imessages.length; i++) { for (TupleUidl uidl : known.values()) {
Message imessage = imessages[i]; EntityLog.log(context, account.name + " POP purging uidl=" + uidl.uidl);
MessageHelper helper = new MessageHelper((MimeMessage) imessage, context); db.message().deleteMessage(uidl.id);
String msgid = helper.getMessageID(); // expensive! }
if (!TextUtils.isEmpty(msgid)) } else {
known.remove(msgid); Map<String, TupleUidl> known = new HashMap<>();
} for (TupleUidl id : ids)
if (id.msgid != null)
known.put(id.msgid, id);
for (int i = imessages.length - max; i < imessages.length; i++) {
Message imessage = imessages[i];
MessageHelper helper = new MessageHelper((MimeMessage) imessage, context);
String msgid = helper.getMessageID(); // expensive!
if (!TextUtils.isEmpty(msgid))
known.remove(msgid);
}
for (TupleUidl uidl : known.values()) { for (TupleUidl uidl : known.values()) {
EntityLog.log(context, account.name + " POP purging msgid=" + uidl.msgid); EntityLog.log(context, account.name + " POP purging msgid=" + uidl.msgid);
db.message().deleteMessage(uidl.id); db.message().deleteMessage(uidl.id);
}
} }
} }
}
boolean _new = true; boolean _new = true;
for (int i = imessages.length - 1; i >= imessages.length - max; i--) { for (int i = imessages.length - 1; i >= imessages.length - max; i--) {
Message imessage = imessages[i]; Message imessage = imessages[i];
try { try {
if (!state.isRunning()) if (!state.isRunning())
return; return;
MessageHelper helper = new MessageHelper((MimeMessage) imessage, context); MessageHelper helper = new MessageHelper((MimeMessage) imessage, context);
String uidl; String uidl;
String msgid; String msgid;
if (hasUidl) { if (hasUidl) {
uidl = ifolder.getUID(imessage); uidl = ifolder.getUID(imessage);
if (TextUtils.isEmpty(uidl)) { if (TextUtils.isEmpty(uidl)) {
EntityLog.log(context, account.name + " POP no uidl"); EntityLog.log(context, account.name + " POP no uidl");
continue; continue;
} }
msgid = uidlMsgId.get(uidl); msgid = uidlMsgId.get(uidl);
if (msgid == null) { if (msgid == null) {
msgid = helper.getMessageID();
if (TextUtils.isEmpty(msgid))
msgid = uidl;
}
} else {
uidl = null;
msgid = helper.getMessageID(); msgid = helper.getMessageID();
if (TextUtils.isEmpty(msgid))
msgid = uidl; if (TextUtils.isEmpty(msgid)) {
Long time = helper.getReceived();
if (time == null)
time = helper.getSent();
if (time != null)
msgid = Long.toString(time);
}
} }
} else {
uidl = null;
msgid = helper.getMessageID();
if (TextUtils.isEmpty(msgid)) { if (TextUtils.isEmpty(msgid)) {
Long time = helper.getReceived(); EntityLog.log(context, account.name + " POP no msgid uidl=" + uidl);
if (time == null) continue;
time = helper.getSent();
if (time != null)
msgid = Long.toString(time);
} }
}
if (TextUtils.isEmpty(msgid)) { if (db.message().countMessageByMsgId(folder.id, msgid) > 0) {
EntityLog.log(context, account.name + " POP no msgid uidl=" + uidl); _new = false;
continue; Log.i(account.name + " POP having " + msgid + "/" + uidl);
} continue;
}
if (db.message().countMessageByMsgId(folder.id, msgid) > 0) { try {
_new = false; Long sent = helper.getSent();
Log.i(account.name + " POP having " + msgid + "/" + uidl); Long received = helper.getReceivedHeader();
continue; if (received == null)
} received = sent;
if (received == null)
received = 0L;
boolean seen = (received <= account.created);
EntityLog.log(context, account.name + " POP sync=" + uidl + "/" + msgid +
" new=" + _new + " seen=" + seen);
String[] authentication = helper.getAuthentication();
MessageHelper.MessageParts parts = helper.getMessageParts();
EntityMessage message = new EntityMessage();
message.account = folder.account;
message.folder = folder.id;
message.uid = null;
message.uidl = uidl;
message.msgid = msgid;
message.hash = helper.getHash();
message.references = TextUtils.join(" ", helper.getReferences());
message.inreplyto = helper.getInReplyTo();
message.deliveredto = helper.getDeliveredTo();
message.thread = helper.getThreadId(context, account.id, 0);
message.priority = helper.getPriority();
message.auto_submitted = helper.getAutoSubmitted();
message.receipt_request = helper.getReceiptRequested();
message.receipt_to = helper.getReceiptTo();
message.bimi_selector = helper.getBimiSelector();
message.dkim = MessageHelper.getAuthentication("dkim", authentication);
message.spf = MessageHelper.getAuthentication("spf", authentication);
message.dmarc = MessageHelper.getAuthentication("dmarc", authentication);
message.return_path = helper.getReturnPath();
message.submitter = helper.getSender();
message.from = helper.getFrom();
message.to = helper.getTo();
message.cc = helper.getCc();
message.bcc = helper.getBcc();
message.reply = helper.getReply();
message.list_post = helper.getListPost();
message.unsubscribe = helper.getListUnsubscribe();
message.headers = helper.getHeaders();
message.subject = helper.getSubject();
message.size = parts.getBodySize();
message.total = helper.getSize();
message.content = false;
message.encrypt = parts.getEncryption();
message.ui_encrypt = message.encrypt;
message.received = received;
message.sent = sent;
message.seen = seen;
message.answered = false;
message.flagged = false;
message.flags = null;
message.keywords = new String[0];
message.ui_seen = seen;
message.ui_answered = false;
message.ui_flagged = false;
message.ui_hide = false;
message.ui_found = false;
message.ui_ignored = !_new;
message.ui_browsed = false;
if (message.deliveredto != null)
try {
Address deliveredto = new InternetAddress(message.deliveredto);
if (MessageHelper.equalEmail(new Address[]{deliveredto}, message.to))
message.deliveredto = null;
} catch (AddressException ex) {
Log.w(ex);
}
try { if (MessageHelper.equalEmail(message.submitter, message.from))
Long sent = helper.getSent(); message.submitter = null;
Long received = helper.getReceivedHeader();
if (received == null) if (message.size == null && message.total != null)
received = sent; message.size = message.total;
if (received == null)
received = 0L;
boolean seen = (received <= account.created);
EntityLog.log(context, account.name + " POP sync=" + uidl + "/" + msgid +
" new=" + _new + " seen=" + seen);
String[] authentication = helper.getAuthentication();
MessageHelper.MessageParts parts = helper.getMessageParts();
EntityMessage message = new EntityMessage();
message.account = folder.account;
message.folder = folder.id;
message.uid = null;
message.uidl = uidl;
message.msgid = msgid;
message.hash = helper.getHash();
message.references = TextUtils.join(" ", helper.getReferences());
message.inreplyto = helper.getInReplyTo();
message.deliveredto = helper.getDeliveredTo();
message.thread = helper.getThreadId(context, account.id, 0);
message.priority = helper.getPriority();
message.auto_submitted = helper.getAutoSubmitted();
message.receipt_request = helper.getReceiptRequested();
message.receipt_to = helper.getReceiptTo();
message.bimi_selector = helper.getBimiSelector();
message.dkim = MessageHelper.getAuthentication("dkim", authentication);
message.spf = MessageHelper.getAuthentication("spf", authentication);
message.dmarc = MessageHelper.getAuthentication("dmarc", authentication);
message.return_path = helper.getReturnPath();
message.submitter = helper.getSender();
message.from = helper.getFrom();
message.to = helper.getTo();
message.cc = helper.getCc();
message.bcc = helper.getBcc();
message.reply = helper.getReply();
message.list_post = helper.getListPost();
message.unsubscribe = helper.getListUnsubscribe();
message.headers = helper.getHeaders();
message.subject = helper.getSubject();
message.size = parts.getBodySize();
message.total = helper.getSize();
message.content = false;
message.encrypt = parts.getEncryption();
message.ui_encrypt = message.encrypt;
message.received = received;
message.sent = sent;
message.seen = seen;
message.answered = false;
message.flagged = false;
message.flags = null;
message.keywords = new String[0];
message.ui_seen = seen;
message.ui_answered = false;
message.ui_flagged = false;
message.ui_hide = false;
message.ui_found = false;
message.ui_ignored = !_new;
message.ui_browsed = false;
if (message.deliveredto != null)
try {
Address deliveredto = new InternetAddress(message.deliveredto);
if (MessageHelper.equalEmail(new Address[]{deliveredto}, message.to))
message.deliveredto = null;
} catch (AddressException ex) {
Log.w(ex);
}
if (MessageHelper.equalEmail(message.submitter, message.from)) EntityIdentity identity = matchIdentity(context, folder, message);
message.submitter = null; message.identity = (identity == null ? null : identity.id);
if (message.size == null && message.total != null) message.sender = MessageHelper.getSortKey(message.from);
message.size = message.total; Uri lookupUri = ContactInfo.getLookupUri(message.from);
message.avatar = (lookupUri == null ? null : lookupUri.toString());
if (message.avatar == null && notify_known && pro)
message.ui_ignored = true;
EntityIdentity identity = matchIdentity(context, folder, message); // No MX check
message.identity = (identity == null ? null : identity.id);
message.sender = MessageHelper.getSortKey(message.from); try {
Uri lookupUri = ContactInfo.getLookupUri(message.from); db.beginTransaction();
message.avatar = (lookupUri == null ? null : lookupUri.toString());
if (message.avatar == null && notify_known && pro)
message.ui_ignored = true;
// No MX check message.id = db.message().insertMessage(message);
EntityLog.log(context, account.name + " POP added id=" + message.id +
" uidl/msgid=" + message.uidl + "/" + message.msgid);
int sequence = 1;
for (EntityAttachment attachment : parts.getAttachments()) {
Log.i(account.name + " POP attachment seq=" + sequence +
" name=" + attachment.name + " type=" + attachment.type +
" cid=" + attachment.cid + " pgp=" + attachment.encryption +
" size=" + attachment.size);
attachment.message = message.id;
attachment.sequence = sequence++;
attachment.id = db.attachment().insertAttachment(attachment);
}
try { runRules(context, imessage, account, folder, message, rules);
db.beginTransaction(); reportNewMessage(context, account, folder, message);
message.id = db.message().insertMessage(message); db.setTransactionSuccessful();
EntityLog.log(context, account.name + " POP added id=" + message.id + } finally {
" uidl/msgid=" + message.uidl + "/" + message.msgid); db.endTransaction();
int sequence = 1;
for (EntityAttachment attachment : parts.getAttachments()) {
Log.i(account.name + " POP attachment seq=" + sequence +
" name=" + attachment.name + " type=" + attachment.type +
" cid=" + attachment.cid + " pgp=" + attachment.encryption +
" size=" + attachment.size);
attachment.message = message.id;
attachment.sequence = sequence++;
attachment.id = db.attachment().insertAttachment(attachment);
} }
runRules(context, imessage, account, folder, message, rules); String body = parts.getHtml(context);
reportNewMessage(context, account, folder, message); File file = message.getFile(context);
Helper.writeText(file, body);
String text = HtmlHelper.getFullText(body);
message.preview = HtmlHelper.getPreview(text);
message.language = HtmlHelper.getLanguage(context, message.subject, text);
db.message().setMessageContent(message.id,
true,
message.language,
parts.isPlainOnly(),
message.preview,
parts.getWarnings(message.warning));
for (EntityAttachment attachment : parts.getAttachments())
if (attachment.subsequence == null)
parts.downloadAttachment(context, attachment);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
String body = parts.getHtml(context); ContactInfo.update(context, account, folder, message);
File file = message.getFile(context); } catch (Throwable ex) {
Helper.writeText(file, body); db.folder().setFolderError(folder.id, Log.formatThrowable(ex));
String text = HtmlHelper.getFullText(body); }
message.preview = HtmlHelper.getPreview(text); } finally {
message.language = HtmlHelper.getLanguage(context, message.subject, text); ((POP3Message) imessage).invalidate(true);
db.message().setMessageContent(message.id,
true,
message.language,
parts.isPlainOnly(),
message.preview,
parts.getWarnings(message.warning));
for (EntityAttachment attachment : parts.getAttachments())
if (attachment.subsequence == null)
parts.downloadAttachment(context, attachment);
ContactInfo.update(context, account, folder, message);
} catch (Throwable ex) {
db.folder().setFolderError(folder.id, Log.formatThrowable(ex));
} }
} finally {
((POP3Message) imessage).invalidate(true);
} }
} }

@ -65,7 +65,7 @@ import static eu.faircode.email.ServiceAuthenticator.AUTH_TYPE_PASSWORD;
// https://developer.android.com/topic/libraries/architecture/room.html // https://developer.android.com/topic/libraries/architecture/room.html
@Database( @Database(
version = 202, version = 203,
entities = { entities = {
EntityIdentity.class, EntityIdentity.class,
EntityAccount.class, EntityAccount.class,
@ -2052,6 +2052,12 @@ public abstract class DB extends RoomDatabase {
Log.i("DB migration from version " + startVersion + " to " + endVersion); Log.i("DB migration from version " + startVersion + " to " + endVersion);
db.execSQL("UPDATE identity SET use_ip = 0 WHERE host = 'smtp.office365.com'"); db.execSQL("UPDATE identity SET use_ip = 0 WHERE host = 'smtp.office365.com'");
} }
}).addMigrations(new Migration(202, 203) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
Log.i("DB migration from version " + startVersion + " to " + endVersion);
db.execSQL("ALTER TABLE `folder` ADD COLUMN `last_sync_count` INTEGER");
}
}).addMigrations(new Migration(998, 999) { }).addMigrations(new Migration(998, 999) {
@Override @Override
public void migrate(@NonNull SupportSQLiteDatabase db) { public void migrate(@NonNull SupportSQLiteDatabase db) {

@ -353,6 +353,9 @@ public interface DaoFolder {
@Query("UPDATE folder SET last_sync = :last_sync WHERE id = :id AND NOT (last_sync IS :last_sync)") @Query("UPDATE folder SET last_sync = :last_sync WHERE id = :id AND NOT (last_sync IS :last_sync)")
int setFolderLastSync(long id, long last_sync); int setFolderLastSync(long id, long last_sync);
@Query("UPDATE folder SET last_sync_count = :last_sync_count WHERE id = :id AND NOT (last_sync_count IS :last_sync_count)")
int setFolderLastSyncCount(long id, Integer last_sync_count);
@Query("UPDATE folder SET read_only = :read_only WHERE id = :id AND NOT (read_only IS :read_only)") @Query("UPDATE folder SET read_only = :read_only WHERE id = :id AND NOT (read_only IS :read_only)")
int setFolderReadOnly(long id, boolean read_only); int setFolderReadOnly(long id, boolean read_only);

@ -136,6 +136,7 @@ public class EntityFolder extends EntityOrder implements Serializable {
public Boolean inferiors = true; public Boolean inferiors = true;
public String error; public String error;
public Long last_sync; public Long last_sync;
public Integer last_sync_count; // POP3
static final String INBOX = "Inbox"; static final String INBOX = "Inbox";
static final String OUTBOX = "Outbox"; static final String OUTBOX = "Outbox";

Loading…
Cancel
Save