[SES-1002] Synced blind requests (#1303)

* feat: update config to use blinded-msg-requests pr

* feat: add block community message requests bool to protos

* feat: add everything needed for recipientDB to have blocked community requests potentially

* feat: add db migrations

* feat: add sending community block flags and preference options

* feat: add parsing block request flag

* fix: open group message requests were broken anyway

* fix: delete all encoded open group inbox ID bs, fix privacy settings using user config as privacy store

* feat: initial creation sets flag, rename to match libsession implementation value

* fix: recipient blinded checks from open group message for blocking community requests on blinded ID version of recipient, use correct (inverted) values from before for checking polling and empty states etc

* fix: pr comments for view model factory context ref, simplified user config object check for category in PrivacySettingsPreferenceFragment

* fix: pr comments

* fix: migrate some dependencies and functionality out of VM into repository to remove content resolver and context dependecy so tests pass again

* refactor: better naming for hidesInputBar and add more tests for expected recipient view states

* fix: use contact information as opposed to active conversations

* fix: PR comments
This commit is contained in:
0x330a 2023-08-28 09:51:48 +10:00 committed by GitHub
parent f6345c86ce
commit 2466d9b4c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 522 additions and 157 deletions

View File

@ -10,7 +10,6 @@ import androidx.annotation.DimenRes
import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.engine.DiskCacheStrategy
import network.loki.messenger.R import network.loki.messenger.R
import network.loki.messenger.databinding.ViewProfilePictureBinding import network.loki.messenger.databinding.ViewProfilePictureBinding
import network.loki.messenger.databinding.ViewUserBinding
import org.session.libsession.avatars.ContactColors import org.session.libsession.avatars.ContactColors
import org.session.libsession.avatars.PlaceholderAvatarPhoto import org.session.libsession.avatars.PlaceholderAvatarPhoto
import org.session.libsession.avatars.ProfileContactPhoto import org.session.libsession.avatars.ProfileContactPhoto
@ -74,7 +73,7 @@ class ProfilePictureView @JvmOverloads constructor(
additionalDisplayName = getUserDisplayName(apk) additionalDisplayName = getUserDisplayName(apk)
} }
} else if(recipient.isOpenGroupInboxRecipient) { } else if(recipient.isOpenGroupInboxRecipient) {
val publicKey = GroupUtil.getDecodedOpenGroupInbox(recipient.address.serialize()) val publicKey = GroupUtil.getDecodedOpenGroupInboxSessionId(recipient.address.serialize())
this.publicKey = publicKey this.publicKey = publicKey
displayName = getUserDisplayName(publicKey) displayName = getUserDisplayName(publicKey)
additionalPublicKey = null additionalPublicKey = null

View File

@ -40,6 +40,7 @@ import androidx.annotation.DimenRes
import androidx.core.text.set import androidx.core.text.set
import androidx.core.text.toSpannable import androidx.core.text.toSpannable
import androidx.core.view.drawToBitmap import androidx.core.view.drawToBitmap
import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
@ -78,7 +79,6 @@ import org.session.libsession.messaging.messages.signal.OutgoingTextMessage
import org.session.libsession.messaging.messages.visible.Reaction import org.session.libsession.messaging.messages.visible.Reaction
import org.session.libsession.messaging.messages.visible.VisibleMessage import org.session.libsession.messaging.messages.visible.VisibleMessage
import org.session.libsession.messaging.open_groups.OpenGroupApi import org.session.libsession.messaging.open_groups.OpenGroupApi
import org.session.libsession.messaging.open_groups.OpenGroupApi.Capability
import org.session.libsession.messaging.sending_receiving.MessageSender import org.session.libsession.messaging.sending_receiving.MessageSender
import org.session.libsession.messaging.sending_receiving.attachments.Attachment import org.session.libsession.messaging.sending_receiving.attachments.Attachment
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview
@ -105,13 +105,12 @@ import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.attachments.ScreenshotObserver import org.thoughtcrime.securesms.attachments.ScreenshotObserver
import org.thoughtcrime.securesms.audio.AudioRecorder import org.thoughtcrime.securesms.audio.AudioRecorder
import org.thoughtcrime.securesms.contacts.SelectContactsActivity.Companion.selectedContactsKey import org.thoughtcrime.securesms.contacts.SelectContactsActivity.Companion.selectedContactsKey
import org.thoughtcrime.securesms.util.SimpleTextWatcher
import org.thoughtcrime.securesms.conversation.v2.ConversationReactionOverlay.OnActionSelectedListener import org.thoughtcrime.securesms.conversation.v2.ConversationReactionOverlay.OnActionSelectedListener
import org.thoughtcrime.securesms.conversation.v2.ConversationReactionOverlay.OnReactionSelectedListener import org.thoughtcrime.securesms.conversation.v2.ConversationReactionOverlay.OnReactionSelectedListener
import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.MESSAGE_TIMESTAMP import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.MESSAGE_TIMESTAMP
import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_DELETE
import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_REPLY import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_REPLY
import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_RESEND import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_RESEND
import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_DELETE
import org.thoughtcrime.securesms.conversation.v2.dialogs.BlockedDialog import org.thoughtcrime.securesms.conversation.v2.dialogs.BlockedDialog
import org.thoughtcrime.securesms.conversation.v2.dialogs.LinkPreviewDialog import org.thoughtcrime.securesms.conversation.v2.dialogs.LinkPreviewDialog
import org.thoughtcrime.securesms.conversation.v2.dialogs.SendSeedDialog import org.thoughtcrime.securesms.conversation.v2.dialogs.SendSeedDialog
@ -174,6 +173,7 @@ import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
import org.thoughtcrime.securesms.util.DateUtils import org.thoughtcrime.securesms.util.DateUtils
import org.thoughtcrime.securesms.util.MediaUtil import org.thoughtcrime.securesms.util.MediaUtil
import org.thoughtcrime.securesms.util.SaveAttachmentTask import org.thoughtcrime.securesms.util.SaveAttachmentTask
import org.thoughtcrime.securesms.util.SimpleTextWatcher
import org.thoughtcrime.securesms.util.isScrolledToBottom import org.thoughtcrime.securesms.util.isScrolledToBottom
import org.thoughtcrime.securesms.util.push import org.thoughtcrime.securesms.util.push
import org.thoughtcrime.securesms.util.toPx import org.thoughtcrime.securesms.util.toPx
@ -240,11 +240,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
val address = if (sessionId.prefix == IdPrefix.BLINDED && openGroup != null) { val address = if (sessionId.prefix == IdPrefix.BLINDED && openGroup != null) {
storage.getOrCreateBlindedIdMapping(sessionId.hexString, openGroup.server, openGroup.publicKey).sessionId?.let { storage.getOrCreateBlindedIdMapping(sessionId.hexString, openGroup.server, openGroup.publicKey).sessionId?.let {
fromSerialized(it) fromSerialized(it)
} ?: run { } ?: GroupUtil.getEncodedOpenGroupInboxID(openGroup, sessionId)
val openGroupInboxId =
"${openGroup.server}!${openGroup.publicKey}!${sessionId.hexString}".toByteArray()
fromSerialized(GroupUtil.getEncodedOpenGroupInboxID(openGroupInboxId))
}
} else { } else {
it it
} }
@ -253,7 +249,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
} }
} ?: finish() } ?: finish()
} }
viewModelFactory.create(threadId, MessagingModuleConfiguration.shared.getUserED25519KeyPair(), contentResolver) viewModelFactory.create(threadId, MessagingModuleConfiguration.shared.getUserED25519KeyPair())
} }
private var actionMode: ActionMode? = null private var actionMode: ActionMode? = null
private var unreadCount = 0 private var unreadCount = 0
@ -312,8 +308,8 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
handleSwipeToReply(message) handleSwipeToReply(message)
}, },
onItemLongPress = { message, position, view -> onItemLongPress = { message, position, view ->
if (!isMessageRequestThread() && if (!viewModel.isMessageRequestThread &&
(viewModel.openGroup == null || Capability.REACTIONS.name.lowercase() in viewModel.serverCapabilities) viewModel.canReactToMessages
) { ) {
showEmojiPicker(message, view) showEmojiPicker(message, view)
} else { } else {
@ -596,26 +592,27 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
// called from onCreate // called from onCreate
private fun setUpInputBar() { private fun setUpInputBar() {
binding!!.inputBar.isVisible = viewModel.openGroup == null || viewModel.openGroup?.canWrite == true val binding = binding ?: return
binding!!.inputBar.delegate = this binding.inputBar.isGone = viewModel.hidesInputBar()
binding!!.inputBarRecordingView.delegate = this binding.inputBar.delegate = this
binding.inputBarRecordingView.delegate = this
// GIF button // GIF button
binding!!.gifButtonContainer.addView(gifButton) binding.gifButtonContainer.addView(gifButton)
gifButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT) gifButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
gifButton.onUp = { showGIFPicker() } gifButton.onUp = { showGIFPicker() }
gifButton.snIsEnabled = false gifButton.snIsEnabled = false
// Document button // Document button
binding!!.documentButtonContainer.addView(documentButton) binding.documentButtonContainer.addView(documentButton)
documentButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT) documentButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
documentButton.onUp = { showDocumentPicker() } documentButton.onUp = { showDocumentPicker() }
documentButton.snIsEnabled = false documentButton.snIsEnabled = false
// Library button // Library button
binding!!.libraryButtonContainer.addView(libraryButton) binding.libraryButtonContainer.addView(libraryButton)
libraryButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT) libraryButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
libraryButton.onUp = { pickFromLibrary() } libraryButton.onUp = { pickFromLibrary() }
libraryButton.snIsEnabled = false libraryButton.snIsEnabled = false
// Camera button // Camera button
binding!!.cameraButtonContainer.addView(cameraButton) binding.cameraButtonContainer.addView(cameraButton)
cameraButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT) cameraButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
cameraButton.onUp = { showCamera() } cameraButton.onUp = { showCamera() }
cameraButton.snIsEnabled = false cameraButton.snIsEnabled = false
@ -764,7 +761,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
override fun onPrepareOptionsMenu(menu: Menu): Boolean { override fun onPrepareOptionsMenu(menu: Menu): Boolean {
val recipient = viewModel.recipient ?: return false val recipient = viewModel.recipient ?: return false
if (!isMessageRequestThread()) { if (!viewModel.isMessageRequestThread) {
ConversationMenuHelper.onPrepareOptionsMenu( ConversationMenuHelper.onPrepareOptionsMenu(
menu, menu,
menuInflater, menuInflater,
@ -850,11 +847,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
} }
} }
private fun isMessageRequestThread(): Boolean {
val recipient = viewModel.recipient ?: return false
return !recipient.isGroupRecipient && !recipient.isApproved
}
private fun isOutgoingMessageRequestThread(): Boolean { private fun isOutgoingMessageRequestThread(): Boolean {
val recipient = viewModel.recipient ?: return false val recipient = viewModel.recipient ?: return false
return !recipient.isGroupRecipient && return !recipient.isGroupRecipient &&
@ -1069,11 +1061,13 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
private fun updatePlaceholder() { private fun updatePlaceholder() {
val recipient = viewModel.recipient val recipient = viewModel.recipient
?: return Log.w("Loki", "recipient was null in placeholder update") ?: return Log.w("Loki", "recipient was null in placeholder update")
val blindedRecipient = viewModel.blindedRecipient
val binding = binding ?: return val binding = binding ?: return
val openGroup = viewModel.openGroup val openGroup = viewModel.openGroup
val (textResource, insertParam) = when { val (textResource, insertParam) = when {
recipient.isLocalNumber -> R.string.activity_conversation_empty_state_note_to_self to null recipient.isLocalNumber -> R.string.activity_conversation_empty_state_note_to_self to null
openGroup != null && !openGroup.canWrite -> R.string.activity_conversation_empty_state_read_only to recipient.toShortString() openGroup != null && !openGroup.canWrite -> R.string.activity_conversation_empty_state_read_only to recipient.toShortString()
blindedRecipient?.blocksCommunityMessageRequests == true -> R.string.activity_conversation_empty_state_blocks_community_requests to recipient.toShortString()
else -> R.string.activity_conversation_empty_state_default to recipient.toShortString() else -> R.string.activity_conversation_empty_state_default to recipient.toShortString()
} }
val showPlaceholder = adapter.itemCount == 0 val showPlaceholder = adapter.itemCount == 0

View File

@ -1,10 +1,8 @@
package org.thoughtcrime.securesms.conversation.v2 package org.thoughtcrime.securesms.conversation.v2
import android.content.ContentResolver
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import app.cash.copper.flow.observeQuery
import com.goterl.lazysodium.utils.KeyPair import com.goterl.lazysodium.utils.KeyPair
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
@ -21,7 +19,6 @@ import org.session.libsession.messaging.utilities.SodiumUtilities
import org.session.libsession.utilities.recipients.Recipient import org.session.libsession.utilities.recipients.Recipient
import org.session.libsignal.utilities.IdPrefix import org.session.libsignal.utilities.IdPrefix
import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.database.DatabaseContentProviders
import org.thoughtcrime.securesms.database.Storage import org.thoughtcrime.securesms.database.Storage
import org.thoughtcrime.securesms.database.model.MessageRecord import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.repository.ConversationRepository import org.thoughtcrime.securesms.repository.ConversationRepository
@ -30,7 +27,6 @@ import java.util.UUID
class ConversationViewModel( class ConversationViewModel(
val threadId: Long, val threadId: Long,
val edKeyPair: KeyPair?, val edKeyPair: KeyPair?,
private val contentResolver: ContentResolver,
private val repository: ConversationRepository, private val repository: ConversationRepository,
private val storage: Storage private val storage: Storage
) : ViewModel() { ) : ViewModel() {
@ -47,6 +43,15 @@ class ConversationViewModel(
val recipient: Recipient? val recipient: Recipient?
get() = _recipient.value get() = _recipient.value
val blindedRecipient: Recipient?
get() = _recipient.value?.let { recipient ->
when {
recipient.isOpenGroupOutboxRecipient -> recipient
recipient.isOpenGroupInboxRecipient -> repository.maybeGetBlindedRecipient(recipient)
else -> null
}
}
private var _openGroup: RetrieveOnce<OpenGroup> = RetrieveOnce { private var _openGroup: RetrieveOnce<OpenGroup> = RetrieveOnce {
storage.getOpenGroup(threadId) storage.getOpenGroup(threadId)
} }
@ -62,12 +67,22 @@ class ConversationViewModel(
?.let { SessionId(IdPrefix.BLINDED, it) }?.hexString ?.let { SessionId(IdPrefix.BLINDED, it) }?.hexString
} }
val isMessageRequestThread : Boolean
get() {
val recipient = recipient ?: return false
return !recipient.isLocalNumber && !recipient.isGroupRecipient && !recipient.isApproved
}
val canReactToMessages: Boolean
// allow reactions if the open group is null (normal conversations) or the open group's capabilities include reactions
get() = (openGroup == null || OpenGroupApi.Capability.REACTIONS.name.lowercase() in serverCapabilities)
init { init {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
contentResolver.observeQuery(DatabaseContentProviders.Conversation.getUriForThread(threadId)) repository.recipientUpdateFlow(threadId)
.collect { .collect { recipient ->
val recipientExists = storage.getRecipientForThread(threadId) != null if (recipient == null && _uiState.value.conversationExists) {
if (!recipientExists && _uiState.value.conversationExists) {
_uiState.update { it.copy(conversationExists = false) } _uiState.update { it.copy(conversationExists = false) }
} }
} }
@ -199,22 +214,25 @@ class ConversationViewModel(
_recipient.updateTo(repository.maybeGetRecipientForThreadId(threadId)) _recipient.updateTo(repository.maybeGetRecipientForThreadId(threadId))
} }
fun hidesInputBar(): Boolean = openGroup?.canWrite != true &&
blindedRecipient?.blocksCommunityMessageRequests == true
@dagger.assisted.AssistedFactory @dagger.assisted.AssistedFactory
interface AssistedFactory { interface AssistedFactory {
fun create(threadId: Long, edKeyPair: KeyPair?, contentResolver: ContentResolver): Factory fun create(threadId: Long, edKeyPair: KeyPair?): Factory
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
class Factory @AssistedInject constructor( class Factory @AssistedInject constructor(
@Assisted private val threadId: Long, @Assisted private val threadId: Long,
@Assisted private val edKeyPair: KeyPair?, @Assisted private val edKeyPair: KeyPair?,
@Assisted private val contentResolver: ContentResolver,
private val repository: ConversationRepository, private val repository: ConversationRepository,
private val storage: Storage private val storage: Storage
) : ViewModelProvider.Factory { ) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T { override fun <T : ViewModel> create(modelClass: Class<T>): T {
return ConversationViewModel(threadId, edKeyPair, contentResolver, repository, storage) as T return ConversationViewModel(threadId, edKeyPair, repository, storage) as T
} }
} }
} }

View File

@ -63,13 +63,14 @@ public class RecipientDatabase extends Database {
private static final String FORCE_SMS_SELECTION = "force_sms_selection"; private static final String FORCE_SMS_SELECTION = "force_sms_selection";
private static final String NOTIFY_TYPE = "notify_type"; // all, mentions only, none private static final String NOTIFY_TYPE = "notify_type"; // all, mentions only, none
private static final String WRAPPER_HASH = "wrapper_hash"; private static final String WRAPPER_HASH = "wrapper_hash";
private static final String BLOCKS_COMMUNITY_MESSAGE_REQUESTS = "blocks_community_message_requests";
private static final String[] RECIPIENT_PROJECTION = new String[] { private static final String[] RECIPIENT_PROJECTION = new String[] {
BLOCK, APPROVED, APPROVED_ME, NOTIFICATION, CALL_RINGTONE, VIBRATE, CALL_VIBRATE, MUTE_UNTIL, COLOR, SEEN_INVITE_REMINDER, DEFAULT_SUBSCRIPTION_ID, EXPIRE_MESSAGES, REGISTERED, BLOCK, APPROVED, APPROVED_ME, NOTIFICATION, CALL_RINGTONE, VIBRATE, CALL_VIBRATE, MUTE_UNTIL, COLOR, SEEN_INVITE_REMINDER, DEFAULT_SUBSCRIPTION_ID, EXPIRE_MESSAGES, REGISTERED,
PROFILE_KEY, SYSTEM_DISPLAY_NAME, SYSTEM_PHOTO_URI, SYSTEM_PHONE_LABEL, SYSTEM_CONTACT_URI, PROFILE_KEY, SYSTEM_DISPLAY_NAME, SYSTEM_PHOTO_URI, SYSTEM_PHONE_LABEL, SYSTEM_CONTACT_URI,
SIGNAL_PROFILE_NAME, SIGNAL_PROFILE_AVATAR, PROFILE_SHARING, NOTIFICATION_CHANNEL, SIGNAL_PROFILE_NAME, SIGNAL_PROFILE_AVATAR, PROFILE_SHARING, NOTIFICATION_CHANNEL,
UNIDENTIFIED_ACCESS_MODE, UNIDENTIFIED_ACCESS_MODE,
FORCE_SMS_SELECTION, NOTIFY_TYPE, WRAPPER_HASH FORCE_SMS_SELECTION, NOTIFY_TYPE, WRAPPER_HASH, BLOCKS_COMMUNITY_MESSAGE_REQUESTS
}; };
static final List<String> TYPED_RECIPIENT_PROJECTION = Stream.of(RECIPIENT_PROJECTION) static final List<String> TYPED_RECIPIENT_PROJECTION = Stream.of(RECIPIENT_PROJECTION)
@ -142,6 +143,11 @@ public class RecipientDatabase extends Database {
"ADD COLUMN "+WRAPPER_HASH+" TEXT DEFAULT NULL;"; "ADD COLUMN "+WRAPPER_HASH+" TEXT DEFAULT NULL;";
} }
public static String getAddBlocksCommunityMessageRequests() {
return "ALTER TABLE "+TABLE_NAME+" "+
"ADD COLUMN "+BLOCKS_COMMUNITY_MESSAGE_REQUESTS+" INT DEFAULT 0;";
}
public static final int NOTIFY_TYPE_ALL = 0; public static final int NOTIFY_TYPE_ALL = 0;
public static final int NOTIFY_TYPE_MENTIONS = 1; public static final int NOTIFY_TYPE_MENTIONS = 1;
public static final int NOTIFY_TYPE_NONE = 2; public static final int NOTIFY_TYPE_NONE = 2;
@ -197,6 +203,7 @@ public class RecipientDatabase extends Database {
int unidentifiedAccessMode = cursor.getInt(cursor.getColumnIndexOrThrow(UNIDENTIFIED_ACCESS_MODE)); int unidentifiedAccessMode = cursor.getInt(cursor.getColumnIndexOrThrow(UNIDENTIFIED_ACCESS_MODE));
boolean forceSmsSelection = cursor.getInt(cursor.getColumnIndexOrThrow(FORCE_SMS_SELECTION)) == 1; boolean forceSmsSelection = cursor.getInt(cursor.getColumnIndexOrThrow(FORCE_SMS_SELECTION)) == 1;
String wrapperHash = cursor.getString(cursor.getColumnIndexOrThrow(WRAPPER_HASH)); String wrapperHash = cursor.getString(cursor.getColumnIndexOrThrow(WRAPPER_HASH));
boolean blocksCommunityMessageRequests = cursor.getInt(cursor.getColumnIndexOrThrow(BLOCKS_COMMUNITY_MESSAGE_REQUESTS)) == 1;
MaterialColor color; MaterialColor color;
byte[] profileKey = null; byte[] profileKey = null;
@ -228,7 +235,7 @@ public class RecipientDatabase extends Database {
systemPhoneLabel, systemContactUri, systemPhoneLabel, systemContactUri,
signalProfileName, signalProfileAvatar, profileSharing, signalProfileName, signalProfileAvatar, profileSharing,
notificationChannel, Recipient.UnidentifiedAccessMode.fromMode(unidentifiedAccessMode), notificationChannel, Recipient.UnidentifiedAccessMode.fromMode(unidentifiedAccessMode),
forceSmsSelection, wrapperHash)); forceSmsSelection, wrapperHash, blocksCommunityMessageRequests));
} }
public void setColor(@NonNull Recipient recipient, @NonNull MaterialColor color) { public void setColor(@NonNull Recipient recipient, @NonNull MaterialColor color) {
@ -395,6 +402,14 @@ public class RecipientDatabase extends Database {
notifyRecipientListeners(); notifyRecipientListeners();
} }
public void setBlocksCommunityMessageRequests(@NonNull Recipient recipient, boolean isBlocked) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(BLOCKS_COMMUNITY_MESSAGE_REQUESTS, isBlocked ? 1 : 0);
updateOrInsert(recipient.getAddress(), contentValues);
recipient.resolve().setBlocksCommunityMessageRequests(isBlocked);
notifyRecipientListeners();
}
private void updateOrInsert(Address address, ContentValues contentValues) { private void updateOrInsert(Address address, ContentValues contentValues) {
SQLiteDatabase database = databaseHelper.getWritableDatabase(); SQLiteDatabase database = databaseHelper.getWritableDatabase();

View File

@ -190,6 +190,11 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
db.setProfileKey(recipient, newProfileKey) db.setProfileKey(recipient, newProfileKey)
} }
override fun setBlocksCommunityMessageRequests(recipient: Recipient, blocksMessageRequests: Boolean) {
val db = DatabaseComponent.get(context).recipientDatabase()
db.setBlocksCommunityMessageRequests(recipient, blocksMessageRequests)
}
override fun setUserProfilePicture(newProfilePicture: String?, newProfileKey: ByteArray?) { override fun setUserProfilePicture(newProfilePicture: String?, newProfileKey: ByteArray?) {
val ourRecipient = fromSerialized(getUserPublicKey()!!).let { val ourRecipient = fromSerialized(getUserPublicKey()!!).let {
Recipient.from(context, it, false) Recipient.from(context, it, false)
@ -430,6 +435,10 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
return configFactory.canPerformChange(variant, publicKey, changeTimestampMs) return configFactory.canPerformChange(variant, publicKey, changeTimestampMs)
} }
override fun isCheckingCommunityRequests(): Boolean {
return configFactory.user?.getCommunityMessageRequests() == true
}
fun notifyUpdates(forConfigObject: ConfigBase) { fun notifyUpdates(forConfigObject: ConfigBase) {
when (forConfigObject) { when (forConfigObject) {
is UserProfile -> updateUser(forConfigObject) is UserProfile -> updateUser(forConfigObject)
@ -1405,7 +1414,7 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
val blindedId = when { val blindedId = when {
recipient.isGroupRecipient -> null recipient.isGroupRecipient -> null
recipient.isOpenGroupInboxRecipient -> { recipient.isOpenGroupInboxRecipient -> {
GroupUtil.getDecodedOpenGroupInbox(address) GroupUtil.getDecodedOpenGroupInboxSessionId(address)
} }
else -> { else -> {
if (SessionId(address).prefix == IdPrefix.BLINDED) { if (SessionId(address).prefix == IdPrefix.BLINDED) {
@ -1524,16 +1533,12 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
if (mapping.sessionId != null) { if (mapping.sessionId != null) {
return mapping return mapping
} }
val threadDb = DatabaseComponent.get(context).threadDatabase() getAllContacts().forEach { contact ->
threadDb.readerFor(threadDb.conversationList).use { reader -> val sessionId = SessionId(contact.sessionID)
while (reader.next != null) { if (sessionId.prefix == IdPrefix.STANDARD && SodiumUtilities.sessionId(sessionId.hexString, blindedId, serverPublicKey)) {
val recipient = reader.current.recipient val contactMapping = mapping.copy(sessionId = sessionId.hexString)
val sessionId = recipient.address.serialize() db.addBlindedIdMapping(contactMapping)
if (!recipient.isGroupRecipient && SodiumUtilities.sessionId(sessionId, blindedId, serverPublicKey)) { return contactMapping
val contactMapping = mapping.copy(sessionId = sessionId)
db.addBlindedIdMapping(contactMapping)
return contactMapping
}
} }
} }
db.getBlindedIdMappingsExceptFor(server).forEach { db.getBlindedIdMappingsExceptFor(server).forEach {

View File

@ -88,9 +88,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
private static final int lokiV40 = 61; private static final int lokiV40 = 61;
private static final int lokiV41 = 62; private static final int lokiV41 = 62;
private static final int lokiV42 = 63; private static final int lokiV42 = 63;
private static final int lokiV43 = 64;
// Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes // Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes
private static final int DATABASE_VERSION = lokiV42; private static final int DATABASE_VERSION = lokiV43;
private static final int MIN_DATABASE_VERSION = lokiV7; private static final int MIN_DATABASE_VERSION = lokiV7;
private static final String CIPHER3_DATABASE_NAME = "signal.db"; private static final String CIPHER3_DATABASE_NAME = "signal.db";
public static final String DATABASE_NAME = "signal_v4.db"; public static final String DATABASE_NAME = "signal_v4.db";
@ -356,6 +357,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
executeStatements(db, ReactionDatabase.CREATE_REACTION_TRIGGERS); executeStatements(db, ReactionDatabase.CREATE_REACTION_TRIGGERS);
db.execSQL(RecipientDatabase.getAddWrapperHash()); db.execSQL(RecipientDatabase.getAddWrapperHash());
db.execSQL(RecipientDatabase.getAddBlocksCommunityMessageRequests());
} }
@Override @Override
@ -598,6 +600,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
db.execSQL(RecipientDatabase.getAddWrapperHash()); db.execSQL(RecipientDatabase.getAddWrapperHash());
} }
if (oldVersion < lokiV43) {
db.execSQL(RecipientDatabase.getAddBlocksCommunityMessageRequests());
}
db.setTransactionSuccessful(); db.setTransactionSuccessful();
} finally { } finally {
db.endTransaction(); db.endTransaction();

View File

@ -0,0 +1,17 @@
package org.thoughtcrime.securesms.dependencies
import android.content.Context
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
@Module
@InstallIn(SingletonComponent::class)
object ContentModule {
@Provides
fun providesContentResolver(@ApplicationContext context: Context) =context.contentResolver
}

View File

@ -72,8 +72,8 @@ import org.thoughtcrime.securesms.onboarding.SeedActivity
import org.thoughtcrime.securesms.onboarding.SeedReminderViewDelegate import org.thoughtcrime.securesms.onboarding.SeedReminderViewDelegate
import org.thoughtcrime.securesms.permissions.Permissions import org.thoughtcrime.securesms.permissions.Permissions
import org.thoughtcrime.securesms.preferences.SettingsActivity import org.thoughtcrime.securesms.preferences.SettingsActivity
import org.thoughtcrime.securesms.showSessionDialog
import org.thoughtcrime.securesms.showMuteDialog import org.thoughtcrime.securesms.showMuteDialog
import org.thoughtcrime.securesms.showSessionDialog
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
import org.thoughtcrime.securesms.util.DateUtils import org.thoughtcrime.securesms.util.DateUtils
import org.thoughtcrime.securesms.util.IP2Country import org.thoughtcrime.securesms.util.IP2Country
@ -299,12 +299,17 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
} }
EventBus.getDefault().register(this@HomeActivity) EventBus.getDefault().register(this@HomeActivity)
if (intent.hasExtra(FROM_ONBOARDING) if (intent.hasExtra(FROM_ONBOARDING)
&& intent.getBooleanExtra(FROM_ONBOARDING, false) && intent.getBooleanExtra(FROM_ONBOARDING, false)) {
&& !(getSystemService(NOTIFICATION_SERVICE) as NotificationManager).areNotificationsEnabled() if ((getSystemService(NOTIFICATION_SERVICE) as NotificationManager).areNotificationsEnabled().not()) {
) { Permissions.with(this)
Permissions.with(this) .request(Manifest.permission.POST_NOTIFICATIONS)
.request(Manifest.permission.POST_NOTIFICATIONS) .execute()
.execute() }
configFactory.user?.let { user ->
if (!user.isBlockCommunityMessageRequestsSet()) {
user.setCommunityMessageRequests(false)
}
}
} }
} }

View File

@ -1,9 +1,11 @@
package org.thoughtcrime.securesms.preferences package org.thoughtcrime.securesms.preferences
import android.os.Bundle import android.os.Bundle
import dagger.hilt.android.AndroidEntryPoint
import network.loki.messenger.R import network.loki.messenger.R
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
@AndroidEntryPoint
class PrivacySettingsActivity : PassphraseRequiredActionBarActivity() { class PrivacySettingsActivity : PassphraseRequiredActionBarActivity() {
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) { override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {

View File

@ -8,6 +8,9 @@ import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.provider.Settings import android.provider.Settings
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceDataStore
import dagger.hilt.android.AndroidEntryPoint
import network.loki.messenger.BuildConfig import network.loki.messenger.BuildConfig
import network.loki.messenger.R import network.loki.messenger.R
import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.TextSecurePreferences
@ -15,13 +18,19 @@ import org.session.libsession.utilities.TextSecurePreferences.Companion.isPasswo
import org.session.libsession.utilities.TextSecurePreferences.Companion.setScreenLockEnabled import org.session.libsession.utilities.TextSecurePreferences.Companion.setScreenLockEnabled
import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.components.SwitchPreferenceCompat import org.thoughtcrime.securesms.components.SwitchPreferenceCompat
import org.thoughtcrime.securesms.dependencies.ConfigFactory
import org.thoughtcrime.securesms.permissions.Permissions import org.thoughtcrime.securesms.permissions.Permissions
import org.thoughtcrime.securesms.service.KeyCachingService import org.thoughtcrime.securesms.service.KeyCachingService
import org.thoughtcrime.securesms.showSessionDialog import org.thoughtcrime.securesms.showSessionDialog
import org.thoughtcrime.securesms.util.CallNotificationBuilder.Companion.areNotificationsEnabled import org.thoughtcrime.securesms.util.CallNotificationBuilder.Companion.areNotificationsEnabled
import org.thoughtcrime.securesms.util.IntentUtils import org.thoughtcrime.securesms.util.IntentUtils
import javax.inject.Inject
@AndroidEntryPoint
class PrivacySettingsPreferenceFragment : ListSummaryPreferenceFragment() { class PrivacySettingsPreferenceFragment : ListSummaryPreferenceFragment() {
@Inject lateinit var configFactory: ConfigFactory
override fun onCreate(paramBundle: Bundle?) { override fun onCreate(paramBundle: Bundle?) {
super.onCreate(paramBundle) super.onCreate(paramBundle)
findPreference<Preference>(TextSecurePreferences.SCREEN_LOCK)!! findPreference<Preference>(TextSecurePreferences.SCREEN_LOCK)!!
@ -30,6 +39,33 @@ class PrivacySettingsPreferenceFragment : ListSummaryPreferenceFragment() {
.onPreferenceChangeListener = TypingIndicatorsToggleListener() .onPreferenceChangeListener = TypingIndicatorsToggleListener()
findPreference<Preference>(TextSecurePreferences.CALL_NOTIFICATIONS_ENABLED)!! findPreference<Preference>(TextSecurePreferences.CALL_NOTIFICATIONS_ENABLED)!!
.onPreferenceChangeListener = CallToggleListener(this) { setCall(it) } .onPreferenceChangeListener = CallToggleListener(this) { setCall(it) }
findPreference<PreferenceCategory>(getString(R.string.preferences__message_requests_category))?.let { category ->
when (val user = configFactory.user) {
null -> category.isVisible = false
else -> SwitchPreferenceCompat(requireContext()).apply {
key = TextSecurePreferences.ALLOW_MESSAGE_REQUESTS
preferenceDataStore = object : PreferenceDataStore() {
override fun getBoolean(key: String?, defValue: Boolean): Boolean {
if (key == TextSecurePreferences.ALLOW_MESSAGE_REQUESTS) {
return user.getCommunityMessageRequests()
}
return super.getBoolean(key, defValue)
}
override fun putBoolean(key: String?, value: Boolean) {
if (key == TextSecurePreferences.ALLOW_MESSAGE_REQUESTS) {
user.setCommunityMessageRequests(value)
return
}
super.putBoolean(key, value)
}
}
title = getString(R.string.preferences__message_requests_title)
summary = getString(R.string.preferences__message_requests_summary)
}.let(category::addPreference)
}
}
initializeVisibility() initializeVisibility()
} }

View File

@ -1,5 +1,11 @@
package org.thoughtcrime.securesms.repository package org.thoughtcrime.securesms.repository
import android.content.ContentResolver
import android.content.Context
import app.cash.copper.flow.observeQuery
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import org.session.libsession.database.MessageDataProvider import org.session.libsession.database.MessageDataProvider
import org.session.libsession.messaging.messages.Destination import org.session.libsession.messaging.messages.Destination
import org.session.libsession.messaging.messages.control.MessageRequestResponse import org.session.libsession.messaging.messages.control.MessageRequestResponse
@ -15,6 +21,7 @@ import org.session.libsession.utilities.GroupUtil
import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.recipients.Recipient import org.session.libsession.utilities.recipients.Recipient
import org.session.libsignal.utilities.toHexString import org.session.libsignal.utilities.toHexString
import org.thoughtcrime.securesms.database.DatabaseContentProviders
import org.thoughtcrime.securesms.database.DraftDatabase import org.thoughtcrime.securesms.database.DraftDatabase
import org.thoughtcrime.securesms.database.LokiMessageDatabase import org.thoughtcrime.securesms.database.LokiMessageDatabase
import org.thoughtcrime.securesms.database.LokiThreadDatabase import org.thoughtcrime.securesms.database.LokiThreadDatabase
@ -35,6 +42,8 @@ import kotlin.coroutines.suspendCoroutine
interface ConversationRepository { interface ConversationRepository {
fun maybeGetRecipientForThreadId(threadId: Long): Recipient? fun maybeGetRecipientForThreadId(threadId: Long): Recipient?
fun maybeGetBlindedRecipient(recipient: Recipient): Recipient?
fun recipientUpdateFlow(threadId: Long): Flow<Recipient?>
fun saveDraft(threadId: Long, text: String) fun saveDraft(threadId: Long, text: String)
fun getDraft(threadId: Long): String? fun getDraft(threadId: Long): String?
fun clearDrafts(threadId: Long) fun clearDrafts(threadId: Long)
@ -75,6 +84,7 @@ interface ConversationRepository {
} }
class DefaultConversationRepository @Inject constructor( class DefaultConversationRepository @Inject constructor(
@ApplicationContext private val context: Context,
private val textSecurePreferences: TextSecurePreferences, private val textSecurePreferences: TextSecurePreferences,
private val messageDataProvider: MessageDataProvider, private val messageDataProvider: MessageDataProvider,
private val threadDb: ThreadDatabase, private val threadDb: ThreadDatabase,
@ -87,13 +97,29 @@ class DefaultConversationRepository @Inject constructor(
private val storage: Storage, private val storage: Storage,
private val lokiMessageDb: LokiMessageDatabase, private val lokiMessageDb: LokiMessageDatabase,
private val sessionJobDb: SessionJobDatabase, private val sessionJobDb: SessionJobDatabase,
private val configFactory: ConfigFactory private val configFactory: ConfigFactory,
private val contentResolver: ContentResolver,
) : ConversationRepository { ) : ConversationRepository {
override fun maybeGetRecipientForThreadId(threadId: Long): Recipient? { override fun maybeGetRecipientForThreadId(threadId: Long): Recipient? {
return threadDb.getRecipientForThreadId(threadId) return threadDb.getRecipientForThreadId(threadId)
} }
override fun maybeGetBlindedRecipient(recipient: Recipient): Recipient? {
if (!recipient.isOpenGroupInboxRecipient) return null
return Recipient.from(
context,
Address.fromSerialized(GroupUtil.getDecodedOpenGroupInboxSessionId(recipient.address.serialize())),
false
)
}
override fun recipientUpdateFlow(threadId: Long): Flow<Recipient?> {
return contentResolver.observeQuery(DatabaseContentProviders.Conversation.getUriForThread(threadId)).map {
maybeGetRecipientForThreadId(threadId)
}
}
override fun saveDraft(threadId: Long, text: String) { override fun saveDraft(threadId: Long, text: String) {
if (text.isEmpty()) return if (text.isEmpty()) return
val drafts = DraftDatabase.Drafts() val drafts = DraftDatabase.Drafts()

View File

@ -627,6 +627,9 @@
<string name="preferences_notifications__priority">Priority</string> <string name="preferences_notifications__priority">Priority</string>
<string name="preferences_app_protection__screenshot_notifications">Screenshot Notifications</string> <string name="preferences_app_protection__screenshot_notifications">Screenshot Notifications</string>
<string name="preferences_app_protected__screenshot_notifications_summary">Receive a notification when a contact takes a screenshot of a one-to-one chat.</string> <string name="preferences_app_protected__screenshot_notifications_summary">Receive a notification when a contact takes a screenshot of a one-to-one chat.</string>
<string name="preferences__message_requests_category">Message Requests</string>
<string name="preferences__message_requests_title">Community Message Requests</string>
<string name="preferences__message_requests_summary">Allow message requests from Community conversations</string>
<!-- **************************************** --> <!-- **************************************** -->
<!-- menus --> <!-- menus -->
<!-- **************************************** --> <!-- **************************************** -->
@ -1033,6 +1036,7 @@
<string name="activity_home_outdated_client_config">Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.</string> <string name="activity_home_outdated_client_config">Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.</string>
<string name="activity_conversation_empty_state_read_only">There are no messages in <b>%s</b>.</string> <string name="activity_conversation_empty_state_read_only">There are no messages in <b>%s</b>.</string>
<string name="activity_conversation_empty_state_blocks_community_requests"><b>%s</b> has message requests from Community conversations turned off, so you cannot send them a message.</string>
<string name="activity_conversation_empty_state_note_to_self">You have no messages in Note to Self.</string> <string name="activity_conversation_empty_state_note_to_self">You have no messages in Note to Self.</string>
<string name="activity_conversation_empty_state_default">You have no messages from <b>%s</b>.\nSend a message to start the conversation!</string> <string name="activity_conversation_empty_state_default">You have no messages from <b>%s</b>.\nSend a message to start the conversation!</string>

View File

@ -20,6 +20,12 @@
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory
android:title="@string/preferences__message_requests_category"
android:key="@string/preferences__message_requests_category"
android:persistent="false">
</PreferenceCategory>
<PreferenceCategory android:title="@string/preferences__read_receipts"> <PreferenceCategory android:title="@string/preferences__read_receipts">
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat <org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:defaultValue="false" android:defaultValue="false"

View File

@ -1,42 +1,46 @@
package org.thoughtcrime.securesms.conversation.v2 package org.thoughtcrime.securesms.conversation.v2
import com.goterl.lazysodium.utils.KeyPair import com.goterl.lazysodium.utils.KeyPair
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import org.hamcrest.CoreMatchers.endsWith import org.hamcrest.CoreMatchers.endsWith
import org.hamcrest.CoreMatchers.equalTo import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.CoreMatchers.notNullValue
import org.hamcrest.CoreMatchers.nullValue
import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.MatcherAssert.assertThat
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.mockito.Mockito.anyLong import org.mockito.Mockito.anyLong
import org.mockito.Mockito.anySet import org.mockito.Mockito.anySet
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify import org.mockito.Mockito.verify
import org.mockito.kotlin.any import org.mockito.kotlin.any
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import org.session.libsession.utilities.recipients.Recipient import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.BaseViewModelTest import org.thoughtcrime.securesms.BaseViewModelTest
import org.thoughtcrime.securesms.database.Storage import org.thoughtcrime.securesms.database.Storage
import org.thoughtcrime.securesms.database.model.MessageRecord import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.repository.ConversationRepository import org.thoughtcrime.securesms.repository.ConversationRepository
import org.thoughtcrime.securesms.repository.ResultOf import org.thoughtcrime.securesms.repository.ResultOf
import org.mockito.Mockito.`when` as whenever
class ConversationViewModelTest: BaseViewModelTest() { class ConversationViewModelTest: BaseViewModelTest() {
private val repository = mock(ConversationRepository::class.java) private val repository = mock<ConversationRepository>()
private val storage = mock(Storage::class.java) private val storage = mock<Storage>()
private val threadId = 123L private val threadId = 123L
private val edKeyPair = mock(KeyPair::class.java) private val edKeyPair = mock<KeyPair>()
private lateinit var recipient: Recipient private lateinit var recipient: Recipient
private val viewModel: ConversationViewModel by lazy { private val viewModel: ConversationViewModel by lazy {
ConversationViewModel(threadId, edKeyPair, mock(), repository, storage) ConversationViewModel(threadId, edKeyPair, repository, storage)
} }
@Before @Before
fun setUp() { fun setUp() {
recipient = mock(Recipient::class.java) recipient = mock()
whenever(repository.maybeGetRecipientForThreadId(anyLong())).thenReturn(recipient) whenever(repository.maybeGetRecipientForThreadId(anyLong())).thenReturn(recipient)
whenever(repository.recipientUpdateFlow(anyLong())).thenReturn(emptyFlow())
} }
@Test @Test
@ -79,7 +83,7 @@ class ConversationViewModelTest: BaseViewModelTest() {
@Test @Test
fun `should delete locally`() { fun `should delete locally`() {
val message = mock(MessageRecord::class.java) val message = mock<MessageRecord>()
viewModel.deleteLocally(message) viewModel.deleteLocally(message)
@ -88,7 +92,7 @@ class ConversationViewModelTest: BaseViewModelTest() {
@Test @Test
fun `should emit error message on failure to delete a message for everyone`() = runBlockingTest { fun `should emit error message on failure to delete a message for everyone`() = runBlockingTest {
val message = mock(MessageRecord::class.java) val message = mock<MessageRecord>()
val error = Throwable() val error = Throwable()
whenever(repository.deleteForEveryone(anyLong(), any(), any())) whenever(repository.deleteForEveryone(anyLong(), any(), any()))
.thenReturn(ResultOf.Failure(error)) .thenReturn(ResultOf.Failure(error))
@ -101,7 +105,7 @@ class ConversationViewModelTest: BaseViewModelTest() {
@Test @Test
fun `should emit error message on failure to delete messages without unsend request`() = fun `should emit error message on failure to delete messages without unsend request`() =
runBlockingTest { runBlockingTest {
val message = mock(MessageRecord::class.java) val message = mock<MessageRecord>()
val error = Throwable() val error = Throwable()
whenever(repository.deleteMessageWithoutUnsendRequest(anyLong(), anySet())) whenever(repository.deleteMessageWithoutUnsendRequest(anyLong(), anySet()))
.thenReturn(ResultOf.Failure(error)) .thenReturn(ResultOf.Failure(error))
@ -181,4 +185,30 @@ class ConversationViewModelTest: BaseViewModelTest() {
assertThat(viewModel.uiState.value.uiMessages.size, equalTo(0)) assertThat(viewModel.uiState.value.uiMessages.size, equalTo(0))
} }
@Test
fun `open group recipient should have no blinded recipient`() {
whenever(recipient.isOpenGroupRecipient).thenReturn(true)
whenever(recipient.isOpenGroupOutboxRecipient).thenReturn(false)
whenever(recipient.isOpenGroupInboxRecipient).thenReturn(false)
assertThat(viewModel.blindedRecipient, nullValue())
}
@Test
fun `local recipient should have input and no blinded recipient`() {
whenever(recipient.isLocalNumber).thenReturn(true)
assertThat(viewModel.hidesInputBar(), equalTo(false))
assertThat(viewModel.blindedRecipient, nullValue())
}
@Test
fun `contact recipient should hide input bar if not accepting requests`() {
whenever(recipient.isOpenGroupInboxRecipient).thenReturn(true)
val blinded = mock<Recipient> {
whenever(it.blocksCommunityMessageRequests).thenReturn(true)
}
whenever(repository.maybeGetBlindedRecipient(recipient)).thenReturn(blinded)
assertThat(viewModel.blindedRecipient, notNullValue())
assertThat(viewModel.hidesInputBar(), equalTo(true))
}
} }

@ -1 +1 @@
Subproject commit 7eb87028355bfc89950102c52d5b2927a25b2e22 Subproject commit e3ccf29db08aaf0b9bb6bbe72ae5967cd183a78d

View File

@ -95,4 +95,33 @@ Java_network_loki_messenger_libsession_1util_UserProfile_getNtsPriority(JNIEnv *
std::lock_guard lock{util::util_mutex_}; std::lock_guard lock{util::util_mutex_};
auto profile = ptrToProfile(env, thiz); auto profile = ptrToProfile(env, thiz);
return profile->get_nts_priority(); return profile->get_nts_priority();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_network_loki_messenger_libsession_1util_UserProfile_getCommunityMessageRequests(
JNIEnv *env, jobject thiz) {
std::lock_guard lock{util::util_mutex_};
auto profile = ptrToProfile(env, thiz);
auto blinded_msg_requests = profile->get_blinded_msgreqs();
if (blinded_msg_requests.has_value()) {
return *blinded_msg_requests;
}
return true;
}
extern "C"
JNIEXPORT void JNICALL
Java_network_loki_messenger_libsession_1util_UserProfile_setCommunityMessageRequests(
JNIEnv *env, jobject thiz, jboolean blocks) {
std::lock_guard lock{util::util_mutex_};
auto profile = ptrToProfile(env, thiz);
profile->set_blinded_msgreqs(std::optional{(bool)blocks});
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_network_loki_messenger_libsession_1util_UserProfile_isBlockCommunityMessageRequestsSet(
JNIEnv *env, jobject thiz) {
std::lock_guard lock{util::util_mutex_};
auto profile = ptrToProfile(env, thiz);
return profile->get_blinded_msgreqs().has_value();
} }

View File

@ -126,6 +126,9 @@ class UserProfile(pointer: Long) : ConfigBase(pointer) {
external fun setPic(userPic: UserPic) external fun setPic(userPic: UserPic)
external fun setNtsPriority(priority: Int) external fun setNtsPriority(priority: Int)
external fun getNtsPriority(): Int external fun getNtsPriority(): Int
external fun getCommunityMessageRequests(): Boolean
external fun setCommunityMessageRequests(blocks: Boolean)
external fun isBlockCommunityMessageRequestsSet(): Boolean
} }
class ConversationVolatileConfig(pointer: Long): ConfigBase(pointer) { class ConversationVolatileConfig(pointer: Long): ConfigBase(pointer) {

View File

@ -42,6 +42,7 @@ interface StorageProtocol {
fun getUserProfile(): Profile fun getUserProfile(): Profile
fun setProfileAvatar(recipient: Recipient, profileAvatar: String?) fun setProfileAvatar(recipient: Recipient, profileAvatar: String?)
fun setProfilePicture(recipient: Recipient, newProfilePicture: String?, newProfileKey: ByteArray?) fun setProfilePicture(recipient: Recipient, newProfilePicture: String?, newProfileKey: ByteArray?)
fun setBlocksCommunityMessageRequests(recipient: Recipient, blocksMessageRequests: Boolean)
fun setUserProfilePicture(newProfilePicture: String?, newProfileKey: ByteArray?) fun setUserProfilePicture(newProfilePicture: String?, newProfileKey: ByteArray?)
fun clearUserPic() fun clearUserPic()
// Signal // Signal
@ -228,4 +229,5 @@ interface StorageProtocol {
fun notifyConfigUpdates(forConfigObject: ConfigBase) fun notifyConfigUpdates(forConfigObject: ConfigBase)
fun conversationInConfig(publicKey: String?, groupPublicKey: String?, openGroupId: String?, visibleOnly: Boolean): Boolean fun conversationInConfig(publicKey: String?, groupPublicKey: String?, openGroupId: String?, visibleOnly: Boolean): Boolean
fun canPerformConfigChange(variant: String, publicKey: String, changeTimestampMs: Long): Boolean fun canPerformConfigChange(variant: String, publicKey: String, changeTimestampMs: Long): Boolean
fun isCheckingCommunityRequests(): Boolean
} }

View File

@ -25,7 +25,8 @@ class VisibleMessage(
var profile: Profile? = null, var profile: Profile? = null,
var openGroupInvitation: OpenGroupInvitation? = null, var openGroupInvitation: OpenGroupInvitation? = null,
var reaction: Reaction? = null, var reaction: Reaction? = null,
var hasMention: Boolean = false var hasMention: Boolean = false,
var blocksMessageRequests: Boolean = false
) : Message() { ) : Message() {
override val isSelfSendValid: Boolean = true override val isSelfSendValid: Boolean = true
@ -74,6 +75,9 @@ class VisibleMessage(
val reaction = Reaction.fromProto(reactionProto) val reaction = Reaction.fromProto(reactionProto)
result.reaction = reaction result.reaction = reaction
} }
result.blocksMessageRequests = with (dataMessage) { hasBlocksCommunityMessageRequests() && blocksCommunityMessageRequests }
return result return result
} }
} }
@ -141,6 +145,8 @@ class VisibleMessage(
return null return null
} }
} }
// Community blocked message requests flag
dataMessage.blocksCommunityMessageRequests = blocksMessageRequests
// Sync target // Sync target
if (syncTarget != null) { if (syncTarget != null) {
dataMessage.syncTarget = syncTarget dataMessage.syncTarget = syncTarget

View File

@ -753,7 +753,8 @@ object OpenGroupApi {
) )
} }
val serverCapabilities = storage.getServerCapabilities(server) val serverCapabilities = storage.getServerCapabilities(server)
if (serverCapabilities.contains(Capability.BLIND.name.lowercase())) { val isAcceptingCommunityRequests = storage.isCheckingCommunityRequests()
if (serverCapabilities.contains(Capability.BLIND.name.lowercase()) && isAcceptingCommunityRequests) {
requests.add( requests.add(
if (lastInboxMessageId == null) { if (lastInboxMessageId == null) {
BatchRequestInfo( BatchRequestInfo(

View File

@ -242,9 +242,16 @@ object MessageSender {
private fun sendToOpenGroupDestination(destination: Destination, message: Message): Promise<Unit, Exception> { private fun sendToOpenGroupDestination(destination: Destination, message: Message): Promise<Unit, Exception> {
val deferred = deferred<Unit, Exception>() val deferred = deferred<Unit, Exception>()
val storage = MessagingModuleConfiguration.shared.storage val storage = MessagingModuleConfiguration.shared.storage
val configFactory = MessagingModuleConfiguration.shared.configFactory
if (message.sentTimestamp == null) { if (message.sentTimestamp == null) {
message.sentTimestamp = SnodeAPI.nowWithOffset message.sentTimestamp = SnodeAPI.nowWithOffset
} }
// Attach the blocks message requests info
configFactory.user?.let { user ->
if (message is VisibleMessage) {
message.blocksMessageRequests = !user.getCommunityMessageRequests()
}
}
val userEdKeyPair = MessagingModuleConfiguration.shared.getUserED25519KeyPair()!! val userEdKeyPair = MessagingModuleConfiguration.shared.getUserED25519KeyPair()!!
var serverCapabilities = listOf<String>() var serverCapabilities = listOf<String>()
var blindedPublicKey: ByteArray? = null var blindedPublicKey: ByteArray? = null

View File

@ -304,6 +304,10 @@ fun MessageReceiver.handleVisibleMessage(
profileManager.setProfilePicture(context, recipient, null, null) profileManager.setProfilePicture(context, recipient, null, null)
} }
} }
if (userPublicKey != messageSender && !isUserBlindedSender) {
storage.setBlocksCommunityMessageRequests(recipient, message.blocksMessageRequests)
}
} }
// Parse quote if needed // Parse quote if needed
var quoteModel: QuoteModel? = null var quoteModel: QuoteModel? = null

View File

@ -1,6 +1,7 @@
package org.session.libsession.utilities package org.session.libsession.utilities
import network.loki.messenger.libsession_util.util.GroupInfo import org.session.libsession.messaging.open_groups.OpenGroup
import org.session.libsession.messaging.utilities.SessionId
import org.session.libsignal.messages.SignalServiceGroup import org.session.libsignal.messages.SignalServiceGroup
import org.session.libsignal.utilities.Hex import org.session.libsignal.utilities.Hex
import java.io.IOException import java.io.IOException
@ -16,8 +17,15 @@ object GroupUtil {
} }
@JvmStatic @JvmStatic
fun getEncodedOpenGroupInboxID(groupInboxID: ByteArray): String { fun getEncodedOpenGroupInboxID(openGroup: OpenGroup, sessionId: SessionId): Address {
return OPEN_GROUP_INBOX_PREFIX + Hex.toStringCondensed(groupInboxID) val openGroupInboxId =
"${openGroup.server}!${openGroup.publicKey}!${sessionId.hexString}".toByteArray()
return getEncodedOpenGroupInboxID(openGroupInboxId)
}
@JvmStatic
fun getEncodedOpenGroupInboxID(groupInboxID: ByteArray): Address {
return Address.fromSerialized(OPEN_GROUP_INBOX_PREFIX + Hex.toStringCondensed(groupInboxID))
} }
@JvmStatic @JvmStatic
@ -52,7 +60,7 @@ object GroupUtil {
} }
@JvmStatic @JvmStatic
fun getDecodedOpenGroupInbox(groupID: String): String { fun getDecodedOpenGroupInboxSessionId(groupID: String): String {
val decodedGroupId = getDecodedGroupID(groupID) val decodedGroupId = getDecodedGroupID(groupID)
if (decodedGroupId.split("!").count() > 2) { if (decodedGroupId.split("!").count() > 2) {
return decodedGroupId.split("!", limit = 3)[2] return decodedGroupId.split("!", limit = 3)[2]

View File

@ -287,6 +287,8 @@ interface TextSecurePreferences {
const val OCEAN_DARK = "ocean.dark" const val OCEAN_DARK = "ocean.dark"
const val OCEAN_LIGHT = "ocean.light" const val OCEAN_LIGHT = "ocean.light"
const val ALLOW_MESSAGE_REQUESTS = "libsession.ALLOW_MESSAGE_REQUESTS"
@JvmStatic @JvmStatic
fun getLastConfigurationSyncTime(context: Context): Long { fun getLastConfigurationSyncTime(context: Context): Long {
return getLongPreference(context, LAST_CONFIGURATION_SYNC_TIME, 0) return getLongPreference(context, LAST_CONFIGURATION_SYNC_TIME, 0)

View File

@ -100,6 +100,7 @@ public class Recipient implements RecipientModifiedListener {
private String notificationChannel; private String notificationChannel;
private boolean forceSmsSelection; private boolean forceSmsSelection;
private String wrapperHash; private String wrapperHash;
private boolean blocksCommunityMessageRequests;
private @NonNull UnidentifiedAccessMode unidentifiedAccessMode = UnidentifiedAccessMode.ENABLED; private @NonNull UnidentifiedAccessMode unidentifiedAccessMode = UnidentifiedAccessMode.ENABLED;
@ -192,6 +193,7 @@ public class Recipient implements RecipientModifiedListener {
this.unidentifiedAccessMode = details.get().unidentifiedAccessMode; this.unidentifiedAccessMode = details.get().unidentifiedAccessMode;
this.forceSmsSelection = details.get().forceSmsSelection; this.forceSmsSelection = details.get().forceSmsSelection;
this.notifyType = details.get().notifyType; this.notifyType = details.get().notifyType;
this.blocksCommunityMessageRequests = details.get().blocksCommunityMessageRequests;
this.participants.clear(); this.participants.clear();
this.participants.addAll(details.get().participants); this.participants.addAll(details.get().participants);
@ -228,6 +230,7 @@ public class Recipient implements RecipientModifiedListener {
Recipient.this.unidentifiedAccessMode = result.unidentifiedAccessMode; Recipient.this.unidentifiedAccessMode = result.unidentifiedAccessMode;
Recipient.this.forceSmsSelection = result.forceSmsSelection; Recipient.this.forceSmsSelection = result.forceSmsSelection;
Recipient.this.notifyType = result.notifyType; Recipient.this.notifyType = result.notifyType;
Recipient.this.blocksCommunityMessageRequests = result.blocksCommunityMessageRequests;
Recipient.this.participants.clear(); Recipient.this.participants.clear();
Recipient.this.participants.addAll(result.participants); Recipient.this.participants.addAll(result.participants);
@ -281,6 +284,7 @@ public class Recipient implements RecipientModifiedListener {
this.unidentifiedAccessMode = details.unidentifiedAccessMode; this.unidentifiedAccessMode = details.unidentifiedAccessMode;
this.forceSmsSelection = details.forceSmsSelection; this.forceSmsSelection = details.forceSmsSelection;
this.wrapperHash = details.wrapperHash; this.wrapperHash = details.wrapperHash;
this.blocksCommunityMessageRequests = details.blocksCommunityMessageRequests;
this.participants.addAll(details.participants); this.participants.addAll(details.participants);
this.resolving = false; this.resolving = false;
@ -321,7 +325,7 @@ public class Recipient implements RecipientModifiedListener {
return this.name; return this.name;
} }
} else if (isOpenGroupInboxRecipient()){ } else if (isOpenGroupInboxRecipient()){
String inboxID = GroupUtil.getDecodedOpenGroupInbox(sessionID); String inboxID = GroupUtil.getDecodedOpenGroupInboxSessionId(sessionID);
Contact contact = storage.getContactWithSessionID(inboxID); Contact contact = storage.getContactWithSessionID(inboxID);
if (contact == null) { return sessionID; } if (contact == null) { return sessionID; }
return contact.displayName(Contact.ContactContext.REGULAR); return contact.displayName(Contact.ContactContext.REGULAR);
@ -345,6 +349,18 @@ public class Recipient implements RecipientModifiedListener {
if (notify) notifyListeners(); if (notify) notifyListeners();
} }
public boolean getBlocksCommunityMessageRequests() {
return blocksCommunityMessageRequests;
}
public void setBlocksCommunityMessageRequests(boolean blocksCommunityMessageRequests) {
synchronized (this) {
this.blocksCommunityMessageRequests = blocksCommunityMessageRequests;
}
notifyListeners();
}
public synchronized @NonNull MaterialColor getColor() { public synchronized @NonNull MaterialColor getColor() {
if (isGroupRecipient()) return MaterialColor.GROUP; if (isGroupRecipient()) return MaterialColor.GROUP;
else if (color != null) return color; else if (color != null) return color;
@ -759,12 +775,43 @@ public class Recipient implements RecipientModifiedListener {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
Recipient recipient = (Recipient) o; Recipient recipient = (Recipient) o;
return resolving == recipient.resolving && mutedUntil == recipient.mutedUntil && notifyType == recipient.notifyType && blocked == recipient.blocked && approved == recipient.approved && approvedMe == recipient.approvedMe && expireMessages == recipient.expireMessages && address.equals(recipient.address) && Objects.equals(name, recipient.name) && Objects.equals(customLabel, recipient.customLabel) && Objects.equals(groupAvatarId, recipient.groupAvatarId) && Arrays.equals(profileKey, recipient.profileKey) && Objects.equals(profileName, recipient.profileName) && Objects.equals(profileAvatar, recipient.profileAvatar) && Objects.equals(wrapperHash, recipient.wrapperHash); return resolving == recipient.resolving
&& mutedUntil == recipient.mutedUntil
&& notifyType == recipient.notifyType
&& blocked == recipient.blocked
&& approved == recipient.approved
&& approvedMe == recipient.approvedMe
&& expireMessages == recipient.expireMessages
&& address.equals(recipient.address)
&& Objects.equals(name, recipient.name)
&& Objects.equals(customLabel, recipient.customLabel)
&& Objects.equals(groupAvatarId, recipient.groupAvatarId)
&& Arrays.equals(profileKey, recipient.profileKey)
&& Objects.equals(profileName, recipient.profileName)
&& Objects.equals(profileAvatar, recipient.profileAvatar)
&& Objects.equals(wrapperHash, recipient.wrapperHash)
&& blocksCommunityMessageRequests == recipient.blocksCommunityMessageRequests;
} }
@Override @Override
public int hashCode() { public int hashCode() {
int result = Objects.hash(address, name, customLabel, resolving, groupAvatarId, mutedUntil, notifyType, blocked, approved, approvedMe, expireMessages, profileName, profileAvatar, wrapperHash); int result = Objects.hash(
address,
name,
customLabel,
resolving,
groupAvatarId,
mutedUntil,
notifyType,
blocked,
approved,
approvedMe,
expireMessages,
profileName,
profileAvatar,
wrapperHash,
blocksCommunityMessageRequests
);
result = 31 * result + Arrays.hashCode(profileKey); result = 31 * result + Arrays.hashCode(profileKey);
return result; return result;
} }
@ -869,55 +916,59 @@ public class Recipient implements RecipientModifiedListener {
private final UnidentifiedAccessMode unidentifiedAccessMode; private final UnidentifiedAccessMode unidentifiedAccessMode;
private final boolean forceSmsSelection; private final boolean forceSmsSelection;
private final String wrapperHash; private final String wrapperHash;
private final boolean blocksCommunityMessageRequests;
public RecipientSettings(boolean blocked, boolean approved, boolean approvedMe, long muteUntil, public RecipientSettings(boolean blocked, boolean approved, boolean approvedMe, long muteUntil,
int notifyType, int notifyType,
@NonNull VibrateState messageVibrateState, @NonNull VibrateState messageVibrateState,
@NonNull VibrateState callVibrateState, @NonNull VibrateState callVibrateState,
@Nullable Uri messageRingtone, @Nullable Uri messageRingtone,
@Nullable Uri callRingtone, @Nullable Uri callRingtone,
@Nullable MaterialColor color, @Nullable MaterialColor color,
int defaultSubscriptionId, int defaultSubscriptionId,
int expireMessages, int expireMessages,
@NonNull RegisteredState registered, @NonNull RegisteredState registered,
@Nullable byte[] profileKey, @Nullable byte[] profileKey,
@Nullable String systemDisplayName, @Nullable String systemDisplayName,
@Nullable String systemContactPhoto, @Nullable String systemContactPhoto,
@Nullable String systemPhoneLabel, @Nullable String systemPhoneLabel,
@Nullable String systemContactUri, @Nullable String systemContactUri,
@Nullable String signalProfileName, @Nullable String signalProfileName,
@Nullable String signalProfileAvatar, @Nullable String signalProfileAvatar,
boolean profileSharing, boolean profileSharing,
@Nullable String notificationChannel, @Nullable String notificationChannel,
@NonNull UnidentifiedAccessMode unidentifiedAccessMode, @NonNull UnidentifiedAccessMode unidentifiedAccessMode,
boolean forceSmsSelection, boolean forceSmsSelection,
String wrapperHash) String wrapperHash,
boolean blocksCommunityMessageRequests
)
{ {
this.blocked = blocked; this.blocked = blocked;
this.approved = approved; this.approved = approved;
this.approvedMe = approvedMe; this.approvedMe = approvedMe;
this.muteUntil = muteUntil; this.muteUntil = muteUntil;
this.notifyType = notifyType; this.notifyType = notifyType;
this.messageVibrateState = messageVibrateState; this.messageVibrateState = messageVibrateState;
this.callVibrateState = callVibrateState; this.callVibrateState = callVibrateState;
this.messageRingtone = messageRingtone; this.messageRingtone = messageRingtone;
this.callRingtone = callRingtone; this.callRingtone = callRingtone;
this.color = color; this.color = color;
this.defaultSubscriptionId = defaultSubscriptionId; this.defaultSubscriptionId = defaultSubscriptionId;
this.expireMessages = expireMessages; this.expireMessages = expireMessages;
this.registered = registered; this.registered = registered;
this.profileKey = profileKey; this.profileKey = profileKey;
this.systemDisplayName = systemDisplayName; this.systemDisplayName = systemDisplayName;
this.systemContactPhoto = systemContactPhoto; this.systemContactPhoto = systemContactPhoto;
this.systemPhoneLabel = systemPhoneLabel; this.systemPhoneLabel = systemPhoneLabel;
this.systemContactUri = systemContactUri; this.systemContactUri = systemContactUri;
this.signalProfileName = signalProfileName; this.signalProfileName = signalProfileName;
this.signalProfileAvatar = signalProfileAvatar; this.signalProfileAvatar = signalProfileAvatar;
this.profileSharing = profileSharing; this.profileSharing = profileSharing;
this.notificationChannel = notificationChannel; this.notificationChannel = notificationChannel;
this.unidentifiedAccessMode = unidentifiedAccessMode; this.unidentifiedAccessMode = unidentifiedAccessMode;
this.forceSmsSelection = forceSmsSelection; this.forceSmsSelection = forceSmsSelection;
this.wrapperHash = wrapperHash; this.wrapperHash = wrapperHash;
this.blocksCommunityMessageRequests = blocksCommunityMessageRequests;
} }
public @Nullable MaterialColor getColor() { public @Nullable MaterialColor getColor() {
@ -1020,6 +1071,10 @@ public class Recipient implements RecipientModifiedListener {
return wrapperHash; return wrapperHash;
} }
public boolean getBlocksCommunityMessageRequests() {
return blocksCommunityMessageRequests;
}
} }

View File

@ -178,6 +178,7 @@ class RecipientProvider {
@NonNull final UnidentifiedAccessMode unidentifiedAccessMode; @NonNull final UnidentifiedAccessMode unidentifiedAccessMode;
final boolean forceSmsSelection; final boolean forceSmsSelection;
final String wrapperHash; final String wrapperHash;
final boolean blocksCommunityMessageRequests;
RecipientDetails(@Nullable String name, @Nullable Long groupAvatarId, RecipientDetails(@Nullable String name, @Nullable Long groupAvatarId,
boolean systemContact, boolean isLocalNumber, @Nullable RecipientSettings settings, boolean systemContact, boolean isLocalNumber, @Nullable RecipientSettings settings,
@ -211,6 +212,7 @@ class RecipientProvider {
this.unidentifiedAccessMode = settings != null ? settings.getUnidentifiedAccessMode() : UnidentifiedAccessMode.DISABLED; this.unidentifiedAccessMode = settings != null ? settings.getUnidentifiedAccessMode() : UnidentifiedAccessMode.DISABLED;
this.forceSmsSelection = settings != null && settings.isForceSmsSelection(); this.forceSmsSelection = settings != null && settings.isForceSmsSelection();
this.wrapperHash = settings != null ? settings.getWrapperHash() : null; this.wrapperHash = settings != null ? settings.getWrapperHash() : null;
this.blocksCommunityMessageRequests = settings != null && settings.getBlocksCommunityMessageRequests();
if (name == null && settings != null) this.name = settings.getSystemDisplayName(); if (name == null && settings != null) this.name = settings.getSystemDisplayName();
else this.name = name; else this.name = name;

View File

@ -163,20 +163,21 @@ message DataMessage {
required Action action = 4; required Action action = 4;
} }
optional string body = 1; optional string body = 1;
repeated AttachmentPointer attachments = 2; repeated AttachmentPointer attachments = 2;
optional GroupContext group = 3; optional GroupContext group = 3;
optional uint32 flags = 4; optional uint32 flags = 4;
optional uint32 expireTimer = 5; optional uint32 expireTimer = 5;
optional bytes profileKey = 6; optional bytes profileKey = 6;
optional uint64 timestamp = 7; optional uint64 timestamp = 7;
optional Quote quote = 8; optional Quote quote = 8;
repeated Preview preview = 10; repeated Preview preview = 10;
optional Reaction reaction = 11; optional Reaction reaction = 11;
optional LokiProfile profile = 101; optional LokiProfile profile = 101;
optional OpenGroupInvitation openGroupInvitation = 102; optional OpenGroupInvitation openGroupInvitation = 102;
optional ClosedGroupControlMessage closedGroupControlMessage = 104; optional ClosedGroupControlMessage closedGroupControlMessage = 104;
optional string syncTarget = 105; optional string syncTarget = 105;
optional bool blocksCommunityMessageRequests = 106;
} }
message CallMessage { message CallMessage {

View File

@ -5890,6 +5890,16 @@ public final class SignalServiceProtos {
*/ */
com.google.protobuf.ByteString com.google.protobuf.ByteString
getSyncTargetBytes(); getSyncTargetBytes();
// optional bool blocksCommunityMessageRequests = 106;
/**
* <code>optional bool blocksCommunityMessageRequests = 106;</code>
*/
boolean hasBlocksCommunityMessageRequests();
/**
* <code>optional bool blocksCommunityMessageRequests = 106;</code>
*/
boolean getBlocksCommunityMessageRequests();
} }
/** /**
* Protobuf type {@code signalservice.DataMessage} * Protobuf type {@code signalservice.DataMessage}
@ -6066,6 +6076,11 @@ public final class SignalServiceProtos {
syncTarget_ = input.readBytes(); syncTarget_ = input.readBytes();
break; break;
} }
case 848: {
bitField0_ |= 0x00001000;
blocksCommunityMessageRequests_ = input.readBool();
break;
}
} }
} }
} catch (com.google.protobuf.InvalidProtocolBufferException e) { } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@ -14336,6 +14351,22 @@ public final class SignalServiceProtos {
} }
} }
// optional bool blocksCommunityMessageRequests = 106;
public static final int BLOCKSCOMMUNITYMESSAGEREQUESTS_FIELD_NUMBER = 106;
private boolean blocksCommunityMessageRequests_;
/**
* <code>optional bool blocksCommunityMessageRequests = 106;</code>
*/
public boolean hasBlocksCommunityMessageRequests() {
return ((bitField0_ & 0x00001000) == 0x00001000);
}
/**
* <code>optional bool blocksCommunityMessageRequests = 106;</code>
*/
public boolean getBlocksCommunityMessageRequests() {
return blocksCommunityMessageRequests_;
}
private void initFields() { private void initFields() {
body_ = ""; body_ = "";
attachments_ = java.util.Collections.emptyList(); attachments_ = java.util.Collections.emptyList();
@ -14351,6 +14382,7 @@ public final class SignalServiceProtos {
openGroupInvitation_ = org.session.libsignal.protos.SignalServiceProtos.DataMessage.OpenGroupInvitation.getDefaultInstance(); openGroupInvitation_ = org.session.libsignal.protos.SignalServiceProtos.DataMessage.OpenGroupInvitation.getDefaultInstance();
closedGroupControlMessage_ = org.session.libsignal.protos.SignalServiceProtos.DataMessage.ClosedGroupControlMessage.getDefaultInstance(); closedGroupControlMessage_ = org.session.libsignal.protos.SignalServiceProtos.DataMessage.ClosedGroupControlMessage.getDefaultInstance();
syncTarget_ = ""; syncTarget_ = "";
blocksCommunityMessageRequests_ = false;
} }
private byte memoizedIsInitialized = -1; private byte memoizedIsInitialized = -1;
public final boolean isInitialized() { public final boolean isInitialized() {
@ -14448,6 +14480,9 @@ public final class SignalServiceProtos {
if (((bitField0_ & 0x00000800) == 0x00000800)) { if (((bitField0_ & 0x00000800) == 0x00000800)) {
output.writeBytes(105, getSyncTargetBytes()); output.writeBytes(105, getSyncTargetBytes());
} }
if (((bitField0_ & 0x00001000) == 0x00001000)) {
output.writeBool(106, blocksCommunityMessageRequests_);
}
getUnknownFields().writeTo(output); getUnknownFields().writeTo(output);
} }
@ -14513,6 +14548,10 @@ public final class SignalServiceProtos {
size += com.google.protobuf.CodedOutputStream size += com.google.protobuf.CodedOutputStream
.computeBytesSize(105, getSyncTargetBytes()); .computeBytesSize(105, getSyncTargetBytes());
} }
if (((bitField0_ & 0x00001000) == 0x00001000)) {
size += com.google.protobuf.CodedOutputStream
.computeBoolSize(106, blocksCommunityMessageRequests_);
}
size += getUnknownFields().getSerializedSize(); size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size; memoizedSerializedSize = size;
return size; return size;
@ -14697,6 +14736,8 @@ public final class SignalServiceProtos {
bitField0_ = (bitField0_ & ~0x00001000); bitField0_ = (bitField0_ & ~0x00001000);
syncTarget_ = ""; syncTarget_ = "";
bitField0_ = (bitField0_ & ~0x00002000); bitField0_ = (bitField0_ & ~0x00002000);
blocksCommunityMessageRequests_ = false;
bitField0_ = (bitField0_ & ~0x00004000);
return this; return this;
} }
@ -14815,6 +14856,10 @@ public final class SignalServiceProtos {
to_bitField0_ |= 0x00000800; to_bitField0_ |= 0x00000800;
} }
result.syncTarget_ = syncTarget_; result.syncTarget_ = syncTarget_;
if (((from_bitField0_ & 0x00004000) == 0x00004000)) {
to_bitField0_ |= 0x00001000;
}
result.blocksCommunityMessageRequests_ = blocksCommunityMessageRequests_;
result.bitField0_ = to_bitField0_; result.bitField0_ = to_bitField0_;
onBuilt(); onBuilt();
return result; return result;
@ -14923,6 +14968,9 @@ public final class SignalServiceProtos {
syncTarget_ = other.syncTarget_; syncTarget_ = other.syncTarget_;
onChanged(); onChanged();
} }
if (other.hasBlocksCommunityMessageRequests()) {
setBlocksCommunityMessageRequests(other.getBlocksCommunityMessageRequests());
}
this.mergeUnknownFields(other.getUnknownFields()); this.mergeUnknownFields(other.getUnknownFields());
return this; return this;
} }
@ -16457,6 +16505,39 @@ public final class SignalServiceProtos {
return this; return this;
} }
// optional bool blocksCommunityMessageRequests = 106;
private boolean blocksCommunityMessageRequests_ ;
/**
* <code>optional bool blocksCommunityMessageRequests = 106;</code>
*/
public boolean hasBlocksCommunityMessageRequests() {
return ((bitField0_ & 0x00004000) == 0x00004000);
}
/**
* <code>optional bool blocksCommunityMessageRequests = 106;</code>
*/
public boolean getBlocksCommunityMessageRequests() {
return blocksCommunityMessageRequests_;
}
/**
* <code>optional bool blocksCommunityMessageRequests = 106;</code>
*/
public Builder setBlocksCommunityMessageRequests(boolean value) {
bitField0_ |= 0x00004000;
blocksCommunityMessageRequests_ = value;
onChanged();
return this;
}
/**
* <code>optional bool blocksCommunityMessageRequests = 106;</code>
*/
public Builder clearBlocksCommunityMessageRequests() {
bitField0_ = (bitField0_ & ~0x00004000);
blocksCommunityMessageRequests_ = false;
onChanged();
return this;
}
// @@protoc_insertion_point(builder_scope:signalservice.DataMessage) // @@protoc_insertion_point(builder_scope:signalservice.DataMessage)
} }
@ -27160,7 +27241,7 @@ public final class SignalServiceProtos {
"actionNotification\022<\n\004type\030\001 \002(\0162..signa" + "actionNotification\022<\n\004type\030\001 \002(\0162..signa" +
"lservice.DataExtractionNotification.Type" + "lservice.DataExtractionNotification.Type" +
"\022\021\n\ttimestamp\030\002 \001(\004\"\'\n\004Type\022\016\n\nSCREENSHO" + "\022\021\n\ttimestamp\030\002 \001(\004\"\'\n\004Type\022\016\n\nSCREENSHO" +
"T\020\001\022\017\n\013MEDIA_SAVED\020\002\"\361\r\n\013DataMessage\022\014\n\004", "T\020\001\022\017\n\013MEDIA_SAVED\020\002\"\231\016\n\013DataMessage\022\014\n\004",
"body\030\001 \001(\t\0225\n\013attachments\030\002 \003(\0132 .signal" + "body\030\001 \001(\t\0225\n\013attachments\030\002 \003(\0132 .signal" +
"service.AttachmentPointer\022*\n\005group\030\003 \001(\013" + "service.AttachmentPointer\022*\n\005group\030\003 \001(\013" +
"2\033.signalservice.GroupContext\022\r\n\005flags\030\004" + "2\033.signalservice.GroupContext\022\r\n\005flags\030\004" +
@ -27175,12 +27256,13 @@ public final class SignalServiceProtos {
"ice.DataMessage.OpenGroupInvitation\022W\n\031c" + "ice.DataMessage.OpenGroupInvitation\022W\n\031c" +
"losedGroupControlMessage\030h \001(\01324.signals" + "losedGroupControlMessage\030h \001(\01324.signals" +
"ervice.DataMessage.ClosedGroupControlMes" + "ervice.DataMessage.ClosedGroupControlMes" +
"sage\022\022\n\nsyncTarget\030i \001(\t\032\225\002\n\005Quote\022\n\n\002id" + "sage\022\022\n\nsyncTarget\030i \001(\t\022&\n\036blocksCommun" +
"ityMessageRequests\030j \001(\010\032\225\002\n\005Quote\022\n\n\002id" +
"\030\001 \002(\004\022\016\n\006author\030\002 \002(\t\022\014\n\004text\030\003 \001(\t\022F\n\013" + "\030\001 \002(\004\022\016\n\006author\030\002 \002(\t\022\014\n\004text\030\003 \001(\t\022F\n\013" +
"attachments\030\004 \003(\01321.signalservice.DataMe" + "attachments\030\004 \003(\01321.signalservice.DataMe" +
"ssage.Quote.QuotedAttachment\032\231\001\n\020QuotedA" + "ssage.Quote.QuotedAttachment\032\231\001\n\020QuotedA" +
"ttachment\022\023\n\013contentType\030\001 \001(\t\022\020\n\010fileNa" + "ttachment\022\023\n\013contentType\030\001 \001(\t\022\020\n\010fileNa",
"me\030\002 \001(\t\0223\n\tthumbnail\030\003 \001(\0132 .signalserv", "me\030\002 \001(\t\0223\n\tthumbnail\030\003 \001(\0132 .signalserv" +
"ice.AttachmentPointer\022\r\n\005flags\030\004 \001(\r\"\032\n\005" + "ice.AttachmentPointer\022\r\n\005flags\030\004 \001(\r\"\032\n\005" +
"Flags\022\021\n\rVOICE_MESSAGE\020\001\032V\n\007Preview\022\013\n\003u" + "Flags\022\021\n\rVOICE_MESSAGE\020\001\032V\n\007Preview\022\013\n\003u" +
"rl\030\001 \002(\t\022\r\n\005title\030\002 \001(\t\022/\n\005image\030\003 \001(\0132 " + "rl\030\001 \002(\t\022\r\n\005title\030\002 \001(\t\022/\n\005image\030\003 \001(\0132 " +
@ -27189,8 +27271,8 @@ public final class SignalServiceProtos {
"icture\030\002 \001(\t\0320\n\023OpenGroupInvitation\022\013\n\003u" + "icture\030\002 \001(\t\0320\n\023OpenGroupInvitation\022\013\n\003u" +
"rl\030\001 \002(\t\022\014\n\004name\030\003 \002(\t\032\374\003\n\031ClosedGroupCo" + "rl\030\001 \002(\t\022\014\n\004name\030\003 \002(\t\032\374\003\n\031ClosedGroupCo" +
"ntrolMessage\022G\n\004type\030\001 \002(\01629.signalservi" + "ntrolMessage\022G\n\004type\030\001 \002(\01629.signalservi" +
"ce.DataMessage.ClosedGroupControlMessage" + "ce.DataMessage.ClosedGroupControlMessage",
".Type\022\021\n\tpublicKey\030\002 \001(\014\022\014\n\004name\030\003 \001(\t\0221", ".Type\022\021\n\tpublicKey\030\002 \001(\014\022\014\n\004name\030\003 \001(\t\0221" +
"\n\021encryptionKeyPair\030\004 \001(\0132\026.signalservic" + "\n\021encryptionKeyPair\030\004 \001(\0132\026.signalservic" +
"e.KeyPair\022\017\n\007members\030\005 \003(\014\022\016\n\006admins\030\006 \003" + "e.KeyPair\022\017\n\007members\030\005 \003(\014\022\016\n\006admins\030\006 \003" +
"(\014\022U\n\010wrappers\030\007 \003(\0132C.signalservice.Dat" + "(\014\022U\n\010wrappers\030\007 \003(\0132C.signalservice.Dat" +
@ -27199,8 +27281,8 @@ public final class SignalServiceProtos {
"yPairWrapper\022\021\n\tpublicKey\030\001 \002(\014\022\030\n\020encry" + "yPairWrapper\022\021\n\tpublicKey\030\001 \002(\014\022\030\n\020encry" +
"ptedKeyPair\030\002 \002(\014\"r\n\004Type\022\007\n\003NEW\020\001\022\027\n\023EN" + "ptedKeyPair\030\002 \002(\014\"r\n\004Type\022\007\n\003NEW\020\001\022\027\n\023EN" +
"CRYPTION_KEY_PAIR\020\003\022\017\n\013NAME_CHANGE\020\004\022\021\n\r" + "CRYPTION_KEY_PAIR\020\003\022\017\n\013NAME_CHANGE\020\004\022\021\n\r" +
"MEMBERS_ADDED\020\005\022\023\n\017MEMBERS_REMOVED\020\006\022\017\n\013" + "MEMBERS_ADDED\020\005\022\023\n\017MEMBERS_REMOVED\020\006\022\017\n\013",
"MEMBER_LEFT\020\007\032\222\001\n\010Reaction\022\n\n\002id\030\001 \002(\004\022\016", "MEMBER_LEFT\020\007\032\222\001\n\010Reaction\022\n\n\002id\030\001 \002(\004\022\016" +
"\n\006author\030\002 \002(\t\022\r\n\005emoji\030\003 \001(\t\022:\n\006action\030" + "\n\006author\030\002 \002(\t\022\r\n\005emoji\030\003 \001(\t\022:\n\006action\030" +
"\004 \002(\0162*.signalservice.DataMessage.Reacti" + "\004 \002(\0162*.signalservice.DataMessage.Reacti" +
"on.Action\"\037\n\006Action\022\t\n\005REACT\020\000\022\n\n\006REMOVE" + "on.Action\"\037\n\006Action\022\t\n\005REACT\020\000\022\n\n\006REMOVE" +
@ -27209,8 +27291,8 @@ public final class SignalServiceProtos {
"ervice.CallMessage.Type\022\014\n\004sdps\030\002 \003(\t\022\027\n" + "ervice.CallMessage.Type\022\014\n\004sdps\030\002 \003(\t\022\027\n" +
"\017sdpMLineIndexes\030\003 \003(\r\022\017\n\007sdpMids\030\004 \003(\t\022" + "\017sdpMLineIndexes\030\003 \003(\r\022\017\n\007sdpMids\030\004 \003(\t\022" +
"\014\n\004uuid\030\005 \002(\t\"f\n\004Type\022\r\n\tPRE_OFFER\020\006\022\t\n\005" + "\014\n\004uuid\030\005 \002(\t\"f\n\004Type\022\r\n\tPRE_OFFER\020\006\022\t\n\005" +
"OFFER\020\001\022\n\n\006ANSWER\020\002\022\026\n\022PROVISIONAL_ANSWE" + "OFFER\020\001\022\n\n\006ANSWER\020\002\022\026\n\022PROVISIONAL_ANSWE",
"R\020\003\022\022\n\016ICE_CANDIDATES\020\004\022\014\n\010END_CALL\020\005\"\245\004", "R\020\003\022\022\n\016ICE_CANDIDATES\020\004\022\014\n\010END_CALL\020\005\"\245\004" +
"\n\024ConfigurationMessage\022E\n\014closedGroups\030\001" + "\n\024ConfigurationMessage\022E\n\014closedGroups\030\001" +
" \003(\0132/.signalservice.ConfigurationMessag" + " \003(\0132/.signalservice.ConfigurationMessag" +
"e.ClosedGroup\022\022\n\nopenGroups\030\002 \003(\t\022\023\n\013dis" + "e.ClosedGroup\022\022\n\nopenGroups\030\002 \003(\t\022\023\n\013dis" +
@ -27219,8 +27301,8 @@ public final class SignalServiceProtos {
"ignalservice.ConfigurationMessage.Contac" + "ignalservice.ConfigurationMessage.Contac" +
"t\032\233\001\n\013ClosedGroup\022\021\n\tpublicKey\030\001 \001(\014\022\014\n\004" + "t\032\233\001\n\013ClosedGroup\022\021\n\tpublicKey\030\001 \001(\014\022\014\n\004" +
"name\030\002 \001(\t\0221\n\021encryptionKeyPair\030\003 \001(\0132\026." + "name\030\002 \001(\t\0221\n\021encryptionKeyPair\030\003 \001(\0132\026." +
"signalservice.KeyPair\022\017\n\007members\030\004 \003(\014\022\016" + "signalservice.KeyPair\022\017\n\007members\030\004 \003(\014\022\016",
"\n\006admins\030\005 \003(\014\022\027\n\017expirationTimer\030\006 \001(\r\032", "\n\006admins\030\005 \003(\014\022\027\n\017expirationTimer\030\006 \001(\r\032" +
"\223\001\n\007Contact\022\021\n\tpublicKey\030\001 \002(\014\022\014\n\004name\030\002" + "\223\001\n\007Contact\022\021\n\tpublicKey\030\001 \002(\014\022\014\n\004name\030\002" +
" \002(\t\022\026\n\016profilePicture\030\003 \001(\t\022\022\n\nprofileK" + " \002(\t\022\026\n\016profilePicture\030\003 \001(\t\022\022\n\nprofileK" +
"ey\030\004 \001(\014\022\022\n\nisApproved\030\005 \001(\010\022\021\n\tisBlocke" + "ey\030\004 \001(\014\022\022\n\nisApproved\030\005 \001(\010\022\021\n\tisBlocke" +
@ -27229,8 +27311,8 @@ public final class SignalServiceProtos {
"rofileKey\030\002 \001(\014\0227\n\007profile\030\003 \001(\0132&.signa" + "rofileKey\030\002 \001(\014\0227\n\007profile\030\003 \001(\0132&.signa" +
"lservice.DataMessage.LokiProfile\"\375\001\n\023Sha" + "lservice.DataMessage.LokiProfile\"\375\001\n\023Sha" +
"redConfigMessage\0225\n\004kind\030\001 \002(\0162\'.signals" + "redConfigMessage\0225\n\004kind\030\001 \002(\0162\'.signals" +
"ervice.SharedConfigMessage.Kind\022\r\n\005seqno" + "ervice.SharedConfigMessage.Kind\022\r\n\005seqno",
"\030\002 \002(\003\022\014\n\004data\030\003 \002(\014\"\221\001\n\004Kind\022\020\n\014USER_PR", "\030\002 \002(\003\022\014\n\004data\030\003 \002(\014\"\221\001\n\004Kind\022\020\n\014USER_PR" +
"OFILE\020\001\022\014\n\010CONTACTS\020\002\022\027\n\023CONVO_INFO_VOLA" + "OFILE\020\001\022\014\n\010CONTACTS\020\002\022\027\n\023CONVO_INFO_VOLA" +
"TILE\020\003\022\n\n\006GROUPS\020\004\022\025\n\021CLOSED_GROUP_INFO\020" + "TILE\020\003\022\n\n\006GROUPS\020\004\022\025\n\021CLOSED_GROUP_INFO\020" +
"\005\022\030\n\024CLOSED_GROUP_MEMBERS\020\006\022\023\n\017ENCRYPTIO" + "\005\022\030\n\024CLOSED_GROUP_MEMBERS\020\006\022\023\n\017ENCRYPTIO" +
@ -27239,8 +27321,8 @@ public final class SignalServiceProtos {
"timestamp\030\002 \003(\004\"\036\n\004Type\022\014\n\010DELIVERY\020\000\022\010\n" + "timestamp\030\002 \003(\004\"\036\n\004Type\022\014\n\010DELIVERY\020\000\022\010\n" +
"\004READ\020\001\"\354\001\n\021AttachmentPointer\022\n\n\002id\030\001 \002(" + "\004READ\020\001\"\354\001\n\021AttachmentPointer\022\n\n\002id\030\001 \002(" +
"\006\022\023\n\013contentType\030\002 \001(\t\022\013\n\003key\030\003 \001(\014\022\014\n\004s" + "\006\022\023\n\013contentType\030\002 \001(\t\022\013\n\003key\030\003 \001(\014\022\014\n\004s" +
"ize\030\004 \001(\r\022\021\n\tthumbnail\030\005 \001(\014\022\016\n\006digest\030\006" + "ize\030\004 \001(\r\022\021\n\tthumbnail\030\005 \001(\014\022\016\n\006digest\030\006",
" \001(\014\022\020\n\010fileName\030\007 \001(\t\022\r\n\005flags\030\010 \001(\r\022\r\n", " \001(\014\022\020\n\010fileName\030\007 \001(\t\022\r\n\005flags\030\010 \001(\r\022\r\n" +
"\005width\030\t \001(\r\022\016\n\006height\030\n \001(\r\022\017\n\007caption\030" + "\005width\030\t \001(\r\022\016\n\006height\030\n \001(\r\022\017\n\007caption\030" +
"\013 \001(\t\022\013\n\003url\030e \001(\t\"\032\n\005Flags\022\021\n\rVOICE_MES" + "\013 \001(\t\022\013\n\003url\030e \001(\t\"\032\n\005Flags\022\021\n\rVOICE_MES" +
"SAGE\020\001\"\365\001\n\014GroupContext\022\n\n\002id\030\001 \001(\014\022.\n\004t" + "SAGE\020\001\"\365\001\n\014GroupContext\022\n\n\002id\030\001 \001(\014\022.\n\004t" +
@ -27249,7 +27331,7 @@ public final class SignalServiceProtos {
"atar\030\005 \001(\0132 .signalservice.AttachmentPoi" + "atar\030\005 \001(\0132 .signalservice.AttachmentPoi" +
"nter\022\016\n\006admins\030\006 \003(\t\"H\n\004Type\022\013\n\007UNKNOWN\020" + "nter\022\016\n\006admins\030\006 \003(\t\"H\n\004Type\022\013\n\007UNKNOWN\020" +
"\000\022\n\n\006UPDATE\020\001\022\013\n\007DELIVER\020\002\022\010\n\004QUIT\020\003\022\020\n\014" + "\000\022\n\n\006UPDATE\020\001\022\013\n\007DELIVER\020\002\022\010\n\004QUIT\020\003\022\020\n\014" +
"REQUEST_INFO\020\004B3\n\034org.session.libsignal." + "REQUEST_INFO\020\004B3\n\034org.session.libsignal.",
"protosB\023SignalServiceProtos" "protosB\023SignalServiceProtos"
}; };
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
@ -27298,7 +27380,7 @@ public final class SignalServiceProtos {
internal_static_signalservice_DataMessage_fieldAccessorTable = new internal_static_signalservice_DataMessage_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable( com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_signalservice_DataMessage_descriptor, internal_static_signalservice_DataMessage_descriptor,
new java.lang.String[] { "Body", "Attachments", "Group", "Flags", "ExpireTimer", "ProfileKey", "Timestamp", "Quote", "Preview", "Reaction", "Profile", "OpenGroupInvitation", "ClosedGroupControlMessage", "SyncTarget", }); new java.lang.String[] { "Body", "Attachments", "Group", "Flags", "ExpireTimer", "ProfileKey", "Timestamp", "Quote", "Preview", "Reaction", "Profile", "OpenGroupInvitation", "ClosedGroupControlMessage", "SyncTarget", "BlocksCommunityMessageRequests", });
internal_static_signalservice_DataMessage_Quote_descriptor = internal_static_signalservice_DataMessage_Quote_descriptor =
internal_static_signalservice_DataMessage_descriptor.getNestedTypes().get(0); internal_static_signalservice_DataMessage_descriptor.getNestedTypes().get(0);
internal_static_signalservice_DataMessage_Quote_fieldAccessorTable = new internal_static_signalservice_DataMessage_Quote_fieldAccessorTable = new