Added experimental HIGHESTMODSEQ support

pull/197/head
M66B 5 years ago
parent 9867cb1c50
commit 136b4a4744

@ -2460,6 +2460,7 @@ class Core {
boolean sync_flagged = prefs.getBoolean("sync_flagged", false); boolean sync_flagged = prefs.getBoolean("sync_flagged", false);
boolean sync_kept = prefs.getBoolean("sync_kept", true); boolean sync_kept = prefs.getBoolean("sync_kept", true);
boolean delete_unseen = prefs.getBoolean("delete_unseen", false); boolean delete_unseen = prefs.getBoolean("delete_unseen", false);
boolean use_modseq = prefs.getBoolean("use_modseq", BuildConfig.DEBUG);
boolean perform_expunge = prefs.getBoolean("perform_expunge", true); boolean perform_expunge = prefs.getBoolean("perform_expunge", true);
Log.i(folder.name + " start sync after=" + sync_days + "/" + keep_days + Log.i(folder.name + " start sync after=" + sync_days + "/" + keep_days +
@ -2482,6 +2483,23 @@ class Core {
Log.w(folder.name, ex); Log.w(folder.name, ex);
} }
// https://tools.ietf.org/html/rfc4551
// https://wiki.mozilla.org/Thunderbird:IMAP_RFC_4551_Implementation
boolean modified = true;
try {
if (use_modseq &&
!force && initialize == 0 &&
MessageHelper.hasCapability(ifolder, "CONDSTORE")) {
long modseq = ifolder.getHighestModSeq();
Log.i(folder.name + " modseq=" + modseq + "/" + folder.modseq);
modified = (folder.modseq == null || !folder.modseq.equals(modseq));
folder.modseq = modseq;
db.folder().setFolderModSeq(folder.id, folder.modseq);
}
} catch (MessagingException ex) {
Log.w(folder.name, ex);
}
// Get reference times // Get reference times
Calendar cal_sync = Calendar.getInstance(); Calendar cal_sync = Calendar.getInstance();
cal_sync.add(Calendar.DAY_OF_MONTH, -sync_days); cal_sync.add(Calendar.DAY_OF_MONTH, -sync_days);
@ -2562,7 +2580,47 @@ class Core {
stats.search_ms = (SystemClock.elapsedRealtime() - search); stats.search_ms = (SystemClock.elapsedRealtime() - search);
Log.i(folder.name + " remote count=" + imessages.length + " search=" + stats.search_ms + " ms"); Log.i(folder.name + " remote count=" + imessages.length + " search=" + stats.search_ms + " ms");
Long[] ids = new Long[imessages.length];
if (!modified) {
Log.i(folder.name + " quick check");
long fetch = SystemClock.elapsedRealtime();
FetchProfile fp = new FetchProfile();
fp.add(UIDFolder.FetchProfileItem.UID);
ifolder.fetch(imessages, fp);
stats.flags = imessages.length;
stats.flags_ms = (SystemClock.elapsedRealtime() - fetch);
Log.i(folder.name + " remote fetched=" + stats.flags_ms + " ms");
try {
for (int i = 0; i < imessages.length && state.isRunning() && state.isRecoverable(); i++) {
long uid = ifolder.getUID(imessages[i]);
ids[i] = db.message().getMessageMsgIdByUid(folder.id, uid);
if (ids[i] == null) {
Log.i(folder.name + " missing uid=" + uid);
modified = true;
break;
} else
uids.remove(uid);
}
} catch (Throwable ex) {
Log.w(ex);
modified = true;
db.folder().setFolderModSeq(folder.id, null);
}
if (uids.size() > 0) {
Log.i(folder.name + " remaining=" + uids.size());
modified = true;
}
EntityLog.log(context, folder.name + " modified=" + modified);
}
if (modified) {
long fetch = SystemClock.elapsedRealtime(); long fetch = SystemClock.elapsedRealtime();
FetchProfile fp = new FetchProfile(); FetchProfile fp = new FetchProfile();
fp.add(UIDFolder.FetchProfileItem.UID); // To check if message exists fp.add(UIDFolder.FetchProfileItem.UID); // To check if message exists
fp.add(FetchProfile.Item.FLAGS); // To update existing messages fp.add(FetchProfile.Item.FLAGS); // To update existing messages
@ -2756,7 +2814,6 @@ class Core {
// Add/update local messages // Add/update local messages
int synced = 0; int synced = 0;
Long[] ids = new Long[imessages.length];
Log.i(folder.name + " add=" + imessages.length); Log.i(folder.name + " add=" + imessages.length);
for (int i = imessages.length - 1; i >= 0 && state.isRunning() && state.isRecoverable(); i -= SYNC_BATCH_SIZE) { for (int i = imessages.length - 1; i >= 0 && state.isRunning() && state.isRecoverable(); i -= SYNC_BATCH_SIZE) {
int from = Math.max(0, i - SYNC_BATCH_SIZE + 1); int from = Math.max(0, i - SYNC_BATCH_SIZE + 1);
@ -2841,6 +2898,7 @@ class Core {
((IMAPMessage) isub[j]).invalidateHeaders(); ((IMAPMessage) isub[j]).invalidateHeaders();
} }
} }
}
// Delete not synchronized messages without uid // Delete not synchronized messages without uid
if (!EntityFolder.isOutgoing(folder.type)) { if (!EntityFolder.isOutgoing(folder.type)) {

@ -296,6 +296,12 @@ public interface DaoMessage {
" AND uid = :uid") " AND uid = :uid")
EntityMessage getMessageByUid(long folder, long uid); EntityMessage getMessageByUid(long folder, long uid);
@Query("SELECT id" +
" FROM message" +
" WHERE folder = :folder" +
" AND uid = :uid")
Long getMessageMsgIdByUid(long folder, long uid);
@Query("SELECT id" + @Query("SELECT id" +
" FROM message" + " FROM message" +
" WHERE folder = :folder" + " WHERE folder = :folder" +

@ -112,6 +112,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
private SwitchCompat swDebug; private SwitchCompat swDebug;
private SwitchCompat swQueries; private SwitchCompat swQueries;
private SwitchCompat swWal; private SwitchCompat swWal;
private SwitchCompat swModSeq;
private SwitchCompat swExpunge; private SwitchCompat swExpunge;
private SwitchCompat swAuthPlain; private SwitchCompat swAuthPlain;
private SwitchCompat swAuthLogin; private SwitchCompat swAuthLogin;
@ -139,7 +140,9 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
"classification", "class_min_probability", "class_min_difference", "classification", "class_min_probability", "class_min_difference",
"language", "watchdog", "updates", "language", "watchdog", "updates",
"experiments", "wal", "query_threads", "crash_reports", "cleanup_attachments", "experiments", "wal", "query_threads", "crash_reports", "cleanup_attachments",
"protocol", "debug", "log_level", "perform_expunge", "auth_plain", "auth_login", "auth_ntlm", "auth_sasl" "protocol", "debug", "log_level",
"use_modseq", "perform_expunge",
"auth_plain", "auth_login", "auth_ntlm", "auth_sasl"
}; };
private final static String[] RESET_QUESTIONS = new String[]{ private final static String[] RESET_QUESTIONS = new String[]{
@ -213,6 +216,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
swDebug = view.findViewById(R.id.swDebug); swDebug = view.findViewById(R.id.swDebug);
swQueries = view.findViewById(R.id.swQueries); swQueries = view.findViewById(R.id.swQueries);
swWal = view.findViewById(R.id.swWal); swWal = view.findViewById(R.id.swWal);
swModSeq = view.findViewById(R.id.swModSeq);
swExpunge = view.findViewById(R.id.swExpunge); swExpunge = view.findViewById(R.id.swExpunge);
swAuthPlain = view.findViewById(R.id.swAuthPlain); swAuthPlain = view.findViewById(R.id.swAuthPlain);
swAuthLogin = view.findViewById(R.id.swAuthLogin); swAuthLogin = view.findViewById(R.id.swAuthLogin);
@ -529,11 +533,19 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
} }
}); });
swModSeq.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
prefs.edit().putBoolean("use_modseq", checked).apply();
ServiceSynchronize.reload(compoundButton.getContext(), null, true, "use_modseq");
}
});
swExpunge.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { swExpunge.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
prefs.edit().putBoolean("perform_expunge", checked).apply(); prefs.edit().putBoolean("perform_expunge", checked).apply();
ServiceSynchronize.reload(getContext(), null, true, "perform_expunge"); ServiceSynchronize.reload(compoundButton.getContext(), null, true, "perform_expunge");
} }
}); });
@ -918,6 +930,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
swDebug.setChecked(prefs.getBoolean("debug", false)); swDebug.setChecked(prefs.getBoolean("debug", false));
swQueries.setChecked(prefs.getInt("query_threads", 4) < 4); swQueries.setChecked(prefs.getInt("query_threads", 4) < 4);
swWal.setChecked(prefs.getBoolean("wal", true)); swWal.setChecked(prefs.getBoolean("wal", true));
swModSeq.setChecked(prefs.getBoolean("use_modseq", BuildConfig.DEBUG));
swExpunge.setChecked(prefs.getBoolean("perform_expunge", true)); swExpunge.setChecked(prefs.getBoolean("perform_expunge", true));
swAuthPlain.setChecked(prefs.getBoolean("auth_plain", true)); swAuthPlain.setChecked(prefs.getBoolean("auth_plain", true));
swAuthLogin.setChecked(prefs.getBoolean("auth_login", true)); swAuthLogin.setChecked(prefs.getBoolean("auth_login", true));

