diff --git a/FAQ.md b/FAQ.md
index f90b5d07d1..8fa186015b 100644
--- a/FAQ.md
+++ b/FAQ.md
@@ -146,6 +146,7 @@ FairEmail follows all the best practices for an email client as decribed in [thi
* [(83) What does 'User is authenticated but not connected' mean?](#user-content-faq83)
* [(84) What are local contacts for?](#user-content-faq84)
* [(85) Why is an identity not available?](#user-content-faq85)
+* [(86) What are 'extra privacy features'?](#user-content-faq86)
[I have another question.](#support)
@@ -1398,6 +1399,16 @@ FairEmail will try to select the best identity based on the *to* address of the
+
+**(86) What are 'extra privacy features'?**
+
+The advanced option *extra privacy features* enables:
+
+* Detection and removal of [tracking images](#user-content-faq82)
+* Splitting linked images into an image and a link
+
+
+
## Support
diff --git a/app/src/main/java/eu/faircode/email/FragmentOptions.java b/app/src/main/java/eu/faircode/email/FragmentOptions.java
index 48f1f4ec88..c408bd9364 100644
--- a/app/src/main/java/eu/faircode/email/FragmentOptions.java
+++ b/app/src/main/java/eu/faircode/email/FragmentOptions.java
@@ -84,7 +84,6 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
private SwitchCompat swAddresses;
private SwitchCompat swMonospaced;
private SwitchCompat swHtml;
- private SwitchCompat swTracking;
private SwitchCompat swImages;
private SwitchCompat swActionbar;
@@ -106,6 +105,7 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
private SwitchCompat swLight;
private Button btnSound;
+ private SwitchCompat swParanoid;
private SwitchCompat swEnglish;
private SwitchCompat swUpdates;
private SwitchCompat swDebug;
@@ -124,11 +124,11 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
"enabled", "schedule_start", "schedule_end",
"metered", "download",
"startup", "date", "threading", "avatars", "identicons", "name_email", "subject_italic", "flags", "preview",
- "addresses", "monospaced", "autohtml", "remove_tracking", "autoimages", "actionbar",
+ "addresses", "monospaced", "autohtml", "autoimages", "actionbar",
"pull", "swipenav", "autoexpand", "autoclose", "autonext", "collapse", "autoread", "automove",
"autoresize", "sender", "autosend",
"notify_preview", "search_local", "light", "sound",
- "updates", "debug",
+ "paranoid", "updates", "debug",
"first", "why", "last_update_check", "app_support", "message_swipe", "message_select", "folder_actions", "folder_sync",
"edit_ref_confirmed", "show_html_confirmed", "show_images_confirmed", "print_html_confirmed", "show_organization", "style_toolbar"
};
@@ -163,7 +163,6 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
swAddresses = view.findViewById(R.id.swAddresses);
swMonospaced = view.findViewById(R.id.swMonospaced);
swHtml = view.findViewById(R.id.swHtml);
- swTracking = view.findViewById(R.id.swTracking);
swImages = view.findViewById(R.id.swImages);
swActionbar = view.findViewById(R.id.swActionbar);
@@ -185,6 +184,7 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
swLight = view.findViewById(R.id.swLight);
btnSound = view.findViewById(R.id.btnSound);
+ swParanoid = view.findViewById(R.id.swParanoid);
swEnglish = view.findViewById(R.id.swEnglish);
swUpdates = view.findViewById(R.id.swUpdates);
swDebug = view.findViewById(R.id.swDebug);
@@ -251,6 +251,13 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
}
});
+ swParanoid.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
+ prefs.edit().putBoolean("paranoid", checked).apply();
+ }
+ });
+
swEnglish.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
@@ -388,13 +395,6 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
}
});
- swTracking.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
- prefs.edit().putBoolean("remove_tracking", checked).apply();
- }
- });
-
swImages.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
@@ -635,7 +635,6 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
swAddresses.setChecked(prefs.getBoolean("addresses", true));
swMonospaced.setChecked(prefs.getBoolean("monospaced", false));
swHtml.setChecked(prefs.getBoolean("autohtml", false));
- swTracking.setChecked(prefs.getBoolean("remove_tracking", true));
swImages.setChecked(prefs.getBoolean("autoimages", false));
swActionbar.setChecked(prefs.getBoolean("actionbar", true));
@@ -657,6 +656,7 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
swNotifyPreview.setEnabled(Helper.isPro(getContext()));
swSearchLocal.setChecked(prefs.getBoolean("search_local", false));
swLight.setChecked(prefs.getBoolean("light", false));
+ swParanoid.setChecked(prefs.getBoolean("paranoid", true));
swEnglish.setChecked(prefs.getBoolean("english", false));
swUpdates.setChecked(prefs.getBoolean("updates", true));
swUpdates.setVisibility(Helper.isPlayStoreInstall(getContext()) ? View.GONE : View.VISIBLE);
diff --git a/app/src/main/java/eu/faircode/email/HtmlHelper.java b/app/src/main/java/eu/faircode/email/HtmlHelper.java
index 83fe1c4ea1..e3248d95cf 100644
--- a/app/src/main/java/eu/faircode/email/HtmlHelper.java
+++ b/app/src/main/java/eu/faircode/email/HtmlHelper.java
@@ -75,8 +75,8 @@ public class HtmlHelper {
static String removeTracking(Context context, String html) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- boolean remove_tracking = prefs.getBoolean("remove_tracking", true);
- if (!remove_tracking)
+ boolean paranoid = prefs.getBoolean("paranoid", true);
+ if (!paranoid)
return html;
Document document = Jsoup.parse(html);
@@ -101,6 +101,9 @@ public class HtmlHelper {
}
static String sanitize(Context context, String html, boolean showQuotes) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ boolean paranoid = prefs.getBoolean("paranoid", true);
+
Document parsed = Jsoup.parse(html);
Whitelist whitelist = Whitelist.relaxed()
.addTags("hr", "abbr")
@@ -190,7 +193,7 @@ public class HtmlHelper {
String src = img.attr("src");
String alt = img.attr("alt");
String title = img.attr("title");
- boolean tracking = isTrackingPixel(img);
+ boolean tracking = (paranoid && isTrackingPixel(img));
// Create image container
Element div = document.createElement("div");
@@ -225,26 +228,27 @@ public class HtmlHelper {
// Split parent link and linked image
boolean linked = false;
- for (Element parent : img.parents())
- if ("a".equals(parent.tagName()) &&
- !TextUtils.isEmpty(parent.attr("href"))) {
- String text = parent.attr("title").trim();
- if (TextUtils.isEmpty(text))
- text = parent.attr("alt").trim();
- if (TextUtils.isEmpty(text))
- text = context.getString(R.string.title_hint_image_link);
-
- img.remove();
- parent.appendText(text);
- String outer = parent.outerHtml();
-
- parent.tagName("span");
- parent.html(outer);
- parent.appendChild(div);
-
- linked = true;
- break;
- }
+ if (paranoid)
+ for (Element parent : img.parents())
+ if ("a".equals(parent.tagName()) &&
+ !TextUtils.isEmpty(parent.attr("href"))) {
+ String text = parent.attr("title").trim();
+ if (TextUtils.isEmpty(text))
+ text = parent.attr("alt").trim();
+ if (TextUtils.isEmpty(text))
+ text = context.getString(R.string.title_hint_image_link);
+
+ img.remove();
+ parent.appendText(text);
+ String outer = parent.outerHtml();
+
+ parent.tagName("span");
+ parent.html(outer);
+ parent.appendChild(div);
+
+ linked = true;
+ break;
+ }
if (!linked) {
img.tagName("div");
diff --git a/app/src/main/res/layout/fragment_options.xml b/app/src/main/res/layout/fragment_options.xml
index e7186c2a87..c20cdc9de3 100644
--- a/app/src/main/res/layout/fragment_options.xml
+++ b/app/src/main/res/layout/fragment_options.xml
@@ -439,18 +439,6 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swHtml" />
-
-
+
+
Show address details by default
Use monospaced font for message text
Automatically show original message for known contacts
- Attempt to remove tracking from original messages
Automatically show images for known contacts
Conversation action bar
@@ -190,6 +189,7 @@
Use notification light
Select notification sound
Force English language
+ Extra privacy features
Check for updates
Debug mode