diff --git a/app/src/main/java/eu/faircode/email/Core.java b/app/src/main/java/eu/faircode/email/Core.java index 3b74321436..678215c52d 100644 --- a/app/src/main/java/eu/faircode/email/Core.java +++ b/app/src/main/java/eu/faircode/email/Core.java @@ -3758,6 +3758,8 @@ class Core { // Local address contains control or whitespace in string ``mailing list someone@example.org'' message.deliveredto = helper.getDeliveredTo(); message.thread = helper.getThreadId(context, account.id, folder.id, uid); + if (BuildConfig.DEBUG && message.thread.startsWith("outlook:")) + message.warning = message.thread; message.priority = helper.getPriority(); for (String keyword : keywords) diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsSynchronize.java b/app/src/main/java/eu/faircode/email/FragmentOptionsSynchronize.java index 4a4e5838ec..a62fcb6086 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsSynchronize.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsSynchronize.java @@ -81,6 +81,7 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr private SwitchCompat swDeleteUnseen; private SwitchCompat swSyncKept; private SwitchCompat swGmailThread; + private SwitchCompat swOutlookThread; private SwitchCompat swSubjectThreading; private TextView tvSubjectThreading; private SwitchCompat swSyncFolders; @@ -107,7 +108,7 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr "enabled", "poll_interval", "auto_optimize", "schedule", "schedule_start", "schedule_end", "sync_quick_imap", "sync_quick_pop", "sync_nodate", "sync_unseen", "sync_flagged", "delete_unseen", "sync_kept", - "gmail_thread_id", "subject_threading", + "gmail_thread_id", "outlook_thread_id", "subject_threading", "sync_folders", "sync_folders_poll", "sync_shared_folders", "subscriptions", "check_authentication", "check_tls", "check_reply_domain", "check_mx", "check_blocklist", "use_blocklist", "tune_keep_alive" @@ -153,6 +154,7 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr swDeleteUnseen = view.findViewById(R.id.swDeleteUnseen); swSyncKept = view.findViewById(R.id.swSyncKept); swGmailThread = view.findViewById(R.id.swGmailThread); + swOutlookThread = view.findViewById(R.id.swOutlookThread); swSubjectThreading = view.findViewById(R.id.swSubjectThreading); tvSubjectThreading = view.findViewById(R.id.tvSubjectThreading); swSyncFolders = view.findViewById(R.id.swSyncFolders); @@ -333,7 +335,15 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr @Override public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { prefs.edit().putBoolean("gmail_thread_id", checked).apply(); - swSubjectThreading.setEnabled(!checked); + swSubjectThreading.setEnabled(!swGmailThread.isChecked() && !swOutlookThread.isChecked()); + } + }); + + swOutlookThread.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + prefs.edit().putBoolean("outlook_thread_id", checked).apply(); + swSubjectThreading.setEnabled(!swGmailThread.isChecked() && !swOutlookThread.isChecked()); } }); @@ -442,6 +452,7 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr // Initialize FragmentDialogTheme.setBackground(getContext(), view, false); + swOutlookThread.setVisibility(BuildConfig.DEBUG ? View.VISIBLE : View.GONE); tvSubjectThreading.setText(getString(R.string.title_advanced_subject_threading_hint, MessageHelper.MAX_SUBJECT_AGE)); DB db = DB.getInstance(getContext()); @@ -526,8 +537,9 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr swDeleteUnseen.setChecked(prefs.getBoolean("delete_unseen", false)); swSyncKept.setChecked(prefs.getBoolean("sync_kept", true)); swGmailThread.setChecked(prefs.getBoolean("gmail_thread_id", false)); + swOutlookThread.setChecked(prefs.getBoolean("outlook_thread_id", false)); swSubjectThreading.setChecked(prefs.getBoolean("subject_threading", false)); - swSubjectThreading.setEnabled(!swGmailThread.isChecked()); + swSubjectThreading.setEnabled(!swGmailThread.isChecked() && !swOutlookThread.isChecked()); swSyncFolders.setChecked(prefs.getBoolean("sync_folders", true)); swSyncFoldersPoll.setChecked(prefs.getBoolean("sync_folders_poll", false)); swSyncFoldersPoll.setEnabled(swSyncFolders.isChecked()); diff --git a/app/src/main/java/eu/faircode/email/MessageHelper.java b/app/src/main/java/eu/faircode/email/MessageHelper.java index 269eaf5bbc..277a7785ed 100644 --- a/app/src/main/java/eu/faircode/email/MessageHelper.java +++ b/app/src/main/java/eu/faircode/email/MessageHelper.java @@ -26,6 +26,7 @@ import android.content.SharedPreferences; import android.net.Uri; import android.system.ErrnoException; import android.text.TextUtils; +import android.util.Base64; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -86,6 +87,7 @@ import java.util.Map; import java.util.Objects; import java.util.Properties; import java.util.TimeZone; +import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -1390,11 +1392,35 @@ public class MessageHelper { boolean gmail_thread_id = prefs.getBoolean("gmail_thread_id", false); if (gmail_thread_id) { long thrid = ((GmailMessage) imessage).getThrId(); + Log.i("Gmail thread=" + thrid); if (thrid > 0) return "gmail:" + thrid; } } + // https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxomsg/9e994fbb-b839-495f-84e3-2c8c02c7dd9b + String tindex = imessage.getHeader("Thread-Index", null); + try { + if (tindex != null) { + boolean outlook_thread_id = prefs.getBoolean("outlook_thread_id", false); + if (outlook_thread_id) { + byte[] data = Base64.decode(tindex, Base64.DEFAULT); + if (data.length >= 22) { + long msb = 0, lsb = 0; + for (int i = 0 + 6; i < 8 + 6; i++) + msb = (msb << 8) | (data[i] & 0xff); + for (int i = 8 + 6; i < 16 + 6; i++) + lsb = (lsb << 8) | (data[i] & 0xff); + UUID guid = new UUID(msb, lsb); + Log.i("Outlook thread=" + guid); + return "outlook:" + guid; + } + } + } + } catch (Throwable ex) { + Log.w(ex); + } + String thread = null; String msgid = getMessageID(); diff --git a/app/src/main/res/layout/fragment_options_synchronize.xml b/app/src/main/res/layout/fragment_options_synchronize.xml index b2962cc490..b80bdbf83d 100644 --- a/app/src/main/res/layout/fragment_options_synchronize.xml +++ b/app/src/main/res/layout/fragment_options_synchronize.xml @@ -577,6 +577,29 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/swGmailThread" /> + + + + Delete old unread messages Check if old messages were removed from the server Gmail message grouping style for Gmail accounts + Use Outlook thread index Group messages by sender and subject Synchronize folder list Actively synchronize folder list