@ -529,6 +529,18 @@
app:layout_constraintTop_toBottomOf="@id/tvQueriesRemark" app:layout_constraintTop_toBottomOf="@id/tvQueriesRemark"
app:switchPadding="12dp" /> app:switchPadding="12dp" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/swModSeq"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:checked="true"
android:text="@string/title_advanced_modseq"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swWal"
app:switchPadding="12dp" />
<androidx.appcompat.widget.SwitchCompat <androidx.appcompat.widget.SwitchCompat
android:id="@+id/swExpunge" android:id="@+id/swExpunge"
android:layout_width="0dp" android:layout_width="0dp"
@ -538,7 +550,7 @@
android:text="@string/title_advanced_expunge" android:text="@string/title_advanced_expunge"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swWal" app:layout_constraintTop_toBottomOf="@id/swModSeq"
app:switchPadding="12dp" /> app:switchPadding="12dp" />
<androidx.appcompat.widget.SwitchCompat <androidx.appcompat.widget.SwitchCompat
@ -694,7 +706,7 @@
android:layout_height="0dp" android:layout_height="0dp"
app:constraint_referenced_ids=" app:constraint_referenced_ids="
swQueries,tvQueriesHint,tvQueriesRemark,swWal, swQueries,tvQueriesHint,tvQueriesRemark,swWal,
swExpunge, swModSeq,swExpunge,
swAuthPlain,swAuthLogin,swAuthNtlm,swAuthSasl, swAuthPlain,swAuthLogin,swAuthNtlm,swAuthSasl,
tvProcessors,tvMemoryClass,tvMemoryUsage,tvStorageUsage, tvProcessors,tvMemoryClass,tvMemoryUsage,tvStorageUsage,
tvFingerprint, tvFingerprint,

@ -536,6 +536,7 @@
<string name="title_advanced_language">Language</string> <string name="title_advanced_language">Language</string>
<string name="title_advanced_language_system">System</string> <string name="title_advanced_language_system">System</string>
<string name="title_advanced_watchdog">Periodically check if FairEmail is still active</string> <string name="title_advanced_watchdog">Periodically check if FairEmail is still active</string>
<string name="title_advanced_modseq" translatable="false">MODSEQ (debug only)</string>
<string name="title_advanced_expunge" translatable="false">EXPUNGE (debug only)</string> <string name="title_advanced_expunge" translatable="false">EXPUNGE (debug only)</string>
<string name="title_advanced_auth_plain" translatable="false">PLAIN (debug only)</string> <string name="title_advanced_auth_plain" translatable="false">PLAIN (debug only)</string>
<string name="title_advanced_auth_login" translatable="false">LOGIN (debug only)</string> <string name="title_advanced_auth_login" translatable="false">LOGIN (debug only)</string>

Loading…
Cancel
Save