Added Libravatar support

pull/207/head
M66B 3 years ago
parent 32921af0de
commit fb52254c73

@ -4492,7 +4492,7 @@ Related questions:
🌎 [Google Translate](https://translate.google.com/translate?sl=en&u=https://github.com/M66B/FairEmail/blob/master/FAQ.md%23user-content-faq173) 🌎 [Google Translate](https://translate.google.com/translate?sl=en&u=https://github.com/M66B/FairEmail/blob/master/FAQ.md%23user-content-faq173)
* The Play store version does not support Android Auto, see [this FAQ](#user-content-faq165) for more information * The Play store version does not support Android Auto, see [this FAQ](#user-content-faq165) for more information
* The Play store version does not support [Gravatars](https://gravatar.com/), see [here](https://forum.xda-developers.com/t/app-5-0-fairemail-fully-featured-open-source-privacy-oriented-email-app.3824168/post-85226179) for the reason * The Play store version does not support [Gravatars](https://gravatar.com/) and [Libravatars](https://www.libravatar.org/), see [here](https://forum.xda-developers.com/t/app-5-0-fairemail-fully-featured-open-source-privacy-oriented-email-app.3824168/post-85226179) for the reason
* The Play store version does not support Amazon devices with Android 5 Lollipop because there are critical bugs in this Android version of Amazon * The Play store version does not support Amazon devices with Android 5 Lollipop because there are critical bugs in this Android version of Amazon
* The GitHub version will check for [updates on GitHub](https://github.com/M66B/FairEmail/releases) and is updated more frequently * The GitHub version will check for [updates on GitHub](https://github.com/M66B/FairEmail/releases) and is updated more frequently
* The GitHub version has some different links, some more options (like sharing the HTML of a message) and some different default values (more geared to advanced users) * The GitHub version has some different links, some more options (like sharing the HTML of a message) and some different default values (more geared to advanced users)

@ -158,6 +158,9 @@ android {
buildConfigField "String", "GITHUB_LATEST_API", "\"https://api.github.com/repos/M66B/FairEmail/releases/latest\"" buildConfigField "String", "GITHUB_LATEST_API", "\"https://api.github.com/repos/M66B/FairEmail/releases/latest\""
buildConfigField "String", "GITHUB_LATEST_URI", "\"https://github.com/M66B/FairEmail/releases\"" buildConfigField "String", "GITHUB_LATEST_URI", "\"https://github.com/M66B/FairEmail/releases\""
buildConfigField "String", "GRAVATAR_URI", "\"https://www.gravatar.com/avatar/\"" buildConfigField "String", "GRAVATAR_URI", "\"https://www.gravatar.com/avatar/\""
buildConfigField "String", "LIBRAVATAR_DNS", "\"_avatars-sec._tcp,_avatars._tcp\""
buildConfigField "String", "LIBRAVATAR_URI", "\"https://seccdn.libravatar.org/avatar/\""
buildConfigField "String", "LIBRAVATAR_INFO", "\"https://libravatar.org/\""
buildConfigField "String", "GPA_URI", localProperties.getProperty("gpa.uri", "\"\"") buildConfigField "String", "GPA_URI", localProperties.getProperty("gpa.uri", "\"\"")
buildConfigField "String", "PAYPAL_URI", localProperties.getProperty("paypal.uri", "\"\"") buildConfigField "String", "PAYPAL_URI", localProperties.getProperty("paypal.uri", "\"\"")
} }
@ -172,6 +175,9 @@ android {
buildConfigField "String", "GITHUB_LATEST_API", "\"https://api.github.com/repos/M66B/FairEmail/releases/latest\"" buildConfigField "String", "GITHUB_LATEST_API", "\"https://api.github.com/repos/M66B/FairEmail/releases/latest\""
buildConfigField "String", "GITHUB_LATEST_URI", "\"https://github.com/M66B/FairEmail/releases\"" buildConfigField "String", "GITHUB_LATEST_URI", "\"https://github.com/M66B/FairEmail/releases\""
buildConfigField "String", "GRAVATAR_URI", "\"https://www.gravatar.com/avatar/\"" buildConfigField "String", "GRAVATAR_URI", "\"https://www.gravatar.com/avatar/\""
buildConfigField "String", "LIBRAVATAR_DNS", "\"_avatars-sec._tcp,_avatars._tcp\""
buildConfigField "String", "LIBRAVATAR_URI", "\"https://seccdn.libravatar.org/avatar/\""
buildConfigField "String", "LIBRAVATAR_INFO", "\"https://libravatar.org/\""
buildConfigField "String", "PAYPAL_URI", "\"\"" buildConfigField "String", "PAYPAL_URI", "\"\""
buildConfigField "String", "GPA_URI", "\"\"" buildConfigField "String", "GPA_URI", "\"\""
} }
@ -187,6 +193,9 @@ android {
buildConfigField "String", "GITHUB_LATEST_API", "\"\"" buildConfigField "String", "GITHUB_LATEST_API", "\"\""
buildConfigField "String", "GITHUB_LATEST_URI", "\"\"" buildConfigField "String", "GITHUB_LATEST_URI", "\"\""
buildConfigField "String", "GRAVATAR_URI", "\"\"" buildConfigField "String", "GRAVATAR_URI", "\"\""
buildConfigField "String", "LIBRAVATAR_DNS", "\"\""
buildConfigField "String", "LIBRAVATAR_URI", "\"\""
buildConfigField "String", "LIBRAVATAR_INFO", "\"\""
buildConfigField "String", "PAYPAL_URI", "\"\"" buildConfigField "String", "PAYPAL_URI", "\"\""
buildConfigField "String", "GPA_URI", "\"\"" buildConfigField "String", "GPA_URI", "\"\""
} }
@ -202,6 +211,9 @@ android {
buildConfigField "String", "GITHUB_LATEST_API", "\"\"" buildConfigField "String", "GITHUB_LATEST_API", "\"\""
buildConfigField "String", "GITHUB_LATEST_URI", "\"\"" buildConfigField "String", "GITHUB_LATEST_URI", "\"\""
buildConfigField "String", "GRAVATAR_URI", "\"\"" buildConfigField "String", "GRAVATAR_URI", "\"\""
buildConfigField "String", "LIBRAVATAR_DNS", "\"\""
buildConfigField "String", "LIBRAVATAR_URI", "\"\""
buildConfigField "String", "LIBRAVATAR_INFO", "\"\""
buildConfigField "String", "PAYPAL_URI", "\"\"" buildConfigField "String", "PAYPAL_URI", "\"\""
buildConfigField "String", "GPA_URI", "\"\"" buildConfigField "String", "GPA_URI", "\"\""
} }

