mirror of
https://github.com/M66B/FairEmail.git
synced 2026-04-09 10:33:41 +02:00
Added auto block junk senders
This commit is contained in:
@@ -126,6 +126,9 @@ public class AdapterContact extends RecyclerView.Adapter<AdapterContact.ViewHold
|
||||
} else if (contact.type == EntityContact.TYPE_TO) {
|
||||
ivType.setImageResource(R.drawable.twotone_call_made_24);
|
||||
ivType.setContentDescription(context.getString(R.string.title_accessibility_to));
|
||||
} else if (contact.type == EntityContact.TYPE_JUNK) {
|
||||
ivType.setImageResource(R.drawable.twotone_report_24);
|
||||
ivType.setContentDescription(context.getString(R.string.title_legend_junk));
|
||||
} else if (contact.type == EntityContact.TYPE_NO_JUNK) {
|
||||
ivType.setImageResource(R.drawable.twotone_report_off_24);
|
||||
ivType.setContentDescription(context.getString(R.string.title_no_junk));
|
||||
|
||||
@@ -1335,38 +1335,6 @@ class Core {
|
||||
Flags notJunk = new Flags(MessageHelper.FLAG_NOT_JUNK);
|
||||
imessage.setFlags(notJunk, true);
|
||||
}
|
||||
|
||||
EntityMessage message = map.get(imessage);
|
||||
if (message != null && message.from != null) {
|
||||
for (Address from : message.from) {
|
||||
String email = ((InternetAddress) from).getAddress();
|
||||
if (TextUtils.isEmpty(email))
|
||||
continue;
|
||||
if (EntityFolder.JUNK.equals(folder.type)) {
|
||||
// From junk
|
||||
long now = new Date().getTime();
|
||||
EntityContact contact = db.contact().getContact(message.account, EntityContact.TYPE_NO_JUNK, email);
|
||||
if (contact == null) {
|
||||
contact = new EntityContact();
|
||||
contact.account = message.account;
|
||||
contact.name = ((InternetAddress) from).getPersonal();
|
||||
contact.email = email;
|
||||
contact.type = EntityContact.TYPE_NO_JUNK;
|
||||
contact.first_contacted = now;
|
||||
contact.last_contacted = now;
|
||||
contact.times_contacted = 1;
|
||||
db.contact().insertContact(contact);
|
||||
} else {
|
||||
contact.times_contacted++;
|
||||
contact.last_contacted = now;
|
||||
db.contact().updateContact(contact);
|
||||
}
|
||||
} else if (EntityFolder.JUNK.equals(target.type)) {
|
||||
// To junk
|
||||
int count = db.contact().deleteContact(message.account, EntityContact.TYPE_NO_JUNK, email);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://tools.ietf.org/html/rfc6851
|
||||
@@ -2746,7 +2714,7 @@ class Core {
|
||||
Log.w(ex);
|
||||
}
|
||||
|
||||
EntityContact.update(context, account, folder, message);
|
||||
EntityContact.received(context, account, folder, message);
|
||||
} catch (Throwable ex) {
|
||||
db.folder().setFolderError(folder.id, Log.formatThrowable(ex));
|
||||
}
|
||||
@@ -3753,7 +3721,7 @@ class Core {
|
||||
}
|
||||
|
||||
try {
|
||||
EntityContact.update(context, account, folder, message);
|
||||
EntityContact.received(context, account, folder, message);
|
||||
|
||||
// Download small messages inline
|
||||
if (download && !message.ui_hide) {
|
||||
@@ -3928,7 +3896,7 @@ class Core {
|
||||
}
|
||||
|
||||
if (process) {
|
||||
EntityContact.update(context, account, folder, message);
|
||||
EntityContact.received(context, account, folder, message);
|
||||
MessageClassifier.classify(message, folder, null, context);
|
||||
} else
|
||||
Log.d(folder.name + " unchanged uid=" + uid);
|
||||
@@ -4040,6 +4008,25 @@ class Core {
|
||||
if (rule.stop)
|
||||
break;
|
||||
}
|
||||
|
||||
if (EntityFolder.INBOX.equals(folder.type))
|
||||
if (message.from != null)
|
||||
for (Address from : message.from) {
|
||||
String email = ((InternetAddress) from).getAddress();
|
||||
if (TextUtils.isEmpty(email))
|
||||
continue;
|
||||
|
||||
EntityContact badboy = db.contact().getContact(message.account, EntityContact.TYPE_JUNK, email);
|
||||
if (badboy != null) {
|
||||
EntityFolder junk = db.folder().getFolderByType(message.account, EntityFolder.JUNK);
|
||||
if (junk != null) {
|
||||
EntityOperation.queue(context, message, EntityOperation.MOVE, junk.id);
|
||||
executed = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (executed &&
|
||||
!message.hasKeyword(MessageHelper.FLAG_FILTERED))
|
||||
EntityOperation.queue(context, message, EntityOperation.KEYWORD, MessageHelper.FLAG_FILTERED, true);
|
||||
|
||||
@@ -68,6 +68,7 @@ public class EntityContact implements Serializable {
|
||||
|
||||
static final int TYPE_TO = 0;
|
||||
static final int TYPE_FROM = 1;
|
||||
static final int TYPE_JUNK = 2;
|
||||
static final int TYPE_NO_JUNK = 3;
|
||||
|
||||
static final int STATE_DEFAULT = 0;
|
||||
@@ -94,41 +95,50 @@ public class EntityContact implements Serializable {
|
||||
@NonNull
|
||||
public Integer state = STATE_DEFAULT;
|
||||
|
||||
static void update(
|
||||
static void received(
|
||||
@NonNull Context context,
|
||||
@NonNull EntityAccount account,
|
||||
@NonNull EntityFolder folder,
|
||||
@NonNull EntityMessage message) {
|
||||
int days = (folder.isOutgoing() ? folder.keep_days : folder.sync_days);
|
||||
if (days == Integer.MAX_VALUE)
|
||||
days = EntityFolder.DEFAULT_KEEP;
|
||||
if (message.received < account.created - days * 24 * 3600 * 1000L)
|
||||
return;
|
||||
if (!EntityFolder.JUNK.equals(folder.type)) {
|
||||
int days = (folder.isOutgoing() ? folder.keep_days : folder.sync_days);
|
||||
if (days == Integer.MAX_VALUE)
|
||||
days = EntityFolder.DEFAULT_KEEP;
|
||||
if (message.received < account.created - days * 24 * 3600 * 1000L)
|
||||
return;
|
||||
}
|
||||
|
||||
if (EntityFolder.DRAFTS.equals(folder.type) ||
|
||||
EntityFolder.ARCHIVE.equals(folder.type) ||
|
||||
EntityFolder.TRASH.equals(folder.type) ||
|
||||
EntityFolder.JUNK.equals(folder.type))
|
||||
EntityFolder.TRASH.equals(folder.type))
|
||||
return;
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
boolean suggest_sent = prefs.getBoolean("suggest_sent", true);
|
||||
boolean suggest_received = prefs.getBoolean("suggest_received", false);
|
||||
if (!suggest_sent && !suggest_received)
|
||||
boolean auto_junk = prefs.getBoolean("auto_junk", false);
|
||||
|
||||
// Shortcut
|
||||
if (!suggest_sent && !suggest_received &&
|
||||
!(EntityFolder.JUNK.equals(folder.type) && auto_junk))
|
||||
return;
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
|
||||
int type = (folder.isOutgoing() ? TYPE_TO : TYPE_FROM);
|
||||
int type;
|
||||
if (EntityFolder.JUNK.equals(folder.type))
|
||||
type = TYPE_JUNK;
|
||||
else
|
||||
type = (folder.isOutgoing() ? TYPE_TO : TYPE_FROM);
|
||||
|
||||
// Check if from self
|
||||
if (type == TYPE_FROM) {
|
||||
if (type == TYPE_FROM || type == TYPE_JUNK) {
|
||||
if (message.from != null) {
|
||||
List<EntityIdentity> identities = Core.getIdentities(folder.account, context);
|
||||
if (identities != null) {
|
||||
for (Address sender : message.from) {
|
||||
for (EntityIdentity identity : identities)
|
||||
if (identity.similarAddress(sender)) {
|
||||
if (type == TYPE_JUNK)
|
||||
return;
|
||||
type = TYPE_TO;
|
||||
break;
|
||||
}
|
||||
@@ -143,6 +153,8 @@ public class EntityContact implements Serializable {
|
||||
return;
|
||||
if (type == TYPE_FROM && !suggest_received)
|
||||
return;
|
||||
if (type == TYPE_JUNK && !auto_junk)
|
||||
return;
|
||||
|
||||
List<Address> addresses = new ArrayList<>();
|
||||
if (type == TYPE_FROM) {
|
||||
@@ -156,8 +168,29 @@ public class EntityContact implements Serializable {
|
||||
addresses.addAll(Arrays.asList(message.to));
|
||||
if (message.cc != null)
|
||||
addresses.addAll(Arrays.asList(message.cc));
|
||||
} else if (type == TYPE_JUNK) {
|
||||
if (message.from != null) {
|
||||
DB db = DB.getInstance(context);
|
||||
for (Address from : message.from) {
|
||||
String email = ((InternetAddress) from).getAddress();
|
||||
if (TextUtils.isEmpty(email))
|
||||
continue;
|
||||
EntityContact nojunk = db.contact().getContact(message.account, TYPE_NO_JUNK, email);
|
||||
if (nojunk != null)
|
||||
return;
|
||||
}
|
||||
addresses.addAll(Arrays.asList(message.from));
|
||||
}
|
||||
}
|
||||
|
||||
update(context, folder.account, addresses.toArray(new Address[0]), type, message.received);
|
||||
}
|
||||
|
||||
public static void update(Context context, long account, Address[] addresses, int type, long time) {
|
||||
if (addresses == null)
|
||||
return;
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
for (Address address : addresses) {
|
||||
String email = ((InternetAddress) address).getAddress();
|
||||
String name = ((InternetAddress) address).getPersonal();
|
||||
@@ -171,17 +204,17 @@ public class EntityContact implements Serializable {
|
||||
try {
|
||||
db.beginTransaction();
|
||||
|
||||
EntityContact contact = db.contact().getContact(folder.account, type, email);
|
||||
EntityContact contact = db.contact().getContact(account, type, email);
|
||||
if (contact == null) {
|
||||
contact = new EntityContact();
|
||||
contact.account = folder.account;
|
||||
contact.account = account;
|
||||
contact.type = type;
|
||||
contact.email = email;
|
||||
contact.name = name;
|
||||
contact.avatar = (avatar == null ? null : avatar.toString());
|
||||
contact.times_contacted = 1;
|
||||
contact.first_contacted = message.received;
|
||||
contact.last_contacted = message.received;
|
||||
contact.first_contacted = time;
|
||||
contact.last_contacted = time;
|
||||
contact.id = db.contact().insertContact(contact);
|
||||
Log.i("Inserted contact=" + contact + " type=" + type);
|
||||
} else {
|
||||
@@ -189,8 +222,8 @@ public class EntityContact implements Serializable {
|
||||
contact.name = name;
|
||||
contact.avatar = (avatar == null ? null : avatar.toString());
|
||||
contact.times_contacted++;
|
||||
contact.first_contacted = Math.min(contact.first_contacted, message.received);
|
||||
contact.last_contacted = message.received;
|
||||
contact.first_contacted = Math.min(contact.first_contacted, time);
|
||||
contact.last_contacted = time;
|
||||
db.contact().updateContact(contact);
|
||||
Log.i("Updated contact=" + contact + " type=" + type);
|
||||
}
|
||||
@@ -202,6 +235,19 @@ public class EntityContact implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
public static void delete(Context context, long account, Address[] addresses, int type) {
|
||||
if (addresses == null)
|
||||
return;
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
for (Address address : addresses) {
|
||||
String email = ((InternetAddress) address).getAddress();
|
||||
if (TextUtils.isEmpty(email))
|
||||
continue;
|
||||
db.contact().deleteContact(account, type, email);
|
||||
}
|
||||
}
|
||||
|
||||
public JSONObject toJSON() throws JSONException {
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("id", id);
|
||||
|
||||
@@ -246,13 +246,19 @@ public class EntityOperation {
|
||||
EntityMessage.snooze(context, message.id, null);
|
||||
}
|
||||
|
||||
if (EntityFolder.JUNK.equals(source.type) && EntityFolder.INBOX.equals(target.type)) {
|
||||
if (EntityFolder.JUNK.equals(source.type)) {
|
||||
List<EntityRule> rules = db.rule().getRules(target.id);
|
||||
for (EntityRule rule : rules)
|
||||
if (rule.isBlockingSender(message, source))
|
||||
db.rule().deleteRule(rule.id);
|
||||
|
||||
EntityContact.delete(context, message.account, message.from, EntityContact.TYPE_JUNK);
|
||||
EntityContact.update(context, message.account, message.from, EntityContact.TYPE_NO_JUNK, message.received);
|
||||
}
|
||||
|
||||
if (EntityFolder.JUNK.equals(target.type))
|
||||
EntityContact.delete(context, message.account, message.from, EntityContact.TYPE_NO_JUNK);
|
||||
|
||||
// Create copy without uid in target folder
|
||||
// Message with same msgid can be in archive
|
||||
if (message.uid != null &&
|
||||
|
||||
@@ -64,6 +64,7 @@ public class FragmentDialogJunk extends FragmentDialogBase {
|
||||
final ImageButton ibMore = view.findViewById(R.id.ibMore);
|
||||
final TextView tvMore = view.findViewById(R.id.tvMore);
|
||||
final Button btnEditRules = view.findViewById(R.id.btnEditRules);
|
||||
final CheckBox cbJunkAuto = view.findViewById(R.id.cbJunkAuto);
|
||||
final CheckBox cbJunkFilter = view.findViewById(R.id.cbJunkFilter);
|
||||
final ImageButton ibInfoFilter = view.findViewById(R.id.ibInfoFilter);
|
||||
final CheckBox cbBlocklist = view.findViewById(R.id.cbBlocklist);
|
||||
@@ -73,6 +74,7 @@ public class FragmentDialogJunk extends FragmentDialogBase {
|
||||
final Group grpMore = view.findViewById(R.id.grpMore);
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
boolean auto_junk = prefs.getBoolean("auto_junk", false);
|
||||
boolean check_blocklist = prefs.getBoolean("check_blocklist", false);
|
||||
boolean use_blocklist = prefs.getBoolean("use_blocklist", false);
|
||||
|
||||
@@ -88,7 +90,7 @@ public class FragmentDialogJunk extends FragmentDialogBase {
|
||||
cbBlockSender.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
cbBlockDomain.setEnabled(isChecked);
|
||||
cbBlockDomain.setEnabled(isChecked && ActivityBilling.isPro(context));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -156,6 +158,13 @@ public class FragmentDialogJunk extends FragmentDialogBase {
|
||||
}
|
||||
});
|
||||
|
||||
cbJunkAuto.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
prefs.edit().putBoolean("auto_junk", isChecked).apply();
|
||||
}
|
||||
});
|
||||
|
||||
cbJunkFilter.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
@@ -241,9 +250,10 @@ public class FragmentDialogJunk extends FragmentDialogBase {
|
||||
tvMessage.setText(inJunk
|
||||
? getString(R.string.title_folder_junk)
|
||||
: getString(R.string.title_ask_spam_who, from));
|
||||
cbBlockSender.setEnabled(canBlock && ActivityBilling.isPro(context));
|
||||
cbBlockSender.setEnabled(canBlock);
|
||||
cbBlockDomain.setEnabled(false);
|
||||
ibMore.setImageLevel(1);
|
||||
cbJunkAuto.setChecked(auto_junk);
|
||||
cbBlocklist.setChecked(check_blocklist && use_blocklist);
|
||||
tvBlocklist.setText(TextUtils.join(", ", DnsBlockList.getNamesEnabled(context)));
|
||||
grpInJunk.setVisibility(inJunk ? View.GONE : View.VISIBLE);
|
||||
@@ -256,7 +266,7 @@ public class FragmentDialogJunk extends FragmentDialogBase {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean onExecute(Context context, Bundle args) throws Throwable {
|
||||
protected Boolean onExecute(Context context, Bundle args) {
|
||||
long aid = args.getLong("account");
|
||||
long fid = args.getLong("folder");
|
||||
|
||||
|
||||
@@ -7827,6 +7827,10 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
|
||||
if (message == null)
|
||||
return null;
|
||||
|
||||
EntityAccount account = db.account().getAccount(message.account);
|
||||
if (account == null)
|
||||
return null;
|
||||
|
||||
EntityFolder junk = db.folder().getFolderByType(message.account, EntityFolder.JUNK);
|
||||
if (junk == null)
|
||||
throw new IllegalArgumentException(context.getString(R.string.title_no_junk_folder));
|
||||
@@ -7834,7 +7838,12 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
|
||||
if (!message.folder.equals(junk.id))
|
||||
EntityOperation.queue(context, message, EntityOperation.MOVE, junk.id);
|
||||
|
||||
if (block_sender || block_domain) {
|
||||
if (block_sender)
|
||||
EntityContact.update(context,
|
||||
message.account, message.from,
|
||||
EntityContact.TYPE_JUNK, message.received);
|
||||
|
||||
if (block_domain) {
|
||||
EntityRule rule = EntityRule.blockSender(context, message, junk, block_domain, whitelist);
|
||||
if (rule != null) {
|
||||
if (message.folder.equals(junk.id)) {
|
||||
|
||||
Reference in New Issue
Block a user