diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index 63461eb08..e5580e51a 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -234,6 +234,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl private byte[] symmetricKey; private String mLastReceivedOtrMessageId = null; + protected boolean anyMatchSpam = false; public Conversation(final String name, final Account account, final Jid contactJid, final int mode) { @@ -1553,19 +1554,36 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl } } + public void checkSpam(Message... messages) { + if (anyMatchSpam) return; + + final var locale = java.util.Locale.getDefault(); + final var script = locale.getScript(); + for (final var m : messages) { + final var body = m.getRawBody(); + if (body.length() > 320 || (!"Cyrl".equals(script) && body.matches(".*\\p{IsCyrillic}.*")) || body.matches(".*(?:\\n.*\\n.*\\n|[Aa]\\s*d\\s*v\\s*v\\s*e\\s*r\\s*t|[Pp]romotion|[Dd][Dd][Oo][Ss]|[Ee]scrow|payout|seller|write me when will be|[Pp]rii?vee?t|there online|bit\\.ly|goo\\.gl|tinyurl\\.com|tiny\\.cc|lc\\.chat|is\\.gd|soo\\.gd|s2r\\.co|clicky\\.me|budrul\\.com|bc\\.vc|uguu\\.se).*")) { + anyMatchSpam = true; + return; + } + } + } + public void add(Message message) { + checkSpam(message); synchronized (this.messages) { this.messages.add(message); } } public void prepend(int offset, Message message) { + checkSpam(message); synchronized (this.messages) { this.messages.add(Math.min(offset, this.messages.size()), message); } } public void addAll(int index, List messages) { + checkSpam(messages.toArray(new Message[0])); synchronized (this.messages) { this.messages.addAll(index, messages); } @@ -1659,6 +1677,13 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl return sentMessagesCount() > 0; } + public boolean isChatRequest(final String pref) { + if ("disable".equals(pref)) return false; + if ("strangers".equals(pref)) return isWithStranger(); + if (!isWithStranger() && !strangerInvited()) return false; + return anyMatchSpam; + } + public boolean isWithStranger() { final Contact contact = getContact(); return mode == MODE_SINGLE diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index be6e0841b..5cf142207 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -389,10 +389,11 @@ public class NotificationService { private boolean notifyMessage(final Message message) { final Conversation conversation = (Conversation) message.getConversation(); + final var chatRequestsPref = mXmppConnectionService.getStringPreference("chat_requests", R.string.default_chat_requests); return message.getStatus() == Message.STATUS_RECEIVED && !conversation.isMuted() && (conversation.alwaysNotify() || (wasHighlightedOrPrivate(message) || (conversation.notifyReplies() && wasReplyToMe(message)))) - && (!conversation.isWithStranger() || notificationsFromStrangers()) + && !conversation.isChatRequest(chatRequestsPref) && message.getType() != Message.TYPE_RTP_SESSION; } @@ -401,11 +402,6 @@ public class NotificationService { && message.getStatus() == Message.STATUS_RECEIVED; } - public boolean notificationsFromStrangers() { - return mXmppConnectionService.getBooleanPreference( - "notifications_from_strangers", R.bool.notifications_from_strangers); - } - private boolean isQuietHours(Account account) { return isQuietHours(mXmppConnectionService, account); } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 38bc1514b..d6b400f1c 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -5126,6 +5126,10 @@ public class XmppConnectionService extends Service { return getPreferences().getBoolean(name, getResources().getBoolean(res)); } + public String getStringPreference(String name, @BoolRes int res) { + return getPreferences().getString(name, getResources().getString(res)); + } + public boolean confirmMessages() { return getBooleanPreference("confirm_messages", R.bool.confirm_messages); } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java index cf4a95a41..18952331f 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java @@ -170,13 +170,14 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio public static final long DRAWER_MANAGE_ACCOUNT = 4; public static final long DRAWER_MANAGE_PHONE_ACCOUNTS = 5; public static final long DRAWER_CHANNELS = 6; - public static final long DRAWER_SETTINGS = 7; - public static final long DRAWER_START_CHAT = 8; - public static final long DRAWER_START_CHAT_CONTACT = 9; - public static final long DRAWER_START_CHAT_NEW = 10; - public static final long DRAWER_START_CHAT_GROUP = 11; - public static final long DRAWER_START_CHAT_PUBLIC = 12; - public static final long DRAWER_START_CHAT_DISCOVER = 13; + public static final long DRAWER_CHAT_REQUESTS = 7; + public static final long DRAWER_SETTINGS = 8; + public static final long DRAWER_START_CHAT = 9; + public static final long DRAWER_START_CHAT_CONTACT = 10; + public static final long DRAWER_START_CHAT_NEW = 11; + public static final long DRAWER_START_CHAT_GROUP = 12; + public static final long DRAWER_START_CHAT_PUBLIC = 13; + public static final long DRAWER_START_CHAT_DISCOVER = 14; //secondary fragment (when holding the conversation, must be initialized before refreshing the overview fragment private static final @IdRes @@ -224,6 +225,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio } if (accountHeader == null) return; + final var chatRequestsPref = xmppConnectionService.getStringPreference("chat_requests", R.string.default_chat_requests); final var accountUnreads = new HashMap(); binding.drawer.apply(dr -> { final var items = binding.drawer.getItemAdapter().getAdapterItems(); @@ -232,6 +234,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio var totalUnread = 0; var dmUnread = 0; var channelUnread = 0; + var chatRequests = 0; final var selectedAccount = selectedAccount(); populateWithOrderedConversations(conversations, false, false); for (final var c : conversations) { @@ -243,6 +246,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio } else { dmUnread += unread; } + if (c.isChatRequest(chatRequestsPref)) chatRequests++; } var accountUnread = accountUnreads.get(c.getAccount()); if (accountUnread == null) accountUnread = 0; @@ -279,6 +283,27 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio new com.mikepenz.materialdrawer.holder.StringHolder(channelUnread > 0 ? new Integer(channelUnread).toString() : null) ); + if (chatRequests > 0) { + if (binding.drawer.getItemAdapter().getAdapterPosition(DRAWER_CHAT_REQUESTS) < 0) { + final var color = MaterialColors.getColor(binding.drawer, com.google.android.material.R.attr.colorPrimaryContainer); + final var textColor = MaterialColors.getColor(binding.drawer, com.google.android.material.R.attr.colorOnPrimaryContainer); + final var requests = new com.mikepenz.materialdrawer.model.PrimaryDrawerItem(); + requests.setIdentifier(DRAWER_CHAT_REQUESTS); + com.mikepenz.materialdrawer.model.interfaces.NameableKt.setNameText(requests, "Chat Requests"); + com.mikepenz.materialdrawer.model.interfaces.IconableKt.setIconRes(requests, R.drawable.ic_person_add_24dp); + requests.setBadgeStyle(new com.mikepenz.materialdrawer.holder.BadgeStyle(com.mikepenz.materialdrawer.R.drawable.material_drawer_badge, color, color, textColor)); + binding.drawer.getItemAdapter().add(binding.drawer.getItemAdapter().getGlobalPosition(binding.drawer.getItemAdapter().getAdapterPosition(DRAWER_CHANNELS) + 1), requests); + } + com.mikepenz.materialdrawer.util.MaterialDrawerSliderViewExtensionsKt.updateBadge( + binding.drawer, + DRAWER_CHAT_REQUESTS, + new com.mikepenz.materialdrawer.holder.StringHolder(chatRequests > 0 ? new Integer(chatRequests).toString() : null) + ); + } else { + binding.drawer.getItemAdapter().removeByIdentifier(DRAWER_CHAT_REQUESTS); + } + + final var endOfMainFilters = chatRequests > 0 ? 6 : 5; long id = 1000; final var inDrawer = new HashMap(); for (final var item : ImmutableList.copyOf(items)) { @@ -307,11 +332,11 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio final var color = MaterialColors.getColor(binding.drawer, com.google.android.material.R.attr.colorPrimaryContainer); final var textColor = MaterialColors.getColor(binding.drawer, com.google.android.material.R.attr.colorOnPrimaryContainer); item.setBadgeStyle(new com.mikepenz.materialdrawer.holder.BadgeStyle(com.mikepenz.materialdrawer.R.drawable.material_drawer_badge, color, color, textColor)); - binding.drawer.getItemAdapter().add(binding.drawer.getItemAdapter().getGlobalPosition(5), item); + binding.drawer.getItemAdapter().add(binding.drawer.getItemAdapter().getGlobalPosition(endOfMainFilters), item); } } - items.subList(5, 5 + tags.size()).sort((x, y) -> x.getTag() == null ? -1 : ((Comparable) x.getTag()).compareTo(y.getTag())); + items.subList(endOfMainFilters, endOfMainFilters + tags.size()).sort((x, y) -> x.getTag() == null ? -1 : ((Comparable) x.getTag()).compareTo(y.getTag())); binding.drawer.getItemAdapter().getFastAdapter().notifyDataSetChanged(); return kotlin.Unit.INSTANCE; }); @@ -513,7 +538,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio launchStartConversation(R.id.create_public_channel); } else if (id == DRAWER_START_CHAT_DISCOVER) { launchStartConversation(R.id.discover_public_channels); - } else if (id == DRAWER_ALL_CHATS || id == DRAWER_UNREAD_CHATS || id == DRAWER_DIRECT_MESSAGES || id == DRAWER_CHANNELS) { + } else if (id == DRAWER_ALL_CHATS || id == DRAWER_UNREAD_CHATS || id == DRAWER_DIRECT_MESSAGES || id == DRAWER_CHANNELS || id == DRAWER_CHAT_REQUESTS) { selectedTag.clear(); mainFilter = id; binding.drawer.getSelectExtension().deselect(); @@ -540,7 +565,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio binding.drawer.setOnDrawerItemLongClickListener((v, drawerItem, pos) -> { final var id = drawerItem.getIdentifier(); - if (id == DRAWER_ALL_CHATS || id == DRAWER_UNREAD_CHATS || id == DRAWER_DIRECT_MESSAGES || id == DRAWER_CHANNELS) { + if (id == DRAWER_ALL_CHATS || id == DRAWER_UNREAD_CHATS || id == DRAWER_DIRECT_MESSAGES || id == DRAWER_CHANNELS || id == DRAWER_CHAT_REQUESTS) { selectedTag.clear(); mainFilter = id; binding.drawer.getSelectExtension().deselect(); @@ -663,6 +688,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio } protected void filterByMainFilter(List list) { + final var chatRequests = xmppConnectionService.getStringPreference("chat_requests", R.string.default_chat_requests); for (final var c : ImmutableList.copyOf(list)) { if (mainFilter == DRAWER_CHANNELS && c.getMode() != Conversation.MODE_MULTI) { list.remove(c); @@ -670,6 +696,11 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio list.remove(c); } else if (mainFilter == DRAWER_UNREAD_CHATS && c.unreadCount(xmppConnectionService) < 1) { list.remove(c); + } else if (mainFilter == DRAWER_CHAT_REQUESTS && !c.isChatRequest(chatRequests)) { + list.remove(c); + } + if (mainFilter != DRAWER_CHAT_REQUESTS && c.isChatRequest(chatRequests)) { + list.remove(c); } } } diff --git a/src/main/java/eu/siacs/conversations/ui/fragment/settings/NotificationsSettingsFragment.java b/src/main/java/eu/siacs/conversations/ui/fragment/settings/NotificationsSettingsFragment.java index 3af9a0c38..4ba9ac8c4 100644 --- a/src/main/java/eu/siacs/conversations/ui/fragment/settings/NotificationsSettingsFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/fragment/settings/NotificationsSettingsFragment.java @@ -15,6 +15,7 @@ import androidx.activity.result.ActivityResultLauncher; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.preference.Preference; +import androidx.preference.ListPreference; import com.google.common.base.Optional; @@ -65,6 +66,7 @@ public class NotificationsSettingsFragment extends XmppPreferenceFragment { final var notificationHeadsUp = findPreference(AppSettings.NOTIFICATION_HEADS_UP); final var notificationVibrate = findPreference(AppSettings.NOTIFICATION_VIBRATE); final var notificationLed = findPreference(AppSettings.NOTIFICATION_LED); + final var chatRequests = (ListPreference) findPreference("chat_requests"); final var foregroundService = findPreference(AppSettings.KEEP_FOREGROUND_SERVICE); if (messageNotificationSettings == null || fullscreenNotification == null @@ -91,6 +93,11 @@ public class NotificationsSettingsFragment extends XmppPreferenceFragment { .canUseFullScreenIntent()) { fullscreenNotification.setVisible(false); } + + final var sharedPreferences = getPreferenceManager().getSharedPreferences(); + if (!sharedPreferences.getBoolean("notifications_from_strangers", true) && sharedPreferences.getString("chat_requests", null) == null) { + chatRequests.setValue("strangers"); + } } @Override diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java index 5ba46300b..af0e984f3 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java @@ -16,6 +16,7 @@ import com.google.common.collect.Collections2; import com.google.common.collect.ComparisonChain; import com.google.common.collect.ImmutableSet; +import eu.siacs.conversations.R; import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; @@ -255,13 +256,9 @@ public class JingleConnectionManager extends AbstractConnectionManager { } private boolean isWithStrangerAndStrangerNotificationsAreOff(final Account account, Jid with) { - final boolean notifyForStrangers = - mXmppConnectionService.getNotificationService().notificationsFromStrangers(); - if (notifyForStrangers) { - return false; - } - final Contact contact = account.getRoster().getContact(with); - return !contact.showInContactList(); + final var chatRequestsPref = mXmppConnectionService.getStringPreference("chat_requests", R.string.default_chat_requests); + final var conversation = mXmppConnectionService.findOrCreateConversation(account, with, false, true); + return conversation.isChatRequest(chatRequestsPref); } ScheduledFuture schedule( diff --git a/src/main/res/values/arrays.xml b/src/main/res/values/arrays.xml index e07ba2403..d4fc31c56 100644 --- a/src/main/res/values/arrays.xml +++ b/src/main/res/values/arrays.xml @@ -118,6 +118,18 @@ @string/video_original + + Never + Suspected SPAM + Chats from strangers + + + + disable + spam + strangers + + @string/jabber_network @string/local_server diff --git a/src/main/res/values/defaults.xml b/src/main/res/values/defaults.xml index a76c00b6b..94f7b60f9 100644 --- a/src/main/res/values/defaults.xml +++ b/src/main/res/values/defaults.xml @@ -58,4 +58,5 @@ oval true false + spam diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index b8306cecf..fcd3606fa 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -1307,4 +1307,5 @@ Do you really want to close the text formatting toolbar? You can enable the toolbar in the settings again. Show text formatting toolbar in chat while keyboard is shown Text formatting toolbar + Hide chats in Chat Requests area \ No newline at end of file diff --git a/src/main/res/xml/preferences_notifications.xml b/src/main/res/xml/preferences_notifications.xml index 5daa4c524..8088a8549 100644 --- a/src/main/res/xml/preferences_notifications.xml +++ b/src/main/res/xml/preferences_notifications.xml @@ -1,5 +1,6 @@ - + - + android:key="chat_requests" + android:title="@string/pref_chat_requests" + app:useSimpleSummaryProvider="true" />