@ -90,7 +90,7 @@ import javax.net.ssl.SSLSession;
public class ContactInfo { public class ContactInfo {
private String email; private String email;
private Bitmap bitmap; private Bitmap bitmap;
private String type; private String type; // contact, vmc, gravatar, libravatar, favicon, identicon, letter, unknown
private boolean verified; private boolean verified;
private String displayName; private String displayName;
private Uri lookupUri; private Uri lookupUri;
@ -159,6 +159,10 @@ public class ContactInfo {
return lookupUri; return lookupUri;
} }
boolean isEmailBased() {
return ("gravatar".equals(type) || "libravatar".equals(type));
}
boolean isKnown() { boolean isKnown() {
return known; return known;
} }
@ -258,6 +262,7 @@ public class ContactInfo {
boolean avatars = prefs.getBoolean("avatars", true); boolean avatars = prefs.getBoolean("avatars", true);
boolean bimi = prefs.getBoolean("bimi", false); boolean bimi = prefs.getBoolean("bimi", false);
boolean gravatars = prefs.getBoolean("gravatars", false); boolean gravatars = prefs.getBoolean("gravatars", false);
boolean libravatars = prefs.getBoolean("libravatars", false);
boolean favicons = prefs.getBoolean("favicons", false); boolean favicons = prefs.getBoolean("favicons", false);
boolean generated = prefs.getBoolean("generated_icons", true); boolean generated = prefs.getBoolean("generated_icons", true);
boolean identicons = prefs.getBoolean("identicons", false); boolean identicons = prefs.getBoolean("identicons", false);
@ -308,7 +313,7 @@ public class ContactInfo {
// Favicon // Favicon
if (info.bitmap == null && if (info.bitmap == null &&
!EntityFolder.JUNK.equals(folderType) && !EntityFolder.JUNK.equals(folderType) &&
(bimi || (gravatars && canGravatars()) || favicons)) { (bimi || (canGravatars() && (gravatars || libravatars)) || favicons)) {
String d = UriHelper.getEmailDomain(info.email); String d = UriHelper.getEmailDomain(info.email);
if (d != null) { if (d != null) {
// Prevent using Doodles // Prevent using Doodles
@ -334,6 +339,8 @@ public class ContactInfo {
File[] files = null; File[] files = null;
if (gravatars && canGravatars()) { if (gravatars && canGravatars()) {
File f = new File(dir, email + ".gravatar"); File f = new File(dir, email + ".gravatar");
if (!f.exists())
f = new File(dir, email + ".libravatar");
if (f.exists()) if (f.exists())
files = new File[]{f}; files = new File[]{f};
} }
@ -404,6 +411,49 @@ public class ContactInfo {
} }
})); }));
if (libravatars && canGravatars())
futures.add(executorFavicon.submit(new Callable<Favicon>() {
@Override
public Favicon call() throws Exception {
// https://wiki.libravatar.org/api/
String baseUrl = BuildConfig.LIBRAVATAR_URI;
for (String dns : BuildConfig.LIBRAVATAR_DNS.split(",")) {
DnsHelper.DnsRecord[] records = DnsHelper.lookup(context, dns + "." + domain, "srv");
if (records.length > 0) {
baseUrl = (records[0].port == 443 ? "https" : "http") + "://" + records[0].name + "/avatar/";
break;
}
}
String hash = Helper.md5(email.getBytes());
URL url = new URL(baseUrl + hash + "?d=404");
Log.i("Libravatar key=" + email + " url=" + url);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setReadTimeout(GRAVATAR_TIMEOUT);
urlConnection.setConnectTimeout(GRAVATAR_TIMEOUT);
urlConnection.setRequestProperty("User-Agent", WebViewEx.getUserAgent(context));
urlConnection.connect();
try {
int status = urlConnection.getResponseCode();
if (status == HttpURLConnection.HTTP_OK) {
// Positive reply
Bitmap bitmap = BitmapFactory.decodeStream(urlConnection.getInputStream());
return (bitmap == null ? null : new Favicon(bitmap, "libravatar", false));
} else if (status == HttpURLConnection.HTTP_NOT_FOUND) {
// Negative reply
return null;
} else
throw new IOException("Error " + status + ": " + urlConnection.getResponseMessage());
} finally {
urlConnection.disconnect();
}
}
}));
if (favicons) { if (favicons) {
String host = domain; String host = domain;
while (host.indexOf('.') > 0) { while (host.indexOf('.') > 0) {
@ -480,7 +530,7 @@ public class ContactInfo {
// Add to cache // Add to cache
File output = new File(dir, File output = new File(dir,
("gravatar".equals(info.type) ? email : domain) + (info.isEmailBased() ? email : domain) +
"." + info.type + "." + info.type +
(info.verified ? "_verified" : "")); (info.verified ? "_verified" : ""));
try (OutputStream os = new BufferedOutputStream(new FileOutputStream(output))) { try (OutputStream os = new BufferedOutputStream(new FileOutputStream(output))) {

@ -106,6 +106,8 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
private SwitchCompat swBimi; private SwitchCompat swBimi;
private SwitchCompat swGravatars; private SwitchCompat swGravatars;
private TextView tvGravatarsHint; private TextView tvGravatarsHint;
private SwitchCompat swLibravatars;
private ImageButton ibLibravatars;
private SwitchCompat swFavicons; private SwitchCompat swFavicons;
private SwitchCompat swFaviconsPartial; private SwitchCompat swFaviconsPartial;
private TextView tvFaviconsHint; private TextView tvFaviconsHint;
@ -184,7 +186,7 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
"nav_options", "nav_count", "nav_unseen_drafts", "nav_count_pinned", "navbar_colorize", "nav_options", "nav_count", "nav_unseen_drafts", "nav_count_pinned", "navbar_colorize",
"threading", "threading_unread", "indentation", "seekbar", "actionbar", "actionbar_color", "threading", "threading_unread", "indentation", "seekbar", "actionbar", "actionbar_color",
"highlight_unread", "highlight_color", "color_stripe", "color_stripe_wide", "highlight_unread", "highlight_color", "color_stripe", "color_stripe_wide",
"avatars", "bimi", "gravatars", "favicons", "favicons_partial", "generated_icons", "identicons", "avatars", "bimi", "gravatars", "libravatars", "favicons", "favicons_partial", "generated_icons", "identicons",
"circular", "saturation", "brightness", "threshold", "circular", "saturation", "brightness", "threshold",
"email_format", "prefer_contact", "only_contact", "distinguish_contacts", "show_recipients", "email_format", "prefer_contact", "only_contact", "distinguish_contacts", "show_recipients",
"font_size_sender", "sender_ellipsize", "font_size_sender", "sender_ellipsize",
@ -254,6 +256,8 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
ibBimi = view.findViewById(R.id.ibBimi); ibBimi = view.findViewById(R.id.ibBimi);
swGravatars = view.findViewById(R.id.swGravatars); swGravatars = view.findViewById(R.id.swGravatars);
tvGravatarsHint = view.findViewById(R.id.tvGravatarsHint); tvGravatarsHint = view.findViewById(R.id.tvGravatarsHint);
swLibravatars = view.findViewById(R.id.swLibravatars);
ibLibravatars = view.findViewById(R.id.ibLibravatars);
swFavicons = view.findViewById(R.id.swFavicons); swFavicons = view.findViewById(R.id.swFavicons);
swFaviconsPartial = view.findViewById(R.id.swFaviconsPartial); swFaviconsPartial = view.findViewById(R.id.swFaviconsPartial);
tvFaviconsHint = view.findViewById(R.id.tvFaviconsHint); tvFaviconsHint = view.findViewById(R.id.tvFaviconsHint);
@ -712,6 +716,21 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
} }
}); });
swLibravatars.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
prefs.edit().putBoolean("libravatars", checked).apply();
ContactInfo.clearCache(compoundButton.getContext());
}
});
ibLibravatars.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Helper.view(v.getContext(), Uri.parse(BuildConfig.LIBRAVATAR_INFO), true);
}
});
swFavicons.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { swFavicons.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
@ -1302,6 +1321,7 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
swAvatars.setChecked(prefs.getBoolean("avatars", true)); swAvatars.setChecked(prefs.getBoolean("avatars", true));
swBimi.setChecked(prefs.getBoolean("bimi", false)); swBimi.setChecked(prefs.getBoolean("bimi", false));
swGravatars.setChecked(prefs.getBoolean("gravatars", false)); swGravatars.setChecked(prefs.getBoolean("gravatars", false));
swLibravatars.setChecked(prefs.getBoolean("libravatars", false));
swFavicons.setChecked(prefs.getBoolean("favicons", false)); swFavicons.setChecked(prefs.getBoolean("favicons", false));
swFaviconsPartial.setChecked(prefs.getBoolean("favicons_partial", true)); swFaviconsPartial.setChecked(prefs.getBoolean("favicons_partial", true));
swFaviconsPartial.setEnabled(swFavicons.isChecked()); swFaviconsPartial.setEnabled(swFavicons.isChecked());

@ -843,6 +843,28 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swGravatars" /> app:layout_constraintTop_toBottomOf="@id/swGravatars" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/swLibravatars"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_advanced_libravatars"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvGravatarsHint"
app:switchPadding="12dp" />
<eu.faircode.email.FixedImageButton
android:id="@+id/ibLibravatars"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:contentDescription="@string/title_info"
android:tooltipText="@string/title_info"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/swLibravatars"
app:srcCompat="@drawable/twotone_info_24" />
<androidx.appcompat.widget.SwitchCompat <androidx.appcompat.widget.SwitchCompat
android:id="@+id/swFavicons" android:id="@+id/swFavicons"
android:layout_width="0dp" android:layout_width="0dp"
@ -851,7 +873,7 @@
android:text="@string/title_advanced_favicons" android:text="@string/title_advanced_favicons"
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/tvGravatarsHint" app:layout_constraintTop_toBottomOf="@id/ibLibravatars"
app:switchPadding="12dp" /> app:switchPadding="12dp" />
<eu.faircode.email.FixedTextView <eu.faircode.email.FixedTextView
@ -1417,7 +1439,7 @@
android:id="@+id/grpGravatars" android:id="@+id/grpGravatars"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
app:constraint_referenced_ids="swGravatars,tvGravatarsHint" /> app:constraint_referenced_ids="swGravatars,tvGravatarsHint,swLibravatars,ibLibravatars" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>
@ -1873,7 +1895,7 @@
app:layout_constraintTop_toBottomOf="@id/swAuthenticationIndicator" /> app:layout_constraintTop_toBottomOf="@id/swAuthenticationIndicator" />
<eu.faircode.email.FixedTextView <eu.faircode.email.FixedTextView
android:id="@+id/tvAutheAll" android:id="@+id/tvAuthAll"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="12dp" android:layout_marginStart="12dp"

@ -470,6 +470,7 @@
<string name="title_advanced_color_stripe_wide">Use wide color stripe</string> <string name="title_advanced_color_stripe_wide">Use wide color stripe</string>
<string name="title_advanced_avatars">Show contact photos</string> <string name="title_advanced_avatars">Show contact photos</string>
<string name="title_advanced_gravatars">Show Gravatars</string> <string name="title_advanced_gravatars">Show Gravatars</string>
<string name="title_advanced_libravatars">Show Libravatars</string>
<string name="title_advanced_bimi" translatable="false">Show Brand Indicators for Message Identification (BIMI)</string> <string name="title_advanced_bimi" translatable="false">Show Brand Indicators for Message Identification (BIMI)</string>
<string name="title_advanced_bimi_unverified">Unverified sender</string> <string name="title_advanced_bimi_unverified">Unverified sender</string>
<string name="title_advanced_bimi_verified">Verified sender</string> <string name="title_advanced_bimi_verified">Verified sender</string>

Loading…
Cancel
Save