From b172e217b2655fd66fa0d7d4d3145a1c38539261 Mon Sep 17 00:00:00 2001 From: M66B Date: Sat, 10 Feb 2024 09:45:33 +0100 Subject: [PATCH] Improved header highlighting --- .../java/eu/faircode/email/ActivityDSN.java | 28 +- .../java/eu/faircode/email/ActivityEML.java | 6 +- .../eu/faircode/email/AdapterMessage.java | 16 +- .../java/eu/faircode/email/HtmlHelper.java | 291 +++++++++--------- app/src/main/res/layout/activity_eml.xml | 4 +- 5 files changed, 172 insertions(+), 173 deletions(-) diff --git a/app/src/main/java/eu/faircode/email/ActivityDSN.java b/app/src/main/java/eu/faircode/email/ActivityDSN.java index c704cca1c8..1100d2531a 100644 --- a/app/src/main/java/eu/faircode/email/ActivityDSN.java +++ b/app/src/main/java/eu/faircode/email/ActivityDSN.java @@ -87,7 +87,7 @@ public class ActivityDSN extends ActivityBase { Bundle args = new Bundle(); args.putParcelable("uri", uri); - new SimpleTask() { + new SimpleTask() { @Override protected void onPreExecute(Bundle args) { pbWait.setVisibility(View.VISIBLE); @@ -99,35 +99,29 @@ public class ActivityDSN extends ActivityBase { } @Override - protected Result onExecute(Context context, Bundle args) throws Throwable { + protected Spanned onExecute(Context context, Bundle args) throws Throwable { Uri uri = args.getParcelable("uri"); NoStreamException.check(uri, context); - Result result = new Result(); - ContentResolver resolver = context.getContentResolver(); try (InputStream is = resolver.openInputStream(uri)) { if (is == null) throw new FileNotFoundException(uri.toString()); ByteArrayOutputStream bos = new ByteArrayOutputStream(); - byte[] buffer = new byte[Helper.BUFFER_SIZE]; - int length; - while ((length = is.read(buffer)) != -1) - bos.write(buffer, 0, length); + Helper.copy(is, bos); - String headers = MessageHelper.decodeMime(bos.toString(StandardCharsets.UTF_8.name())); - result.headers = HtmlHelper.highlightHeaders(context, - null, null, null, headers, false); + String headers = bos.toString(StandardCharsets.UTF_8.name()); + headers = MessageHelper.decodeMime(headers); + return HtmlHelper.highlightHeaders(context, + null, null, null, headers, false, false); } - - return result; } @Override - protected void onExecuted(Bundle args, Result result) { - tvHeaders.setText(result.headers); + protected void onExecuted(Bundle args, Spanned result) { + tvHeaders.setText(result); grpReady.setVisibility(View.VISIBLE); } @@ -140,8 +134,4 @@ public class ActivityDSN extends ActivityBase { } }.execute(this, args, "disposition:decode"); } - - private class Result { - Spanned headers; - } } diff --git a/app/src/main/java/eu/faircode/email/ActivityEML.java b/app/src/main/java/eu/faircode/email/ActivityEML.java index 422c78e291..ba862ae26e 100644 --- a/app/src/main/java/eu/faircode/email/ActivityEML.java +++ b/app/src/main/java/eu/faircode/email/ActivityEML.java @@ -328,7 +328,11 @@ public class ActivityEML extends ActivityBase { result.structure = ssb; result.headers = HtmlHelper.highlightHeaders(context, - helper.getFrom(), helper.getTo(), helper.getReceivedHeader(), helper.getHeaders(), false); + helper.getFrom(), + helper.getTo(), + helper.getReceivedHeader(), + helper.getHeaders(), + false, false); return result; } diff --git a/app/src/main/java/eu/faircode/email/AdapterMessage.java b/app/src/main/java/eu/faircode/email/AdapterMessage.java index ecde3b5816..2b7ceaaf83 100644 --- a/app/src/main/java/eu/faircode/email/AdapterMessage.java +++ b/app/src/main/java/eu/faircode/email/AdapterMessage.java @@ -2768,11 +2768,16 @@ public class AdapterMessage extends RecyclerView.Adapter 0) { + for (int i = received.length - 1; i >= 0; i--) { + ssb.append('\n'); + String h = MimeUtility.unfold(received[i]); + + int semi = h.lastIndexOf(';'); + if (semi > 0) { + rx = mdf.parse(h, new ParsePosition(semi + 1)); + h = h.substring(0, semi); + } + + int s = ssb.length(); + ssb.append('#').append(Integer.toString(received.length - i)); + if (rx != null) { + ssb.append(' ').append(DTF.format(rx)); + if (tx != null) + ssb.append(" \u0394") + .append(Helper.formatDuration(rx.getTime() - tx.getTime())); + } + ssb.setSpan(new StyleSpan(Typeface.BOLD), s, ssb.length(), 0); + + if (blocklist && i == received.length - 1) { + Drawable d = ContextCompat.getDrawable(context, R.drawable.twotone_flag_24); + + int iconSize = context.getResources().getDimensionPixelSize(R.dimen.menu_item_icon_size); + d.setBounds(0, 0, iconSize, iconSize); + d.setTint(colorWarning); + + ssb.append(" \uFFFC"); // Object replacement character + ssb.setSpan(new ImageSpan(d), ssb.length() - 1, ssb.length(), 0); + + if (!TextUtils.isEmpty(BuildConfig.MXTOOLBOX_URI)) { + final String header = received[i]; + ClickableSpan click = new ClickableSpan() { + @Override + public void onClick(@NonNull View widget) { + DnsBlockList.show(widget.getContext(), header); + } + }; + ssb.setSpan(click, ssb.length() - 1, ssb.length(), 0); + } + } + + ssb.append('\n'); + + int j = 0; + boolean p = false; + String[] w = h.split("\\s+"); + while (j < w.length) { + if (w[j].startsWith("(")) + p = true; + + if (j > 0) + ssb.append(' '); + + s = ssb.length(); + ssb.append(w[j]); + if (!p && MessageHelper.RECEIVED_WORDS.contains(w[j].toLowerCase(Locale.ROOT))) { + ssb.setSpan(new ForegroundColorSpan(textColorLink), s, ssb.length(), 0); + ssb.setSpan(new StyleSpan(Typeface.BOLD), s, ssb.length(), 0); + } + + if (w[j].endsWith(")")) + p = false; + + j++; + } + + Boolean tls = MessageHelper.isTLS(h, i == received.length - 1); + ssb.append(" TLS="); + int t = ssb.length(); + ssb.append(tls == null ? "?" : Boolean.toString(tls)); + if (tls != null) + ssb.setSpan(new ForegroundColorSpan(tls ? colorVerified : colorWarning), t, ssb.length(), 0); + + ssb.append("\n"); + } + } + + if (time != null) { + ssb.append('\n'); + int s = ssb.length(); + ssb.append(DTF.format(time)); + if (rx != null) + ssb.append(" \u0394") + .append(Helper.formatDuration(time - rx.getTime())); + ssb.setSpan(new StyleSpan(Typeface.BOLD), s, ssb.length(), 0); + } + + if (to != null) { + ssb.append('\n'); + int s = ssb.length(); + ssb.append("to"); + ssb.setSpan(new ForegroundColorSpan(textColorLink), s, ssb.length(), 0); + ssb.setSpan(new StyleSpan(Typeface.BOLD), s, ssb.length(), 0); + ssb.append(' ').append(MessageHelper.formatAddresses(to, true, false)); + } + + if (time != null || to != null) + ssb.append('\n'); + } catch (Throwable ex) { Log.w(ex); } - - if (tx != null) { - ssb.append('\n'); - int s = ssb.length(); - ssb.append(DTF.format(tx)); - ssb.setSpan(new StyleSpan(Typeface.BOLD), s, ssb.length(), 0); - } - - if (from != null) { - ssb.append('\n'); - int s = ssb.length(); - ssb.append("from"); - ssb.setSpan(new ForegroundColorSpan(textColorLink), s, ssb.length(), 0); - ssb.setSpan(new StyleSpan(Typeface.BOLD), s, ssb.length(), 0); - ssb.append(' ').append(MessageHelper.formatAddresses(from, true, false)); - } - - if (tx != null || from != null) - ssb.append('\n'); - - Date rx = null; - String[] received = iheaders.getHeader("Received"); - if (received != null && received.length > 0) { - for (int i = received.length - 1; i >= 0; i--) { - ssb.append('\n'); - String h = MimeUtility.unfold(received[i]); - - int semi = h.lastIndexOf(';'); - if (semi > 0) { - rx = mdf.parse(h, new ParsePosition(semi + 1)); - h = h.substring(0, semi); - } - - int s = ssb.length(); - ssb.append('#').append(Integer.toString(received.length - i)); - if (rx != null) { - ssb.append(' ').append(DTF.format(rx)); - if (tx != null) - ssb.append(" \u0394") - .append(Helper.formatDuration(rx.getTime() - tx.getTime())); - } - ssb.setSpan(new StyleSpan(Typeface.BOLD), s, ssb.length(), 0); - - if (blocklist && i == received.length - 1) { - Drawable d = ContextCompat.getDrawable(context, R.drawable.twotone_flag_24); - - int iconSize = context.getResources().getDimensionPixelSize(R.dimen.menu_item_icon_size); - d.setBounds(0, 0, iconSize, iconSize); - d.setTint(colorWarning); - - ssb.append(" \uFFFC"); // Object replacement character - ssb.setSpan(new ImageSpan(d), ssb.length() - 1, ssb.length(), 0); - - if (!TextUtils.isEmpty(BuildConfig.MXTOOLBOX_URI)) { - final String header = received[i]; - ClickableSpan click = new ClickableSpan() { - @Override - public void onClick(@NonNull View widget) { - DnsBlockList.show(widget.getContext(), header); - } - }; - ssb.setSpan(click, ssb.length() - 1, ssb.length(), 0); - } - } - - ssb.append('\n'); - - int j = 0; - boolean p = false; - String[] w = h.split("\\s+"); - while (j < w.length) { - if (w[j].startsWith("(")) - p = true; - - if (j > 0) - ssb.append(' '); - - s = ssb.length(); - ssb.append(w[j]); - if (!p && MessageHelper.RECEIVED_WORDS.contains(w[j].toLowerCase(Locale.ROOT))) { - ssb.setSpan(new ForegroundColorSpan(textColorLink), s, ssb.length(), 0); - ssb.setSpan(new StyleSpan(Typeface.BOLD), s, ssb.length(), 0); - } - - if (w[j].endsWith(")")) - p = false; - - j++; - } - - Boolean tls = MessageHelper.isTLS(h, i == received.length - 1); - ssb.append(" TLS="); - int t = ssb.length(); - ssb.append(tls == null ? "?" : Boolean.toString(tls)); - if (tls != null) - ssb.setSpan(new ForegroundColorSpan(tls ? colorVerified : colorWarning), t, ssb.length(), 0); - - ssb.append("\n"); - } - } - - if (time != null) { - ssb.append('\n'); - int s = ssb.length(); - ssb.append(DTF.format(time)); - if (rx != null) - ssb.append(" \u0394") - .append(Helper.formatDuration(time - rx.getTime())); - ssb.setSpan(new StyleSpan(Typeface.BOLD), s, ssb.length(), 0); - } - - if (to != null) { - ssb.append('\n'); - int s = ssb.length(); - ssb.append("to"); - ssb.setSpan(new ForegroundColorSpan(textColorLink), s, ssb.length(), 0); - ssb.setSpan(new StyleSpan(Typeface.BOLD), s, ssb.length(), 0); - ssb.append(' ').append(MessageHelper.formatAddresses(to, true, false)); - } - - if (time != null || to != null) - ssb.append('\n'); - } catch (Throwable ex) { - Log.w(ex); } - ssb.append("\n\uFFFC"); // Object replacement character - ssb.setSpan(new LineSpan(colorSeparator, stroke, 0), ssb.length() - 1, ssb.length(), 0); - ssb.append('\n'); - return ssb; } diff --git a/app/src/main/res/layout/activity_eml.xml b/app/src/main/res/layout/activity_eml.xml index a3c8e9e738..88069b4ab5 100644 --- a/app/src/main/res/layout/activity_eml.xml +++ b/app/src/main/res/layout/activity_eml.xml @@ -239,7 +239,7 @@ android:id="@+id/vSeparatorBody" android:layout_width="0dp" android:layout_height="1dp" - android:layout_marginTop="3dp" + android:layout_marginTop="12dp" android:background="?attr/colorSeparator" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -249,7 +249,7 @@ android:id="@+id/tvBody" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginTop="3dp" + android:layout_marginTop="12dp" android:text="Body" android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textIsSelectable="true"