Allow selecting blocklists

pull/199/head
M66B 3 years ago
parent 2fb20056f0
commit 53775eb855

@ -3373,7 +3373,7 @@ class Core {
boolean blocklist = false;
for (Address sender : senders) {
String email = ((InternetAddress) sender).getAddress();
if (DnsBlockList.isJunk(email)) {
if (DnsBlockList.isJunk(context, email)) {
blocklist = true;
break;
}

@ -19,8 +19,12 @@ package eu.faircode.email;
Copyright 2018-2021 by Marcel Bokhorst (M66B)
*/
import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;
import androidx.preference.PreferenceManager;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
@ -34,7 +38,7 @@ import java.util.List;
import java.util.Map;
public class DnsBlockList {
private static final List<BlockList> BLOCKLISTS = Collections.unmodifiableList(Arrays.asList(
static final List<BlockList> BLOCKLISTS = Collections.unmodifiableList(Arrays.asList(
// https://www.spamhaus.org/zen/
new BlockList(true, "Spamhaus/zen", "zen.spamhaus.org", true, new String[]{
// https://www.spamhaus.org/faq/section/DNSBL%20Usage#200
@ -73,15 +77,29 @@ public class DnsBlockList {
private static final long CACHE_EXPIRY_AFTER = 3600 * 1000L; // milliseconds
private static final Map<String, CacheEntry> cache = new Hashtable<>();
static List<String> getNames() {
static void setEnabled(Context context, BlockList blocklist, boolean enabled) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs.edit().putBoolean("blocklist." + blocklist.name, enabled).apply();
synchronized (cache) {
cache.clear();
}
}
static boolean isEnabled(Context context, BlockList blocklist) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("blocklist." + blocklist.name, blocklist.enabled);
}
static List<String> getNames(Context context) {
List<String> names = new ArrayList<>();
for (BlockList blocklist : BLOCKLISTS)
if (blocklist.enabled)
if (isEnabled(context, blocklist))
names.add(blocklist.name);
return names;
}
static boolean isJunk(String email) {
static boolean isJunk(Context context, String email) {
if (TextUtils.isEmpty(email))
return false;
@ -89,10 +107,10 @@ public class DnsBlockList {
if (at < 0)
return false;
return isJunk(email.substring(at + 1), BLOCKLISTS);
return isJunk(context, email.substring(at + 1), BLOCKLISTS);
}
private static boolean isJunk(String domain, List<BlockList> blocklists) {
private static boolean isJunk(Context context, String domain, List<BlockList> blocklists) {
synchronized (cache) {
CacheEntry entry = cache.get(domain);
if (entry != null && !entry.isExpired())
@ -101,7 +119,7 @@ public class DnsBlockList {
boolean blocked = false;
for (BlockList blocklist : blocklists)
if (blocklist.enabled && isJunk(domain, blocklist)) {
if (isEnabled(context, blocklist) && isJunk(domain, blocklist)) {
blocked = true;
break;
}
@ -212,13 +230,17 @@ public class DnsBlockList {
}
static class BlockList {
int id;
boolean enabled;
String name;
String address;
boolean numeric;
InetAddress[] responses;
private static int nextid = 1;
BlockList(boolean enabled, String name, String address, boolean numeric, String[] responses) {
this.id = nextid++;
this.enabled = enabled;
this.name = name;
this.address = address;

@ -245,7 +245,7 @@ public class FragmentDialogJunk extends FragmentDialogBase {
cbBlockDomain.setEnabled(false);
ibMore.setImageLevel(1);
cbBlocklist.setChecked(check_blocklist && use_blocklist);
tvBlocklist.setText(TextUtils.join(", ", DnsBlockList.getNames()));
tvBlocklist.setText(TextUtils.join(", ", DnsBlockList.getNames(context)));
grpInJunk.setVisibility(inJunk ? View.GONE : View.VISIBLE);
grpMore.setVisibility(inJunk ? View.VISIBLE : View.GONE);

@ -24,7 +24,6 @@ import android.app.TimePickerDialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.Menu;
@ -86,7 +85,7 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr
private SwitchCompat swCheckReply;
private SwitchCompat swCheckMx;
private SwitchCompat swCheckBlocklist;
private TextView tvCheckBlocklistHint;
private RecyclerView rvBlocklist;
private SwitchCompat swUseBlocklist;
private SwitchCompat swTuneKeepAlive;
private Group grpExempted;
@ -144,7 +143,7 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr
swCheckReply = view.findViewById(R.id.swCheckReply);
swCheckMx = view.findViewById(R.id.swCheckMx);
swCheckBlocklist = view.findViewById(R.id.swCheckBlocklist);
tvCheckBlocklistHint = view.findViewById(R.id.tvCheckBlocklistHint);
rvBlocklist = view.findViewById(R.id.rvBlocklist);
swUseBlocklist = view.findViewById(R.id.swUseBlocklist);
swTuneKeepAlive = view.findViewById(R.id.swTuneKeepAlive);
grpExempted = view.findViewById(R.id.grpExempted);
@ -346,9 +345,15 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
prefs.edit().putBoolean("check_blocklist", checked).apply();
swUseBlocklist.setEnabled(checked);
rvBlocklist.setVisibility(checked ? View.VISIBLE : View.GONE);
}
});
rvBlocklist.setHasFixedSize(false);
rvBlocklist.setLayoutManager(new LinearLayoutManager(getContext()));
AdapterBlocklist badapter = new AdapterBlocklist(getContext(), DnsBlockList.BLOCKLISTS);
rvBlocklist.setAdapter(badapter);
swUseBlocklist.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
@ -381,8 +386,6 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr
}
});
tvCheckBlocklistHint.setText(TextUtils.join(", ", DnsBlockList.getNames()));
PreferenceManager.getDefaultSharedPreferences(getContext()).registerOnSharedPreferenceChangeListener(this);
return view;
@ -454,6 +457,7 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr
swCheckReply.setChecked(prefs.getBoolean("check_reply_domain", true));
swCheckMx.setChecked(prefs.getBoolean("check_mx", false));
swCheckBlocklist.setChecked(prefs.getBoolean("check_blocklist", false));
rvBlocklist.setVisibility(swCheckBlocklist.isChecked() ? View.VISIBLE : View.GONE);
swUseBlocklist.setChecked(prefs.getBoolean("use_blocklist", false));
swUseBlocklist.setEnabled(swCheckBlocklist.isChecked());
swTuneKeepAlive.setChecked(prefs.getBoolean("tune_keep_alive", true));
@ -502,7 +506,7 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr
}
}
public class AdapterAccountExempted extends RecyclerView.Adapter<AdapterAccountExempted.ViewHolder> {
public static class AdapterAccountExempted extends RecyclerView.Adapter<AdapterAccountExempted.ViewHolder> {
private Context context;
private LifecycleOwner owner;
private LayoutInflater inflater;
@ -641,4 +645,75 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr
holder.wire();
}
}
public static class AdapterBlocklist extends RecyclerView.Adapter<AdapterBlocklist.ViewHolder> {
private Context context;
private LayoutInflater inflater;
private List<DnsBlockList.BlockList> items;
public class ViewHolder extends RecyclerView.ViewHolder implements CompoundButton.OnCheckedChangeListener {
private CheckBox cbEnabled;
ViewHolder(View itemView) {
super(itemView);
cbEnabled = itemView.findViewById(R.id.cbEnabled);
}
private void wire() {
cbEnabled.setOnCheckedChangeListener(this);
}
private void unwire() {
cbEnabled.setOnCheckedChangeListener(null);
}
private void bindTo(DnsBlockList.BlockList blocklist) {
cbEnabled.setText(blocklist.name);
cbEnabled.setChecked(DnsBlockList.isEnabled(context, blocklist));
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int pos = getAdapterPosition();
if (pos == RecyclerView.NO_POSITION)
return;
DnsBlockList.BlockList blocklist = items.get(pos);
DnsBlockList.setEnabled(context, blocklist, isChecked);
}
}
AdapterBlocklist(Context context, List<DnsBlockList.BlockList> items) {
this.context = context;
this.inflater = LayoutInflater.from(context);
setHasStableIds(true);
this.items = items;
}
@Override
public long getItemId(int position) {
return items.get(position).id;
}
@Override
public int getItemCount() {
return items.size();
}
@Override
@NonNull
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(inflater.inflate(R.layout.item_blocklist_enabled, parent, false));
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.unwire();
DnsBlockList.BlockList blocklist = items.get(position);
holder.bindTo(blocklist);
holder.wire();
}
}
}

@ -654,29 +654,28 @@
app:switchPadding="12dp" />
<eu.faircode.email.FixedTextView
android:id="@+id/tvCheckBlocklistHint"
android:id="@+id/tvCheckBlocklistWarning"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="48dp"
android:text="blocklists"
android:text="@string/title_advanced_sync_delay_hint"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textColor="?attr/colorWarning"
android:textStyle="italic"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swCheckBlocklist" />
<eu.faircode.email.FixedTextView
android:id="@+id/tvCheckBlocklistWarning"
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvBlocklist"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="48dp"
android:text="@string/title_advanced_sync_delay_hint"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textColor="?attr/colorWarning"
android:textStyle="italic"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvCheckBlocklistHint" />
app:layout_constraintTop_toBottomOf="@id/tvCheckBlocklistWarning" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/swUseBlocklist"
@ -687,7 +686,7 @@
android:text="@string/title_junk_blocklist"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvCheckBlocklistWarning"
app:layout_constraintTop_toBottomOf="@id/rvBlocklist"
app:switchPadding="12dp" />
<androidx.appcompat.widget.SwitchCompat

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/clItem"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox
android:id="@+id/cbEnabled"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="blocklist"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>
Loading…
Cancel
Save